public void CleanUpReadln()
 {
     if (_inputReaderThread != null)
     {
         lock (ConsoleLock)
         {
             var(id, left, top, right, bottom) = ActualWorkArea();
             Out.SetCursorPosConstraintedInWorkArea(_beginOfLineCurPos);
             var txt    = _inputReaderStringBuilder.ToString();
             var slines = Out.GetWorkAreaStringSplits(txt, _beginOfLineCurPos).Splits;
             var enableConstraintConsolePrintInsideWorkArea = EnableConstraintConsolePrintInsideWorkArea;
             EnableConstraintConsolePrintInsideWorkArea = false;
             foreach (var sline in slines)
             {
                 if (sline.Y >= top && sline.Y <= bottom)
                 {
                     Out.SetCursorPos(sline.X, sline.Y);
                     Out.ConsolePrint("".PadLeft(right - sline.X, ' '));
                 }
             }
             EnableConstraintConsolePrintInsideWorkArea = enableConstraintConsolePrintInsideWorkArea;
             Out.SetCursorPosConstraintedInWorkArea(_beginOfLineCurPos);
             _inputReaderStringBuilder.Clear();
         }
     }
 }
        void Initialize(ExpressionEvaluationCommandDelegate evalCommandDelegate = null)
        {
            if (evalCommandDelegate == null && CommandLineProcessor != null)
            {
                _evalCommandDelegate = CommandLineProcessor.Eval;
            }
            ViewSizeChanged += (o, e) =>
            {
                if (_inputReaderThread != null)
                {
                    lock (ConsoleLock)
                    {
                        Out.Echo(_prompt);
                        _beginOfLineCurPos = Out.CursorPos;
                        Out.ConsolePrint(_inputReaderStringBuilder.ToString());
                    }
                }
            };
            WorkAreaScrolled += (o, e) =>
            {
                if (_inputReaderThread != null)
                {
                    lock (ConsoleLock)
                    {
                        _beginOfLineCurPos.X += e.DeltaX;
                        _beginOfLineCurPos.Y += e.DeltaY;
                        var p = Out.CursorPos;
                        var(id, left, top, width, height) = ActualWorkArea();
                        var txt = _inputReaderStringBuilder.ToString();
                        if (!string.IsNullOrWhiteSpace(txt))
                        {
                            var index  = Out.GetIndexInWorkAreaConstraintedString(txt, _beginOfLineCurPos, p);
                            var slines = Out.GetWorkAreaStringSplits(txt, _beginOfLineCurPos).Splits;

                            if (Out.CursorTop == slines.Min(o => o.Y))
                            {
                                Out.CursorLeft = left;
                                Out.Echo(_prompt);
                            }
                            var enableConstraintConsolePrintInsideWorkArea = EnableConstraintConsolePrintInsideWorkArea;
                            EnableConstraintConsolePrintInsideWorkArea = false;
                            foreach (var sline in slines)
                            {
                                if (sline.Y >= top && sline.Y <= height)
                                {
                                    Out.SetCursorPos(sline.X, sline.Y);
                                    Out.ConsolePrint("".PadLeft(width - sline.X, ' '));
                                    Out.SetCursorPos(sline.X, sline.Y);
                                    Out.ConsolePrint(sline.Text);
                                }
                            }
                            EnableConstraintConsolePrintInsideWorkArea = enableConstraintConsolePrintInsideWorkArea;
                            Out.SetCursorPos(p);
                        }
                    }
                }
            };
        }
예제 #3
0
        public CommandVoidResult History(
            CommandEvaluationContext context,
            [Option("i", "invoke the command at the entry number in the history list", true, true)] int num,
            [Option("c", "clear the loaded history list")] bool clear,
            [Option("w", "write history lines to the history file (content of the file is replaced)")]
            [OptionRequireParameter("file")]  bool writeToFile,
            [Option("a", "append history lines to the history file")]
            [OptionRequireParameter("file")]  bool appendToFile,
            [Option("r", "read the history file and append the content to the history list")]
            [OptionRequireParameter("file")]  bool readFromFile,
            [Option("n", "read the history file and append the content not already in the history list to the history list")]
            [OptionRequireParameter("file")] bool appendFromFile,
            [Parameter(1, "file", true)] FilePath file
            )
        {
            var hist = context.CommandLineProcessor.CmdsHistory.History;
            var max  = hist.Count().ToString().Length;
            int i    = 1;
            var f    = DefaultForegroundCmd;

            if (num > 0)
            {
                if (num < 1 || num > hist.Count)
                {
                    Errorln($"history entry number out of range (1..{hist.Count})");
                    return(new CommandVoidResult(ReturnCode.Error));
                }
                var h = hist[num - 1];
                context.CommandLineProcessor.CommandLineReader.SendNextInput(h);
                return(new CommandVoidResult());
            }

            if (clear)
            {
                context.CommandLineProcessor.CmdsHistory.ClearHistory();
                return(new CommandVoidResult());
            }

            if (appendToFile || readFromFile || appendFromFile || writeToFile)
            {
                file ??= context.CommandLineProcessor.CmdsHistory.FilePath;
                if (file.CheckPathExists())
                {
                    if (writeToFile)
                    {
                        File.Delete(context.CommandLineProcessor.CmdsHistory.FilePath.FullName);
                        File.AppendAllLines(file.FullName, hist);
                    }
                    if (appendToFile)
                    {
                        File.AppendAllLines(file.FullName, hist);
                    }
                    if (readFromFile)
                    {
                        var lines = File.ReadAllLines(file.FullName);
                        foreach (var line in lines)
                        {
                            context.CommandLineProcessor.CmdsHistory.HistoryAppend(line);
                        }
                        context.CommandLineProcessor.CmdsHistory.HistorySetIndex(-1, false);
                    }
                    if (appendFromFile)
                    {
                        var lines = File.ReadAllLines(file.FullName);
                        foreach (var line in lines)
                        {
                            if (!context.CommandLineProcessor.CmdsHistory.HistoryContains(line))
                            {
                                context.CommandLineProcessor.CmdsHistory.HistoryAppend(line);
                            }
                        }
                        context.CommandLineProcessor.CmdsHistory.HistorySetIndex(-1, false);
                    }
                }
                return(new CommandVoidResult());
            }

            foreach (var h in hist)
            {
                if (context.CommandLineProcessor.CancellationTokenSource.IsCancellationRequested)
                {
                    break;
                }
                var hp = $"  {ColorSettings.Numeric}{i.ToString().PadRight(max + 2, ' ')}{f}";
                context.Out.Echo(hp);
                Out.ConsolePrint(h, true);
                i++;
            }
            return(new CommandVoidResult());
        }
예제 #4
0
        public int BeginReadln(
            AsyncCallback asyncCallback,
            string prompt            = null,
            bool waitForReaderExited = true,
            bool loop = true
            )
        {
            _waitForReaderExited = waitForReaderExited;
            prompt ??= _defaultPrompt;
            _prompt = prompt;
            bool  noWorkArea   = !InWorkArea;
            Point?lastInputPos = null;
            var   hm           = CommandLineProcessor?.ModuleManager?.ModuleHookManager;
            var   context      = CommandLineProcessor?.CommandEvaluationContext;

            _inputReaderThread = new Thread(() =>
            {
                try
                {
                    var isRunning = true;
                    while (isRunning)
                    {
                        if (!loop)
                        {
                            isRunning = false;
                        }
                        _inputReaderStringBuilder ??= new StringBuilder();
                        if (!_readingStarted)
                        {
                            lock (ConsoleLock)
                            {
                                hm?.InvokeHooks(context, Hooks.PromptOutputBegin);

                                var _beginPromptPos = Out.CursorPos;
                                Out.Echo(prompt);

                                hm?.InvokeHooks(context, Hooks.PromptOutputEnd);

                                _beginOfLineCurPos = Out.CursorPos;
                                lastInputPos       = _beginOfLineCurPos;
                                Out.ConsoleCursorPosBackup();

#if FIX_LOW_ANSI    // TODO only if compatibility mode is enabled OR never (check the best)
                                Thread.Sleep(25);
                                Out.ConsoleCursorPosRestore();
#endif
                                _readingStarted = true;
                            }
                        }
                        var eol = false;

                        try
                        {
                            while (!eol)
                            {
                                ConsoleKeyInfo c;
                                var printed       = false;
                                string printedStr = "";
                                var(id, left, top, right, bottom) = ActualWorkArea();

                                if (sc.IsInputRedirected)
                                {
                                    _sentInput = sc.In.ReadToEnd();
                                    isRunning  = false;
                                }

                                if (_sentInput == null)
                                {
                                    c = sc.ReadKey(true);
#if dbg
                                    System.Diagnostics.Debug.WriteLine($"{c.KeyChar}={c.Key}");
#endif
                                    #region handle special keys - edition mode, movement

                                    if (!_ignoreNextKey)
                                    {
                                        // normally the cursor has moved of 1 character right or left
                                        var cPos = Out.CursorPos;
                                        if (lastInputPos.HasValue &&
                                            lastInputPos.Value != cPos)
                                        {
                                            int dx = Math.Abs(cPos.X - lastInputPos.Value.X);
                                            int dy = Math.Abs(cPos.Y - lastInputPos.Value.Y);
                                            if (dx > 1 || dy > 1)
                                            {
                                                // restore the good position
                                                Out.CursorPos =
                                                    new Point(
                                                        lastInputPos.Value.X + 1,
                                                        lastInputPos.Value.Y);
                                            }
                                        }

                                        lastInputPos = Out.CursorPos;

                                        (id, left, top, right, bottom) = ActualWorkArea();

                                        switch (c.Key)
                                        {
                                        /// <summary>
                                        /// CR: default end of input
                                        /// </summary>
                                        case ConsoleKey.Enter:
                                            eol = true;
                                            break;

                                        /// <summary>
                                        /// ESC : clean-up input and set cursor at begin of line (after prompt)
                                        /// </summary>
                                        case ConsoleKey.Escape:
                                            //Out.HideCur();
                                            CleanUpReadln();
                                            lastInputPos = _beginOfLineCurPos;
                                            //Out.ShowCur();
                                            break;

                                        /// <summary>
                                        /// HOME : set cursor position at begin of input (just after prompt)
                                        /// </summary>
                                        case ConsoleKey.Home:
                                            lock (ConsoleLock)
                                            {
                                                Out.SetCursorPosConstraintedInWorkArea(_beginOfLineCurPos);
                                                lastInputPos = _beginOfLineCurPos;
                                            }
                                            break;

                                        /// <summary>
                                        /// END : set cursor position at end of input
                                        /// </summary>
                                        case ConsoleKey.End:
                                            lock (ConsoleLock)
                                            {
                                                var slines = Out.GetWorkAreaStringSplits(_inputReaderStringBuilder.ToString(), _beginOfLineCurPos);
                                                var sline  = slines.Splits.Last();
                                                Out.SetCursorPosConstraintedInWorkArea(sline.X + sline.Length, sline.Y);
                                                lastInputPos = Out.CursorPos;
                                            }
                                            break;

                                        case ConsoleKey.Tab:
                                            lock (ConsoleLock)
                                            {
                                                printedStr = "".PadLeft(TabLength, ' ');
                                                printed    = true;
                                            }
                                            break;

                                        case ConsoleKey.LeftArrow:
                                            lock (ConsoleLock)
                                            {
                                                var p = Out.CursorPos;
                                                if (p.Y == _beginOfLineCurPos.Y)
                                                {
                                                    if (p.X > _beginOfLineCurPos.X)
                                                    {
                                                        Out.CursorLeft = p.X - 1;
                                                    }
                                                }
                                                else
                                                {
                                                    var x = p.X - 1;
                                                    if (x < left)
                                                    {
                                                        Out.SetCursorPosConstraintedInWorkArea(right - 1, p.Y - 1);
                                                    }
                                                    else
                                                    {
                                                        Out.CursorLeft = x;
                                                    }
                                                }
                                            }
                                            break;

                                        case ConsoleKey.RightArrow:
                                            lock (ConsoleLock)
                                            {
                                                var txt   = _inputReaderStringBuilder.ToString();
                                                var index = Out.GetIndexInWorkAreaConstraintedString(txt, _beginOfLineCurPos, Out.CursorPos);
                                                if (index < txt.Length)
                                                {
                                                    Out.SetCursorPosConstraintedInWorkArea(Out.CursorLeft + 1, Out.CursorTop);
                                                }
                                            }
                                            break;

                                        case ConsoleKey.Backspace:
                                            lock (ConsoleLock)
                                            {
                                                var txt   = _inputReaderStringBuilder.ToString();
                                                var index = Out.GetIndexInWorkAreaConstraintedString(txt, _beginOfLineCurPos, Out.CursorPos) - 1;
                                                var x     = Out.CursorLeft - 1;
                                                var y     = Out.CursorTop;
                                                if (index >= 0)
                                                {
                                                    _inputReaderStringBuilder.Remove(index, 1);
                                                    _inputReaderStringBuilder.Append(" ");
                                                    Out.HideCur();
                                                    Out.SetCursorPosConstraintedInWorkArea(ref x, ref y);
                                                    var slines = Out.GetWorkAreaStringSplits(_inputReaderStringBuilder.ToString(), _beginOfLineCurPos).Splits;
                                                    var enableConstraintConsolePrintInsideWorkArea = EnableConstraintConsolePrintInsideWorkArea;
                                                    EnableConstraintConsolePrintInsideWorkArea     = false;
                                                    foreach (var sline in slines)
                                                    {
                                                        if (sline.Y >= top && sline.Y <= bottom)
                                                        {
                                                            Out.SetCursorPos(sline.X, sline.Y);
                                                            Out.ConsolePrint("".PadLeft(right - sline.X, ' '));
                                                            Out.SetCursorPos(sline.X, sline.Y);
                                                            Out.ConsolePrint(sline.Text);
                                                        }
                                                    }
                                                    _inputReaderStringBuilder.Remove(_inputReaderStringBuilder.Length - 1, 1);
                                                    EnableConstraintConsolePrintInsideWorkArea = enableConstraintConsolePrintInsideWorkArea;
                                                    Out.SetCursorPos(x, y);
                                                    Out.ShowCur();
                                                }
                                            }
                                            break;

                                        case ConsoleKey.Delete:
                                            lock (ConsoleLock)
                                            {
                                                var txt   = _inputReaderStringBuilder.ToString();
                                                var index = Out.GetIndexInWorkAreaConstraintedString(txt, _beginOfLineCurPos, Out.CursorPos);
                                                var x     = Out.CursorLeft;
                                                var y     = Out.CursorTop;
                                                if (index >= 0 && index < txt.Length)
                                                {
                                                    _inputReaderStringBuilder.Remove(index, 1);
                                                    _inputReaderStringBuilder.Append(" ");
                                                    Out.HideCur();
                                                    Out.SetCursorPosConstraintedInWorkArea(ref x, ref y);
                                                    var slines = Out.GetWorkAreaStringSplits(_inputReaderStringBuilder.ToString(), _beginOfLineCurPos).Splits;
                                                    var enableConstraintConsolePrintInsideWorkArea = EnableConstraintConsolePrintInsideWorkArea;
                                                    EnableConstraintConsolePrintInsideWorkArea     = false;
                                                    foreach (var sline in slines)
                                                    {
                                                        if (sline.Y >= top && sline.Y <= bottom)
                                                        {
                                                            Out.SetCursorPos(sline.X, sline.Y);
                                                            Out.ConsolePrint("".PadLeft(right - sline.X, ' '));
                                                            Out.SetCursorPos(sline.X, sline.Y);
                                                            Out.ConsolePrint(sline.Text);
                                                        }
                                                    }
                                                    _inputReaderStringBuilder.Remove(_inputReaderStringBuilder.Length - 1, 1);
                                                    EnableConstraintConsolePrintInsideWorkArea = enableConstraintConsolePrintInsideWorkArea;
                                                    Out.SetCursorPos(x, y);
                                                    Out.ShowCur();
                                                }
                                            }
                                            break;

                                        case ConsoleKey.UpArrow:
                                            lock (ConsoleLock)
                                            {
                                                if (Out.CursorTop == _beginOfLineCurPos.Y)
                                                {
                                                    var h = CommandLineProcessor.CmdsHistory.GetBackwardHistory();
                                                    if (h != null)
                                                    {
                                                        Out.HideCur();
                                                        CleanUpReadln();
                                                        _inputReaderStringBuilder.Append(h);
                                                        Out.ConsolePrint(h);
                                                        lastInputPos = Out.CursorPos;
                                                        Out.ShowCur();
                                                    }
                                                }
                                                else
                                                {
                                                    Out.SetCursorPosConstraintedInWorkArea(
                                                        (Out.CursorTop - 1) == _beginOfLineCurPos.Y ?
                                                        Math.Max(_beginOfLineCurPos.X, Out.CursorLeft) : Out.CursorLeft,
                                                        Out.CursorTop - 1);
                                                }
                                            }
                                            break;

                                        case ConsoleKey.DownArrow:
                                            lock (ConsoleLock)
                                            {
                                                var slines = Out.GetWorkAreaStringSplits(_inputReaderStringBuilder.ToString(), _beginOfLineCurPos).Splits;
                                                if (Out.CursorTop == slines.Max(o => o.Y))
                                                {
                                                    var fh = CommandLineProcessor.CmdsHistory.GetForwardHistory();
                                                    if (fh != null)
                                                    {
                                                        Out.HideCur();
                                                        CleanUpReadln();
                                                        _inputReaderStringBuilder.Append(fh);
                                                        Out.ConsolePrint(fh);
                                                        lastInputPos = Out.CursorPos;
                                                        Out.ShowCur();
                                                    }
                                                }
                                                else
                                                {
                                                    var sline = slines.Where(o => o.Y == Out.CursorTop + 1).FirstOrDefault();
                                                    // BUG: ici sline est null
                                                    if (sline.Text != null)
                                                    {
                                                        Out.SetCursorPosConstraintedInWorkArea(Math.Min(Out.CursorLeft, sline.X + sline.Length), Out.CursorTop + 1);
                                                    }
                                                }
                                            }
                                            break;

                                        default:
                                            printedStr = c.KeyChar + "";
                                            printed    = true;
                                            break;
                                        }
                                    }
                                    else
                                    {
                                        _ignoreNextKey = false;
                                    }

                                    #endregion
                                }
                                else
                                {
                                    printedStr = _sentInput;
                                    _sentInput = null;
                                    printed    = true;
                                    eol        = printedStr.EndsWith(Environment.NewLine);
                                    if (eol)
                                    {
                                        printedStr = printedStr.Trim();
                                    }
                                }

                                if (printed)
                                {
                                    var index  = 0;
                                    var insert = false;
                                    lock (ConsoleLock)
                                    {
                                        var x0  = Out.CursorLeft;
                                        var y0  = Out.CursorTop;
                                        var txt = _inputReaderStringBuilder.ToString();
                                        index   = Out.GetIndexInWorkAreaConstraintedString(txt, _beginOfLineCurPos, x0, y0);
                                        insert  = index - txt.Length < 0;

                                        if (insert)
                                        {
                                            Out.HideCur();
                                            var x = x0;
                                            var y = y0;
                                            Out.SetCursorPosConstraintedInWorkArea(ref x, ref y);
                                            _inputReaderStringBuilder.Insert(index, printedStr);
                                            var slines = Out.GetWorkAreaStringSplits(_inputReaderStringBuilder.ToString(), _beginOfLineCurPos).Splits;
                                            var enableConstraintConsolePrintInsideWorkArea = EnableConstraintConsolePrintInsideWorkArea;
                                            EnableConstraintConsolePrintInsideWorkArea     = false;
                                            foreach (var sline in slines)
                                            {
                                                if (sline.Y >= top && sline.Y <= bottom)
                                                {
                                                    Out.SetCursorPos(sline.X, sline.Y);
                                                    Out.ConsolePrint(sline.Text);
                                                }
                                            }
                                            EnableConstraintConsolePrintInsideWorkArea = enableConstraintConsolePrintInsideWorkArea;
                                            x += printedStr.Length;
                                            Out.SetCursorPosConstraintedInWorkArea(ref x, ref y);
                                            Out.ShowCur();
                                        }
                                        if (!insert)
                                        {
                                            _inputReaderStringBuilder.Append(printedStr);
                                            Out.ConsolePrint(printedStr, false);
                                        }
                                    }
                                }

                                if (eol)
                                {
                                    break;
                                }
                            }
                        }
                        catch /*(Exception inputProcessingException)*/
                        {
                            // input processing crashed : re-engage prompt, mute error
                        }

                        // process input

                        var s = _inputReaderStringBuilder.ToString();
                        _inputReaderStringBuilder.Clear();

                        // put the cursor at the end of the input
                        try
                        {
                            var slines = Out.GetWorkAreaStringSplits(s, _beginOfLineCurPos).Splits;
                            if (slines.Count() > 0)
                            {
                                var sline     = slines.Last();
                                Out.CursorPos = new Point(/*(sline.Text.Length==0)?0:*/ sline.Text.Length + sline.X, sline.Y);
                            }
                        }
                        catch (Exception) { }

                        var _enableConstraintConsolePrintInsideWorkArea = EnableConstraintConsolePrintInsideWorkArea;
                        if (noWorkArea)
                        {
                            EnableConstraintConsolePrintInsideWorkArea = false;
                        }

                        asyncCallback?.Invoke(
                            new BeginReadlnAsyncResult(s)
                            );

                        if (noWorkArea)
                        {
                            EnableConstraintConsolePrintInsideWorkArea = _enableConstraintConsolePrintInsideWorkArea;
                        }

                        _readingStarted = false;
                        if (_nextPrompt != null)
                        {
                            prompt      = _prompt = _nextPrompt;
                            _nextPrompt = null;
                        }
                    }
                }
                catch (ThreadInterruptedException)
                {
                    // normal end
                }
                catch (Exception inputStreamReaderThreadException)
                {
                    LogException(inputStreamReaderThreadException, "input stream reader crashed");
                }
            })
            {
                Name = "input stream reader"
            };
            _inputReaderThread.Start();
            if (waitForReaderExited)
            {
                _inputReaderThread.Join();
            }
            return((int)ReturnCode.OK);
        }
        public int BeginReadln(
            AsyncCallback asyncCallback,
            string prompt            = null,
            bool waitForReaderExited = true,
            bool loop = true
            )
        {
            _waitForReaderExited = waitForReaderExited;
            prompt ??= _defaultPrompt;
            _prompt = prompt;
            bool noWorkArea = !InWorkArea;

            _inputReaderThread = new Thread(() =>
            {
                try
                {
                    var isRunning = true;
                    while (isRunning)
                    {
                        if (!loop)
                        {
                            isRunning = false;
                        }
                        _inputReaderStringBuilder ??= new StringBuilder();
                        if (!_readingStarted)
                        {
                            lock (ConsoleLock)
                            {
                                Out.Echo(prompt);
                                _beginOfLineCurPos = Out.CursorPos;
                            }
                            _readingStarted = true;
                        }
                        var eol = false;
                        while (!eol)
                        {
                            ConsoleKeyInfo c;
                            var printed       = false;
                            string printedStr = "";
                            var(id, left, top, right, bottom) = ActualWorkArea();

                            if (sc.IsInputRedirected)
                            {
                                _sentInput = sc.In.ReadToEnd();
                                isRunning  = false;
                            }

                            if (_sentInput == null)
                            {
                                c = sc.ReadKey(true);
#if dbg
                                System.Diagnostics.Debug.WriteLine($"{c.KeyChar}={c.Key}");
#endif
                                #region handle special keys - edition mode, movement

                                if (!_ignoreNextKey)
                                {
                                    (id, left, top, right, bottom) = ActualWorkArea();

                                    switch (c.Key)
                                    {
                                    case ConsoleKey.Enter:
                                        eol = true;
                                        break;

                                    case ConsoleKey.Escape:
                                        Out.HideCur();
                                        CleanUpReadln();
                                        Out.ShowCur();
                                        break;

                                    case ConsoleKey.Home:
                                        lock (ConsoleLock)
                                        {
                                            Out.SetCursorPosConstraintedInWorkArea(_beginOfLineCurPos);
                                        }
                                        break;

                                    case ConsoleKey.End:
                                        lock (ConsoleLock)
                                        {
                                            var slines = Out.GetWorkAreaStringSplits(_inputReaderStringBuilder.ToString(), _beginOfLineCurPos);
                                            var sline  = slines.Splits.Last();
                                            Out.SetCursorPosConstraintedInWorkArea(sline.X + sline.Length, sline.Y);
                                        }
                                        break;

                                    case ConsoleKey.Tab:
                                        lock (ConsoleLock)
                                        {
                                            printedStr = "".PadLeft(TabLength, ' ');
                                            printed    = true;
                                        }
                                        break;

                                    case ConsoleKey.LeftArrow:
                                        lock (ConsoleLock)
                                        {
                                            var p = Out.CursorPos;
                                            if (p.Y == _beginOfLineCurPos.Y)
                                            {
                                                if (p.X > _beginOfLineCurPos.X)
                                                {
                                                    Out.CursorLeft = p.X - 1;
                                                }
                                            }
                                            else
                                            {
                                                var x = p.X - 1;
                                                if (x < left)
                                                {
                                                    Out.SetCursorPosConstraintedInWorkArea(right - 1, p.Y - 1);
                                                }
                                                else
                                                {
                                                    Out.CursorLeft = x;
                                                }
                                            }
                                        }
                                        break;

                                    case ConsoleKey.RightArrow:
                                        lock (ConsoleLock)
                                        {
                                            var txt   = _inputReaderStringBuilder.ToString();
                                            var index = Out.GetIndexInWorkAreaConstraintedString(txt, _beginOfLineCurPos, Out.CursorPos);
                                            if (index < txt.Length)
                                            {
                                                Out.SetCursorPosConstraintedInWorkArea(Out.CursorLeft + 1, Out.CursorTop);
                                            }
                                        }
                                        break;

                                    case ConsoleKey.Backspace:
                                        lock (ConsoleLock)
                                        {
                                            var txt   = _inputReaderStringBuilder.ToString();
                                            var index = Out.GetIndexInWorkAreaConstraintedString(txt, _beginOfLineCurPos, Out.CursorPos) - 1;
                                            var x     = Out.CursorLeft - 1;
                                            var y     = Out.CursorTop;
                                            if (index >= 0)
                                            {
                                                _inputReaderStringBuilder.Remove(index, 1);
                                                _inputReaderStringBuilder.Append(" ");
                                                Out.HideCur();
                                                Out.SetCursorPosConstraintedInWorkArea(ref x, ref y);
                                                var slines = Out.GetWorkAreaStringSplits(_inputReaderStringBuilder.ToString(), _beginOfLineCurPos).Splits;
                                                var enableConstraintConsolePrintInsideWorkArea = EnableConstraintConsolePrintInsideWorkArea;
                                                EnableConstraintConsolePrintInsideWorkArea     = false;
                                                foreach (var sline in slines)
                                                {
                                                    if (sline.Y >= top && sline.Y <= bottom)
                                                    {
                                                        Out.SetCursorPos(sline.X, sline.Y);
                                                        Out.ConsolePrint("".PadLeft(right - sline.X, ' '));
                                                        Out.SetCursorPos(sline.X, sline.Y);
                                                        Out.ConsolePrint(sline.Text);
                                                    }
                                                }
                                                _inputReaderStringBuilder.Remove(_inputReaderStringBuilder.Length - 1, 1);
                                                EnableConstraintConsolePrintInsideWorkArea = enableConstraintConsolePrintInsideWorkArea;
                                                Out.SetCursorPos(x, y);
                                                Out.ShowCur();
                                            }
                                        }
                                        break;

                                    case ConsoleKey.Delete:
                                        lock (ConsoleLock)
                                        {
                                            var txt   = _inputReaderStringBuilder.ToString();
                                            var index = Out.GetIndexInWorkAreaConstraintedString(txt, _beginOfLineCurPos, Out.CursorPos);
                                            var x     = Out.CursorLeft;
                                            var y     = Out.CursorTop;
                                            if (index >= 0 && index < txt.Length)
                                            {
                                                _inputReaderStringBuilder.Remove(index, 1);
                                                _inputReaderStringBuilder.Append(" ");
                                                Out.HideCur();
                                                Out.SetCursorPosConstraintedInWorkArea(ref x, ref y);
                                                var slines = Out.GetWorkAreaStringSplits(_inputReaderStringBuilder.ToString(), _beginOfLineCurPos).Splits;
                                                var enableConstraintConsolePrintInsideWorkArea = EnableConstraintConsolePrintInsideWorkArea;
                                                EnableConstraintConsolePrintInsideWorkArea     = false;
                                                foreach (var sline in slines)
                                                {
                                                    if (sline.Y >= top && sline.Y <= bottom)
                                                    {
                                                        Out.SetCursorPos(sline.X, sline.Y);
                                                        Out.ConsolePrint("".PadLeft(right - sline.X, ' '));
                                                        Out.SetCursorPos(sline.X, sline.Y);
                                                        Out.ConsolePrint(sline.Text);
                                                    }
                                                }
                                                _inputReaderStringBuilder.Remove(_inputReaderStringBuilder.Length - 1, 1);
                                                EnableConstraintConsolePrintInsideWorkArea = enableConstraintConsolePrintInsideWorkArea;
                                                Out.SetCursorPos(x, y);
                                                Out.ShowCur();
                                            }
                                        }
                                        break;

                                    case ConsoleKey.UpArrow:
                                        lock (ConsoleLock)
                                        {
                                            if (Out.CursorTop == _beginOfLineCurPos.Y)
                                            {
                                                var h = CommandLineProcessor.CmdsHistory.GetBackwardHistory();
                                                if (h != null)
                                                {
                                                    Out.HideCur();
                                                    CleanUpReadln();
                                                    _inputReaderStringBuilder.Append(h);
                                                    Out.ConsolePrint(h);
                                                    Out.ShowCur();
                                                }
                                            }
                                            else
                                            {
                                                Out.SetCursorPosConstraintedInWorkArea(
                                                    (Out.CursorTop - 1) == _beginOfLineCurPos.Y ?
                                                    Math.Max(_beginOfLineCurPos.X, Out.CursorLeft) : Out.CursorLeft,
                                                    Out.CursorTop - 1);
                                            }
                                        }
                                        break;

                                    case ConsoleKey.DownArrow:
                                        lock (ConsoleLock)
                                        {
                                            var slines = Out.GetWorkAreaStringSplits(_inputReaderStringBuilder.ToString(), _beginOfLineCurPos).Splits;
                                            if (Out.CursorTop == slines.Max(o => o.Y))
                                            {
                                                var fh = CommandLineProcessor.CmdsHistory.GetForwardHistory();
                                                if (fh != null)
                                                {
                                                    Out.HideCur();
                                                    CleanUpReadln();
                                                    _inputReaderStringBuilder.Append(fh);
                                                    Out.ConsolePrint(fh);
                                                    Out.ShowCur();
                                                }
                                            }
                                            else
                                            {
                                                var sline = slines.Where(o => o.Y == Out.CursorTop + 1).FirstOrDefault();
                                                // BUG: ici sline est null
                                                if (sline.Text != null)
                                                {
                                                    Out.SetCursorPosConstraintedInWorkArea(Math.Min(Out.CursorLeft, sline.X + sline.Length), Out.CursorTop + 1);
                                                }
                                            }
                                        }
                                        break;

                                    default:
                                        printedStr = c.KeyChar + "";
                                        printed    = true;
                                        break;
                                    }
                                }
                                else
                                {
                                    _ignoreNextKey = false;
                                }

                                #endregion
                            }
                            else
                            {
                                printedStr = _sentInput;
                                _sentInput = null;
                                printed    = true;
                                eol        = printedStr.EndsWith(Environment.NewLine);
                                if (eol)
                                {
                                    printedStr = printedStr.Trim();
                                }
                            }

                            if (printed)
                            {
                                var index  = 0;
                                var insert = false;
                                lock (ConsoleLock)
                                {
                                    var x0  = Out.CursorLeft;
                                    var y0  = Out.CursorTop;
                                    var txt = _inputReaderStringBuilder.ToString();
                                    index   = Out.GetIndexInWorkAreaConstraintedString(txt, _beginOfLineCurPos, x0, y0);
                                    insert  = index - txt.Length < 0;

                                    if (insert)
                                    {
                                        Out.HideCur();
                                        var x = x0;
                                        var y = y0;
                                        Out.SetCursorPosConstraintedInWorkArea(ref x, ref y);
                                        _inputReaderStringBuilder.Insert(index, printedStr);
                                        var slines = Out.GetWorkAreaStringSplits(_inputReaderStringBuilder.ToString(), _beginOfLineCurPos).Splits;
                                        var enableConstraintConsolePrintInsideWorkArea = EnableConstraintConsolePrintInsideWorkArea;
                                        EnableConstraintConsolePrintInsideWorkArea     = false;
                                        foreach (var sline in slines)
                                        {
                                            if (sline.Y >= top && sline.Y <= bottom)
                                            {
                                                Out.SetCursorPos(sline.X, sline.Y);
                                                Out.ConsolePrint(sline.Text);
                                            }
                                        }
                                        EnableConstraintConsolePrintInsideWorkArea = enableConstraintConsolePrintInsideWorkArea;
                                        x += printedStr.Length;
                                        Out.SetCursorPosConstraintedInWorkArea(ref x, ref y);
                                        Out.ShowCur();
                                    }
                                    if (!insert)
                                    {
                                        _inputReaderStringBuilder.Append(printedStr);
                                        Out.ConsolePrint(printedStr, false);
                                    }
                                }
                            }

                            if (eol)
                            {
                                break;
                            }
                        }

                        // process input
                        var s = _inputReaderStringBuilder.ToString();
                        _inputReaderStringBuilder.Clear();

                        if (noWorkArea)
                        {
                            EnableConstraintConsolePrintInsideWorkArea = false;
                        }

                        asyncCallback?.Invoke(
                            new BeginReadlnAsyncResult(s)
                            );

                        if (noWorkArea)
                        {
                            EnableConstraintConsolePrintInsideWorkArea = true;
                        }

                        _readingStarted = false;
                        if (_nextPrompt != null)
                        {
                            prompt      = _prompt = _nextPrompt;
                            _nextPrompt = null;
                        }
                    }
                }
                catch (ThreadInterruptedException) {
                }
                catch (Exception ex)
                {
                    LogException(ex, "input stream reader crashed");
                }
            })
            {
                Name = "input stream reader"
            };
            _inputReaderThread.Start();
            if (waitForReaderExited)
            {
                _inputReaderThread.Join();
            }
            return((int)ReturnCode.OK);
        }