[
  {
    "path": ".ci/azure-pipelines.yml",
    "content": "name: $(Build.SourceBranchName)-$(Build.SourceVersion)-$(Rev:r)\n\ntrigger:\n  - main\n  - refs/tags/*\n\npr:\n  - main\n\nresources:\n  repositories:\n    - repository: internal-templates\n      type: github\n      name: xamarin/yaml-templates\n      endpoint: xamarin\n    - repository: components\n      type: github\n      name: xamarin/XamarinComponents\n      endpoint: xamarin\n\njobs:\n  - template: .ci/build.yml@components\n    parameters:\n      publishJob: windows\n      buildType: none\n      areaPath: 'DevDiv\\Xamarin SDK'\n      linuxImage: '' # skip linux builds\n      validPackagePrefixes: [ 'Mono' ]\n      steps:\n        - task: MSBuild@1\n          displayName: msbuild LineEditor.sln\n          inputs:\n            solution: LineEditor.sln\n            configuration: Release\n            msbuildArguments: /restore /t:Pack /p:PackageOutputPath=$(Build.SourcesDirectory)/output\n\n  - ${{ if eq(variables['System.TeamProject'], 'devdiv') }}:\n    - template: sign-artifacts/jobs/v1.yml@internal-templates\n      parameters:\n        dependsOn: [ 'build' ]\n        realSign: true\n        signTags: true\n        signMain: true\n"
  },
  {
    "path": ".gitignore",
    "content": "bin\nobj\n*.userprefs\n\n"
  },
  {
    "path": "CODE-OF-CONDUCT.md",
    "content": "# Code of Conduct\n\nThis project has adopted the code of conduct defined by the Contributor Covenant\nto clarify expected behavior in our community.\n\nFor more information, see the [.NET Foundation Code of Conduct](https://dotnetfoundation.org/code-of-conduct).\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2017 Mono Project\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "LineEditor/LineEditor.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>netstandard2.0</TargetFramework>\n    <PackageId>Mono.Terminal</PackageId>\n    <PackageVersion>5.4.2</PackageVersion>\n    <Authors>Microsoft</Authors>\n    <Copyright>© Microsoft Corporation. All rights reserved.</Copyright>\n    <PackageIconUrl>https://github.com/mono/LineEditor/raw/main/icon_128x128.png</PackageIconUrl>\n    <PackageLicenseUrl>https://github.com/mono/LineEditor/blob/main/LICENSE</PackageLicenseUrl>\n    <Owners>Xamarin</Owners>\n    <PackageProjectUrl>https://github.com/mono/LineEditor</PackageProjectUrl>\n    <PackageReleaseNotes>Release 5.4.2 improves Windows support.</PackageReleaseNotes>\n    <PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>\n    <Summary>An interactive commmand line editor</Summary>\n    <Title>Mono.Terminal - LineEdit, GetLine</Title>\n    <Description>Interactive Command Line Editor</Description>\n    <InferPackageContents>false</InferPackageContents>\n    <AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>\n    <IncludeSymbols>True</IncludeSymbols>\n    <SymbolPackageFormat>snupkg</SymbolPackageFormat>\n  </PropertyGroup>\n\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' \">\n    <DocumentationFile>bin\\Debug\\netstandard2.0\\LineEditor.xml</DocumentationFile>\n  </PropertyGroup>\n\n  <PropertyGroup Condition=\" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' \">\n    <DocumentationFile>bin\\Release\\netstandard2.0\\LineEditor.xml</DocumentationFile>\n  </PropertyGroup>\n\n</Project>\n"
  },
  {
    "path": "LineEditor/getline.cs",
    "content": "//\n// getline.cs: A command line editor\n//\n// Authors:\n//   Miguel de Icaza (miguel@microsoft.com)\n//\n// Copyright 2008 Novell, Inc.\n// Copyright 2016 Xamarin Inc\n// Copyright 2017 Microsoft\n//\n// Completion wanted:\n//\n//   * Enable bash-like completion window the window as an option for non-GUI people?\n//\n//   * Continue completing when Backspace is used?\n//\n//   * Should we keep the auto-complete on \".\"?\n//\n//   * Completion produces an error if the value is not resolvable, we should hide those errors\n//\n// Dual-licensed under the terms of the MIT X11 license or the\n// Apache License 2.0\n//\n// USE -define:DEMO to build this as a standalone file and test it\n//\n// TODO:\n//    Enter an error (a = 1);  Notice how the prompt is in the wrong line\n//\t\tThis is caused by Stderr not being tracked by System.Console.\n//    Completion support\n//    Why is Thread.Interrupt not working?   Currently I resort to Abort which is too much.\n//\n// Limitations in System.Console:\n//    Console needs SIGWINCH support of some sort\n//    Console needs a way of updating its position after things have been written\n//    behind its back (P/Invoke puts for example).\n//    System.Console needs to get the DELETE character, and report accordingly.\n//\n// Bug:\n//   About 8 lines missing, type \"Con<TAB>\" and not enough lines are inserted at the bottom.\n// \n//\nusing System;\nusing System.Text;\nusing System.IO;\nusing System.Threading;\nusing System.Reflection;\nusing System.Runtime.InteropServices;\n\nnamespace Mono.Terminal {\n\n\t/// <summary>\n\t/// Interactive line editor.\n\t/// </summary>\n\t/// <remarks>\n\t///   <para>\n\t///     LineEditor is an interative line editor for .NET applications that provides\n\t///     editing capabilities for an input line with common editing capabilities and\n\t///     navigation expected in modern application as well as history, incremental\n\t///     search over the history, completion (both textual or visual) and various \n\t///     Emacs-like commands.\n\t///   </para>\n\t///   <para>\n\t///     When you create your line editor, you can pass the name of your application, \n\t///     which will be used to load and save the history of commands entered by the user\n\t///     for this particular application.    \n\t///   </para>\n\t///   <para>\n\t///     \n\t///   </para>\n\t///   <example>\n\t///     The following example shows how you can instantiate a line editor that\n\t///     can provide code completion for some words when the user presses TAB\n\t///     and how the user can edit them. \n\t///     <code>\n\t/// LineEditor le = new LineEditor (\"myshell\") { HeuristicsMode = \"csharp\" };\n\t/// le.AutoCompleteEvent += delegate (string line, int point){\n\t///     string prefix = \"\";\n\t///     var completions = new string [] { \n\t///         \"One\", \"Two\", \"Three\", \"Four\", \"Five\", \n\t///          \"Six\", \"Seven\", \"Eight\", \"Nine\", \"Ten\" \n\t///     };\n\t///     return new Mono.Terminal.LineEditor.Completion(prefix, completions);\n\t/// };\n\t///\t\t\n\t/// string s;\n\t///\t\t\n\t/// while ((s = le.Edit(\"shell> \", \"\")) != null)\n\t///    Console.WriteLine(\"You typed: [{0}]\", s);\t\t\t}\n\t///     </code>\n\t///   </example>\n\t///   <para>\n\t///      Users can use the cursor keys to navigate both the text on the current\n\t///      line, or move back and forward through the history of commands that have\n\t///      been entered.   \n\t///   </para>\n\t///   <para>\n\t///     The interactive commands and keybindings are inspired by the GNU bash and\n\t///     GNU readline capabilities and follow the same concepts found there.\n\t///   </para>\n\t///   <para>\n\t///      Copy and pasting works like bash, deleted words or regions are added to \n\t///      the kill buffer.   Repeated invocations of the same deleting operation will\n\t///      append to the kill buffer (for example, repeatedly deleting words) and to\n\t///      paste the results you would use the Control-y command (yank).\n\t///   </para>\n\t///   <para>\n\t///      The history search capability is triggered when you press \n\t///      Control-r to start a reverse interactive-search\n\t///      and start typing the text you are looking for, the edited line will\n\t///      be updated with matches.  Typing control-r again will go to the next\n\t///      match in history and so on.\n\t///   </para>\n\t///   <list type=\"table\"> \n\t///     <listheader>\n\t///       <term>Shortcut</term>\n\t///       <description>Action performed</description>\n\t///     </listheader>\n\t///     <item>\n\t///        <term>Left cursor, Control-b</term>\n\t///        <description>\n\t///          Moves the editing point left.\n\t///        </description>\n\t///     </item>\n\t///     <item>\n\t///        <term>Right cursor, Control-f</term>\n\t///        <description>\n\t///          Moves the editing point right.\n\t///        </description>\n\t///     </item>\n\t///     <item>\n\t///        <term>Alt-b</term>\n\t///        <description>\n\t///          Moves one word back.\n\t///        </description>\n\t///     </item>\n\t///     <item>\n\t///        <term>Alt-f</term>\n\t///        <description>\n\t///          Moves one word forward.\n\t///        </description>\n\t///     </item>\n\t///     <item>\n\t///        <term>Up cursor, Control-p</term>\n\t///        <description>\n\t///          Selects the previous item in the editing history.\n\t///        </description>\n\t///     </item>\n\t///     <item>\n\t///        <term>Down cursor, Control-n</term>\n\t///        <description>\n\t///          Selects the next item in the editing history.\n\t///        </description>\n\t///     </item>\n\t///     <item>\n\t///        <term>Home key, Control-a</term>\n\t///        <description>\n\t///          Moves the cursor to the beginning of the line.\n\t///        </description>\n\t///     </item>\n\t///     <item>\n\t///        <term>End key, Control-e</term>\n\t///        <description>\n\t///          Moves the cursor to the end of the line.\n\t///        </description>\n\t///     </item>\n\t///     <item>\n\t///        <term>Delete, Control-d</term>\n\t///        <description>\n\t///          Deletes the character in front of the cursor.\n\t///        </description>\n\t///     </item>\n\t///     <item>\n\t///        <term>Backspace</term>\n\t///        <description>\n\t///          Deletes the character behind the cursor.\n\t///        </description>\n\t///     </item>\n\t///     <item>\n\t///        <term>Tab</term>\n\t///        <description>\n\t///           Triggers the completion and invokes the AutoCompleteEvent which gets\n\t///           both the line contents and the position where the cursor is.\n\t///        </description>\n\t///     </item>\n\t///     <item>\n\t///        <term>Control-k</term>\n\t///        <description>\n\t///          Deletes the text until the end of the line and replaces the kill buffer\n\t///          with the deleted text.   You can paste this text in a different place by\n\t///          using Control-y.\n\t///        </description>\n\t///     </item>\n\t///     <item>\n\t///        <term>Control-l refresh</term>\n\t///        <description>\n\t///           Clears the screen and forces a refresh of the line editor, useful when\n\t///           a background process writes to the console and garbles the contents of\n\t///           the screen.\n\t///        </description>\n\t///     </item>\n\t///     <item>\n\t///        <term>Control-r</term>\n\t///        <description>\n\t///          Initiates the reverse search in history.\n\t///        </description>\n\t///     </item>\n\t///     <item>\n\t///        <term>Alt-backspace</term>\n\t///        <description>\n\t///           Deletes the word behind the cursor and adds it to the kill ring.  You \n\t///           can paste the contents of the kill ring with Control-y.\n\t///        </description>\n\t///     </item>\n\t///     <item>\n\t///        <term>Alt-d</term>\n\t///        <description>\n\t///           Deletes the word above the cursor and adds it to the kill ring.  You \n\t///           can paste the contents of the kill ring with Control-y.\n\t///        </description>\n\t///     </item>\n\t///     <item>\n\t///        <term>Control-y</term>\n\t///        <description>\n\t///           Pastes the content of the kill ring into the current position.\n\t///        </description>\n\t///     </item>\n\t///     <item>\n\t///        <term>Control-q</term>\n\t///        <description>\n\t///          Quotes the next input character, to prevent the normal processing of\n\t///          key handling to take place.\n\t///        </description>\n\t///     </item>\n\t///   </list>\n\t/// </remarks>\n\tpublic class LineEditor {\n\n\t\t/// <summary>\n\t\t/// Completion results returned by the completion handler.\n\t\t/// </summary>\n\t\t/// <remarks>\n\t\t/// You create an instance of this class to return the completion\n\t\t/// results for the text at the specific position.   The prefix parameter\n\t\t/// indicates the common prefix in the results, and the results contain the\n\t\t/// results without the prefix.   For example, when completing \"ToString\" and \"ToDate\"\n\t\t/// prefix would be \"To\" and the completions would be \"String\" and \"Date\".\n\t\t/// </remarks>\n\t\tpublic class Completion {\n\t\t\t/// <summary>\n\t\t\t/// Array of results, with the stem removed.\n\t\t\t/// </summary>\n\t\t\tpublic string [] Result;\n\n\t\t\t/// <summary>\n\t\t\t/// Shared prefix for the completion results.\n\t\t\t/// </summary>\n\t\t\tpublic string Prefix;\n\n\t\t\t/// <summary>\n\t\t\t/// Initializes a new instance of the <see cref=\"T:Mono.Terminal.LineEditor.Completion\"/> class.\n\t\t\t/// </summary>\n\t\t\t/// <param name=\"prefix\">Common prefix for all results, an be null.</param>\n\t\t\t/// <param name=\"result\">Array of possible completions.</param>\n\t\t\tpublic Completion (string prefix, string [] result)\n\t\t\t{\n\t\t\t\tPrefix = prefix;\n\t\t\t\tResult = result;\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Method signature for auto completion handlers.\n\t\t/// </summary>\n\t\t/// <remarks>\n\t\t/// The completion handler receives the text as it is being edited as\n\t\t/// well as the position of the cursor in that line.   The method\n\t\t/// must return an instance of Completion with the possible completions.\n\t\t/// </remarks>\n\t\tpublic delegate Completion AutoCompleteHandler (string text, int pos);\n\n\t\t/// <summary>\n\t\t/// The heuristics mode used by code completion.\n\t\t/// </summary>\n\t\t/// <remarks>\n\t\t///    <para>\n\t\t///      This controls the heuristics style used to show the code\n\t\t///      completion popup as well as when to accept an entry.\n\t\t///    </para>\n\t\t///    <para>\n\t\t///      The default value is null which requires the user to explicitly\n\t\t///      use the TAB key to trigger a completion.    \n\t\t///    </para>\n\t\t///    <para>\n\t\t///      Another possible value is \"csharp\" which will trigger auto-completion when a \n\t\t///      \".\" is entered.\n\t\t///    </para>\n\t\t/// </remarks>\n\t\tpublic string HeuristicsMode;\n\t\t\n\t\t//static StreamWriter log;\n\t\t\n\t\t// The text being edited.\n\t\tStringBuilder text;\n\n\t\t// The text as it is rendered (replaces (char)1 with ^A on display for example).\n\t\tStringBuilder rendered_text;\n\n\t\t// The prompt specified, and the prompt shown to the user.\n\t\tstring prompt;\n\t\tstring shown_prompt;\n\t\t\n\t\t// The current cursor position, indexes into \"text\", for an index\n\t\t// into rendered_text, use TextToRenderPos\n\t\tint cursor;\n\n\t\t// The row where we started displaying data.\n\t\tint home_row;\n\n\t\t// The maximum length that has been displayed on the screen\n\t\tint max_rendered;\n\n\t\t// If we are done editing, this breaks the interactive loop\n\t\tbool done = false;\n\n\t\t// The thread where the Editing started taking place\n\t\tThread edit_thread;\n\n\t\t// Our object that tracks history\n\t\tHistory history;\n\n\t\t// The contents of the kill buffer (cut/paste in Emacs parlance)\n\t\tstring kill_buffer = \"\";\n\n\t\t// The string being searched for\n\t\tstring search;\n\t\tstring last_search;\n\n\t\t// whether we are searching (-1= reverse; 0 = no; 1 = forward)\n\t\tint searching;\n\n\t\t// The position where we found the match.\n\t\tint match_at;\n\t\t\n\t\t// Used to implement the Kill semantics (multiple Alt-Ds accumulate)\n\t\tKeyHandler last_handler;\n\n\t\t// If we have a popup completion, this is not null and holds the state.\n\t\tCompletionState current_completion;\n\n\t\t// If this is set, it contains an escape sequence to reset the Unix colors to the ones that were used on startup\n\t\tstatic byte [] unix_reset_colors;\n\n\t\t// This contains a raw stream pointing to stdout, used to bypass the TermInfoDriver\n\t\tstatic Stream unix_raw_output;\n\t\t\n\t\tdelegate void KeyHandler ();\n\t\t\n\t\tstruct Handler {\n\t\t\tpublic ConsoleKeyInfo CKI;\n\t\t\tpublic KeyHandler KeyHandler;\n\t\t\tpublic bool ResetCompletion;\n\t\t\t\n\t\t\tpublic Handler (ConsoleKey key, KeyHandler h, bool resetCompletion = true)\n\t\t\t{\n\t\t\t\tCKI = new ConsoleKeyInfo ((char) 0, key, false, false, false);\n\t\t\t\tKeyHandler = h;\n\t\t\t\tResetCompletion = resetCompletion;\n\t\t\t}\n\n\t\t\tpublic Handler (char c, KeyHandler h, bool resetCompletion = true)\n\t\t\t{\n\t\t\t\tKeyHandler = h;\n\t\t\t\t// Use the \"Zoom\" as a flag that we only have a character.\n\t\t\t\tCKI = new ConsoleKeyInfo (c, ConsoleKey.Zoom, false, false, false);\n\t\t\t\tResetCompletion = resetCompletion;\n\t\t\t}\n\n\t\t\tpublic Handler (ConsoleKeyInfo cki, KeyHandler h, bool resetCompletion = true)\n\t\t\t{\n\t\t\t\tCKI = cki;\n\t\t\t\tKeyHandler = h;\n\t\t\t\tResetCompletion = resetCompletion;\n\t\t\t}\n\t\t\t\n\t\t\tpublic static Handler Control (char c, KeyHandler h, bool resetCompletion = true)\n\t\t\t{\n\t\t\t\treturn new Handler ((char) (c - 'A' + 1), h, resetCompletion);\n\t\t\t}\n\n\t\t\tpublic static Handler Alt (char c, ConsoleKey k, KeyHandler h)\n\t\t\t{\n\t\t\t\tConsoleKeyInfo cki = new ConsoleKeyInfo ((char) c, k, false, true, false);\n\t\t\t\treturn new Handler (cki, h);\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t///   Invoked when the user requests auto-completion using the tab character\n\t\t/// </summary>\n\t\t/// <remarks>\n\t\t///    The result is null for no values found, an array with a single\n\t\t///    string, in that case the string should be the text to be inserted\n\t\t///    for example if the word at pos is \"T\", the result for a completion\n\t\t///    of \"ToString\" should be \"oString\", not \"ToString\".\n\t\t///\n\t\t///    When there are multiple results, the result should be the full\n\t\t///    text\n\t\t/// </remarks>\n\t\tpublic AutoCompleteHandler AutoCompleteEvent;\n\n\t\tstatic Handler [] handlers;\n\n\t\tprivate readonly bool isWindows;\n\n\t\t/// <summary>\n\t\t/// Initializes a new instance of the LineEditor, using the specified name for \n\t\t/// retrieving and storing the history.   The history will default to 10 entries.\n\t\t/// </summary>\n\t\t/// <param name=\"name\">Prefix for storing the editing history.</param>\n\t\tpublic LineEditor (string name) : this (name, 10) { }\n\t\t\n\t\t/// <summary>\n\t\t/// Initializes a new instance of the LineEditor, using the specified name for \n\t\t/// retrieving and storing the history.   \n\t\t/// </summary>\n\t\t/// <param name=\"name\">Prefix for storing the editing history.</param>\n\t\t/// <param name=\"histsize\">Number of entries to store in the history file.</param>\n\t\tpublic LineEditor (string name, int histsize)\n\t\t{\n\t\t\thandlers = new Handler [] {\n\t\t\t\tnew Handler (ConsoleKey.Home,       CmdHome),\n\t\t\t\tnew Handler (ConsoleKey.End,        CmdEnd),\n\t\t\t\tnew Handler (ConsoleKey.LeftArrow,  CmdLeft),\n\t\t\t\tnew Handler (ConsoleKey.RightArrow, CmdRight),\n\t\t\t\tnew Handler (ConsoleKey.UpArrow,    CmdUp, resetCompletion: false),\n\t\t\t\tnew Handler (ConsoleKey.DownArrow,  CmdDown, resetCompletion: false),\n\t\t\t\tnew Handler (ConsoleKey.Enter,      CmdDone, resetCompletion: false),\n\t\t\t\tnew Handler (ConsoleKey.Backspace,  CmdBackspace, resetCompletion: false),\n\t\t\t\tnew Handler (ConsoleKey.Delete,     CmdDeleteChar),\n\t\t\t\tnew Handler (ConsoleKey.Tab,        CmdTabOrComplete, resetCompletion: false),\n\t\t\t\t\n\t\t\t\t// Emacs keys\n\t\t\t\tHandler.Control ('A', CmdHome),\n\t\t\t\tHandler.Control ('E', CmdEnd),\n\t\t\t\tHandler.Control ('B', CmdLeft),\n\t\t\t\tHandler.Control ('F', CmdRight),\n\t\t\t\tHandler.Control ('P', CmdUp, resetCompletion: false),\n\t\t\t\tHandler.Control ('N', CmdDown, resetCompletion: false),\n\t\t\t\tHandler.Control ('K', CmdKillToEOF),\n\t\t\t\tHandler.Control ('Y', CmdYank),\n\t\t\t\tHandler.Control ('D', CmdDeleteChar),\n\t\t\t\tHandler.Control ('L', CmdRefresh),\n\t\t\t\tHandler.Control ('R', CmdReverseSearch),\n\t\t\t\tHandler.Control ('G', delegate {} ),\n\t\t\t\tHandler.Alt ('B', ConsoleKey.B, CmdBackwardWord),\n\t\t\t\tHandler.Alt ('F', ConsoleKey.F, CmdForwardWord),\n\t\t\t\t\n\t\t\t\tHandler.Alt ('D', ConsoleKey.D, CmdDeleteWord),\n\t\t\t\tHandler.Alt ((char) 8, ConsoleKey.Backspace, CmdDeleteBackword),\n\t\t\t\t\n\t\t\t\t// DEBUG\n\t\t\t\t//Handler.Control ('T', CmdDebug),\n\n\t\t\t\t// quote\n\t\t\t\tHandler.Control ('Q', delegate { HandleChar (Console.ReadKey (true).KeyChar); })\n\t\t\t};\n\n\t\t\trendered_text = new StringBuilder ();\n\t\t\ttext = new StringBuilder ();\n\n\t\t\thistory = new History (name, histsize);\n\n\t\t\tisWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);\n\t\t\tGetUnixConsoleReset ();\n\t\t\t//if (File.Exists (\"log\"))File.Delete (\"log\");\n\t\t\t//log = File.CreateText (\"log\"); \n\t\t}\n\n\t\t// On Unix, there is a \"default\" color which is not represented by any colors in\n\t\t// ConsoleColor and it is not possible to set is by setting the ForegroundColor or\n\t\t// BackgroundColor properties, so we have to use the terminfo driver in Mono to\n\t\t// fetch these values\n\n\t\tvoid GetUnixConsoleReset ()\n\t\t{\n\t\t\t//\n\t\t\t// On Unix, we want to be able to reset the color for the pop-up completion\n\t\t\t//\n\t\t\tif (isWindows)\n\t\t\t\treturn;\n\n\t\t\t// Sole purpose of this call is to initialize the Terminfo driver\n\t\t\tvar x = Console.CursorLeft;\n\t\t\t\n\t\t\ttry {\n\t\t\t\tvar terminfo_driver = Type.GetType (\"System.ConsoleDriver\")?.GetField (\"driver\", BindingFlags.Static | BindingFlags.NonPublic)?.GetValue (null);\n\t\t\t\tif (terminfo_driver == null)\n\t\t\t\t\treturn;\n\n\t\t\t\tvar unix_reset_colors_str = (terminfo_driver?.GetType ()?.GetField (\"origPair\", BindingFlags.Instance | BindingFlags.NonPublic))?.GetValue (terminfo_driver) as string;\n\t\t\t\t\n\t\t\t\tif (unix_reset_colors_str != null)\n\t\t\t\t\tunix_reset_colors = Encoding.UTF8.GetBytes ((string)unix_reset_colors_str);\n\t\t\t\tunix_raw_output = Console.OpenStandardOutput ();\n\t\t\t} catch (Exception e){\n\t\t\t\tConsole.WriteLine (\"Error: \" + e);\n\t\t\t}\n\t\t}\n\t\t\n\n\t\tvoid CmdDebug ()\n\t\t{\n\t\t\thistory.Dump ();\n\t\t\tConsole.WriteLine ();\n\t\t\tRender ();\n\t\t}\n\n\t\tvoid Render ()\n\t\t{\n\t\t\tConsole.Write (shown_prompt);\n\t\t\tConsole.Write (rendered_text);\n\n\t\t\tint max = System.Math.Max (rendered_text.Length + shown_prompt.Length, max_rendered);\n\t\t\t\n\t\t\tfor (int i = rendered_text.Length + shown_prompt.Length; i < max_rendered; i++)\n\t\t\t\tConsole.Write (' ');\n\t\t\tmax_rendered = shown_prompt.Length + rendered_text.Length;\n\n\t\t\t// Write one more to ensure that we always wrap around properly if we are at the\n\t\t\t// end of a line.\n\t\t\tConsole.Write (' ');\n\n\t\t\tUpdateHomeRow (max);\n\t\t}\n\n\t\tvoid UpdateHomeRow (int screenpos)\n\t\t{\n\t\t\tint lines = 1 + (screenpos / Console.WindowWidth);\n\n\t\t\thome_row = Console.CursorTop - (lines - 1);\n\t\t\tif (home_row < 0)\n\t\t\t\thome_row = 0;\n\t\t}\n\t\t\n\n\t\tvoid RenderFrom (int pos)\n\t\t{\n\t\t\tint rpos = TextToRenderPos (pos);\n\t\t\tint i;\n\t\t\t\n\t\t\tfor (i = rpos; i < rendered_text.Length; i++)\n\t\t\t\tConsole.Write (rendered_text [i]);\n\n\t\t\tif ((shown_prompt.Length + rendered_text.Length) > max_rendered)\n\t\t\t\tmax_rendered = shown_prompt.Length + rendered_text.Length;\n\t\t\telse {\n\t\t\t\tint max_extra = max_rendered - shown_prompt.Length;\n\t\t\t\tfor (; i < max_extra; i++)\n\t\t\t\t\tConsole.Write (' ');\n\t\t\t}\n\t\t}\n\n\t\tvoid ComputeRendered ()\n\t\t{\n\t\t\trendered_text.Length = 0;\n\n\t\t\tfor (int i = 0; i < text.Length; i++){\n\t\t\t\tint c = (int) text [i];\n\t\t\t\tif (c < 26){\n\t\t\t\t\tif (c == '\\t')\n\t\t\t\t\t\trendered_text.Append (\"    \");\n\t\t\t\t\telse {\n\t\t\t\t\t\trendered_text.Append ('^');\n\t\t\t\t\t\trendered_text.Append ((char) (c + (int) 'A' - 1));\n\t\t\t\t\t}\n\t\t\t\t} else\n\t\t\t\t\trendered_text.Append ((char)c);\n\t\t\t}\n\t\t}\n\n\t\tint TextToRenderPos (int pos)\n\t\t{\n\t\t\tint p = 0;\n\n\t\t\tfor (int i = 0; i < pos; i++){\n\t\t\t\tint c;\n\n\t\t\t\tc = (int) text [i];\n\t\t\t\t\n\t\t\t\tif (c < 26){\n\t\t\t\t\tif (c == 9)\n\t\t\t\t\t\tp += 4;\n\t\t\t\t\telse\n\t\t\t\t\t\tp += 2;\n\t\t\t\t} else\n\t\t\t\t\tp++;\n\t\t\t}\n\n\t\t\treturn p;\n\t\t}\n\n\t\tint TextToScreenPos (int pos)\n\t\t{\n\t\t\treturn shown_prompt.Length + TextToRenderPos (pos);\n\t\t}\n\t\t\n\t\tstring Prompt {\n\t\t\tget { return prompt; }\n\t\t\tset { prompt = value; }\n\t\t}\n\n\t\tint LineCount {\n\t\t\tget {\n\t\t\t\treturn (shown_prompt.Length + rendered_text.Length)/Console.WindowWidth;\n\t\t\t}\n\t\t}\n\t\t\n\t\tvoid ForceCursor (int newpos)\n\t\t{\n\t\t\tcursor = newpos;\n\n\t\t\tint actual_pos = shown_prompt.Length + TextToRenderPos (cursor);\n\t\t\tint row = home_row + (actual_pos/Console.WindowWidth);\n\t\t\tint col = actual_pos % Console.WindowWidth;\n\n\t\t\tif (row >= Console.BufferHeight)\n\t\t\t\trow = Console.BufferHeight-1;\n\t\t\tConsole.SetCursorPosition (col, row);\n\t\t\t\n\t\t\t//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);\n\t\t\t//log.Flush ();\n\t\t}\n\n\t\tvoid UpdateCursor (int newpos)\n\t\t{\n\t\t\tif (cursor == newpos)\n\t\t\t\treturn;\n\n\t\t\tForceCursor (newpos);\n\t\t}\n\n\t\tvoid InsertChar (char c)\n\t\t{\n\t\t\tint prev_lines = LineCount;\n\t\t\ttext = text.Insert (cursor, c);\n\t\t\tComputeRendered ();\n\t\t\tif (prev_lines != LineCount){\n\n\t\t\t\tConsole.SetCursorPosition (0, home_row);\n\t\t\t\tRender ();\n\t\t\t\tForceCursor (++cursor);\n\t\t\t} else {\n\t\t\t\tRenderFrom (cursor);\n\t\t\t\tForceCursor (++cursor);\n\t\t\t\tUpdateHomeRow (TextToScreenPos (cursor));\n\t\t\t}\n\t\t}\n\n\t\tstatic void SaveExcursion (Action code)\n\t\t{\n\t\t\tvar saved_col = Console.CursorLeft;\n\t\t\tvar saved_row = Console.CursorTop;\n\t\t\tvar saved_fore = Console.ForegroundColor;\n\t\t\tvar saved_back = Console.BackgroundColor;\n\t\t\t\n\t\t\tcode ();\n\t\t\t\n\t\t\tConsole.CursorLeft = saved_col;\n\t\t\tConsole.CursorTop = saved_row;\n\t\t\tif (unix_reset_colors != null){\n\t\t\t\tunix_raw_output.Write (unix_reset_colors, 0, unix_reset_colors.Length);\n\t\t\t} else {\n\t\t\t\tConsole.ForegroundColor = saved_fore;\n\t\t\t\tConsole.BackgroundColor = saved_back;\n\t\t\t}\n\t\t}\n\t\t\n\t\tclass CompletionState {\n\t\t\tpublic string Prefix;\n\t\t\tpublic string [] Completions;\n\t\t\tpublic int Col, Row, Width, Height;\n\t\t\tint selected_item, top_item;\n\n\t\t\tpublic CompletionState (int col, int row, int width, int height)\n\t\t\t{\n\t\t\t\tCol = col;\n\t\t\t\tRow = row;\n\t\t\t\tWidth = width;\n\t\t\t\tHeight = height;\n\n\t\t\t\tif (Col < 0)\n\t\t\t\t\tthrow new ArgumentException (\"Cannot be less than zero\" + Col, \"Col\");\n\t\t\t\tif (Row < 0)\n\t\t\t\t\tthrow new ArgumentException (\"Cannot be less than zero\", \"Row\");\n\t\t\t\tif (Width < 1)\n\t\t\t\t\tthrow new ArgumentException (\"Cannot be less than one\", \"Width\");\n\t\t\t\tif (Height < 1)\n\t\t\t\t\tthrow new ArgumentException (\"Cannot be less than one\", \"Height\");\n\t\t\t\t\n\t\t\t}\n\t\t\t\n\t\t\tvoid DrawSelection ()\n\t\t\t{\n\t\t\t\tfor (int r = 0; r < Height; r++){\n\t\t\t\t\tint item_idx = top_item + r;\n\t\t\t\t\tbool selected = (item_idx == selected_item);\n\t\t\t\t\t\n\t\t\t\t\tConsole.ForegroundColor = selected ? ConsoleColor.Black : ConsoleColor.Gray;\n\t\t\t\t\tConsole.BackgroundColor = selected ? ConsoleColor.Cyan : ConsoleColor.Blue;\n\n\t\t\t\t\tvar item = Prefix + Completions [item_idx];\n\t\t\t\t\tif (item.Length > Width)\n\t\t\t\t\t\titem = item.Substring (0, Width);\n\n\t\t\t\t\tConsole.CursorLeft = Col;\n\t\t\t\t\tConsole.CursorTop = Row + r;\n\t\t\t\t\tConsole.Write (item);\n\t\t\t\t\tfor (int space = item.Length; space <= Width; space++)\n\t\t\t\t\t\tConsole.Write (\" \");\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tpublic string Current {\n\t\t\t\tget {\n\t\t\t\t\treturn Completions [selected_item];\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tpublic void Show ()\n\t\t\t{\n\t\t\t\tSaveExcursion (DrawSelection);\n\t\t\t}\n\n\t\t\tpublic void SelectNext ()\n\t\t\t{\n\t\t\t\tif (selected_item+1 < Completions.Length){\n\t\t\t\t\tselected_item++;\n\t\t\t\t\tif (selected_item - top_item >= Height)\n\t\t\t\t\t\ttop_item++;\n\t\t\t\t\tSaveExcursion (DrawSelection);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tpublic void SelectPrevious ()\n\t\t\t{\n\t\t\t\tif (selected_item > 0){\n\t\t\t\t\tselected_item--;\n\t\t\t\t\tif (selected_item < top_item)\n\t\t\t\t\t\ttop_item = selected_item;\n\t\t\t\t\tSaveExcursion (DrawSelection);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvoid Clear ()\n\t\t\t{\n\t\t\t\tfor (int r = 0; r < Height; r++){\n\t\t\t\t\tConsole.CursorLeft = Col;\n\t\t\t\t\tConsole.CursorTop = Row + r;\n\t\t\t\t\tfor (int space = 0; space <= Width; space++)\n\t\t\t\t\t\tConsole.Write (\" \");\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tpublic void Remove ()\n\t\t\t{\n\t\t\t\tSaveExcursion (Clear);\n\t\t\t}\n\t\t}\n\n\t\tvoid ShowCompletions (string prefix, string [] completions)\n\t\t{\n\t\t\t// Ensure we have space, determine window size\n\t\t\tint window_height = System.Math.Min (completions.Length, Console.WindowHeight/5);\n\t\t\tint target_line = Console.WindowHeight-window_height-1;\n\t\t\tif (!isWindows && Console.CursorTop > target_line){\n\t\t\t\tvar delta = Console.CursorTop-target_line;\n\t\t\t\tConsole.CursorLeft = 0;\n\t\t\t\tConsole.CursorTop = Console.WindowHeight-1;\n\t\t\t\tfor (int i = 0; i < delta+1; i++){\n\t\t\t\t\tfor (int c = Console.WindowWidth; c > 0; c--)\n\t\t\t\t\t\tConsole.Write (\" \"); // To debug use (\"{0}\", i%10);\n\t\t\t\t}\n\t\t\t\tConsole.CursorTop = target_line;\n\t\t\t\tConsole.CursorLeft = 0;\n\t\t\t\tRender ();\n\t\t\t}\n\n\t\t\tconst int MaxWidth = 50;\n\t\t\tint window_width = 12;\n\t\t\tint plen = prefix.Length;\n\t\t\tforeach (var s in completions)\n\t\t\t\twindow_width = System.Math.Max (plen + s.Length, window_width);\n\t\t\twindow_width = System.Math.Min (window_width, MaxWidth);\n\n\t\t\tif (current_completion == null){\n\t\t\t\tint left = Console.CursorLeft-prefix.Length;\n\t\t\t\t\n\t\t\t\tif (left + window_width + 1 >= Console.WindowWidth)\n\t\t\t\t\tleft = Console.WindowWidth-window_width-1;\n\t\t\t\t\n\t\t\t\tcurrent_completion = new CompletionState (left, Console.CursorTop+1, window_width, window_height) {\n\t\t\t\t\tPrefix = prefix,\n\t\t\t\t\tCompletions = completions,\n\t\t\t\t};\n\t\t\t} else {\n\t\t\t\tcurrent_completion.Prefix = prefix;\n\t\t\t\tcurrent_completion.Completions = completions;\n\t\t\t}\n\t\t\tcurrent_completion.Show ();\n\t\t\tConsole.CursorLeft = 0;\n\t\t}\n\n\t\tvoid HideCompletions ()\n\t\t{\n\t\t\tif (current_completion == null)\n\t\t\t\treturn;\n\t\t\tcurrent_completion.Remove ();\n\t\t\tcurrent_completion = null;\n\t\t}\n\n\t\t//\n\t\t// Triggers the completion engine, if insertBestMatch is true, then this will\n\t\t// insert the best match found, this behaves like the shell \"tab\" which will\n\t\t// complete as much as possible given the options.\n\t\t//\n\t\tvoid Complete ()\n\t\t{\n\t\t\tCompletion completion = AutoCompleteEvent (text.ToString (), cursor);\n\t\t\tstring [] completions = completion.Result;\n\t\t\tif (completions == null){\n\t\t\t\tHideCompletions ();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\t\t\n\t\t\tint ncompletions = completions.Length;\n\t\t\tif (ncompletions == 0){\n\t\t\t\tHideCompletions ();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\t\t\n\t\t\tif (completions.Length == 1){\n\t\t\t\tInsertTextAtCursor (completions [0]);\n\t\t\t\tHideCompletions ();\n\t\t\t} else {\n\t\t\t\tint last = -1;\n\n\t\t\t\tfor (int p = 0; p < completions [0].Length; p++){\n\t\t\t\t\tchar c = completions [0][p];\n\n\n\t\t\t\t\tfor (int i = 1; i < ncompletions; i++){\n\t\t\t\t\t\tif (completions [i].Length < p)\n\t\t\t\t\t\t\tgoto mismatch;\n\t\t\t\t\t\t\t\n\t\t\t\t\t\tif (completions [i][p] != c){\n\t\t\t\t\t\t\tgoto mismatch;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tlast = p;\n\t\t\t\t}\n\t\t\tmismatch:\n\t\t\t\tvar prefix = completion.Prefix;\n\t\t\t\tif (last != -1){\n\t\t\t\t\tInsertTextAtCursor (completions [0].Substring (0, last+1));\n\n\t\t\t\t\t// Adjust the completions to skip the common prefix\n\t\t\t\t\tprefix += completions [0].Substring (0, last+1);\n\t\t\t\t\tfor (int i = 0; i < completions.Length; i++)\n\t\t\t\t\t\tcompletions [i] = completions [i].Substring (last+1);\n\t\t\t\t}\n\t\t\t\tShowCompletions (prefix, completions);\n\t\t\t\tRender ();\n\t\t\t\tForceCursor (cursor);\n\t\t\t}\n\t\t}\n\n\t\t//\n\t\t// When the user has triggered a completion window, this will try to update\n\t\t// the contents of it.   The completion window is assumed to be hidden at this\n\t\t// point\n\t\t// \n\t\tvoid UpdateCompletionWindow ()\n\t\t{\n\t\t\tif (current_completion != null)\n\t\t\t\tthrow new Exception (\"This method should only be called if the window has been hidden\");\n\t\t\t\n\t\t\tCompletion completion = AutoCompleteEvent (text.ToString (), cursor);\n\t\t\tstring [] completions = completion.Result;\n\t\t\tif (completions == null)\n\t\t\t\treturn;\n\t\t\t\t\t\n\t\t\tint ncompletions = completions.Length;\n\t\t\tif (ncompletions == 0)\n\t\t\t\treturn;\n\t\t\t\n\t\t\tShowCompletions (completion.Prefix, completion.Result);\n\t\t\tRender ();\n\t\t\tForceCursor (cursor);\n\t\t}\n\t\t\n\t\t\n\t\t//\n\t\t// Commands\n\t\t//\n\t\tvoid CmdDone ()\n\t\t{\n\t\t\tif (current_completion != null){\n\t\t\t\tInsertTextAtCursor (current_completion.Current);\n\t\t\t\tHideCompletions ();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tdone = true;\n\t\t}\n\n\t\tvoid CmdTabOrComplete ()\n\t\t{\n\t\t\tbool complete = false;\n\n\t\t\tif (AutoCompleteEvent != null){\n\t\t\t\tif (TabAtStartCompletes)\n\t\t\t\t\tcomplete = true;\n\t\t\t\telse {\n\t\t\t\t\tfor (int i = 0; i < cursor; i++){\n\t\t\t\t\t\tif (!Char.IsWhiteSpace (text [i])){\n\t\t\t\t\t\t\tcomplete = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (complete)\n\t\t\t\t\tComplete ();\n\t\t\t\telse\n\t\t\t\t\tHandleChar ('\\t');\n\t\t\t} else\n\t\t\t\tHandleChar ('t');\n\t\t}\n\t\t\n\t\tvoid CmdHome ()\n\t\t{\n\t\t\tUpdateCursor (0);\n\t\t}\n\n\t\tvoid CmdEnd ()\n\t\t{\n\t\t\tUpdateCursor (text.Length);\n\t\t}\n\t\t\n\t\tvoid CmdLeft ()\n\t\t{\n\t\t\tif (cursor == 0)\n\t\t\t\treturn;\n\n\t\t\tUpdateCursor (cursor-1);\n\t\t}\n\n\t\tvoid CmdBackwardWord ()\n\t\t{\n\t\t\tint p = WordBackward (cursor);\n\t\t\tif (p == -1)\n\t\t\t\treturn;\n\t\t\tUpdateCursor (p);\n\t\t}\n\n\t\tvoid CmdForwardWord ()\n\t\t{\n\t\t\tint p = WordForward (cursor);\n\t\t\tif (p == -1)\n\t\t\t\treturn;\n\t\t\tUpdateCursor (p);\n\t\t}\n\n\t\tvoid CmdRight ()\n\t\t{\n\t\t\tif (cursor == text.Length)\n\t\t\t\treturn;\n\n\t\t\tUpdateCursor (cursor+1);\n\t\t}\n\n\t\tvoid RenderAfter (int p)\n\t\t{\n\t\t\tForceCursor (p);\n\t\t\tRenderFrom (p);\n\t\t\tForceCursor (cursor);\n\t\t}\n\t\t\n\t\tvoid CmdBackspace ()\n\t\t{\n\t\t\tif (cursor == 0)\n\t\t\t\treturn;\n\n\t\t\tbool completing = current_completion != null;\n\t\t\tHideCompletions ();\n\t\t\t\n\t\t\ttext.Remove (--cursor, 1);\n\t\t\tComputeRendered ();\n\t\t\tRenderAfter (cursor);\n\t\t\tif (completing)\n\t\t\t\tUpdateCompletionWindow ();\n\t\t}\n\n\t\tvoid CmdDeleteChar ()\n\t\t{\n\t\t\t// If there is no input, this behaves like EOF\n\t\t\tif (text.Length == 0){\n\t\t\t\tdone = true;\n\t\t\t\ttext = null;\n\t\t\t\tConsole.WriteLine ();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t\n\t\t\tif (cursor == text.Length)\n\t\t\t\treturn;\n\t\t\ttext.Remove (cursor, 1);\n\t\t\tComputeRendered ();\n\t\t\tRenderAfter (cursor);\n\t\t}\n\n\t\tint WordForward (int p)\n\t\t{\n\t\t\tif (p >= text.Length)\n\t\t\t\treturn -1;\n\n\t\t\tint i = p;\n\t\t\tif (Char.IsPunctuation (text [p]) || Char.IsSymbol (text [p]) || Char.IsWhiteSpace (text[p])){\n\t\t\t\tfor (; i < text.Length; i++){\n\t\t\t\t\tif (Char.IsLetterOrDigit (text [i]))\n\t\t\t\t\t    break;\n\t\t\t\t}\n\t\t\t\tfor (; i < text.Length; i++){\n\t\t\t\t\tif (!Char.IsLetterOrDigit (text [i]))\n\t\t\t\t\t    break;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor (; i < text.Length; i++){\n\t\t\t\t\tif (!Char.IsLetterOrDigit (text [i]))\n\t\t\t\t\t    break;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (i != p)\n\t\t\t\treturn i;\n\t\t\treturn -1;\n\t\t}\n\n\t\tint WordBackward (int p)\n\t\t{\n\t\t\tif (p == 0)\n\t\t\t\treturn -1;\n\n\t\t\tint i = p-1;\n\t\t\tif (i == 0)\n\t\t\t\treturn 0;\n\t\t\t\n\t\t\tif (Char.IsPunctuation (text [i]) || Char.IsSymbol (text [i]) || Char.IsWhiteSpace (text[i])){\n\t\t\t\tfor (; i >= 0; i--){\n\t\t\t\t\tif (Char.IsLetterOrDigit (text [i]))\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tfor (; i >= 0; i--){\n\t\t\t\t\tif (!Char.IsLetterOrDigit (text[i]))\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor (; i >= 0; i--){\n\t\t\t\t\tif (!Char.IsLetterOrDigit (text [i]))\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\ti++;\n\t\t\t\n\t\t\tif (i != p)\n\t\t\t\treturn i;\n\n\t\t\treturn -1;\n\t\t}\n\t\t\n\t\tvoid CmdDeleteWord ()\n\t\t{\n\t\t\tint pos = WordForward (cursor);\n\n\t\t\tif (pos == -1)\n\t\t\t\treturn;\n\n\t\t\tstring k = text.ToString (cursor, pos-cursor);\n\t\t\t\n\t\t\tif (last_handler == CmdDeleteWord)\n\t\t\t\tkill_buffer = kill_buffer + k;\n\t\t\telse\n\t\t\t\tkill_buffer = k;\n\t\t\t\n\t\t\ttext.Remove (cursor, pos-cursor);\n\t\t\tComputeRendered ();\n\t\t\tRenderAfter (cursor);\n\t\t}\n\t\t\n\t\tvoid CmdDeleteBackword ()\n\t\t{\n\t\t\tint pos = WordBackward (cursor);\n\t\t\tif (pos == -1)\n\t\t\t\treturn;\n\n\t\t\tstring k = text.ToString (pos, cursor-pos);\n\t\t\t\n\t\t\tif (last_handler == CmdDeleteBackword)\n\t\t\t\tkill_buffer = k + kill_buffer;\n\t\t\telse\n\t\t\t\tkill_buffer = k;\n\t\t\t\n\t\t\ttext.Remove (pos, cursor-pos);\n\t\t\tComputeRendered ();\n\t\t\tRenderAfter (pos);\n\t\t}\n\t\t\n\t\t//\n\t\t// Adds the current line to the history if needed\n\t\t//\n\t\tvoid HistoryUpdateLine ()\n\t\t{\n\t\t\thistory.Update (text.ToString ());\n\t\t}\n\t\t\n\t\tvoid CmdHistoryPrev ()\n\t\t{\n\t\t\tif (!history.PreviousAvailable ())\n\t\t\t\treturn;\n\n\t\t\tHistoryUpdateLine ();\n\t\t\t\n\t\t\tSetText (history.Previous ());\n\t\t}\n\n\t\tvoid CmdHistoryNext ()\n\t\t{\n\t\t\tif (!history.NextAvailable())\n\t\t\t\treturn;\n\n\t\t\thistory.Update (text.ToString ());\n\t\t\tSetText (history.Next ());\n\t\t\t\n\t\t}\n\n\t\tvoid CmdUp ()\n\t\t{\n\t\t\tif (current_completion == null)\n\t\t\t\tCmdHistoryPrev ();\n\t\t\telse\n\t\t\t\tcurrent_completion.SelectPrevious ();\n\t\t}\n\n\t\tvoid CmdDown ()\n\t\t{\n\t\t\tif (current_completion == null)\n\t\t\t\tCmdHistoryNext ();\n\t\t\telse\n\t\t\t\tcurrent_completion.SelectNext ();\n\t\t}\n\t\t\n\t\tvoid CmdKillToEOF ()\n\t\t{\n\t\t\tkill_buffer = text.ToString (cursor, text.Length-cursor);\n\t\t\ttext.Length = cursor;\n\t\t\tComputeRendered ();\n\t\t\tRenderAfter (cursor);\n\t\t}\n\n\t\tvoid CmdYank ()\n\t\t{\n\t\t\tInsertTextAtCursor (kill_buffer);\n\t\t}\n\n\t\tvoid InsertTextAtCursor (string str)\n\t\t{\n\t\t\tint prev_lines = LineCount;\n\t\t\ttext.Insert (cursor, str);\n\t\t\tComputeRendered ();\n\t\t\tif (prev_lines != LineCount){\n\t\t\t\tConsole.SetCursorPosition (0, home_row);\n\t\t\t\tRender ();\n\t\t\t\tcursor += str.Length;\n\t\t\t\tForceCursor (cursor);\n\t\t\t} else {\n\t\t\t\tRenderFrom (cursor);\n\t\t\t\tcursor += str.Length;\n\t\t\t\tForceCursor (cursor);\n\t\t\t\tUpdateHomeRow (TextToScreenPos (cursor));\n\t\t\t}\n\t\t}\n\t\t\n\t\tvoid SetSearchPrompt (string s)\n\t\t{\n\t\t\tSetPrompt (\"(reverse-i-search)`\" + s + \"': \");\n\t\t}\n\n\t\tvoid ReverseSearch ()\n\t\t{\n\t\t\tint p;\n\n\t\t\tif (cursor == text.Length){\n\t\t\t\t// The cursor is at the end of the string\n\t\t\t\t\n\t\t\t\tp = text.ToString ().LastIndexOf (search);\n\t\t\t\tif (p != -1){\n\t\t\t\t\tmatch_at = p;\n\t\t\t\t\tcursor = p;\n\t\t\t\t\tForceCursor (cursor);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// The cursor is somewhere in the middle of the string\n\t\t\t\tint start = (cursor == match_at) ? cursor - 1 : cursor;\n\t\t\t\tif (start != -1){\n\t\t\t\t\tp = text.ToString ().LastIndexOf (search, start);\n\t\t\t\t\tif (p != -1){\n\t\t\t\t\t\tmatch_at = p;\n\t\t\t\t\t\tcursor = p;\n\t\t\t\t\t\tForceCursor (cursor);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Need to search backwards in history\n\t\t\tHistoryUpdateLine ();\n\t\t\tstring s = history.SearchBackward (search);\n\t\t\tif (s != null){\n\t\t\t\tmatch_at = -1;\n\t\t\t\tSetText (s);\n\t\t\t\tReverseSearch ();\n\t\t\t}\n\t\t}\n\t\t\n\t\tvoid CmdReverseSearch ()\n\t\t{\n\t\t\tif (searching == 0){\n\t\t\t\tmatch_at = -1;\n\t\t\t\tlast_search = search;\n\t\t\t\tsearching = -1;\n\t\t\t\tsearch = \"\";\n\t\t\t\tSetSearchPrompt (\"\");\n\t\t\t} else {\n\t\t\t\tif (search == \"\"){\n\t\t\t\t\tif (last_search != \"\" && last_search != null){\n\t\t\t\t\t\tsearch = last_search;\n\t\t\t\t\t\tSetSearchPrompt (search);\n\n\t\t\t\t\t\tReverseSearch ();\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tReverseSearch ();\n\t\t\t} \n\t\t}\n\n\t\tvoid SearchAppend (char c)\n\t\t{\n\t\t\tsearch = search + c;\n\t\t\tSetSearchPrompt (search);\n\n\t\t\t//\n\t\t\t// If the new typed data still matches the current text, stay here\n\t\t\t//\n\t\t\tif (cursor < text.Length){\n\t\t\t\tstring r = text.ToString (cursor, text.Length - cursor);\n\t\t\t\tif (r.StartsWith (search))\n\t\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tReverseSearch ();\n\t\t}\n\t\t\n\t\tvoid CmdRefresh ()\n\t\t{\n\t\t\tConsole.Clear ();\n\t\t\tmax_rendered = 0;\n\t\t\tRender ();\n\t\t\tForceCursor (cursor);\n\t\t}\n\n\t\tvoid InterruptEdit (object sender, ConsoleCancelEventArgs a)\n\t\t{\n\t\t\t// Do not abort our program:\n\t\t\ta.Cancel = true;\n\n\t\t\t// Interrupt the editor\n\t\t\tedit_thread.Abort();\n\t\t}\n\n\t\t//\n\t\t// Implements heuristics to show the completion window based on the mode\n\t\t//\n\t\tbool HeuristicAutoComplete (bool wasCompleting, char insertedChar)\n\t\t{\n\t\t\tif (HeuristicsMode == \"csharp\"){\n\t\t\t\t// csharp heuristics\n\t\t\t\tif (wasCompleting){\n\t\t\t\t\tif (insertedChar == ' '){\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\treturn true;\n\t\t\t\t} \n\t\t\t\t// If we were not completing, determine if we want to now\n\t\t\t\tif (insertedChar == '.'){\n\t\t\t\t\t// Avoid completing for numbers \"1.2\" for example\n\t\t\t\t\tif (cursor > 1 && Char.IsDigit (text[cursor-2])){\n\t\t\t\t\t\tfor (int p = cursor-3; p >= 0; p--){\n\t\t\t\t\t\t\tchar c = text[p];\n\t\t\t\t\t\t\tif (Char.IsDigit (c))\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\tif (c == '_')\n\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t\tif (Char.IsLetter (c) || Char.IsPunctuation (c) || Char.IsSymbol (c) || Char.IsControl (c))\n\t\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\t\t\n\t\tvoid HandleChar (char c)\n\t\t{\n\t\t\tif (searching != 0)\n\t\t\t\tSearchAppend (c);\n\t\t\telse {\n\t\t\t\tbool completing = current_completion != null;\n\t\t\t\tHideCompletions ();\n\n\t\t\t\tInsertChar (c);\n\t\t\t\tif (HeuristicAutoComplete (completing, c))\n\t\t\t\t\tUpdateCompletionWindow ();\n\t\t\t}\n\t\t}\n\n\t\tvoid EditLoop ()\n\t\t{\n\t\t\tConsoleKeyInfo cki;\n\n\t\t\twhile (!done){\n\t\t\t\tConsoleModifiers mod;\n\t\t\t\t\n\t\t\t\tcki = Console.ReadKey (true);\n\t\t\t\tif (cki.Key == ConsoleKey.Escape){\n\t\t\t\t\tif (current_completion != null){\n\t\t\t\t\t\tHideCompletions ();\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tcki = Console.ReadKey (true);\n\t\t\t\t\t\t\n\t\t\t\t\t\tmod = ConsoleModifiers.Alt;\n\t\t\t\t\t}\n\t\t\t\t} else\n\t\t\t\t\tmod = cki.Modifiers;\n\t\t\t\t\n\t\t\t\tbool handled = false;\n\n\t\t\t\tforeach (Handler handler in handlers){\n\t\t\t\t\tConsoleKeyInfo t = handler.CKI;\n\n\t\t\t\t\tif (t.Key == cki.Key && t.Modifiers == mod){\n\t\t\t\t\t\thandled = true;\n\t\t\t\t\t\tif (handler.ResetCompletion)\n\t\t\t\t\t\t\tHideCompletions ();\n\t\t\t\t\t\thandler.KeyHandler ();\n\t\t\t\t\t\tlast_handler = handler.KeyHandler;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t} else if (t.KeyChar == cki.KeyChar && t.Key == ConsoleKey.Zoom){\n\t\t\t\t\t\thandled = true;\n\t\t\t\t\t\tif (handler.ResetCompletion)\n\t\t\t\t\t\t\tHideCompletions ();\n\n\t\t\t\t\t\thandler.KeyHandler ();\n\t\t\t\t\t\tlast_handler = handler.KeyHandler;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (handled){\n\t\t\t\t\tif (searching != 0){\n\t\t\t\t\t\tif (last_handler != CmdReverseSearch){\n\t\t\t\t\t\t\tsearching = 0;\n\t\t\t\t\t\t\tSetPrompt (prompt);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (cki.KeyChar != (char) 0){\n\t\t\t\t\tHandleChar (cki.KeyChar);\n\t\t\t\t}\n\t\t\t} \n\t\t}\n\n\t\tvoid InitText (string initial)\n\t\t{\n\t\t\ttext = new StringBuilder (initial);\n\t\t\tComputeRendered ();\n\t\t\tcursor = text.Length;\n\t\t\tRender ();\n\t\t\tForceCursor (cursor);\n\t\t}\n\n\t\tvoid SetText (string newtext)\n\t\t{\n\t\t\tConsole.SetCursorPosition (0, home_row);\n\t\t\tInitText (newtext);\n\t\t}\n\n\t\tvoid SetPrompt (string newprompt)\n\t\t{\n\t\t\tshown_prompt = newprompt;\n\t\t\tConsole.SetCursorPosition (0, home_row);\n\t\t\tRender ();\n\t\t\tForceCursor (cursor);\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Edit a line, and provides both a prompt and the initial contents to edit\n\t\t/// </summary>\n\t\t/// <returns>The edit.</returns>\n\t\t/// <param name=\"prompt\">Prompt shown to edit the line.</param>\n\t\t/// <param name=\"initial\">Initial contents, can be null.</param>\n\t\tpublic string Edit (string prompt, string initial)\n\t\t{\n\t\t\tedit_thread = Thread.CurrentThread;\n\t\t\tsearching = 0;\n\t\t\tConsole.CancelKeyPress += InterruptEdit;\n\t\t\t\t\t\t\n\t\t\tdone = false;\n\t\t\thistory.CursorToEnd ();\n\t\t\tmax_rendered = 0;\n\t\t\t\n\t\t\tPrompt = prompt;\n\t\t\tshown_prompt = prompt;\n\t\t\tInitText (initial);\n\t\t\thistory.Append (initial);\n\n\t\t\tdo {\n\t\t\t\ttry {\n\t\t\t\t\tEditLoop ();\n\t\t\t\t} catch (ThreadAbortException){\n\t\t\t\t\tsearching = 0;\n\t\t\t\t\tThread.ResetAbort ();\n\t\t\t\t\tConsole.WriteLine ();\n\t\t\t\t\tSetPrompt (prompt);\n\t\t\t\t\tSetText (\"\");\n\t\t\t\t}\n\t\t\t} while (!done);\n\t\t\tConsole.WriteLine ();\n\t\t\t\n\t\t\tConsole.CancelKeyPress -= InterruptEdit;\n\n\t\t\tif (text == null){\n\t\t\t\thistory.Close ();\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tstring result = text.ToString ();\n\t\t\tif (result != \"\")\n\t\t\t\thistory.Accept (result);\n\t\t\telse\n\t\t\t\thistory.RemoveLast ();\n\n\t\t\treturn result;\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Triggers the history to be written at this point, usually not necessary, history is saved on each line edited.\n\t\t/// </summary>\n\t\tpublic void SaveHistory ()\n\t\t{\n\t\t\tif (history != null) {\n\t\t\t\thistory.Close ();\n\t\t\t}\n\t\t}\n\n\t\t/// <summary>\n\t\t/// Gets or sets a value indicating whether hitting the TAB key before any text exists triggers completion or inserts a \"tab\" character into the buffer.  This is useful to allow users to copy/paste code that might contain whitespace at the start and you want to preserve it.\n\t\t/// </summary>\n\t\t/// <value><c>true</c> if tab at start completes; otherwise, <c>false</c>.</value>\n\t\tpublic bool TabAtStartCompletes { get; set; }\n\t\t\t\n\t\t//\n\t\t// Emulates the bash-like behavior, where edits done to the\n\t\t// history are recorded\n\t\t//\n\t\tclass History {\n\t\t\tstring [] history;\n\t\t\tint head, tail;\n\t\t\tint cursor, count;\n\t\t\tstring histfile;\n\t\t\t\n\t\t\tpublic History (string app, int size)\n\t\t\t{\n\t\t\t\tif (size < 1)\n\t\t\t\t\tthrow new ArgumentException (\"size\");\n\n\t\t\t\tif (app != null){\n\t\t\t\t\tstring dir = Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData);\n\t\t\t\t\t//Console.WriteLine (dir);\n\t\t\t\t\tif (!Directory.Exists (dir)){\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tDirectory.CreateDirectory (dir);\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\tapp = null;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (app != null)\n\t\t\t\t\t\thistfile = Path.Combine (dir, app) + \".history\";\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\thistory = new string [size];\n\t\t\t\thead = tail = cursor = 0;\n\n\t\t\t\tif (File.Exists (histfile)){\n\t\t\t\t\tusing (StreamReader sr = File.OpenText (histfile)){\n\t\t\t\t\t\tstring line;\n\t\t\t\t\t\t\n\t\t\t\t\t\twhile ((line = sr.ReadLine ()) != null){\n\t\t\t\t\t\t\tif (line != \"\")\n\t\t\t\t\t\t\t\tAppend (line);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tpublic void Close ()\n\t\t\t{\n\t\t\t\tif (histfile == null)\n\t\t\t\t\treturn;\n\n\t\t\t\ttry {\n\t\t\t\t\tusing (StreamWriter sw = File.CreateText (histfile)){\n\t\t\t\t\t\tint start = (count == history.Length) ? head : tail;\n\t\t\t\t\t\tfor (int i = start; i < start+count; i++){\n\t\t\t\t\t\t\tint p = i % history.Length;\n\t\t\t\t\t\t\tsw.WriteLine (history [p]);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// ignore\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t//\n\t\t\t// Appends a value to the history\n\t\t\t//\n\t\t\tpublic void Append (string s)\n\t\t\t{\n\t\t\t\t//Console.WriteLine (\"APPENDING {0} head={1} tail={2}\", s, head, tail);\n\t\t\t\thistory [head] = s;\n\t\t\t\thead = (head+1) % history.Length;\n\t\t\t\tif (head == tail)\n\t\t\t\t\ttail = (tail+1 % history.Length);\n\t\t\t\tif (count != history.Length)\n\t\t\t\t\tcount++;\n\t\t\t\t//Console.WriteLine (\"DONE: head={1} tail={2}\", s, head, tail);\n\t\t\t}\n\n\t\t\t//\n\t\t\t// Updates the current cursor location with the string,\n\t\t\t// to support editing of history items.   For the current\n\t\t\t// line to participate, an Append must be done before.\n\t\t\t//\n\t\t\tpublic void Update (string s)\n\t\t\t{\n\t\t\t\thistory [cursor] = s;\n\t\t\t}\n\n\t\t\tpublic void RemoveLast ()\n\t\t\t{\n\t\t\t\thead = head-1;\n\t\t\t\tif (head < 0)\n\t\t\t\t\thead = history.Length-1;\n\t\t\t}\n\t\t\t\n\t\t\tpublic void Accept (string s)\n\t\t\t{\n\t\t\t\tint t = head-1;\n\t\t\t\tif (t < 0)\n\t\t\t\t\tt = history.Length-1;\n\t\t\t\t\n\t\t\t\thistory [t] = s;\n\t\t\t}\n\t\t\t\n\t\t\tpublic bool PreviousAvailable ()\n\t\t\t{\n\t\t\t\t//Console.WriteLine (\"h={0} t={1} cursor={2}\", head, tail, cursor);\n\t\t\t\tif (count == 0)\n\t\t\t\t\treturn false;\n\t\t\t\tint next = cursor-1;\n\t\t\t\tif (next < 0)\n\t\t\t\t\tnext = count-1;\n\n\t\t\t\tif (next == head)\n\t\t\t\t\treturn false;\n\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tpublic bool NextAvailable ()\n\t\t\t{\n\t\t\t\tif (count == 0)\n\t\t\t\t\treturn false;\n\t\t\t\tint next = (cursor + 1) % history.Length;\n\t\t\t\tif (next == head)\n\t\t\t\t\treturn false;\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\t\n\t\t\t\n\t\t\t//\n\t\t\t// Returns: a string with the previous line contents, or\n\t\t\t// nul if there is no data in the history to move to.\n\t\t\t//\n\t\t\tpublic string Previous ()\n\t\t\t{\n\t\t\t\tif (!PreviousAvailable ())\n\t\t\t\t\treturn null;\n\n\t\t\t\tcursor--;\n\t\t\t\tif (cursor < 0)\n\t\t\t\t\tcursor = history.Length - 1;\n\n\t\t\t\treturn history [cursor];\n\t\t\t}\n\n\t\t\tpublic string Next ()\n\t\t\t{\n\t\t\t\tif (!NextAvailable ())\n\t\t\t\t\treturn null;\n\n\t\t\t\tcursor = (cursor + 1) % history.Length;\n\t\t\t\treturn history [cursor];\n\t\t\t}\n\n\t\t\tpublic void CursorToEnd ()\n\t\t\t{\n\t\t\t\tif (head == tail)\n\t\t\t\t\treturn;\n\n\t\t\t\tcursor = head;\n\t\t\t}\n\n\t\t\tpublic void Dump ()\n\t\t\t{\n\t\t\t\tConsole.WriteLine (\"Head={0} Tail={1} Cursor={2} count={3}\", head, tail, cursor, count);\n\t\t\t\tfor (int i = 0; i < history.Length;i++){\n\t\t\t\t\tConsole.WriteLine (\" {0} {1}: {2}\", i == cursor ? \"==>\" : \"   \", i, history[i]);\n\t\t\t\t}\n\t\t\t\t//log.Flush ();\n\t\t\t}\n\n\t\t\tpublic string SearchBackward (string term)\n\t\t\t{\n\t\t\t\tfor (int i = 0; i < count; i++){\n\t\t\t\t\tint slot = cursor-i-1;\n\t\t\t\t\tif (slot < 0)\n\t\t\t\t\t\tslot = history.Length+slot;\n\t\t\t\t\tif (slot >= history.Length)\n\t\t\t\t\t\tslot = 0;\n\t\t\t\t\tif (history [slot] != null && history [slot].IndexOf (term) != -1){\n\t\t\t\t\t\tcursor = slot;\n\t\t\t\t\t\treturn history [slot];\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\t\n\t\t}\n\t}\n\n#if DEMO\n\tclass Demo {\n\t\tstatic void Main ()\n\t\t{\n\t\t\tLineEditor le = new LineEditor (\"foo\") {\n\t\t\t\tHeuristicsMode = \"csharp\"\n\t\t\t};\n\t\t\tle.AutoCompleteEvent += delegate (string a, int pos){\n\t\t\t\tstring prefix = \"\";\n\t\t\t\tvar completions = new string [] { \"One\", \"Two\", \"Three\", \"Four\", \"Five\", \"Six\", \"Seven\", \"Eight\", \"Nine\", \"Ten\" };\n\t\t\t\treturn new Mono.Terminal.LineEditor.Completion (prefix, completions);\n\t\t\t};\n\t\t\t\n\t\t\tstring s;\n\t\t\t\n\t\t\twhile ((s = le.Edit (\"shell> \", \"\")) != null){\n\t\t\t\tConsole.WriteLine (\"----> [{0}]\", s);\n\t\t\t}\n\t\t}\n\t}\n#endif\n}\n"
  },
  {
    "path": "LineEditor.sln",
    "content": "\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio 2012\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"LineEditor\", \"LineEditor\\LineEditor.csproj\", \"{8E652215-21AE-483F-BCE5-C66A70CFE96C}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{8E652215-21AE-483F-BCE5-C66A70CFE96C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{8E652215-21AE-483F-BCE5-C66A70CFE96C}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{8E652215-21AE-483F-BCE5-C66A70CFE96C}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{8E652215-21AE-483F-BCE5-C66A70CFE96C}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "README.md",
    "content": "# LineEditor\n\nLineEditor is an interative line editor for .NET applications that provides\nediting capabilities for an input line with common editing capabilities and\nnavigation expected in modern application as well as history, incremental\nsearch over the history, completion (both textual or visual) and various \nEmacs-like commands.\n\nThe code was originally developed for Mono's interactive C# shell:\n\n![Screenshot of csharp with a completion window](https://github.com/mono/LineEditor/blob/main/LineEditor/csharp.png)\n\nWhen you create your line editor, you can pass the name of your application, \nwhich will be used to load and save the history of commands entered by the user\nfor this particular application.\n\n# Installation\n\nUse NuGet or Paket to install the `Mono.Terminal` NuGet package.\n\n# Example\n\nThe following example shows how you can instantiate a line editor that\ncan provide code completion for some words when the user presses TAB\nand how the user can edit them. \n\n```csharp\nusing Mono.Terminal;\nusing System;\n\nclass Demo {\n    static void Main ()\n    {\n        // Creates a line editor, and sets the name of the editing session to\n        // \"foo\".  This is used to save the history of input entered\n        LineEditor le = new LineEditor (\"foo\") {\n            HeuristicsMode = \"csharp\"\n        };\n\n        // Configures auto-completion, in this example, the result\n        // is always to offer the numbers as completions\n        le.AutoCompleteEvent += delegate (string text, int pos){\n            string prefix = \"\";\n            var completions = new string [] { \n                \"One\", \"Two\", \"Three\", \"Four\", \"Five\", \n                \"Six\", \"Seven\", \"Eight\", \"Nine\", \"Ten\" };\n            return new Mono.Terminal.LineEditor.Completion (prefix, completions);\n        };\n\n        string s;\n\n        // Prompts the user for input\n        while ((s = le.Edit (\"shell> \", \"\")) != null){\n            Console.WriteLine (\"Your Input: [{0}]\", s);\n        }\n    }\n}\n```\n\n# Editing\n\nUsers can use the cursor keys to navigate both the text on the current\nline, or move back and forward through the history of commands that have\nbeen entered. \n\nThe interactive commands and keybindings are inspired by the GNU bash and\nGNU readline capabilities and follow the same concepts found there.\n\n## Kill Buffer: Copy and Paste\nCopy and pasting works like bash, deleted words or regions are added to \nthe kill buffer. Repeated invocations of the same deleting operation will\nappend to the kill buffer (for example, repeatedly deleting words) and to\npaste the results you would use the Control-y command (yank).\n\n## History and searching\n\nThe history search capability is triggered when you press \nControl-r to start a reverse interactive-search\nand start typing the text you are looking for, the edited line will\nbe updated with matches.Typing control-r again will go to the next\nmatch in history and so on.\n\n## Shortcuts\n\n| Shortcut                 | Action performed                                |\n| ------------------------ | ----------------------------------------------- |\n|Left cursor, `Control`-`b`|Moves the editing point left                     |\n|`Alt`-`b`                 |Moves one word back.                             |\n|`Alt`-`f`                 |Moves one word forward.                          |\n|`↑`, `Control`-`p`        |Selects the previous item in the editing history.|\n|`↓`, `Control`-`n`        |Selects the next item in the editing history.    |\n|`Home` key, `Control`-`a` |Moves the cursor to the beginning of the line.   |\n|`End` key, `Control`-`e`  |Moves the cursor to the end of the line.         |\n|`Delete`, `Control`-`d`   |Deletes the character in front of the cursor.    |\n|`Backspace`               |Deletes the character behind the cursor.         |\n|`Tab`                     |Triggers the completion and invokes the AutoCompleteEvent which gets both the line contents and the position where the cursor is.|\n|`Control`-`k`             |Deletes the text until the end of the line and replaces the kill buffer with the deleted text. You can paste this text in a different place by using Control-y.|\n|`Control`-`l`             |Clears the screen and forces a refresh of the line editor, useful when a background process writes to the console and garbles the contents of the screen.|\n|`Control`-`r`             |Initiates the reverse search in history.         |\n|`Alt`-`backspace`         |Deletes the word behind the cursor and adds it to the kill ring. You can paste the contents of the kill ring with Control-y.|\n|`Alt`-`d`                 |Deletes the word above the cursor and adds it to the kill ring.  You can paste the contents of the kill ring with Control-y.|\n|`Control`-`q`             |Quotes the next input character, to prevent the normal processing of keyhandling to take place|\n|`Control`-`c`             |Interrupts editing                               |\n"
  }
]