Esempio n. 1
0
 /// <summary>
 /// Pretty print the specified object.
 /// </summary>
 /// <param name="obj">Object.</param>
 public static void Write(IodineObject obj)
 {
     ANSI.Write(Format(obj));
 }
Esempio n. 2
0
        string ReadUserInput()
        {
            // Declare variables
            var    accum              = new StringBuilder();
            string lastLine           = string.Empty;
            bool   editingFinished    = false;
            bool   correctIndent      = false;
            bool   correctIndentExtra = false;           // special unindent for matched grouping
            int    foldCount          = 0;
            int    foldBracketDiff    = 0;
            int    foldBraceDiff      = 0;
            int    foldParenDiff      = 0;
            int    line   = 1;
            int    indent = 0;

            // Define getFoldCount function
            var getFoldCount = new Func <string, int> (str => {
                var lexer = new Iodine.Compiler.Tokenizer(
                    new Iodine.Compiler.ErrorSink(),
                    new Iodine.Compiler.SourceReader(str, "__anonymous__")
                    );
                IEnumerable <Iodine.Compiler.Token> tokens;
                try {
                    tokens = lexer.Scan();
                } catch {
                    foldBracketDiff = 0;
                    foldParenDiff   = 0;
                    foldBraceDiff   = 0;
                    return(0);
                }
                foldBracketDiff = (
                    tokens.Count(t => t.Class == global::Iodine.Compiler.TokenClass.OpenBracket) -
                    tokens.Count(t => t.Class == global::Iodine.Compiler.TokenClass.CloseBracket)
                    );
                foldBraceDiff = (
                    tokens.Count(t => t.Class == global::Iodine.Compiler.TokenClass.OpenBrace) -
                    tokens.Count(t => t.Class == global::Iodine.Compiler.TokenClass.CloseBrace)
                    );
                foldParenDiff = (
                    tokens.Count(t => t.Class == global::Iodine.Compiler.TokenClass.OpenParan) -
                    tokens.Count(t => t.Class == global::Iodine.Compiler.TokenClass.CloseParan)
                    );
                return(foldBracketDiff + foldBraceDiff + foldParenDiff);
            });

            // Define getPrompt function
            var getPrompt = new Func <int, string> (lineNum => {
                if (Conf.UsePowerlines)
                {
                    var powerline = Powerline()
                                    .Segment($"IoX {AssemblyVersion.ToString (2)} ", fg: DarkCyan, bg: White)
                                    .Segment($"{lineNum}", fg: White, bg: DarkCyan)
                                    .ToAnsiString();
                    return(powerline);
                }
                return($"{lineNum} λ");
            });

            // Define rewriteIndent function
            var rewriteIndent = new Action(() => {
                // Save cursor state
                var currentCursorTop = Console.CursorTop;
                var targetCursorTop  = Math.Max(0, Console.CursorTop - 1);

                // Rewrite last line
                Console.CursorTop  = targetCursorTop;
                Console.CursorLeft = 0;
                Console.Write("".PadRight(Console.WindowWidth));
                Console.CursorTop  = targetCursorTop;
                Console.CursorLeft = 0;
                Prompt.Push(getPrompt(Math.Max(0, line - 1)));
                ANSI.Write(Prompt.ToString());
                Prompt.Pop();
                Console.Write(string.Empty.PadLeft((correctIndentExtra ? Math.Max(0, indent - 1) : indent) * 2));
                Console.Write(lastLine);

                // Restore cursor state
                Console.CursorTop  = currentCursorTop;
                Console.CursorLeft = 0;
            });

            // Read more lines
            while (!editingFinished)
            {
                // Test if this is the first line
                if (line == 1)
                {
                    // Duplicate prompt
                    Prompt.Dup();
                }
                else
                {
                    // Push new prompt to visually indicate multi-line editing
                    Prompt.Push(getPrompt(line));
                }

                // Test if the indentation of the previous line should be rewritten
                if (correctIndent)
                {
                    // Rewrite line
                    rewriteIndent();

                    // Do not correct the indentation again
                    correctIndent      = false;
                    correctIndentExtra = false;
                }

                // Test if the prompt of the previous line should be rewritten
                if (line == 2)
                {
                    // Save cursor state
                    var currentCursorTop = Console.CursorTop;
                    var targetCursorTop  = Math.Max(0, Console.CursorTop - 1);

                    // Rewrite last line
                    Console.CursorTop  = targetCursorTop;
                    Console.CursorLeft = 0;
                    Console.Write("".PadRight(Console.WindowWidth));
                    Console.CursorTop  = targetCursorTop;
                    Console.CursorLeft = 0;
                    Prompt.Push(getPrompt(1));
                    ANSI.Write(Prompt.ToString());
                    Prompt.Pop();
                    Console.Write(lastLine);

                    // Restore cursor state
                    Console.CursorTop  = currentCursorTop;
                    Console.CursorLeft = 0;
                }

                // Modify prompt
                Prompt.Push($"{Prompt.ToString ().Trim ()}{string.Empty.PadLeft (indent * 2)}");

                // Read line
                lastLine = Hinter.Edit(Prompt.ToString()) ?? string.Empty;

                // Restore prompt
                Prompt.Pop();

                //lastLine = Hinter.ReadHintedLine (
                //	hintSource: Iodine.Engine.Context.Globals.Concat (Iodine.Engine.Context.InteractiveLocals),
                //	hintField: attr => attr.Key,
                //	hintColor: Gray
                //).Trim ();

                // lastLine = Console.ReadLine ().Trim ();

                // Update state
                var localFoldCount = getFoldCount(lastLine);
                foldCount += localFoldCount;

                // Auto-indent based on local fold count
                if (localFoldCount > 0)
                {
                    indent += 1;
                }
                else if (localFoldCount < 0)
                {
                    correctIndent = true;
                    indent        = Math.Max(0, indent - 1);
                }

                // Auto-indent based on total fold count
                if (foldCount == 0)
                {
                    indent = 0;
                }

                // Auto-indent based on matched close-open grouping operators
                if (lastLine.Count(c => new [] { '{', '}', '[', ']', '(', ')' }.Contains(c)) >= 2 &&
                    lastLine.IndexOfAny(new [] { '}', ']', ')' }) < lastLine.IndexOfAny(new [] { '{', '[', '(' }))
                {
                    correctIndentExtra = true;
                    correctIndent      = true;
                }

                editingFinished = foldCount == 0;
                line           += 1;

                // Test for negative (unfixable) grouping mismatch
                if (foldCount < 0)
                {
                    // Clear buffer
                    accum.Clear();

                    // Output error
                    ANSI.WriteLine($"{Red}Mismatched bracket, brace, or parenthesis group!");
                    editingFinished = true;
                }
                else
                {
                    // Append line to buffer
                    accum.AppendLine(lastLine);
                }

                // Restore prompt
                Prompt.Pop();
            }

            // Rewrite indent if fold count is 0
            if (correctIndent)
            {
                rewriteIndent();
            }

            // Return buffer
            return(accum.ToString());
        }
Esempio n. 3
0
        public static string ReadHintedLine <T, TResult> (IEnumerable <T> hintSource, Func <T, TResult> hintField, ANSIColor hintColor, string inputRegex = ".*")
        {
            ConsoleKeyInfo input;
            var            editComplete           = true;
            var            accum                  = string.Empty;
            var            lastWord               = string.Empty;
            var            userInput              = string.Empty;
            var            suggestion             = string.Empty;
            var            initialCursorTop       = Console.CursorTop;
            var            initialCursorLeft      = Console.CursorLeft;
            var            lastInitialCursorTop   = Console.CursorTop;
            var            lastInitialCursorLeft  = Console.CursorLeft;
            var            localInitialCursorTop  = Console.CursorTop;
            var            localInitialCursorLeft = Console.CursorLeft;

#if DEBUG
            var __DEBUG_TRD = new System.Threading.Thread(() => {
                while (true)
                {
                    Console.Title = ($"ACCUM: {accum} | USRIN: {userInput}");
                    System.Threading.Thread.Sleep(100);
                }
            });
            __DEBUG_TRD.Start();
#endif

            // Read next key
            while (ConsoleKey.Enter != (input = Console.ReadKey(intercept: true)).Key)
            {
                // Prepare state
                if (editComplete)
                {
                    lastWord               = string.Empty;
                    userInput              = string.Empty;
                    suggestion             = string.Empty;
                    editComplete           = false;
                    lastInitialCursorTop   = localInitialCursorTop;
                    lastInitialCursorLeft  = localInitialCursorLeft;
                    localInitialCursorTop  = Console.CursorTop;
                    localInitialCursorLeft = Console.CursorLeft;
                }

                // Handle backspace
                if (input.Key == ConsoleKey.Backspace)
                {
                    if (userInput.Any())
                    {
                        userInput = userInput.Any() ? userInput.Remove(userInput.Length - 1, 1) : string.Empty;
                    }
                    else
                    {
                        accum        = accum.Remove(Math.Max(0, accum.Length - 1), accum.Length > 0 ? 1 : 0);
                        editComplete = true;

                        // Clear line
                        Console.SetCursorPosition(initialCursorLeft, initialCursorTop);
                        Console.Write(string.Empty.PadLeft(Console.WindowWidth - initialCursorLeft));
                        Console.SetCursorPosition(initialCursorLeft, initialCursorTop);

                        // Write finished line
                        Console.Write(accum);
                        continue;
                    }
                }

                // Handle member access
                else if (input.Key == ConsoleKey.OemPeriod)
                {
                    editComplete = true;
                    userInput   += input.KeyChar;
                }

                // Handle space
                else if (input.Key == ConsoleKey.Spacebar)
                {
                    editComplete = true;
                    userInput   += input.KeyChar;
                }

                // Handle tab (accept suggestion)
                else if (input.Key == ConsoleKey.Tab)
                {
                    editComplete = true;
                    userInput    = suggestion ?? userInput;
                }

                // Test if keychar is not alphanumeric
                else if (!char.IsLetterOrDigit(input.KeyChar))
                {
                    editComplete = true;
                    userInput   += input.KeyChar;
                }

                // Test if keychar matches input regex
                else if (Regex.IsMatch(input.KeyChar.ToString(), inputRegex))
                {
                    Console.CursorLeft++;
                    userInput += input.KeyChar;
                }

                // Get the suggestion
                suggestion = (
                    hintSource.Select(item => hintField(item).ToString())
                    .FirstOrDefault(
                        item => (
                            item.Length > userInput.Length &&
                            item.Substring(0, userInput.Length) == userInput
                            )
                        )
                    );

                // Get line
                lastWord = suggestion ?? userInput;

                // Clear line
                Console.SetCursorPosition(localInitialCursorLeft, localInitialCursorTop);
                Console.Write(string.Empty.PadLeft(Console.WindowWidth - localInitialCursorLeft));
                Console.SetCursorPosition(localInitialCursorLeft, localInitialCursorTop);

                // Write user input
                ANSI.Write($"{(suggestion != null ? White : Default)}{userInput}");

                // Write suggestion
                if (userInput.Any())
                {
                    ANSI.Write($"{hintColor}{lastWord.Substring (userInput.Length, lastWord.Length - userInput.Length)}");
                    if (editComplete)
                    {
                        // Clear line
                        Console.SetCursorPosition(initialCursorLeft, initialCursorTop);
                        Console.Write(string.Empty.PadLeft(Console.WindowWidth - initialCursorLeft));
                        Console.SetCursorPosition(initialCursorLeft, initialCursorTop);

                        // Write finished line
                        accum += lastWord;
                        Console.Write(accum);
                    }
                }

                continue;
            }

            if (!editComplete)
            {
                accum += userInput;
            }

            // Clear line
            Console.SetCursorPosition(initialCursorLeft, initialCursorTop);
            Console.Write(string.Empty.PadLeft(Console.WindowWidth - initialCursorLeft));
            Console.SetCursorPosition(initialCursorLeft, initialCursorTop);

            // Write finished line
            Console.WriteLine(accum);

#if DEBUG
            __DEBUG_TRD.Abort();
#endif

            // Return read line
            return(accum);
        }