Created
March 25, 2010 02:53
-
-
Save 7shi/343115 to your computer and use it in GitHub Desktop.
F# Interactiveの改造
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#light | |
namespace Microsoft.FSharp.Compiler.Interactive | |
open System | |
open System.IO | |
open System.Text | |
open System.Collections.Generic | |
type ReadLineConsole(complete: (string option * string -> seq<string>)) as this = | |
let history = new List<string>() | |
let log = Path.Combine(Directory.GetCurrentDirectory(), "log.fsx") | |
let mutable complete = complete | |
do | |
if File.Exists(log) then this.AppendLog("") | |
this.AppendLog("// " + DateTime.Now.ToString()) | |
member x.Complete with set(v) = (complete <- v) | |
member x.Prompt = "> " | |
member x.ReadLine() = | |
let count(s : string, ch : char) = | |
let mutable ret = 0 | |
for c in s do if c = ch then ret <- ret + 1 | |
ret | |
let getWords(s : string) = | |
let ret = new List<string>() | |
let rec getWords(p1, p2) = | |
if p2 >= s.Length || not (Char.IsLetterOrDigit(s.[p2])) then | |
if p1 < p2 then ret.Add(s.Substring(p1, p2 - p1)) | |
if p2 < s.Length then getWords(p2 + 1, p2 + 1) | |
else | |
getWords(p1, p2 + 1) | |
getWords(0, 0) | |
ret | |
let lines = ref 0 | |
let p1 = ref 0 | |
let p2 = ref 0 | |
let sb = new StringBuilder() | |
let rec readLine(indent : string) = | |
if indent <> "" || !lines > 0 then | |
Console.Write(indent + "- ") | |
let line = Console.ReadLine().Trim() | |
if indent = "" && line = "#h" then | |
for cmd in history do Console.WriteLine(cmd) | |
Console.Write(x.Prompt) | |
readLine(indent) | |
else if indent = "" && line.StartsWith("#cd ") then | |
Directory.SetCurrentDirectory(line.Substring(4)); | |
Console.Write(x.Prompt) | |
readLine(indent) | |
else if indent = "" && line = "#pwd" then | |
Console.WriteLine(Directory.GetCurrentDirectory()) | |
Console.Write(x.Prompt) | |
readLine(indent) | |
else if indent = "" && line = "#dir" then | |
let di = new DirectoryInfo(Directory.GetCurrentDirectory()) | |
Console.WriteLine(di.FullName) | |
for di in di.GetDirectories() do | |
Console.WriteLine("{0}/", di) | |
for fi in di.GetFiles() do | |
Console.WriteLine(fi) | |
Console.Write(x.Prompt) | |
readLine(indent) | |
else if String.IsNullOrEmpty(line) then | |
() | |
else | |
if sb.Length > 0 then sb.AppendLine() |> ignore | |
sb.Append(indent + line) |> ignore | |
lines := !lines + 1 | |
if line.StartsWith("//") then | |
readLine(indent) | |
else | |
let d1 = count(line, '(') - count(line, ')') | |
let d2 = count(line, '[') - count(line, ']') | |
p1 := !p1 + d1 | |
p2 := !p2 + d2 | |
let words = getWords(line) | |
let w1 = if words.Count > 0 then words.[words.Count - 1] else "" | |
if (!p1 <> 0 && d1 <> 0) || (!p2 <> 0 && d2 <> 0) | |
|| line.EndsWith("=") || line.EndsWith("->") | |
|| w1 = "in" || w1 = "do" || w1 = "then" || w1 = "else" | |
then | |
readLine(indent + " ") | |
let w2 = if words.Count > 0 then words.[0] else "" | |
if !p1 <> 0 || !p2 <> 0 || indent <> "" | |
|| (line.EndsWith(";") && not(line.EndsWith(";;"))) | |
|| (w2 = "if" && not(words.Contains("then") && words.Contains("else"))) | |
|| w2 = "match" | |
then | |
readLine(indent) | |
readLine("") | |
let ret = sb.ToString() | |
history.Add(ret) | |
x.AppendLog(ret) | |
if ret.EndsWith(";;") then | |
ret | |
else | |
if !lines = 1 then | |
ret + ";;" | |
else | |
ret + Environment.NewLine + ";;" | |
member x.AppendLog(cmd : string) = | |
use fs = new FileStream(log, FileMode.Append) | |
use sw = new StreamWriter(fs) | |
sw.WriteLine(cmd) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment