Move implementations into impls/ dir
[jackhill/mal.git] / vb / getline.cs
diff --git a/vb/getline.cs b/vb/getline.cs
deleted file mode 100644 (file)
index c11a11d..0000000
+++ /dev/null
@@ -1,1089 +0,0 @@
-//
-// getline.cs: A command line editor
-//
-// Authors:
-//   Miguel de Icaza (miguel@novell.com)
-//
-// Copyright 2008 Novell, Inc.
-//
-// Dual-licensed under the terms of the MIT X11 license or the
-// Apache License 2.0
-//
-// USE -define:DEMO to build this as a standalone file and test it
-//
-// TODO:
-//    Enter an error (a = 1);  Notice how the prompt is in the wrong line
-//             This is caused by Stderr not being tracked by System.Console.
-//    Completion support
-//    Why is Thread.Interrupt not working?   Currently I resort to Abort which is too much.
-//
-// Limitations in System.Console:
-//    Console needs SIGWINCH support of some sort
-//    Console needs a way of updating its position after things have been written
-//    behind its back (P/Invoke puts for example).
-//    System.Console needs to get the DELETE character, and report accordingly.
-//
-
-using System;
-using System.Text;
-using System.IO;
-using System.Threading;
-using System.Reflection;
-
-namespace Mono.Terminal {
-
-       public class LineEditor {
-
-               public class Completion {
-                       public string [] Result;
-                       public string Prefix;
-
-                       public Completion (string prefix, string [] result)
-                       {
-                               Prefix = prefix;
-                               Result = result;
-                       }
-               }
-               
-               public delegate Completion AutoCompleteHandler (string text, int pos);
-               
-               //static StreamWriter log;
-               
-               // The text being edited.
-               StringBuilder text;
-
-               // The text as it is rendered (replaces (char)1 with ^A on display for example).
-               StringBuilder rendered_text;
-
-               // The prompt specified, and the prompt shown to the user.
-               string prompt;
-               string shown_prompt;
-               
-               // The current cursor position, indexes into "text", for an index
-               // into rendered_text, use TextToRenderPos
-               int cursor;
-
-               // The row where we started displaying data.
-               int home_row;
-
-               // The maximum length that has been displayed on the screen
-               int max_rendered;
-
-               // If we are done editing, this breaks the interactive loop
-               bool done = false;
-
-               // The thread where the Editing started taking place
-               Thread edit_thread;
-
-               // Our object that tracks history
-               History history;
-
-               // The contents of the kill buffer (cut/paste in Emacs parlance)
-               string kill_buffer = "";
-
-               // The string being searched for
-               string search;
-               string last_search;
-
-               // whether we are searching (-1= reverse; 0 = no; 1 = forward)
-               int searching;
-
-               // The position where we found the match.
-               int match_at;
-               
-               // Used to implement the Kill semantics (multiple Alt-Ds accumulate)
-               KeyHandler last_handler;
-               
-               delegate void KeyHandler ();
-               
-               struct Handler {
-                       public ConsoleKeyInfo CKI;
-                       public KeyHandler KeyHandler;
-
-                       public Handler (ConsoleKey key, KeyHandler h)
-                       {
-                               CKI = new ConsoleKeyInfo ((char) 0, key, false, false, false);
-                               KeyHandler = h;
-                       }
-
-                       public Handler (char c, KeyHandler h)
-                       {
-                               KeyHandler = h;
-                               // Use the "Zoom" as a flag that we only have a character.
-                               CKI = new ConsoleKeyInfo (c, ConsoleKey.Zoom, false, false, false);
-                       }
-
-                       public Handler (ConsoleKeyInfo cki, KeyHandler h)
-                       {
-                               CKI = cki;
-                               KeyHandler = h;
-                       }
-                       
-                       public static Handler Control (char c, KeyHandler h)
-                       {
-                               return new Handler ((char) (c - 'A' + 1), h);
-                       }
-
-                       public static Handler Alt (char c, ConsoleKey k, KeyHandler h)
-                       {
-                               ConsoleKeyInfo cki = new ConsoleKeyInfo ((char) c, k, false, true, false);
-                               return new Handler (cki, h);
-                       }
-               }
-
-               /// <summary>
-               ///   Invoked when the user requests auto-completion using the tab character
-               /// </summary>
-               /// <remarks>
-               ///    The result is null for no values found, an array with a single
-               ///    string, in that case the string should be the text to be inserted
-               ///    for example if the word at pos is "T", the result for a completion
-               ///    of "ToString" should be "oString", not "ToString".
-               ///
-               ///    When there are multiple results, the result should be the full
-               ///    text
-               /// </remarks>
-               public AutoCompleteHandler AutoCompleteEvent;
-               
-               static Handler [] handlers;
-
-               public LineEditor (string name) : this (name, 10) { }
-               
-               public LineEditor (string name, int histsize)
-               {
-                       handlers = new Handler [] {
-                               new Handler (ConsoleKey.Home,       CmdHome),
-                               new Handler (ConsoleKey.End,        CmdEnd),
-                               new Handler (ConsoleKey.LeftArrow,  CmdLeft),
-                               new Handler (ConsoleKey.RightArrow, CmdRight),
-                               new Handler (ConsoleKey.UpArrow,    CmdHistoryPrev),
-                               new Handler (ConsoleKey.DownArrow,  CmdHistoryNext),
-                               new Handler (ConsoleKey.Enter,      CmdDone),
-                               new Handler (ConsoleKey.Backspace,  CmdBackspace),
-                               new Handler (ConsoleKey.Delete,     CmdDeleteChar),
-                               new Handler (ConsoleKey.Tab,        CmdTabOrComplete),
-                               
-                               // Emacs keys
-                               Handler.Control ('A', CmdHome),
-                               Handler.Control ('E', CmdEnd),
-                               Handler.Control ('B', CmdLeft),
-                               Handler.Control ('F', CmdRight),
-                               Handler.Control ('P', CmdHistoryPrev),
-                               Handler.Control ('N', CmdHistoryNext),
-                               Handler.Control ('K', CmdKillToEOF),
-                               Handler.Control ('Y', CmdYank),
-                               Handler.Control ('D', CmdDeleteChar),
-                               Handler.Control ('L', CmdRefresh),
-                               Handler.Control ('R', CmdReverseSearch),
-                               Handler.Control ('G', delegate {} ),
-                               Handler.Alt ('B', ConsoleKey.B, CmdBackwardWord),
-                               Handler.Alt ('F', ConsoleKey.F, CmdForwardWord),
-                               
-                               Handler.Alt ('D', ConsoleKey.D, CmdDeleteWord),
-                               Handler.Alt ((char) 8, ConsoleKey.Backspace, CmdDeleteBackword),
-                               
-                               // DEBUG
-                               //Handler.Control ('T', CmdDebug),
-
-                               // quote
-                               Handler.Control ('Q', delegate { HandleChar (Console.ReadKey (true).KeyChar); })
-                       };
-
-                       rendered_text = new StringBuilder ();
-                       text = new StringBuilder ();
-
-                       history = new History (name, histsize);
-                       
-                       //if (File.Exists ("log"))File.Delete ("log");
-                       //log = File.CreateText ("log"); 
-               }
-
-               void CmdDebug ()
-               {
-                       history.Dump ();
-                       Console.WriteLine ();
-                       Render ();
-               }
-
-               void Render ()
-               {
-                       Console.Write (shown_prompt);
-                       Console.Write (rendered_text);
-
-                       int max = System.Math.Max (rendered_text.Length + shown_prompt.Length, max_rendered);
-                       
-                       for (int i = rendered_text.Length + shown_prompt.Length; i < max_rendered; i++)
-                               Console.Write (' ');
-                       max_rendered = shown_prompt.Length + rendered_text.Length;
-
-                       // Write one more to ensure that we always wrap around properly if we are at the
-                       // end of a line.
-                       Console.Write (' ');
-
-                       UpdateHomeRow (max);
-               }
-
-               void UpdateHomeRow (int screenpos)
-               {
-                       int lines = 1 + (screenpos / Console.WindowWidth);
-
-                       home_row = Console.CursorTop - (lines - 1);
-                       if (home_row < 0)
-                               home_row = 0;
-               }
-               
-
-               void RenderFrom (int pos)
-               {
-                       int rpos = TextToRenderPos (pos);
-                       int i;
-                       
-                       for (i = rpos; i < rendered_text.Length; i++)
-                               Console.Write (rendered_text [i]);
-
-                       if ((shown_prompt.Length + rendered_text.Length) > max_rendered)
-                               max_rendered = shown_prompt.Length + rendered_text.Length;
-                       else {
-                               int max_extra = max_rendered - shown_prompt.Length;
-                               for (; i < max_extra; i++)
-                                       Console.Write (' ');
-                       }
-               }
-
-               void ComputeRendered ()
-               {
-                       rendered_text.Length = 0;
-
-                       for (int i = 0; i < text.Length; i++){
-                               int c = (int) text [i];
-                               if (c < 26){
-                                       if (c == '\t')
-                                               rendered_text.Append ("    ");
-                                       else {
-                                               rendered_text.Append ('^');
-                                               rendered_text.Append ((char) (c + (int) 'A' - 1));
-                                       }
-                               } else
-                                       rendered_text.Append ((char)c);
-                       }
-               }
-
-               int TextToRenderPos (int pos)
-               {
-                       int p = 0;
-
-                       for (int i = 0; i < pos; i++){
-                               int c;
-
-                               c = (int) text [i];
-                               
-                               if (c < 26){
-                                       if (c == 9)
-                                               p += 4;
-                                       else
-                                               p += 2;
-                               } else
-                                       p++;
-                       }
-
-                       return p;
-               }
-
-               int TextToScreenPos (int pos)
-               {
-                       return shown_prompt.Length + TextToRenderPos (pos);
-               }
-               
-               string Prompt {
-                       get { return prompt; }
-                       set { prompt = value; }
-               }
-
-               int LineCount {
-                       get {
-                               return (shown_prompt.Length + rendered_text.Length)/Console.WindowWidth;
-                       }
-               }
-               
-               void ForceCursor (int newpos)
-               {
-                       cursor = newpos;
-
-                       int actual_pos = shown_prompt.Length + TextToRenderPos (cursor);
-                       int row = home_row + (actual_pos/Console.WindowWidth);
-                       int col = actual_pos % Console.WindowWidth;
-
-                       if (row >= Console.BufferHeight)
-                               row = Console.BufferHeight-1;
-                       Console.SetCursorPosition (col, row);
-                       
-                       //log.WriteLine ("Going to cursor={0} row={1} col={2} actual={3} prompt={4} ttr={5} old={6}", newpos, row, col, actual_pos, prompt.Length, TextToRenderPos (cursor), cursor);
-                       //log.Flush ();
-               }
-
-               void UpdateCursor (int newpos)
-               {
-                       if (cursor == newpos)
-                               return;
-
-                       ForceCursor (newpos);
-               }
-
-               void InsertChar (char c)
-               {
-                       int prev_lines = LineCount;
-                       text = text.Insert (cursor, c);
-                       ComputeRendered ();
-                       if (prev_lines != LineCount){
-
-                               Console.SetCursorPosition (0, home_row);
-                               Render ();
-                               ForceCursor (++cursor);
-                       } else {
-                               RenderFrom (cursor);
-                               ForceCursor (++cursor);
-                               UpdateHomeRow (TextToScreenPos (cursor));
-                       }
-               }
-
-               //
-               // Commands
-               //
-               void CmdDone ()
-               {
-                       done = true;
-               }
-
-               void CmdTabOrComplete ()
-               {
-                       bool complete = false;
-
-                       if (AutoCompleteEvent != null){
-                               if (TabAtStartCompletes)
-                                       complete = true;
-                               else {
-                                       for (int i = 0; i < cursor; i++){
-                                               if (!Char.IsWhiteSpace (text [i])){
-                                                       complete = true;
-                                                       break;
-                                               }
-                                       }
-                               }
-
-                               if (complete){
-                                       Completion completion = AutoCompleteEvent (text.ToString (), cursor);
-                                       string [] completions = completion.Result;
-                                       if (completions == null)
-                                               return;
-                                       
-                                       int ncompletions = completions.Length;
-                                       if (ncompletions == 0)
-                                               return;
-                                       
-                                       if (completions.Length == 1){
-                                               InsertTextAtCursor (completions [0]);
-                                       } else {
-                                               int last = -1;
-                                               
-                                               for (int p = 0; p < completions [0].Length; p++){
-                                                       char c = completions [0][p];
-
-
-                                                       for (int i = 1; i < ncompletions; i++){
-                                                               if (completions [i].Length < p)
-                                                                       goto mismatch;
-                                                       
-                                                               if (completions [i][p] != c){
-                                                                       goto mismatch;
-                                                               }
-                                                       }
-                                                       last = p;
-                                               }
-                                       mismatch:
-                                               if (last != -1){
-                                                       InsertTextAtCursor (completions [0].Substring (0, last+1));
-                                               }
-                                               Console.WriteLine ();
-                                               foreach (string s in completions){
-                                                       Console.Write (completion.Prefix);
-                                                       Console.Write (s);
-                                                       Console.Write (' ');
-                                               }
-                                               Console.WriteLine ();
-                                               Render ();
-                                               ForceCursor (cursor);
-                                       }
-                               } else
-                                       HandleChar ('\t');
-                       } else
-                               HandleChar ('t');
-               }
-               
-               void CmdHome ()
-               {
-                       UpdateCursor (0);
-               }
-
-               void CmdEnd ()
-               {
-                       UpdateCursor (text.Length);
-               }
-               
-               void CmdLeft ()
-               {
-                       if (cursor == 0)
-                               return;
-
-                       UpdateCursor (cursor-1);
-               }
-
-               void CmdBackwardWord ()
-               {
-                       int p = WordBackward (cursor);
-                       if (p == -1)
-                               return;
-                       UpdateCursor (p);
-               }
-
-               void CmdForwardWord ()
-               {
-                       int p = WordForward (cursor);
-                       if (p == -1)
-                               return;
-                       UpdateCursor (p);
-               }
-
-               void CmdRight ()
-               {
-                       if (cursor == text.Length)
-                               return;
-
-                       UpdateCursor (cursor+1);
-               }
-
-               void RenderAfter (int p)
-               {
-                       ForceCursor (p);
-                       RenderFrom (p);
-                       ForceCursor (cursor);
-               }
-               
-               void CmdBackspace ()
-               {
-                       if (cursor == 0)
-                               return;
-
-                       text.Remove (--cursor, 1);
-                       ComputeRendered ();
-                       RenderAfter (cursor);
-               }
-
-               void CmdDeleteChar ()
-               {
-                       // If there is no input, this behaves like EOF
-                       if (text.Length == 0){
-                               done = true;
-                               text = null;
-                               Console.WriteLine ();
-                               return;
-                       }
-                       
-                       if (cursor == text.Length)
-                               return;
-                       text.Remove (cursor, 1);
-                       ComputeRendered ();
-                       RenderAfter (cursor);
-               }
-
-               int WordForward (int p)
-               {
-                       if (p >= text.Length)
-                               return -1;
-
-                       int i = p;
-                       if (Char.IsPunctuation (text [p]) || Char.IsSymbol (text [p]) || Char.IsWhiteSpace (text[p])){
-                               for (; i < text.Length; i++){
-                                       if (Char.IsLetterOrDigit (text [i]))
-                                           break;
-                               }
-                               for (; i < text.Length; i++){
-                                       if (!Char.IsLetterOrDigit (text [i]))
-                                           break;
-                               }
-                       } else {
-                               for (; i < text.Length; i++){
-                                       if (!Char.IsLetterOrDigit (text [i]))
-                                           break;
-                               }
-                       }
-                       if (i != p)
-                               return i;
-                       return -1;
-               }
-
-               int WordBackward (int p)
-               {
-                       if (p == 0)
-                               return -1;
-
-                       int i = p-1;
-                       if (i == 0)
-                               return 0;
-                       
-                       if (Char.IsPunctuation (text [i]) || Char.IsSymbol (text [i]) || Char.IsWhiteSpace (text[i])){
-                               for (; i >= 0; i--){
-                                       if (Char.IsLetterOrDigit (text [i]))
-                                               break;
-                               }
-                               for (; i >= 0; i--){
-                                       if (!Char.IsLetterOrDigit (text[i]))
-                                               break;
-                               }
-                       } else {
-                               for (; i >= 0; i--){
-                                       if (!Char.IsLetterOrDigit (text [i]))
-                                               break;
-                               }
-                       }
-                       i++;
-                       
-                       if (i != p)
-                               return i;
-
-                       return -1;
-               }
-               
-               void CmdDeleteWord ()
-               {
-                       int pos = WordForward (cursor);
-
-                       if (pos == -1)
-                               return;
-
-                       string k = text.ToString (cursor, pos-cursor);
-                       
-                       if (last_handler == CmdDeleteWord)
-                               kill_buffer = kill_buffer + k;
-                       else
-                               kill_buffer = k;
-                       
-                       text.Remove (cursor, pos-cursor);
-                       ComputeRendered ();
-                       RenderAfter (cursor);
-               }
-               
-               void CmdDeleteBackword ()
-               {
-                       int pos = WordBackward (cursor);
-                       if (pos == -1)
-                               return;
-
-                       string k = text.ToString (pos, cursor-pos);
-                       
-                       if (last_handler == CmdDeleteBackword)
-                               kill_buffer = k + kill_buffer;
-                       else
-                               kill_buffer = k;
-                       
-                       text.Remove (pos, cursor-pos);
-                       ComputeRendered ();
-                       RenderAfter (pos);
-               }
-               
-               //
-               // Adds the current line to the history if needed
-               //
-               void HistoryUpdateLine ()
-               {
-                       history.Update (text.ToString ());
-               }
-               
-               void CmdHistoryPrev ()
-               {
-                       if (!history.PreviousAvailable ())
-                               return;
-
-                       HistoryUpdateLine ();
-                       
-                       SetText (history.Previous ());
-               }
-
-               void CmdHistoryNext ()
-               {
-                       if (!history.NextAvailable())
-                               return;
-
-                       history.Update (text.ToString ());
-                       SetText (history.Next ());
-                       
-               }
-
-               void CmdKillToEOF ()
-               {
-                       kill_buffer = text.ToString (cursor, text.Length-cursor);
-                       text.Length = cursor;
-                       ComputeRendered ();
-                       RenderAfter (cursor);
-               }
-
-               void CmdYank ()
-               {
-                       InsertTextAtCursor (kill_buffer);
-               }
-
-               void InsertTextAtCursor (string str)
-               {
-                       int prev_lines = LineCount;
-                       text.Insert (cursor, str);
-                       ComputeRendered ();
-                       if (prev_lines != LineCount){
-                               Console.SetCursorPosition (0, home_row);
-                               Render ();
-                               cursor += str.Length;
-                               ForceCursor (cursor);
-                       } else {
-                               RenderFrom (cursor);
-                               cursor += str.Length;
-                               ForceCursor (cursor);
-                               UpdateHomeRow (TextToScreenPos (cursor));
-                       }
-               }
-               
-               void SetSearchPrompt (string s)
-               {
-                       SetPrompt ("(reverse-i-search)`" + s + "': ");
-               }
-
-               void ReverseSearch ()
-               {
-                       int p;
-
-                       if (cursor == text.Length){
-                               // The cursor is at the end of the string
-                               
-                               p = text.ToString ().LastIndexOf (search);
-                               if (p != -1){
-                                       match_at = p;
-                                       cursor = p;
-                                       ForceCursor (cursor);
-                                       return;
-                               }
-                       } else {
-                               // The cursor is somewhere in the middle of the string
-                               int start = (cursor == match_at) ? cursor - 1 : cursor;
-                               if (start != -1){
-                                       p = text.ToString ().LastIndexOf (search, start);
-                                       if (p != -1){
-                                               match_at = p;
-                                               cursor = p;
-                                               ForceCursor (cursor);
-                                               return;
-                                       }
-                               }
-                       }
-
-                       // Need to search backwards in history
-                       HistoryUpdateLine ();
-                       string s = history.SearchBackward (search);
-                       if (s != null){
-                               match_at = -1;
-                               SetText (s);
-                               ReverseSearch ();
-                       }
-               }
-               
-               void CmdReverseSearch ()
-               {
-                       if (searching == 0){
-                               match_at = -1;
-                               last_search = search;
-                               searching = -1;
-                               search = "";
-                               SetSearchPrompt ("");
-                       } else {
-                               if (search == ""){
-                                       if (last_search != "" && last_search != null){
-                                               search = last_search;
-                                               SetSearchPrompt (search);
-
-                                               ReverseSearch ();
-                                       }
-                                       return;
-                               }
-                               ReverseSearch ();
-                       } 
-               }
-
-               void SearchAppend (char c)
-               {
-                       search = search + c;
-                       SetSearchPrompt (search);
-
-                       //
-                       // If the new typed data still matches the current text, stay here
-                       //
-                       if (cursor < text.Length){
-                               string r = text.ToString (cursor, text.Length - cursor);
-                               if (r.StartsWith (search))
-                                       return;
-                       }
-
-                       ReverseSearch ();
-               }
-               
-               void CmdRefresh ()
-               {
-                       Console.Clear ();
-                       max_rendered = 0;
-                       Render ();
-                       ForceCursor (cursor);
-               }
-
-               void InterruptEdit (object sender, ConsoleCancelEventArgs a)
-               {
-                       // Do not abort our program:
-                       a.Cancel = true;
-
-                       // Interrupt the editor
-                       edit_thread.Abort();
-               }
-
-               void HandleChar (char c)
-               {
-                       if (searching != 0)
-                               SearchAppend (c);
-                       else
-                               InsertChar (c);
-               }
-
-               void EditLoop ()
-               {
-                       ConsoleKeyInfo cki;
-
-                       while (!done){
-                               ConsoleModifiers mod;
-                               
-                               cki = Console.ReadKey (true);
-                               if (cki.Key == ConsoleKey.Escape){
-                                       cki = Console.ReadKey (true);
-
-                                       mod = ConsoleModifiers.Alt;
-                               } else
-                                       mod = cki.Modifiers;
-                               
-                               bool handled = false;
-
-                               foreach (Handler handler in handlers){
-                                       ConsoleKeyInfo t = handler.CKI;
-
-                                       if (t.Key == cki.Key && t.Modifiers == mod){
-                                               handled = true;
-                                               handler.KeyHandler ();
-                                               last_handler = handler.KeyHandler;
-                                               break;
-                                       } else if (t.KeyChar == cki.KeyChar && t.Key == ConsoleKey.Zoom){
-                                               handled = true;
-                                               handler.KeyHandler ();
-                                               last_handler = handler.KeyHandler;
-                                               break;
-                                       }
-                               }
-                               if (handled){
-                                       if (searching != 0){
-                                               if (last_handler != CmdReverseSearch){
-                                                       searching = 0;
-                                                       SetPrompt (prompt);
-                                               }
-                                       }
-                                       continue;
-                               }
-
-                               if (cki.KeyChar != (char) 0)
-                                       HandleChar (cki.KeyChar);
-                       } 
-               }
-
-               void InitText (string initial)
-               {
-                       text = new StringBuilder (initial);
-                       ComputeRendered ();
-                       cursor = text.Length;
-                       Render ();
-                       ForceCursor (cursor);
-               }
-
-               void SetText (string newtext)
-               {
-                       Console.SetCursorPosition (0, home_row);
-                       InitText (newtext);
-               }
-
-               void SetPrompt (string newprompt)
-               {
-                       shown_prompt = newprompt;
-                       Console.SetCursorPosition (0, home_row);
-                       Render ();
-                       ForceCursor (cursor);
-               }
-               
-               public string Edit (string prompt, string initial)
-               {
-                       edit_thread = Thread.CurrentThread;
-                       searching = 0;
-                       Console.CancelKeyPress += InterruptEdit;
-                       
-                       done = false;
-                       history.CursorToEnd ();
-                       max_rendered = 0;
-                       
-                       Prompt = prompt;
-                       shown_prompt = prompt;
-                       InitText (initial);
-                       history.Append (initial);
-
-                       do {
-                               try {
-                                       EditLoop ();
-                               } catch (ThreadAbortException){
-                                       searching = 0;
-                                       Thread.ResetAbort ();
-                                       Console.WriteLine ();
-                                       SetPrompt (prompt);
-                                       SetText ("");
-                               }
-                       } while (!done);
-                       Console.WriteLine ();
-                       
-                       Console.CancelKeyPress -= InterruptEdit;
-
-                       if (text == null){
-                               history.Close ();
-                               return null;
-                       }
-
-                       string result = text.ToString ();
-                       if (result != "")
-                               history.Accept (result);
-                       else
-                               history.RemoveLast ();
-
-                       return result;
-               }
-               
-               public void SaveHistory ()
-               {
-                       if (history != null) {
-                               history.Close ();
-                       }
-               }
-
-               public bool TabAtStartCompletes { get; set; }
-                       
-               //
-               // Emulates the bash-like behavior, where edits done to the
-               // history are recorded
-               //
-               class History {
-                       string [] history;
-                       int head, tail;
-                       int cursor, count;
-                       string histfile;
-                       
-                       public History (string app, int size)
-                       {
-                               if (size < 1)
-                                       throw new ArgumentException ("size");
-
-                               if (app != null){
-                                       string dir = Environment.GetFolderPath (Environment.SpecialFolder.Personal);
-                                       //Console.WriteLine (dir);
-                                       /*
-                                       if (!Directory.Exists (dir)){
-                                               try {
-                                                       Directory.CreateDirectory (dir);
-                                               } catch {
-                                                       app = null;
-                                               }
-                                       }
-                                       if (app != null)
-                                               histfile = Path.Combine (dir, app) + ".history";
-                                       */
-                                       histfile = Path.Combine (dir, ".mal-history");
-                               }
-                               
-                               history = new string [size];
-                               head = tail = cursor = 0;
-
-                               if (File.Exists (histfile)){
-                                       using (StreamReader sr = File.OpenText (histfile)){
-                                               string line;
-                                               
-                                               while ((line = sr.ReadLine ()) != null){
-                                                       if (line != "")
-                                                               Append (line);
-                                               }
-                                       }
-                               }
-                       }
-
-                       public void Close ()
-                       {
-                               if (histfile == null)
-                                       return;
-
-                               try {
-                                       using (StreamWriter sw = File.CreateText (histfile)){
-                                               int start = (count == history.Length) ? head : tail;
-                                               for (int i = start; i < start+count; i++){
-                                                       int p = i % history.Length;
-                                                       sw.WriteLine (history [p]);
-                                               }
-                                       }
-                               } catch {
-                                       // ignore
-                               }
-                       }
-                       
-                       //
-                       // Appends a value to the history
-                       //
-                       public void Append (string s)
-                       {
-                               //Console.WriteLine ("APPENDING {0} head={1} tail={2}", s, head, tail);
-                               history [head] = s;
-                               head = (head+1) % history.Length;
-                               if (head == tail)
-                                       tail = (tail+1 % history.Length);
-                               if (count != history.Length)
-                                       count++;
-                               //Console.WriteLine ("DONE: head={1} tail={2}", s, head, tail);
-                       }
-
-                       //
-                       // Updates the current cursor location with the string,
-                       // to support editing of history items.   For the current
-                       // line to participate, an Append must be done before.
-                       //
-                       public void Update (string s)
-                       {
-                               history [cursor] = s;
-                       }
-
-                       public void RemoveLast ()
-                       {
-                               head = head-1;
-                               if (head < 0)
-                                       head = history.Length-1;
-                       }
-                       
-                       public void Accept (string s)
-                       {
-                               int t = head-1;
-                               if (t < 0)
-                                       t = history.Length-1;
-                               
-                               history [t] = s;
-                       }
-                       
-                       public bool PreviousAvailable ()
-                       {
-                               //Console.WriteLine ("h={0} t={1} cursor={2}", head, tail, cursor);
-                               if (count == 0)
-                                       return false;
-                               int next = cursor-1;
-                               if (next < 0)
-                                       next = count-1;
-
-                               if (next == head)
-                                       return false;
-
-                               return true;
-                       }
-
-                       public bool NextAvailable ()
-                       {
-                               if (count == 0)
-                                       return false;
-                               int next = (cursor + 1) % history.Length;
-                               if (next == head)
-                                       return false;
-                               return true;
-                       }
-                       
-                       
-                       //
-                       // Returns: a string with the previous line contents, or
-                       // nul if there is no data in the history to move to.
-                       //
-                       public string Previous ()
-                       {
-                               if (!PreviousAvailable ())
-                                       return null;
-
-                               cursor--;
-                               if (cursor < 0)
-                                       cursor = history.Length - 1;
-
-                               return history [cursor];
-                       }
-
-                       public string Next ()
-                       {
-                               if (!NextAvailable ())
-                                       return null;
-
-                               cursor = (cursor + 1) % history.Length;
-                               return history [cursor];
-                       }
-
-                       public void CursorToEnd ()
-                       {
-                               if (head == tail)
-                                       return;
-
-                               cursor = head;
-                       }
-
-                       public void Dump ()
-                       {
-                               Console.WriteLine ("Head={0} Tail={1} Cursor={2} count={3}", head, tail, cursor, count);
-                               for (int i = 0; i < history.Length;i++){
-                                       Console.WriteLine (" {0} {1}: {2}", i == cursor ? "==>" : "   ", i, history[i]);
-                               }
-                               //log.Flush ();
-                       }
-
-                       public string SearchBackward (string term)
-                       {
-                               for (int i = 0; i < count; i++){
-                                       int slot = cursor-i-1;
-                                       if (slot < 0)
-                                               slot = history.Length+slot;
-                                       if (slot >= history.Length)
-                                               slot = 0;
-                                       if (history [slot] != null && history [slot].IndexOf (term) != -1){
-                                               cursor = slot;
-                                               return history [slot];
-                                       }
-                               }
-
-                               return null;
-                       }
-                       
-               }
-       }
-
-#if DEMO
-       class Demo {
-               static void Main ()
-               {
-                       LineEditor le = new LineEditor ("foo");
-                       string s;
-                       
-                       while ((s = le.Edit ("shell> ", "")) != null){
-                               Console.WriteLine ("----> [{0}]", s);
-                       }
-               }
-       }
-#endif
-}