Example #1
0
        private void ReallyRender()
        {
            var text = ParseInput();

            int statusLineCount = GetStatusLineCount();
            int bufferLineCount = ConvertOffsetToCoordinates(text.Length).Y - _initialY + 1 + statusLineCount;
            int bufferWidth     = Console.BufferWidth;

            if (_consoleBuffer.Length != bufferLineCount * bufferWidth)
            {
                var newBuffer = new CHAR_INFO[bufferLineCount * bufferWidth];
                Array.Copy(_consoleBuffer, newBuffer, _initialX + (Options.ExtraPromptLineCount * _bufferWidth));
                if (_consoleBuffer.Length > bufferLineCount * bufferWidth)
                {
                    // Need to erase the extra lines that we won't draw again
                    for (int i = bufferLineCount * bufferWidth; i < _consoleBuffer.Length; i++)
                    {
                        _consoleBuffer[i] = _space;
                    }
                    WriteBufferLines(_consoleBuffer, ref _initialY);
                }
                _consoleBuffer = newBuffer;
            }

            var tokenStack = new Stack <SavedTokenState>();

            tokenStack.Push(new SavedTokenState
            {
                Tokens          = _tokens,
                Index           = 0,
                BackgroundColor = _initialBackgroundColor,
                ForegroundColor = _initialForegroundColor
            });

            int  j = _initialX + (_bufferWidth * Options.ExtraPromptLineCount);
            var  backgroundColor = _initialBackgroundColor;
            var  foregroundColor = _initialForegroundColor;
            bool afterLastToken  = false;

            for (int i = 0; i < text.Length; i++)
            {
                SavedTokenState state = null;

                if (!afterLastToken)
                {
                    // Figure out the color of the character - if it's in a token,
                    // use the tokens color otherwise use the initial color.
                    state = tokenStack.Peek();
                    var token = state.Tokens[state.Index];
                    if (i == token.Extent.EndOffset)
                    {
                        if (token == state.Tokens[state.Tokens.Length - 1])
                        {
                            tokenStack.Pop();
                            if (tokenStack.Count == 0)
                            {
                                afterLastToken  = true;
                                token           = null;
                                foregroundColor = _initialForegroundColor;
                                backgroundColor = _initialBackgroundColor;
                            }
                            else
                            {
                                state = tokenStack.Peek();
                            }
                        }

                        if (!afterLastToken)
                        {
                            foregroundColor = state.ForegroundColor;
                            backgroundColor = state.BackgroundColor;

                            token = state.Tokens[++state.Index];
                        }
                    }

                    if (!afterLastToken && i == token.Extent.StartOffset)
                    {
                        GetTokenColors(token, out foregroundColor, out backgroundColor);

                        var stringToken = token as StringExpandableToken;
                        if (stringToken != null)
                        {
                            // We might have nested tokens.
                            if (stringToken.NestedTokens != null && stringToken.NestedTokens.Any())
                            {
                                var tokens = new Token[stringToken.NestedTokens.Count + 1];
                                stringToken.NestedTokens.CopyTo(tokens, 0);
                                // NestedTokens doesn't have an "EOS" token, so we use
                                // the string literal token for that purpose.
                                tokens[tokens.Length - 1] = stringToken;

                                tokenStack.Push(new SavedTokenState
                                {
                                    Tokens          = tokens,
                                    Index           = 0,
                                    BackgroundColor = backgroundColor,
                                    ForegroundColor = foregroundColor
                                });
                            }
                        }
                    }
                }

                if (text[i] == '\n')
                {
                    while ((j % bufferWidth) != 0)
                    {
                        _consoleBuffer[j++] = _space;
                    }

                    for (int k = 0; k < Options.ContinuationPrompt.Length; k++, j++)
                    {
                        _consoleBuffer[j].UnicodeChar     = Options.ContinuationPrompt[k];
                        _consoleBuffer[j].ForegroundColor = Options.ContinuationPromptForegroundColor;
                        _consoleBuffer[j].BackgroundColor = Options.ContinuationPromptBackgroundColor;
                    }
                }
                else if (char.IsControl(text[i]))
                {
                    _consoleBuffer[j].UnicodeChar = '^';
                    MaybeEmphasize(ref _consoleBuffer[j++], i, foregroundColor, backgroundColor);
                    _consoleBuffer[j].UnicodeChar = (char)('@' + text[i]);
                    MaybeEmphasize(ref _consoleBuffer[j++], i, foregroundColor, backgroundColor);
                }
                else
                {
                    _consoleBuffer[j].UnicodeChar = text[i];
                    MaybeEmphasize(ref _consoleBuffer[j++], i, foregroundColor, backgroundColor);
                }
            }

            for (; j < (_consoleBuffer.Length - (statusLineCount * _bufferWidth)); j++)
            {
                _consoleBuffer[j] = _space;
            }

            if (_statusLinePrompt != null)
            {
                foregroundColor = _statusIsErrorMessage ? Options.ErrorForegroundColor : Console.ForegroundColor;
                backgroundColor = _statusIsErrorMessage ? Options.ErrorBackgroundColor : Console.BackgroundColor;

                for (int i = 0; i < _statusLinePrompt.Length; i++, j++)
                {
                    _consoleBuffer[j].UnicodeChar     = _statusLinePrompt[i];
                    _consoleBuffer[j].ForegroundColor = foregroundColor;
                    _consoleBuffer[j].BackgroundColor = backgroundColor;
                }
                for (int i = 0; i < _statusBuffer.Length; i++, j++)
                {
                    _consoleBuffer[j].UnicodeChar     = _statusBuffer[i];
                    _consoleBuffer[j].ForegroundColor = foregroundColor;
                    _consoleBuffer[j].BackgroundColor = backgroundColor;
                }

                for (; j < _consoleBuffer.Length; j++)
                {
                    _consoleBuffer[j] = _space;
                }
            }

            bool rendered = false;

            if (_parseErrors.Length > 0)
            {
                int promptChar = _initialX - 1 + (_bufferWidth * Options.ExtraPromptLineCount);

                while (promptChar >= 0)
                {
                    var c = (char)_consoleBuffer[promptChar].UnicodeChar;
                    if (char.IsWhiteSpace(c))
                    {
                        promptChar -= 1;
                        continue;
                    }

                    ConsoleColor prevColor = _consoleBuffer[promptChar].ForegroundColor;
                    _consoleBuffer[promptChar].ForegroundColor = ConsoleColor.Red;
                    WriteBufferLines(_consoleBuffer, ref _initialY);
                    rendered = true;
                    _consoleBuffer[promptChar].ForegroundColor = prevColor;
                    break;
                }
            }

            if (!rendered)
            {
                WriteBufferLines(_consoleBuffer, ref _initialY);
            }

            PlaceCursor();

            if ((_initialY + bufferLineCount) > (Console.WindowTop + Console.WindowHeight))
            {
                Console.WindowTop = _initialY + bufferLineCount - Console.WindowHeight;
            }

            _lastRenderTime.Restart();
        }
Example #2
0
        private void ReallyRender()
        {
            var text = ParseInput();

            _codePage        = NativeMethods.GetConsoleOutputCP();
            _istmInitialized = false;
            ConsoleHandle        consoleHandle = _outputHandle.Value;
            CONSOLE_FONT_INFO_EX fontInfo      = GetConsoleFontInfo(consoleHandle);
            int fontType = fontInfo.FontFamily & NativeMethods.FontTypeMask;

            _trueTypeInUse = (fontType & NativeMethods.TrueTypeFont) == NativeMethods.TrueTypeFont;

            int  statusLineCount = GetStatusLineCount();
            int  j = _initialX + (_bufferWidth * Options.ExtraPromptLineCount);
            var  backgroundColor = _initialBackgroundColor;
            var  foregroundColor = _initialForegroundColor;
            bool afterLastToken  = false;
            int  totalBytes      = j;
            int  bufferWidth     = Console.BufferWidth;

            var tokenStack = new Stack <SavedTokenState>();

            tokenStack.Push(new SavedTokenState
            {
                Tokens          = _tokens,
                Index           = 0,
                BackgroundColor = _initialBackgroundColor,
                ForegroundColor = _initialForegroundColor
            });

            int bufferLineCount;

            try
            {
                bufferLineCount = ConvertOffsetToCoordinates(text.Length).Y - _initialY + 1 + statusLineCount;
                if (_consoleBuffer.Length != bufferLineCount * bufferWidth)
                {
                    var newBuffer = new CHAR_INFO[bufferLineCount * bufferWidth];
                    Array.Copy(_consoleBuffer, newBuffer, _initialX + (Options.ExtraPromptLineCount * _bufferWidth));
                    if (_consoleBuffer.Length > bufferLineCount * bufferWidth)
                    {
                        int consoleBufferOffset = ConvertOffsetToConsoleBufferOffset(text.Length, _initialX + (Options.ExtraPromptLineCount * _bufferWidth));
                        // Need to erase the extra lines that we won't draw again
                        for (int i = consoleBufferOffset; i < _consoleBuffer.Length; i++)
                        {
                            _consoleBuffer[i] = _space;
                        }
                        WriteBufferLines(_consoleBuffer, ref _initialY);
                    }
                    _consoleBuffer = newBuffer;
                }

                for (int i = 0; i < text.Length; i++)
                {
                    SavedTokenState state = null;
                    totalBytes = totalBytes % bufferWidth;
                    if (!afterLastToken)
                    {
                        // Figure out the color of the character - if it's in a token,
                        // use the tokens color otherwise use the initial color.
                        state = tokenStack.Peek();
                        var token = state.Tokens[state.Index];
                        if (i == token.Extent.EndOffset)
                        {
                            if (token == state.Tokens[state.Tokens.Length - 1])
                            {
                                tokenStack.Pop();
                                if (tokenStack.Count == 0)
                                {
                                    afterLastToken  = true;
                                    token           = null;
                                    foregroundColor = _initialForegroundColor;
                                    backgroundColor = _initialBackgroundColor;
                                }
                                else
                                {
                                    state = tokenStack.Peek();
                                }
                            }

                            if (!afterLastToken)
                            {
                                foregroundColor = state.ForegroundColor;
                                backgroundColor = state.BackgroundColor;

                                token = state.Tokens[++state.Index];
                            }
                        }

                        if (!afterLastToken && i == token.Extent.StartOffset)
                        {
                            GetTokenColors(token, out foregroundColor, out backgroundColor);

                            var stringToken = token as StringExpandableToken;
                            if (stringToken != null)
                            {
                                // We might have nested tokens.
                                if (stringToken.NestedTokens != null && stringToken.NestedTokens.Any())
                                {
                                    var tokens = new Token[stringToken.NestedTokens.Count + 1];
                                    stringToken.NestedTokens.CopyTo(tokens, 0);
                                    // NestedTokens doesn't have an "EOS" token, so we use
                                    // the string literal token for that purpose.
                                    tokens[tokens.Length - 1] = stringToken;

                                    tokenStack.Push(new SavedTokenState
                                    {
                                        Tokens          = tokens,
                                        Index           = 0,
                                        BackgroundColor = backgroundColor,
                                        ForegroundColor = foregroundColor
                                    });
                                }
                            }
                        }
                    }

                    if (text[i] == '\n')
                    {
                        while ((j % bufferWidth) != 0)
                        {
                            _consoleBuffer[j++] = _space;
                        }

                        for (int k = 0; k < Options.ContinuationPrompt.Length; k++, j++)
                        {
                            _consoleBuffer[j].UnicodeChar     = Options.ContinuationPrompt[k];
                            _consoleBuffer[j].ForegroundColor = Options.ContinuationPromptForegroundColor;
                            _consoleBuffer[j].BackgroundColor = Options.ContinuationPromptBackgroundColor;
                        }
                    }
                    else
                    {
                        int size = LengthInBufferCells(text[i]);
                        totalBytes += size;

                        //if there is no enough space for the character at the edge, fill in spaces at the end and
                        //put the character to next line.
                        int filling = totalBytes > bufferWidth ? (totalBytes - bufferWidth) % size : 0;
                        for (int f = 0; f < filling; f++)
                        {
                            _consoleBuffer[j++] = _space;
                            totalBytes++;
                        }

                        if (char.IsControl(text[i]))
                        {
                            _consoleBuffer[j].UnicodeChar = '^';
                            MaybeEmphasize(ref _consoleBuffer[j++], i, foregroundColor, backgroundColor);
                            _consoleBuffer[j].UnicodeChar = (char)('@' + text[i]);
                            MaybeEmphasize(ref _consoleBuffer[j++], i, foregroundColor, backgroundColor);
                        }
                        else if (size > 1 && IsCJKOutputCodePage() && _trueTypeInUse)
                        {
                            _consoleBuffer[j].UnicodeChar = text[i];
                            _consoleBuffer[j].Attributes  = (ushort)((uint)_consoleBuffer[j].Attributes |
                                                                     (uint)CHAR_INFO_Attributes.COMMON_LVB_LEADING_BYTE);
                            MaybeEmphasize(ref _consoleBuffer[j++], i, foregroundColor, backgroundColor);
                            _consoleBuffer[j].UnicodeChar = text[i];
                            _consoleBuffer[j].Attributes  = (ushort)((uint)_consoleBuffer[j].Attributes |
                                                                     (uint)CHAR_INFO_Attributes.COMMON_LVB_TRAILING_BYTE);
                            MaybeEmphasize(ref _consoleBuffer[j++], i, foregroundColor, backgroundColor);
                        }
                        else
                        {
                            _consoleBuffer[j].UnicodeChar = text[i];
                            MaybeEmphasize(ref _consoleBuffer[j++], i, foregroundColor, backgroundColor);
                        }
                    }
                }
            }
            finally
            {
                if (_hwnd != (IntPtr)0 && _hDC != (IntPtr)0)
                {
                    NativeMethods.ReleaseDC(_hwnd, _hDC);
                }
            }

            for (; j < (_consoleBuffer.Length - (statusLineCount * _bufferWidth)); j++)
            {
                _consoleBuffer[j] = _space;
            }

            if (_statusLinePrompt != null)
            {
                foregroundColor = _statusIsErrorMessage ? Options.ErrorForegroundColor : Console.ForegroundColor;
                backgroundColor = _statusIsErrorMessage ? Options.ErrorBackgroundColor : Console.BackgroundColor;

                for (int i = 0; i < _statusLinePrompt.Length; i++, j++)
                {
                    _consoleBuffer[j].UnicodeChar     = _statusLinePrompt[i];
                    _consoleBuffer[j].ForegroundColor = foregroundColor;
                    _consoleBuffer[j].BackgroundColor = backgroundColor;
                }
                for (int i = 0; i < _statusBuffer.Length; i++, j++)
                {
                    _consoleBuffer[j].UnicodeChar     = _statusBuffer[i];
                    _consoleBuffer[j].ForegroundColor = foregroundColor;
                    _consoleBuffer[j].BackgroundColor = backgroundColor;
                }

                for (; j < _consoleBuffer.Length; j++)
                {
                    _consoleBuffer[j] = _space;
                }
            }

            bool rendered = false;

            if (_parseErrors.Length > 0)
            {
                int promptChar = _initialX - 1 + (_bufferWidth * Options.ExtraPromptLineCount);

                while (promptChar >= 0)
                {
                    var c = (char)_consoleBuffer[promptChar].UnicodeChar;
                    if (char.IsWhiteSpace(c))
                    {
                        promptChar -= 1;
                        continue;
                    }

                    ConsoleColor prevColor = _consoleBuffer[promptChar].ForegroundColor;
                    _consoleBuffer[promptChar].ForegroundColor = ConsoleColor.Red;
                    WriteBufferLines(_consoleBuffer, ref _initialY);
                    rendered = true;
                    _consoleBuffer[promptChar].ForegroundColor = prevColor;
                    break;
                }
            }

            if (!rendered)
            {
                WriteBufferLines(_consoleBuffer, ref _initialY);
            }

            PlaceCursor();

            if ((_initialY + bufferLineCount) > (Console.WindowTop + Console.WindowHeight))
            {
                Console.WindowTop = _initialY + bufferLineCount - Console.WindowHeight;
            }

            _lastRenderTime.Restart();
        }