File indexing completed on 2024-05-19 05:54:10

0001 /*
0002     SPDX-FileCopyrightText: 2021-2021 Carlos Alves <cbcalves@gmail.com>
0003     SPDX-FileCopyrightText: 1997, 1998 Lars Doelle <lars.doelle@on-line.de>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 // Own
0009 #include "CompactHistoryScroll.h"
0010 #include "CompactHistoryType.h"
0011 
0012 using namespace Konsole;
0013 
0014 CompactHistoryScroll::CompactHistoryScroll(const unsigned int maxLineCount)
0015     : HistoryScroll(new CompactHistoryType(maxLineCount))
0016     , _maxLineCount(0)
0017 {
0018     setMaxNbLines(maxLineCount);
0019 }
0020 
0021 void CompactHistoryScroll::removeLinesFromTop(size_t lines)
0022 {
0023     if (_lineDatas.size() > 1) {
0024         const unsigned int removing = _lineDatas.at(lines - 1).index;
0025         _lineDatas.erase(_lineDatas.begin(), _lineDatas.begin() + lines);
0026 
0027         _cells.erase(_cells.begin(), _cells.begin() + (removing - _indexBias));
0028         _indexBias = removing;
0029     } else {
0030         _lineDatas.clear();
0031         _cells.clear();
0032     }
0033 }
0034 
0035 void CompactHistoryScroll::addCells(const Character a[], const int count)
0036 {
0037     _cells.insert(_cells.end(), a, a + count);
0038 
0039     // store the (biased) start of next line + default flag
0040     // the flag is later updated when addLine is called
0041     _lineDatas.push_back({static_cast<unsigned int>(_cells.size() + _indexBias), LineProperty()});
0042 
0043     if (_lineDatas.size() > _maxLineCount + 5) {
0044         removeLinesFromTop(5);
0045     }
0046 }
0047 
0048 void CompactHistoryScroll::addCellsMove(Character characters[], const int count)
0049 {
0050     std::move(characters, characters + count, std::back_inserter(_cells));
0051 
0052     // store the (biased) start of next line + default flag
0053     // the flag is later updated when addLine is called
0054     _lineDatas.push_back({static_cast<unsigned int>(_cells.size() + _indexBias), LineProperty()});
0055 
0056     if (_lineDatas.size() > _maxLineCount + 5) {
0057         removeLinesFromTop(5);
0058     }
0059 }
0060 
0061 void CompactHistoryScroll::addLine(const LineProperty lineProperty)
0062 {
0063     auto &flag = _lineDatas.back().flag;
0064     flag = lineProperty;
0065 }
0066 
0067 int CompactHistoryScroll::getLines() const
0068 {
0069     return _lineDatas.size();
0070 }
0071 
0072 int CompactHistoryScroll::getMaxLines() const
0073 {
0074     return _maxLineCount;
0075 }
0076 
0077 int CompactHistoryScroll::getLineLen(int lineNumber) const
0078 {
0079     if (size_t(lineNumber) >= _lineDatas.size()) {
0080         return 0;
0081     }
0082 
0083     return lineLen(lineNumber);
0084 }
0085 
0086 void CompactHistoryScroll::getCells(const int lineNumber, const int startColumn, const int count, Character buffer[]) const
0087 {
0088     if (count == 0) {
0089         return;
0090     }
0091     Q_ASSERT((size_t)lineNumber < _lineDatas.size());
0092 
0093     Q_ASSERT(startColumn >= 0);
0094     Q_ASSERT(startColumn <= lineLen(lineNumber) - count);
0095 
0096     auto startCopy = _cells.begin() + startOfLine(lineNumber) + startColumn;
0097     auto endCopy = startCopy + count;
0098     std::copy(startCopy, endCopy, buffer);
0099 }
0100 
0101 void CompactHistoryScroll::setMaxNbLines(const int lineCount)
0102 {
0103     Q_ASSERT(lineCount >= 0);
0104     _maxLineCount = lineCount;
0105 
0106     if (_lineDatas.size() > _maxLineCount) {
0107         int linesToRemove = _lineDatas.size() - _maxLineCount;
0108         removeLinesFromTop(linesToRemove);
0109     }
0110 }
0111 
0112 void CompactHistoryScroll::removeCells()
0113 {
0114     if (_lineDatas.size() > 1) {
0115         /** Here we remove a line from the "end" of the buffers **/
0116 
0117         // Get last line start
0118         int lastLineStart = startOfLine(_lineDatas.size() - 1);
0119 
0120         // remove info about this line
0121         _lineDatas.pop_back();
0122 
0123         // remove the actual line content
0124         _cells.erase(_cells.begin() + lastLineStart, _cells.end());
0125     } else {
0126         _cells.clear();
0127         _lineDatas.clear();
0128     }
0129 }
0130 
0131 bool CompactHistoryScroll::isWrappedLine(const int lineNumber) const
0132 {
0133     Q_ASSERT((size_t)lineNumber < _lineDatas.size());
0134     return (_lineDatas.at(lineNumber).flag.flags.f.wrapped) > 0;
0135 }
0136 
0137 LineProperty CompactHistoryScroll::getLineProperty(const int lineNumber) const
0138 {
0139     Q_ASSERT((size_t)lineNumber < _lineDatas.size());
0140     return _lineDatas.at(lineNumber).flag;
0141 }
0142 
0143 void CompactHistoryScroll::setLineProperty(const int lineNumber, LineProperty prop)
0144 {
0145     Q_ASSERT((size_t)lineNumber < _lineDatas.size());
0146     _lineDatas.at(lineNumber).flag = prop;
0147 }
0148 
0149 int CompactHistoryScroll::reflowLines(const int columns, std::map<int, int> *deltas)
0150 {
0151     std::vector<LineData> newLineData;
0152 
0153     auto reflowLineLen = [](int start, int end) {
0154         return end - start;
0155     };
0156     auto setNewLine = [](std::vector<LineData> &change, unsigned int index, LineProperty flag) {
0157         change.push_back({index, flag});
0158     };
0159 
0160     int currentPos = 0;
0161     int newPos = 0;
0162     int delta = 0;
0163     while (currentPos < getLines()) {
0164         int startLine = startOfLine(currentPos);
0165         int endLine = startOfLine(currentPos + 1);
0166         LineProperty lineProperty = getLineProperty(currentPos);
0167 
0168         // Join the lines if they are wrapped
0169         while (currentPos < getLines() - 1 && isWrappedLine(currentPos)) {
0170             currentPos++;
0171             endLine = startOfLine(currentPos + 1);
0172         }
0173 
0174         // Now reflow the lines
0175         while (reflowLineLen(startLine, endLine) > columns && !(lineProperty.flags.f.doubleheight_bottom | lineProperty.flags.f.doubleheight_top)) {
0176             startLine += columns;
0177             lineProperty.flags.f.wrapped = 1;
0178             setNewLine(newLineData, startLine + _indexBias, lineProperty);
0179             lineProperty.resetStarts();
0180             newPos++;
0181         }
0182         lineProperty.flags.f.wrapped = 0;
0183         setNewLine(newLineData, endLine + _indexBias, lineProperty);
0184         currentPos++;
0185         newPos++;
0186         if (deltas && delta != newPos - currentPos) {
0187             (*deltas)[currentPos - getLines()] = newPos - currentPos - delta;
0188             delta = newPos - currentPos;
0189         }
0190     }
0191     _lineDatas = std::move(newLineData);
0192 
0193     int deletedLines = 0;
0194     size_t totalLines = getLines();
0195     if (totalLines > _maxLineCount) {
0196         deletedLines = totalLines - _maxLineCount;
0197         removeLinesFromTop(deletedLines);
0198     }
0199 
0200     return deletedLines;
0201 }