X-Git-Url: https://git.josue.xyz/?p=VSoRC%2F.git;a=blobdiff_plain;f=node_modules%2Fnode-pty%2Fdeps%2Fwinpty%2Fsrc%2Fagent%2FTerminal.cc;fp=node_modules%2Fnode-pty%2Fdeps%2Fwinpty%2Fsrc%2Fagent%2FTerminal.cc;h=0000000000000000000000000000000000000000;hp=afa0a362600b5159ab33790090ebd586b76fca2c;hb=5e96dd57ddd883604e87f62bdddcb111c63a6e1a;hpb=acb5f682a2b75b972710cabd81658f63071324b0 diff --git a/node_modules/node-pty/deps/winpty/src/agent/Terminal.cc b/node_modules/node-pty/deps/winpty/src/agent/Terminal.cc deleted file mode 100644 index afa0a36..0000000 --- a/node_modules/node-pty/deps/winpty/src/agent/Terminal.cc +++ /dev/null @@ -1,535 +0,0 @@ -// Copyright (c) 2011-2015 Ryan Prichard -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -// sell copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. - -#include "Terminal.h" - -#include -#include -#include - -#include - -#include "NamedPipe.h" -#include "UnicodeEncoding.h" -#include "../shared/DebugClient.h" -#include "../shared/WinptyAssert.h" -#include "../shared/winpty_snprintf.h" - -#define CSI "\x1b[" - -// Work around the old MinGW, which lacks COMMON_LVB_LEADING_BYTE and -// COMMON_LVB_TRAILING_BYTE. -const int WINPTY_COMMON_LVB_LEADING_BYTE = 0x100; -const int WINPTY_COMMON_LVB_TRAILING_BYTE = 0x200; -const int WINPTY_COMMON_LVB_REVERSE_VIDEO = 0x4000; -const int WINPTY_COMMON_LVB_UNDERSCORE = 0x8000; - -const int COLOR_ATTRIBUTE_MASK = - FOREGROUND_BLUE | - FOREGROUND_GREEN | - FOREGROUND_RED | - FOREGROUND_INTENSITY | - BACKGROUND_BLUE | - BACKGROUND_GREEN | - BACKGROUND_RED | - BACKGROUND_INTENSITY | - WINPTY_COMMON_LVB_REVERSE_VIDEO | - WINPTY_COMMON_LVB_UNDERSCORE; - -const int FLAG_RED = 1; -const int FLAG_GREEN = 2; -const int FLAG_BLUE = 4; -const int FLAG_BRIGHT = 8; - -const int BLACK = 0; -const int DKGRAY = BLACK | FLAG_BRIGHT; -const int LTGRAY = FLAG_RED | FLAG_GREEN | FLAG_BLUE; -const int WHITE = LTGRAY | FLAG_BRIGHT; - -// SGR parameters (Select Graphic Rendition) -const int SGR_FORE = 30; -const int SGR_FORE_HI = 90; -const int SGR_BACK = 40; -const int SGR_BACK_HI = 100; - -namespace { - -static void outUInt(std::string &out, unsigned int n) -{ - char buf[32]; - char *pbuf = &buf[32]; - *(--pbuf) = '\0'; - do { - *(--pbuf) = '0' + n % 10; - n /= 10; - } while (n != 0); - out.append(pbuf); -} - -static void outputSetColorSgrParams(std::string &out, bool isFore, int color) -{ - out.push_back(';'); - const int sgrBase = isFore ? SGR_FORE : SGR_BACK; - if (color & FLAG_BRIGHT) { - // Some terminals don't support the 9X/10X "intensive" color parameters - // (e.g. the Eclipse TM terminal as of this writing). Those terminals - // will quietly ignore a 9X/10X code, and the other terminals will - // ignore a 3X/4X code if it's followed by a 9X/10X code. Therefore, - // output a 3X/4X code as a fallback, then override it. - const int colorBase = color & ~FLAG_BRIGHT; - outUInt(out, sgrBase + colorBase); - out.push_back(';'); - outUInt(out, sgrBase + (SGR_FORE_HI - SGR_FORE) + colorBase); - } else { - outUInt(out, sgrBase + color); - } -} - -static void outputSetColor(std::string &out, int color) -{ - int fore = 0; - int back = 0; - if (color & FOREGROUND_RED) fore |= FLAG_RED; - if (color & FOREGROUND_GREEN) fore |= FLAG_GREEN; - if (color & FOREGROUND_BLUE) fore |= FLAG_BLUE; - if (color & FOREGROUND_INTENSITY) fore |= FLAG_BRIGHT; - if (color & BACKGROUND_RED) back |= FLAG_RED; - if (color & BACKGROUND_GREEN) back |= FLAG_GREEN; - if (color & BACKGROUND_BLUE) back |= FLAG_BLUE; - if (color & BACKGROUND_INTENSITY) back |= FLAG_BRIGHT; - - if (color & WINPTY_COMMON_LVB_REVERSE_VIDEO) { - // n.b.: The COMMON_LVB_REVERSE_VIDEO flag also swaps - // FOREGROUND_INTENSITY and BACKGROUND_INTENSITY. Tested on - // Windows 10 v14393. - std::swap(fore, back); - } - - // Translate the fore/back colors into terminal escape codes using - // a heuristic that works OK with common white-on-black or - // black-on-white color schemes. We don't know which color scheme - // the terminal is using. It is ugly to force white-on-black text - // on a black-on-white terminal, and it's even ugly to force the - // matching scheme. It's probably relevant that the default - // fore/back terminal colors frequently do not match any of the 16 - // palette colors. - - // Typical default terminal color schemes (according to palette, - // when possible): - // - mintty: LtGray-on-Black(A) - // - putty: LtGray-on-Black(A) - // - xterm: LtGray-on-Black(A) - // - Konsole: LtGray-on-Black(A) - // - JediTerm/JetBrains: Black-on-White(B) - // - rxvt: Black-on-White(B) - - // If the background is the default color (black), then it will - // map to Black(A) or White(B). If we translate White to White, - // then a Black background and a White background in the console - // are both White with (B). Therefore, we should translate White - // using SGR 7 (Invert). The typical finished mapping table for - // background grayscale colors is: - // - // (A) White => LtGray(fore) - // (A) Black => Black(back) - // (A) LtGray => LtGray - // (A) DkGray => DkGray - // - // (B) White => Black(fore) - // (B) Black => White(back) - // (B) LtGray => LtGray - // (B) DkGray => DkGray - // - - out.append(CSI "0"); - if (back == BLACK) { - if (fore == LTGRAY) { - // The "default" foreground color. Use the terminal's - // default colors. - } else if (fore == WHITE) { - // Sending the literal color white would behave poorly if - // the terminal were black-on-white. Sending Bold is not - // guaranteed to alter the color, but it will make the text - // visually distinct, so do that instead. - out.append(";1"); - } else if (fore == DKGRAY) { - // Set the foreground color to DkGray(90) with a fallback - // of LtGray(37) for terminals that don't handle the 9X SGR - // parameters (e.g. Eclipse's TM Terminal as of this - // writing). - out.append(";37;90"); - } else { - outputSetColorSgrParams(out, true, fore); - } - } else if (back == WHITE) { - // Set the background color using Invert on the default - // foreground color, and set the foreground color by setting a - // background color. - - // Use the terminal's inverted colors. - out.append(";7"); - if (fore == LTGRAY || fore == BLACK) { - // We're likely mapping Console White to terminal LtGray or - // Black. If they are the Console foreground color, then - // don't set a terminal foreground color to avoid creating - // invisible text. - } else { - outputSetColorSgrParams(out, false, fore); - } - } else { - // Set the foreground and background to match exactly that in - // the Windows console. - outputSetColorSgrParams(out, true, fore); - outputSetColorSgrParams(out, false, back); - } - if (fore == back) { - // The foreground and background colors are exactly equal, so - // attempt to hide the text using the Conceal SGR parameter, - // which some terminals support. - out.append(";8"); - } - if (color & WINPTY_COMMON_LVB_UNDERSCORE) { - out.append(";4"); - } - out.push_back('m'); -} - -static inline unsigned int fixSpecialCharacters(unsigned int ch) -{ - if (ch <= 0x1b) { - switch (ch) { - // The Windows Console has a popup window (e.g. that appears with - // F7) that is sometimes bordered with box-drawing characters. - // With the Japanese and Korean system locales (CP932 and CP949), - // the UnicodeChar values for the box-drawing characters are 1 - // through 6. Detect this and map the values to the correct - // Unicode values. - // - // N.B. In the English locale, the UnicodeChar values are correct, - // and they identify single-line characters rather than - // double-line. In the Chinese Simplified and Traditional locales, - // the popups use ASCII characters instead. - case 1: return 0x2554; // BOX DRAWINGS DOUBLE DOWN AND RIGHT - case 2: return 0x2557; // BOX DRAWINGS DOUBLE DOWN AND LEFT - case 3: return 0x255A; // BOX DRAWINGS DOUBLE UP AND RIGHT - case 4: return 0x255D; // BOX DRAWINGS DOUBLE UP AND LEFT - case 5: return 0x2551; // BOX DRAWINGS DOUBLE VERTICAL - case 6: return 0x2550; // BOX DRAWINGS DOUBLE HORIZONTAL - - // Convert an escape character to some other character. This - // conversion only applies to console cells containing an escape - // character. In newer versions of Windows 10 (e.g. 10.0.10586), - // the non-legacy console recognizes escape sequences in - // WriteConsole and interprets them without writing them to the - // cells of the screen buffer. In that case, the conversion here - // does not apply. - case 0x1b: return '?'; - } - } - return ch; -} - -static inline bool isFullWidthCharacter(const CHAR_INFO *data, int width) -{ - if (width < 2) { - return false; - } - return - (data[0].Attributes & WINPTY_COMMON_LVB_LEADING_BYTE) && - (data[1].Attributes & WINPTY_COMMON_LVB_TRAILING_BYTE) && - data[0].Char.UnicodeChar == data[1].Char.UnicodeChar; -} - -// Scan to find a single Unicode Scalar Value. Full-width characters occupy -// two console cells, and this code also tries to handle UTF-16 surrogate -// pairs. -// -// Windows expands at least some wide characters outside the Basic -// Multilingual Plane into four cells, such as U+20000: -// 1. 0xD840, attr=0x107 -// 2. 0xD840, attr=0x207 -// 3. 0xDC00, attr=0x107 -// 4. 0xDC00, attr=0x207 -// Even in the Traditional Chinese locale on Windows 10, this text is rendered -// as two boxes, but if those boxes are copied-and-pasted, the character is -// copied correctly. -static inline void scanUnicodeScalarValue( - const CHAR_INFO *data, int width, - int &outCellCount, unsigned int &outCharValue) -{ - ASSERT(width >= 1); - - const int w1 = isFullWidthCharacter(data, width) ? 2 : 1; - const wchar_t c1 = data[0].Char.UnicodeChar; - - if ((c1 & 0xF800) == 0xD800) { - // The first cell is either a leading or trailing surrogate pair. - if ((c1 & 0xFC00) != 0xD800 || - width <= w1 || - ((data[w1].Char.UnicodeChar & 0xFC00) != 0xDC00)) { - // Invalid surrogate pair - outCellCount = w1; - outCharValue = '?'; - } else { - // Valid surrogate pair - outCellCount = w1 + (isFullWidthCharacter(&data[w1], width - w1) ? 2 : 1); - outCharValue = decodeSurrogatePair(c1, data[w1].Char.UnicodeChar); - } - } else { - outCellCount = w1; - outCharValue = c1; - } -} - -} // anonymous namespace - -void Terminal::reset(SendClearFlag sendClearFirst, int64_t newLine) -{ - if (sendClearFirst == SendClear && !m_plainMode) { - // 0m ==> reset SGR parameters - // 1;1H ==> move cursor to top-left position - // 2J ==> clear the entire screen - m_output.write(CSI "0m" CSI "1;1H" CSI "2J"); - } - m_remoteLine = newLine; - m_remoteColumn = 0; - m_lineData.clear(); - m_cursorHidden = false; - m_remoteColor = -1; -} - -void Terminal::sendLine(int64_t line, const CHAR_INFO *lineData, int width, - int cursorColumn) -{ - ASSERT(width >= 1); - - moveTerminalToLine(line); - - // If possible, see if we can append to what we've already output for this - // line. - if (m_lineDataValid) { - ASSERT(m_lineData.size() == static_cast(m_remoteColumn)); - if (m_remoteColumn > 0) { - // In normal mode, if m_lineData.size() equals `width`, then we - // will have trouble outputing the "erase rest of line" command, - // which must be output before reaching the end of the line. In - // plain mode, we don't output that command, so we're OK with a - // full line. - bool okWidth = false; - if (m_plainMode) { - okWidth = static_cast(width) >= m_lineData.size(); - } else { - okWidth = static_cast(width) > m_lineData.size(); - } - if (!okWidth || - memcmp(m_lineData.data(), lineData, - sizeof(CHAR_INFO) * m_lineData.size()) != 0) { - m_lineDataValid = false; - } - } - } - if (!m_lineDataValid) { - // We can't reuse, so we must reset this line. - hideTerminalCursor(); - if (m_plainMode) { - // We can't backtrack, so repeat this line. - m_output.write("\r\n"); - } else { - m_output.write("\r"); - } - m_lineDataValid = true; - m_lineData.clear(); - m_remoteColumn = 0; - } - - std::string &termLine = m_termLineWorkingBuffer; - termLine.clear(); - size_t trimmedLineLength = 0; - int trimmedCellCount = m_lineData.size(); - bool alreadyErasedLine = false; - - int cellCount = 1; - for (int i = m_lineData.size(); i < width; i += cellCount) { - if (m_outputColor) { - int color = lineData[i].Attributes & COLOR_ATTRIBUTE_MASK; - if (color != m_remoteColor) { - outputSetColor(termLine, color); - trimmedLineLength = termLine.size(); - m_remoteColor = color; - - // All the cells just up to this color change will be output. - trimmedCellCount = i; - } - } - unsigned int ch; - scanUnicodeScalarValue(&lineData[i], width - i, cellCount, ch); - if (ch == ' ') { - // Tentatively add this space character. We'll only output it if - // we see something interesting after it. - termLine.push_back(' '); - } else { - if (i + cellCount == width) { - // We'd like to erase the line after outputting all non-blank - // characters, but this doesn't work if the last cell in the - // line is non-blank. At the point, the cursor is positioned - // just past the end of the line, but in many terminals, - // issuing a CSI 0K at that point also erases the last cell in - // the line. Work around this behavior by issuing the erase - // one character early in that case. - if (!m_plainMode) { - termLine.append(CSI "0K"); // Erase from cursor to EOL - } - alreadyErasedLine = true; - } - ch = fixSpecialCharacters(ch); - char enc[4]; - int enclen = encodeUtf8(enc, ch); - if (enclen == 0) { - enc[0] = '?'; - enclen = 1; - } - termLine.append(enc, enclen); - trimmedLineLength = termLine.size(); - - // All the cells up to and including this cell will be output. - trimmedCellCount = i + cellCount; - } - } - - if (cursorColumn != -1 && trimmedCellCount > cursorColumn) { - // The line content would run past the cursor, so hide it before we - // output. - hideTerminalCursor(); - } - - m_output.write(termLine.data(), trimmedLineLength); - if (!alreadyErasedLine && !m_plainMode) { - m_output.write(CSI "0K"); // Erase from cursor to EOL - } - - ASSERT(trimmedCellCount <= width); - m_lineData.insert(m_lineData.end(), - &lineData[m_lineData.size()], - &lineData[trimmedCellCount]); - m_remoteColumn = trimmedCellCount; -} - -void Terminal::showTerminalCursor(int column, int64_t line) -{ - moveTerminalToLine(line); - if (!m_plainMode) { - if (m_remoteColumn != column) { - char buffer[32]; - winpty_snprintf(buffer, CSI "%dG", column + 1); - m_output.write(buffer); - m_lineDataValid = (column == 0); - m_lineData.clear(); - m_remoteColumn = column; - } - if (m_cursorHidden) { - m_output.write(CSI "?25h"); - m_cursorHidden = false; - } - } -} - -void Terminal::hideTerminalCursor() -{ - if (!m_plainMode) { - if (m_cursorHidden) { - return; - } - m_output.write(CSI "?25l"); - m_cursorHidden = true; - } -} - -void Terminal::moveTerminalToLine(int64_t line) -{ - if (line == m_remoteLine) { - return; - } - - // Do not use CPL or CNL. Konsole 2.5.4 does not support Cursor Previous - // Line (CPL) -- there are "Undecodable sequence" errors. gnome-terminal - // 2.32.0 does handle it. Cursor Next Line (CNL) does nothing if the - // cursor is on the last line already. - - hideTerminalCursor(); - - if (line < m_remoteLine) { - if (m_plainMode) { - // We can't backtrack, so instead repeat the lines again. - m_output.write("\r\n"); - m_remoteLine = line; - } else { - // Backtrack and overwrite previous lines. - // CUrsor Up (CUU) - char buffer[32]; - winpty_snprintf(buffer, "\r" CSI "%uA", - static_cast(m_remoteLine - line)); - m_output.write(buffer); - m_remoteLine = line; - } - } else if (line > m_remoteLine) { - while (line > m_remoteLine) { - m_output.write("\r\n"); - m_remoteLine++; - } - } - - m_lineDataValid = true; - m_lineData.clear(); - m_remoteColumn = 0; -} - -void Terminal::enableMouseMode(bool enabled) -{ - if (m_mouseModeEnabled == enabled || m_plainMode) { - return; - } - m_mouseModeEnabled = enabled; - if (enabled) { - // Start by disabling UTF-8 coordinate mode (1005), just in case we - // have a terminal that does not support 1006/1015 modes, and 1005 - // happens to be enabled. The UTF-8 coordinates can't be unambiguously - // decoded. - // - // Enable basic mouse support first (1000), then try to switch to - // button-move mode (1002), then try full mouse-move mode (1003). - // Terminals that don't support a mode will be stuck at the highest - // mode they do support. - // - // Enable encoding mode 1015 first, then try to switch to 1006. On - // some terminals, both modes will be enabled, but 1006 will have - // priority. On other terminals, 1006 wins because it's listed last. - // - // See misc/MouseInputNotes.txt for details. - m_output.write( - CSI "?1005l" - CSI "?1000h" CSI "?1002h" CSI "?1003h" CSI "?1015h" CSI "?1006h"); - } else { - // Resetting both encoding modes (1006 and 1015) is necessary, but - // apparently we only need to use reset on one of the 100[023] modes. - // Doing both doesn't hurt. - m_output.write( - CSI "?1006l" CSI "?1015l" CSI "?1003l" CSI "?1002l" CSI "?1000l"); - } -}