File indexing completed on 2024-05-05 05:53:47
0001 /* 0002 SPDX-FileCopyrightText: 1997, 1998 Lars Doelle <lars.doelle@on-line.de> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "HistoryScrollFile.h" 0008 0009 #include "HistoryTypeFile.h" 0010 0011 /* 0012 The history scroll makes a Row(Row(Cell)) from 0013 two history buffers. The index buffer contains 0014 start of line positions which refer to the cells 0015 buffer. 0016 0017 Note that index[0] addresses the second line 0018 (line #1), while the first line (line #0) starts 0019 at 0 in cells. 0020 */ 0021 0022 using namespace Konsole; 0023 0024 HistoryScrollFile::HistoryScrollFile() 0025 : HistoryScroll(new HistoryTypeFile()) 0026 { 0027 } 0028 0029 HistoryScrollFile::~HistoryScrollFile() = default; 0030 0031 int HistoryScrollFile::getLines() const 0032 { 0033 return _index.len() / sizeof(qint64); 0034 } 0035 0036 int HistoryScrollFile::getMaxLines() const 0037 { 0038 return getLines(); 0039 } 0040 0041 int HistoryScrollFile::getLineLen(const int lineno) const 0042 { 0043 return (startOfLine(lineno + 1) - startOfLine(lineno)) / sizeof(Character); 0044 } 0045 0046 bool HistoryScrollFile::isWrappedLine(const int lineno) const 0047 { 0048 return (getLineProperty(lineno).flags.f.wrapped) > 0; 0049 } 0050 0051 LineProperty HistoryScrollFile::getLineProperty(const int lineno) const 0052 { 0053 if (lineno >= 0 && lineno <= getLines()) { 0054 LineProperty flag = LineProperty(); 0055 _lineflags.get(reinterpret_cast<char *>(&flag), sizeof(LineProperty), (lineno) * sizeof(LineProperty)); 0056 return flag; 0057 } 0058 return LineProperty(); 0059 } 0060 0061 void HistoryScrollFile::setLineProperty(const int lineno, LineProperty prop) 0062 { 0063 if (lineno >= 0 && lineno <= getLines()) { 0064 _lineflags.set(reinterpret_cast<char *>(&prop), sizeof(LineProperty), (lineno) * sizeof(LineProperty)); 0065 } 0066 } 0067 0068 qint64 HistoryScrollFile::startOfLine(const int lineno) const 0069 { 0070 Q_ASSERT(lineno >= 0 && lineno <= getLines()); 0071 0072 if (lineno == 0) { 0073 return 0; 0074 } 0075 if (lineno < getLines()) { 0076 qint64 res = 0; 0077 _index.get(reinterpret_cast<char *>(&res), sizeof(qint64), (lineno - 1) * sizeof(qint64)); 0078 return res; 0079 } 0080 return _cells.len(); 0081 } 0082 0083 void HistoryScrollFile::getCells(const int lineno, const int colno, const int count, Character res[]) const 0084 { 0085 _cells.get(reinterpret_cast<char *>(res), count * sizeof(Character), startOfLine(lineno) + colno * sizeof(Character)); 0086 } 0087 0088 void HistoryScrollFile::addCells(const Character text[], const int count) 0089 { 0090 _cells.add(reinterpret_cast<const char *>(text), count * sizeof(Character)); 0091 } 0092 0093 void HistoryScrollFile::addLine(LineProperty lineProperty) 0094 { 0095 qint64 locn = _cells.len(); 0096 _index.add(reinterpret_cast<char *>(&locn), sizeof(qint64)); 0097 _lineflags.add(reinterpret_cast<char *>(&lineProperty), sizeof(LineProperty)); 0098 } 0099 0100 void HistoryScrollFile::removeCells() 0101 { 0102 qint64 res = (getLines() - 2) * sizeof(qint64); 0103 if (getLines() < 2) { 0104 _cells.removeLast(0); 0105 } else { 0106 _index.get(reinterpret_cast<char *>(&res), sizeof(qint64), res); 0107 _cells.removeLast(res); 0108 } 0109 res = qMax(0, getLines() - 1); 0110 _index.removeLast(res * sizeof(qint64)); 0111 _lineflags.removeLast(res * sizeof(LineProperty)); 0112 } 0113 0114 int Konsole::HistoryScrollFile::reflowLines(const int columns, std::map<int, int> *) 0115 { 0116 auto reflowFile = std::make_unique<HistoryFile>(); 0117 reflowData newLine; 0118 0119 auto reflowLineLen = [](qint64 start, qint64 end) { 0120 return (int)((end - start) / sizeof(Character)); 0121 }; 0122 auto setNewLine = [](reflowData &change, qint64 index, LineProperty lineflag) { 0123 change.index = index; 0124 change.lineFlag = lineflag; 0125 }; 0126 0127 // First all changes are saved on an auxiliary file, no real index is changed 0128 int currentPos = 0; 0129 if (getLines() > MAX_REFLOW_LINES) { 0130 currentPos = getLines() - MAX_REFLOW_LINES; 0131 } 0132 while (currentPos < getLines()) { 0133 qint64 startLine = startOfLine(currentPos); 0134 qint64 endLine = startOfLine(currentPos + 1); 0135 LineProperty lineProperty = getLineProperty(currentPos); 0136 0137 // Join the lines if they are wrapped 0138 while (currentPos < getLines() - 1 && isWrappedLine(currentPos)) { 0139 currentPos++; 0140 endLine = startOfLine(currentPos + 1); 0141 } 0142 0143 // Now reflow the lines 0144 while (reflowLineLen(startLine, endLine) > columns && !(lineProperty.flags.f.doubleheight_bottom | lineProperty.flags.f.doubleheight_top)) { 0145 startLine += (qint64)columns * sizeof(Character); 0146 lineProperty.flags.f.wrapped = 1; 0147 setNewLine(newLine, startLine, lineProperty); 0148 lineProperty.resetStarts(); 0149 reflowFile->add(reinterpret_cast<const char *>(&newLine), sizeof(reflowData)); 0150 } 0151 lineProperty.flags.f.wrapped = 0; 0152 setNewLine(newLine, endLine, lineProperty); 0153 reflowFile->add(reinterpret_cast<const char *>(&newLine), sizeof(reflowData)); 0154 currentPos++; 0155 } 0156 0157 // Erase data from index and flag data 0158 if (getLines() > MAX_REFLOW_LINES) { 0159 currentPos = getLines() - MAX_REFLOW_LINES; 0160 _index.removeLast(currentPos * sizeof(qint64)); 0161 _lineflags.removeLast(currentPos * sizeof(LineProperty)); 0162 } else { 0163 _index.removeLast(0); 0164 _lineflags.removeLast(0); 0165 } 0166 0167 // Now save the new indexes and properties to proper files 0168 int totalLines = reflowFile->len() / sizeof(reflowData); 0169 currentPos = 0; 0170 while (currentPos < totalLines) { 0171 reflowFile->get(reinterpret_cast<char *>(&newLine), sizeof(reflowData), currentPos * sizeof(reflowData)); 0172 0173 _lineflags.add(reinterpret_cast<char *>(&newLine.lineFlag), sizeof(LineProperty)); 0174 _index.add(reinterpret_cast<char *>(&newLine.index), sizeof(qint64)); 0175 currentPos++; 0176 } 0177 0178 return 0; 0179 }