File indexing completed on 2024-04-28 05:50:39
0001 /* 0002 SPDX-FileCopyrightText: 2006-2008 Robert Knight <robertknight@gmail.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 // Own 0008 #include "PlainTextDecoder.h" 0009 0010 // Konsole characters 0011 #include <ExtendedCharTable.h> 0012 0013 // Qt 0014 #include <QList> 0015 #include <QTextStream> 0016 0017 using namespace Konsole; 0018 0019 PlainTextDecoder::PlainTextDecoder() 0020 : _output(nullptr) 0021 , _includeLeadingWhitespace(true) 0022 , _includeTrailingWhitespace(true) 0023 , _recordLinePositions(false) 0024 , _linePositions(QList<int>()) 0025 { 0026 } 0027 0028 void PlainTextDecoder::setLeadingWhitespace(bool enable) 0029 { 0030 _includeLeadingWhitespace = enable; 0031 } 0032 0033 void PlainTextDecoder::setTrailingWhitespace(bool enable) 0034 { 0035 _includeTrailingWhitespace = enable; 0036 } 0037 0038 void PlainTextDecoder::begin(QTextStream *output) 0039 { 0040 _output = output; 0041 if (!_linePositions.isEmpty()) { 0042 _linePositions.clear(); 0043 } 0044 } 0045 0046 void PlainTextDecoder::end() 0047 { 0048 _output = nullptr; 0049 } 0050 0051 void PlainTextDecoder::setRecordLinePositions(bool record) 0052 { 0053 _recordLinePositions = record; 0054 } 0055 0056 QList<int> PlainTextDecoder::linePositions() const 0057 { 0058 return _linePositions; 0059 } 0060 0061 void PlainTextDecoder::decodeLine(const Character *const characters, int count, LineProperty /*properties*/) 0062 { 0063 Q_ASSERT(_output); 0064 0065 if (_recordLinePositions && (_output->string() != nullptr)) { 0066 int pos = _output->string()->length(); 0067 _linePositions << pos; 0068 } 0069 0070 // TODO should we ignore or respect the LINE_WRAPPED line property? 0071 0072 // If we should remove leading whitespace find the first non-space character 0073 int start = 0; 0074 if (!_includeLeadingWhitespace) { 0075 while (start < count && characters[start].isSpace()) { 0076 start++; 0077 } 0078 } 0079 0080 int outputCount = count - start; 0081 0082 if (outputCount <= 0) { 0083 return; 0084 } 0085 0086 // if inclusion of trailing whitespace is disabled then find the end of the 0087 // line 0088 if (!_includeTrailingWhitespace) { 0089 while (outputCount > 0 && characters[start + outputCount - 1].isSpace()) { 0090 outputCount--; 0091 } 0092 } 0093 0094 // find out the last technically real character in the line 0095 int realCharacterGuard = -1; 0096 for (int i = count - 1; i >= start; i--) { 0097 // FIXME: the special case of '\n' here is really ugly 0098 // Maybe the '\n' should be added after calling this method in 0099 // Screen::copyLineToStream() 0100 if ((characters[i].flags & EF_REAL) != 0 && characters[i].character != '\n') { 0101 realCharacterGuard = i; 0102 break; 0103 } 0104 } 0105 0106 // note: we build up a QVector<char32_t> and send it to the text stream transformed into a // 0107 // QString rather than writing into the text stream a character at a time because it is more 0108 // efficient (since QTextStream always deals with QStrings internally anyway) 0109 QVector<char32_t> characterBuffer; 0110 characterBuffer.reserve(count); 0111 0112 for (int i = start; i < outputCount;) { 0113 if (characters[i].rendition.f.extended != 0) { 0114 ushort extendedCharLength = 0; 0115 const char32_t *chars = ExtendedCharTable::instance.lookupExtendedChar(characters[i].character, extendedCharLength); 0116 if (chars != nullptr) { 0117 for (uint nchar = 0; nchar < extendedCharLength; nchar++) { 0118 characterBuffer.append(chars[nchar]); 0119 } 0120 i += qMax(1, Character::stringWidth(chars, extendedCharLength)); 0121 } else { 0122 ++i; 0123 } 0124 } else { 0125 // All characters which appear before the last real character are 0126 // seen as real characters, even when they are technically marked as 0127 // non-real. 0128 // 0129 // This feels tricky, but otherwise leading "whitespaces" may be 0130 // lost in some situation. One typical example is copying the result 0131 // of `dialog --infobox "qwe" 10 10` . 0132 if ((characters[i].flags & EF_REAL) != 0 || i <= realCharacterGuard) { 0133 if (characters[i].isRightHalfOfDoubleWide()) { 0134 i += 1; 0135 } else { 0136 characterBuffer.append(characters[i].character); 0137 i += qMax(1, Character::stringWidth(&characters[i].character, 1)); 0138 } 0139 } else { 0140 ++i; // should we 'break' directly here? 0141 } 0142 } 0143 } 0144 *_output << QString::fromUcs4(characterBuffer.data(), characterBuffer.size()); 0145 }