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(); }
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(); }