aboutsummaryrefslogtreecommitdiffstats
path: root/src/libs/3rdparty/winpty/src/agent/ConsoleLine.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/3rdparty/winpty/src/agent/ConsoleLine.cc')
-rw-r--r--src/libs/3rdparty/winpty/src/agent/ConsoleLine.cc152
1 files changed, 152 insertions, 0 deletions
diff --git a/src/libs/3rdparty/winpty/src/agent/ConsoleLine.cc b/src/libs/3rdparty/winpty/src/agent/ConsoleLine.cc
new file mode 100644
index 0000000000..1d2bcb7685
--- /dev/null
+++ b/src/libs/3rdparty/winpty/src/agent/ConsoleLine.cc
@@ -0,0 +1,152 @@
+// Copyright (c) 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.
+
+//
+// ConsoleLine
+//
+// This data structure keep tracks of the previous CHAR_INFO content of an
+// output line and determines when a line has changed. Detecting line changes
+// is made complicated by terminal resizing.
+//
+
+#include "ConsoleLine.h"
+
+#include <algorithm>
+
+#include "../shared/WinptyAssert.h"
+
+static CHAR_INFO blankChar(WORD attributes)
+{
+ // N.B.: As long as we write to UnicodeChar rather than AsciiChar, there
+ // are no padding bytes that could contain uninitialized bytes. This fact
+ // is important for efficient comparison.
+ CHAR_INFO ret;
+ ret.Attributes = attributes;
+ ret.Char.UnicodeChar = L' ';
+ return ret;
+}
+
+static bool isLineBlank(const CHAR_INFO *line, int length, WORD attributes)
+{
+ for (int col = 0; col < length; ++col) {
+ if (line[col].Attributes != attributes ||
+ line[col].Char.UnicodeChar != L' ') {
+ return false;
+ }
+ }
+ return true;
+}
+
+static inline bool areLinesEqual(
+ const CHAR_INFO *line1,
+ const CHAR_INFO *line2,
+ int length)
+{
+ return memcmp(line1, line2, sizeof(CHAR_INFO) * length) == 0;
+}
+
+ConsoleLine::ConsoleLine() : m_prevLength(0)
+{
+}
+
+void ConsoleLine::reset()
+{
+ m_prevLength = 0;
+ m_prevData.clear();
+}
+
+// Determines whether the given line is sufficiently different from the
+// previously seen line as to justify reoutputting the line. The function
+// also sets the `ConsoleLine` to the given line, exactly as if `setLine` had
+// been called.
+bool ConsoleLine::detectChangeAndSetLine(const CHAR_INFO *const line, const int newLength)
+{
+ ASSERT(newLength >= 1);
+ ASSERT(m_prevLength <= static_cast<int>(m_prevData.size()));
+
+ if (newLength == m_prevLength) {
+ bool equalLines = areLinesEqual(m_prevData.data(), line, newLength);
+ if (!equalLines) {
+ setLine(line, newLength);
+ }
+ return !equalLines;
+ } else {
+ if (m_prevLength == 0) {
+ setLine(line, newLength);
+ return true;
+ }
+
+ ASSERT(m_prevLength >= 1);
+ const WORD prevBlank = m_prevData[m_prevLength - 1].Attributes;
+ const WORD newBlank = line[newLength - 1].Attributes;
+
+ bool equalLines = false;
+ if (newLength < m_prevLength) {
+ // The line has become shorter. The lines are equal if the common
+ // part is equal, and if the newly truncated characters were blank.
+ equalLines =
+ areLinesEqual(m_prevData.data(), line, newLength) &&
+ isLineBlank(m_prevData.data() + newLength,
+ m_prevLength - newLength,
+ newBlank);
+ } else {
+ //
+ // The line has become longer. The lines are equal if the common
+ // part is equal, and if both the extra characters and any
+ // potentially reexposed characters are blank.
+ //
+ // Two of the most relevant terminals for winpty--mintty and
+ // jediterm--don't (currently) erase the obscured content when a
+ // line is cleared, so we should anticipate its existence when
+ // making a terminal wider and reoutput the line. See:
+ //
+ // * https://github.com/mintty/mintty/issues/480
+ // * https://github.com/JetBrains/jediterm/issues/118
+ //
+ ASSERT(newLength > m_prevLength);
+ equalLines =
+ areLinesEqual(m_prevData.data(), line, m_prevLength) &&
+ isLineBlank(m_prevData.data() + m_prevLength,
+ std::min<int>(m_prevData.size(), newLength) - m_prevLength,
+ prevBlank) &&
+ isLineBlank(line + m_prevLength,
+ newLength - m_prevLength,
+ prevBlank);
+ }
+ setLine(line, newLength);
+ return !equalLines;
+ }
+}
+
+void ConsoleLine::setLine(const CHAR_INFO *const line, const int newLength)
+{
+ if (static_cast<int>(m_prevData.size()) < newLength) {
+ m_prevData.resize(newLength);
+ }
+ memcpy(m_prevData.data(), line, sizeof(CHAR_INFO) * newLength);
+ m_prevLength = newLength;
+}
+
+void ConsoleLine::blank(WORD attributes)
+{
+ m_prevData.resize(1);
+ m_prevData[0] = blankChar(attributes);
+ m_prevLength = 1;
+}