private void MaybeEmphasize(ref BufferChar charInfo, int i, ConsoleColor foregroundColor, ConsoleColor backgroundColor) { if (i >= _emphasisStart && i < (_emphasisStart + _emphasisLength)) { backgroundColor = _options.EmphasisBackgroundColor; foregroundColor = _options.EmphasisForegroundColor; } else if (_visualSelectionCommandCount > 0 && InRegion(i)) { // We can't quite emulate real console selection because it inverts // based on actual screen colors, our pallete is limited. The choice // to invert only the lower 3 bits to change the color is somewhat // but looks best with the 2 default color schemes - starting PowerShell // from it's shortcut or from a cmd shortcut. #if UNIX // TODO: set Inverse attribute and let render choose what to do. ConsoleColor tempColor = (foregroundColor == UnknownColor) ? ConsoleColor.White : foregroundColor; foregroundColor = (backgroundColor == UnknownColor) ? ConsoleColor.Black : backgroundColor; backgroundColor = tempColor; #else foregroundColor = (ConsoleColor)((int)foregroundColor ^ 7); backgroundColor = (ConsoleColor)((int)backgroundColor ^ 7); #endif } charInfo.ForegroundColor = foregroundColor; charInfo.BackgroundColor = backgroundColor; }
private static void WriteBlankLines(int count, int top) { var console = _singleton._console; var blanks = new BufferChar[count * console.BufferWidth]; for (int i = 0; i < blanks.Length; i++) { blanks[i].BackgroundColor = console.BackgroundColor; blanks[i].ForegroundColor = console.ForegroundColor; blanks[i].UnicodeChar = ' '; } console.WriteBufferLines(blanks, ref top); }
private void Initialize(Runspace runspace, EngineIntrinsics engineIntrinsics) { _engineIntrinsics = engineIntrinsics; _runspace = runspace; if (!_delayedOneTimeInitCompleted) { DelayedOneTimeInitialize(); _delayedOneTimeInitCompleted = true; } _buffer.Clear(); _edits = new List <EditItem>(); _undoEditIndex = 0; _editGroupStart = -1; _current = 0; _mark = 0; _emphasisStart = -1; _emphasisLength = 0; _tokens = null; _parseErrors = null; _inputAccepted = false; _initialX = _console.CursorLeft; _initialY = _console.CursorTop - Options.ExtraPromptLineCount; _initialBackgroundColor = _console.BackgroundColor; _initialForegroundColor = _console.ForegroundColor; _space = new BufferChar { UnicodeChar = ' ', BackgroundColor = _initialBackgroundColor, ForegroundColor = _initialForegroundColor }; _bufferWidth = _console.BufferWidth; _killCommandCount = 0; _yankCommandCount = 0; _yankLastArgCommandCount = 0; _tabCommandCount = 0; _visualSelectionCommandCount = 0; _statusIsErrorMessage = false; #if UNIX // TODO: not necessary if ReadBufferLines worked, or if rendering worked on spans instead of complete lines string newPrompt = GetPrompt(); int index = newPrompt.LastIndexOf('\n'); if (index != -1) { // The prompt text could be a multi-line string, and in such case // we only want the part of it that is shown on the input line. newPrompt = newPrompt.Substring(index + 1); } var bufferLineCount = (newPrompt.Length) / (_console.BufferWidth) + 1; _consoleBuffer = ReadBufferLines(_initialY, bufferLineCount); for (int i = 0; i < newPrompt.Length; ++i) { _consoleBuffer[i].UnicodeChar = newPrompt[i]; } #else _consoleBuffer = ReadBufferLines(_initialY, 1 + Options.ExtraPromptLineCount); #endif _lastRenderTime = Stopwatch.StartNew(); _killCommandCount = 0; _yankCommandCount = 0; _yankLastArgCommandCount = 0; _tabCommandCount = 0; _recallHistoryCommandCount = 0; _visualSelectionCommandCount = 0; _hashedHistory = null; if (_getNextHistoryIndex > 0) { _currentHistoryIndex = _getNextHistoryIndex; UpdateFromHistory(moveCursor: true); _getNextHistoryIndex = 0; if (_searchHistoryCommandCount > 0) { _searchHistoryPrefix = ""; if (Options.HistoryNoDuplicates) { _hashedHistory = new Dictionary <string, int>(); } } } else { _searchHistoryCommandCount = 0; } }
private void ReallyRender() { var text = ParseInput(); 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 { _console.StartRender(); bufferLineCount = ConvertOffsetToCoordinates(text.Length).Y - _initialY + 1 + statusLineCount; if (_consoleBuffer.Length != bufferLineCount * bufferWidth) { var newBuffer = new BufferChar[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; } _console.WriteBufferLines(_consoleBuffer, ref _initialY); } _consoleBuffer = newBuffer; } for (int i = 0; i < text.Length; i++) { 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. var 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 (i == tokens[0].Extent.StartOffset) { GetTokenColors(tokens[0], out foregroundColor, out backgroundColor); } } } } } var charToRender = text[i]; if (charToRender == '\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(charToRender); 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(charToRender)) { _consoleBuffer[j].UnicodeChar = '^'; MaybeEmphasize(ref _consoleBuffer[j++], i, foregroundColor, backgroundColor); _consoleBuffer[j].UnicodeChar = (char)('@' + charToRender); MaybeEmphasize(ref _consoleBuffer[j++], i, foregroundColor, backgroundColor); } #if !UNIX else if (size > 1) { _consoleBuffer[j].UnicodeChar = charToRender; _consoleBuffer[j].IsLeadByte = true; MaybeEmphasize(ref _consoleBuffer[j++], i, foregroundColor, backgroundColor); _consoleBuffer[j].UnicodeChar = charToRender; _consoleBuffer[j].IsTrailByte = true; MaybeEmphasize(ref _consoleBuffer[j++], i, foregroundColor, backgroundColor); } #endif else { _consoleBuffer[j].UnicodeChar = charToRender; MaybeEmphasize(ref _consoleBuffer[j++], i, foregroundColor, backgroundColor); } } } } finally { _console.EndRender(); } 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 = _consoleBuffer[promptChar].UnicodeChar; if (char.IsWhiteSpace(c)) { promptChar -= 1; continue; } ConsoleColor prevColor = _consoleBuffer[promptChar].ForegroundColor; _consoleBuffer[promptChar].ForegroundColor = ConsoleColor.Red; _console.WriteBufferLines(_consoleBuffer, ref _initialY); rendered = true; _consoleBuffer[promptChar].ForegroundColor = prevColor; break; } } if (!rendered) { _console.WriteBufferLines(_consoleBuffer, ref _initialY); } PlaceCursor(); if ((_initialY + bufferLineCount) > (_console.WindowTop + _console.WindowHeight)) { #if !UNIX // TODO: verify this isn't necessary for LINUX _console.WindowTop = _initialY + bufferLineCount - _console.WindowHeight; #endif } _lastRenderTime.Restart(); }