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 }