MauiKit Terminal

History.cpp
1/*
2 This file is part of Konsole, an X terminal.
3 SPDX-FileCopyrightText: 1997, 1998 Lars Doelle <lars.doelle@on-line.de>
4
5 SPDX-License-Identifier: GPL-2.0-or-later
6
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
11
12 You should have received a copy of the GNU General Public License
13 along with this program; if not, write to the Free Software
14 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15 02110-1301 USA.
16*/
17
18// Own
19#include "History.h"
20
21// System
22#include <algorithm>
23#include <cerrno>
24#include <cstdio>
25#include <cstdlib>
26#include <iostream>
27#include <sys/mman.h>
28#include <sys/types.h>
29#include <unistd.h>
30
31#include <QtDebug>
32
33// KDE
34// #include <kde_file.h>
35// #include <kdebug.h>
36
37// Reasonable line size
38#define LINE_SIZE 1024
39#define KDE_lseek lseek
40
41using namespace Konsole;
42
43/*
44 An arbitrary long scroll.
45
46 One can modify the scroll only by adding either cells
47 or newlines, but access it randomly.
48
49 The model is that of an arbitrary wide typewriter scroll
50 in that the scroll is a serie of lines and each line is
51 a serie of cells with no overwriting permitted.
52
53 The implementation provides arbitrary length and numbers
54 of cells and line/column indexed read access to the scroll
55 at constant costs.
56
57KDE4: Can we use QTemporaryFile here, instead of KTempFile?
58
59FIXME: some complain about the history buffer comsuming the
60 memory of their machines. This problem is critical
61 since the history does not behave gracefully in cases
62 where the memory is used up completely.
63
64 I put in a workaround that should handle it problem
65 now gracefully. I'm not satisfied with the solution.
66
67FIXME: Terminating the history is not properly indicated
68 in the menu. We should throw a signal.
69
70FIXME: There is noticeable decrease in speed, also. Perhaps,
71 there whole feature needs to be revisited therefore.
72 Disadvantage of a more elaborated, say block-oriented
73 scheme with wrap around would be it's complexity.
74*/
75
76// FIXME: tempory replacement for tmpfile
77// this is here one for debugging purpose.
78
79// #define tmpfile xTmpFile
80
81// History File ///////////////////////////////////////////
82
83/*
84 A Row(X) data type which allows adding elements to the end.
85*/
86
87HistoryFile::HistoryFile()
88 : ion(-1)
89 , length(0)
90 , fileMap(nullptr)
91 , readWriteBalance(0)
92{
93 if (tmpFile.open()) {
94 tmpFile.setAutoRemove(true);
95 ion = tmpFile.handle();
96 }
97}
98
99HistoryFile::~HistoryFile()
100{
101 if (fileMap)
102 unmap();
103}
104
105// TODO: Mapping the entire file in will cause problems if the history file becomes exceedingly large,
106//(ie. larger than available memory). HistoryFile::map() should only map in sections of the file at a time,
107// to avoid this.
108void HistoryFile::map()
109{
110 Q_ASSERT(fileMap == nullptr);
111
112 fileMap = (char *)mmap(nullptr, length, PROT_READ, MAP_PRIVATE, ion, 0);
113
114 // if mmap'ing fails, fall back to the read-lseek combination
115 if (fileMap == MAP_FAILED) {
116 readWriteBalance = 0;
117 fileMap = nullptr;
118 // qDebug() << __FILE__ << __LINE__ << ": mmap'ing history failed. errno = " << errno;
119 }
120}
121
122void HistoryFile::unmap()
123{
124 int result = munmap(fileMap, length);
125 Q_ASSERT(result == 0);
126 Q_UNUSED(result);
127
128 fileMap = nullptr;
129}
130
131bool HistoryFile::isMapped() const
132{
133 return (fileMap != nullptr);
134}
135
136void HistoryFile::add(const unsigned char *bytes, int len)
137{
138 if (fileMap)
139 unmap();
140
141 readWriteBalance++;
142
143 int rc = 0;
144
145 rc = KDE_lseek(ion, length, SEEK_SET);
146 if (rc < 0) {
147 perror("HistoryFile::add.seek");
148 return;
149 }
150 rc = write(ion, bytes, len);
151 if (rc < 0) {
152 perror("HistoryFile::add.write");
153 return;
154 }
155 length += rc;
156}
157
158void HistoryFile::get(unsigned char *bytes, int len, int loc)
159{
160 // count number of get() calls vs. number of add() calls.
161 // If there are many more get() calls compared with add()
162 // calls (decided by using MAP_THRESHOLD) then mmap the log
163 // file to improve performance.
164 readWriteBalance--;
165 if (!fileMap && readWriteBalance < MAP_THRESHOLD)
166 map();
167
168 if (fileMap) {
169 for (int i = 0; i < len; i++)
170 bytes[i] = fileMap[loc + i];
171 } else {
172 int rc = 0;
173
174 if (loc < 0 || len < 0 || loc + len > length)
175 fprintf(stderr, "getHist(...,%d,%d): invalid args.\n", len, loc);
176 rc = KDE_lseek(ion, loc, SEEK_SET);
177 if (rc < 0) {
178 perror("HistoryFile::get.seek");
179 return;
180 }
181 rc = read(ion, bytes, len);
182 if (rc < 0) {
183 perror("HistoryFile::get.read");
184 return;
185 }
186 }
187}
188
189int HistoryFile::len()
190{
191 return length;
192}
193
194// History Scroll abstract base class //////////////////////////////////////
195
196HistoryScroll::HistoryScroll(HistoryType *t)
197 : m_histType(t)
198{
199}
200
201HistoryScroll::~HistoryScroll()
202{
203 delete m_histType;
204}
205
206bool HistoryScroll::hasScroll()
207{
208 return true;
209}
210
211// History Scroll File //////////////////////////////////////
212
213/*
214 The history scroll makes a Row(Row(Cell)) from
215 two history buffers. The index buffer contains
216 start of line positions which refere to the cells
217 buffer.
218
219 Note that index[0] addresses the second line
220 (line #1), while the first line (line #0) starts
221 at 0 in cells.
222*/
223
224HistoryScrollFile::HistoryScrollFile(const QString &logFileName)
225 : HistoryScroll(new HistoryTypeFile(logFileName))
226 , m_logFileName(logFileName)
227{
228}
229
230HistoryScrollFile::~HistoryScrollFile()
231{
232}
233
234int HistoryScrollFile::getLines()
235{
236 return index.len() / sizeof(int);
237}
238
239int HistoryScrollFile::getLineLen(int lineno)
240{
241 return (startOfLine(lineno + 1) - startOfLine(lineno)) / sizeof(Character);
242}
243
244bool HistoryScrollFile::isWrappedLine(int lineno)
245{
246 if (lineno >= 0 && lineno <= getLines()) {
247 unsigned char flag;
248 lineflags.get((unsigned char *)&flag, sizeof(unsigned char), (lineno) * sizeof(unsigned char));
249 return flag;
250 }
251 return false;
252}
253
254int HistoryScrollFile::startOfLine(int lineno)
255{
256 if (lineno <= 0)
257 return 0;
258 if (lineno <= getLines()) {
259 if (!index.isMapped())
260 index.map();
261
262 int res;
263 index.get((unsigned char *)&res, sizeof(int), (lineno - 1) * sizeof(int));
264 return res;
265 }
266 return cells.len();
267}
268
269void HistoryScrollFile::getCells(int lineno, int colno, int count, std::span<Character> res)
270{
271 cells.get((unsigned char *)res.data(), count * sizeof(Character), startOfLine(lineno) + colno * sizeof(Character));
272}
273
274void HistoryScrollFile::addCells(std::span<const Character> text, int count)
275{
276 cells.add((unsigned char *)text.data(), count * sizeof(Character));
277}
278
279void HistoryScrollFile::addLine(bool previousWrapped)
280{
281 if (index.isMapped())
282 index.unmap();
283
284 int locn = cells.len();
285 index.add((unsigned char *)&locn, sizeof(int));
286 unsigned char flags = previousWrapped ? 0x01 : 0x00;
287 lineflags.add((unsigned char *)&flags, sizeof(unsigned char));
288}
289
290// History Scroll Buffer //////////////////////////////////////
291HistoryScrollBuffer::HistoryScrollBuffer(unsigned int maxLineCount)
292 : HistoryScroll(new HistoryTypeBuffer(maxLineCount))
293 , _historyBuffer()
294 , _maxLineCount(0)
295 , _usedLines(0)
296 , _head(0)
297{
298 setMaxNbLines(maxLineCount);
299}
300
301HistoryScrollBuffer::~HistoryScrollBuffer()
302{
303 delete[] _historyBuffer;
304}
305
306void HistoryScrollBuffer::addCellsVector(const QVector<Character> &cells)
307{
308 _head++;
309 if (_usedLines < _maxLineCount)
310 _usedLines++;
311
312 if (_head >= _maxLineCount) {
313 _head = 0;
314 }
315
316 _historyBuffer[bufferIndex(_usedLines - 1)] = cells;
317 _wrappedLine[bufferIndex(_usedLines - 1)] = false;
318}
319void HistoryScrollBuffer::addCells(std::span<const Character> a, int count)
320{
321 HistoryLine newLine(count);
322 std::copy(a.data(), a.subspan(count).data(), newLine.begin());
323
324 addCellsVector(newLine);
325}
326
327void HistoryScrollBuffer::addLine(bool previousWrapped)
328{
329 _wrappedLine[bufferIndex(_usedLines - 1)] = previousWrapped;
330}
331
332int HistoryScrollBuffer::getLines()
333{
334 return _usedLines;
335}
336
337int HistoryScrollBuffer::getLineLen(int lineNumber)
338{
339 Q_ASSERT(lineNumber >= 0 && lineNumber < _maxLineCount);
340
341 if (lineNumber < _usedLines) {
342 return _historyBuffer[bufferIndex(lineNumber)].size();
343 } else {
344 return 0;
345 }
346}
347
348bool HistoryScrollBuffer::isWrappedLine(int lineNumber)
349{
350 Q_ASSERT(lineNumber >= 0 && lineNumber < _maxLineCount);
351
352 if (lineNumber < _usedLines) {
353 // kDebug() << "Line" << lineNumber << "wrapped is" << _wrappedLine[bufferIndex(lineNumber)];
354 return _wrappedLine[bufferIndex(lineNumber)];
355 } else
356 return false;
357}
358
359void HistoryScrollBuffer::getCells(int lineNumber, int startColumn, int count, std::span<Character> buffer)
360{
361 if (count == 0)
362 return;
363
364 Q_ASSERT(lineNumber < _maxLineCount);
365
366 if (lineNumber >= _usedLines) {
367 memset(static_cast<void *>(buffer.data()), 0, count * sizeof(Character));
368 return;
369 }
370
371 const HistoryLine &line = _historyBuffer[bufferIndex(lineNumber)];
372
373 // kDebug() << "startCol " << startColumn;
374 // kDebug() << "line.size() " << line.size();
375 // kDebug() << "count " << count;
376
377 Q_ASSERT(startColumn <= line.size() - count);
378
379 memcpy(buffer.data(), line.constData() + startColumn, count * sizeof(Character));
380}
381
382void HistoryScrollBuffer::setMaxNbLines(unsigned int lineCount)
383{
384 HistoryLine *oldBuffer = _historyBuffer;
385 HistoryLine *newBuffer = new HistoryLine[lineCount];
386
387 for (int i = 0; i < qMin(_usedLines, (int)lineCount); i++) {
388 newBuffer[i] = oldBuffer[bufferIndex(i)];
389 }
390
391 _usedLines = qMin(_usedLines, (int)lineCount);
392 _maxLineCount = lineCount;
393 _head = (_usedLines == _maxLineCount) ? 0 : _usedLines - 1;
394
395 _historyBuffer = newBuffer;
396 delete[] oldBuffer;
397
398 _wrappedLine.resize(lineCount);
399 dynamic_cast<HistoryTypeBuffer *>(m_histType)->m_nbLines = lineCount;
400}
401
402int HistoryScrollBuffer::bufferIndex(int lineNumber) const
403{
404 Q_ASSERT(lineNumber >= 0);
405 Q_ASSERT(lineNumber < _maxLineCount);
406 Q_ASSERT((_usedLines == _maxLineCount) || lineNumber <= _head);
407
408 if (_usedLines == _maxLineCount) {
409 return (_head + lineNumber + 1) % _maxLineCount;
410 } else {
411 return lineNumber;
412 }
413}
414
415// History Scroll None //////////////////////////////////////
416
417HistoryScrollNone::HistoryScrollNone()
418 : HistoryScroll(new HistoryTypeNone())
419{
420}
421
422HistoryScrollNone::~HistoryScrollNone()
423{
424}
425
426bool HistoryScrollNone::hasScroll()
427{
428 return false;
429}
430
431int HistoryScrollNone::getLines()
432{
433 return 0;
434}
435
436int HistoryScrollNone::getLineLen(int)
437{
438 return 0;
439}
440
441bool HistoryScrollNone::isWrappedLine(int /*lineno*/)
442{
443 return false;
444}
445
446void HistoryScrollNone::getCells(int, int, int, std::span<Character>)
447{
448}
449
450void HistoryScrollNone::addCells(std::span<const Character>, int)
451{
452}
453
454void HistoryScrollNone::addLine(bool)
455{
456}
457
458// History Scroll BlockArray //////////////////////////////////////
459
460HistoryScrollBlockArray::HistoryScrollBlockArray(size_t size)
461 : HistoryScroll(new HistoryTypeBlockArray(size))
462{
463 m_blockArray.setHistorySize(size); // nb. of lines.
464}
465
466HistoryScrollBlockArray::~HistoryScrollBlockArray()
467{
468}
469
470int HistoryScrollBlockArray::getLines()
471{
472 return m_lineLengths.size();
473}
474
475int HistoryScrollBlockArray::getLineLen(int lineno)
476{
477 if (m_lineLengths.contains(lineno))
478 return m_lineLengths[lineno];
479 else
480 return 0;
481}
482
483bool HistoryScrollBlockArray::isWrappedLine(int /*lineno*/)
484{
485 return false;
486}
487
488void HistoryScrollBlockArray::getCells(int lineno, int colno, int count, std::span<Character> res)
489{
490 if (!count)
491 return;
492
493 const Block *b = m_blockArray.at(lineno);
494
495 if (!b) {
496 memset(static_cast<void *>(res.data()), 0, count * sizeof(Character)); // still better than random data
497 return;
498 }
499
500 Q_ASSERT(((colno + count) * sizeof(Character)) < ENTRIES);
501 memcpy(res.data(), b->data + (colno * sizeof(Character)), count * sizeof(Character));
502}
503
504void HistoryScrollBlockArray::addCells(std::span<const Character> a, int count)
505{
506 Block *b = m_blockArray.lastBlock();
507
508 if (!b)
509 return;
510
511 // put cells in block's data
512 Q_ASSERT((count * sizeof(Character)) < ENTRIES);
513
514 memset(b->data, 0, sizeof(b->data));
515
516 memcpy(b->data, a.data(), count * sizeof(Character));
517 b->size = count * sizeof(Character);
518
519 size_t res = m_blockArray.newBlock();
520 Q_ASSERT(res > 0);
521 Q_UNUSED(res);
522
523 m_lineLengths.insert(m_blockArray.getCurrent(), count);
524}
525
526void HistoryScrollBlockArray::addLine(bool)
527{
528}
529
530////////////////////////////////////////////////////////////////
531// Compact History Scroll //////////////////////////////////////
532////////////////////////////////////////////////////////////////
533void *CompactHistoryBlock::allocate(size_t length)
534{
535 Q_ASSERT(length > 0);
536 if (tail - blockStart + length > blockLength)
537 return nullptr;
538
539 void *block = tail;
540 tail += length;
541 // kDebug() << "allocated " << length << " bytes at address " << block;
542 allocCount++;
543 return block;
544}
545
546void CompactHistoryBlock::deallocate()
547{
548 allocCount--;
549 Q_ASSERT(allocCount >= 0);
550}
551
552void *CompactHistoryBlockList::allocate(size_t size)
553{
554 CompactHistoryBlock *block;
555 if (list.isEmpty() || list.last()->remaining() < size) {
556 block = new CompactHistoryBlock();
557 list.append(block);
558 // kDebug() << "new block created, remaining " << block->remaining() << "number of blocks=" << list.size();
559 } else {
560 block = list.last();
561 // kDebug() << "old block used, remaining " << block->remaining();
562 }
563 return block->allocate(size);
564}
565
566void CompactHistoryBlockList::deallocate(void *ptr)
567{
568 Q_ASSERT(!list.isEmpty());
569
570 int i = 0;
571 CompactHistoryBlock *block = list.at(i);
572 while (i < list.size() && !block->contains(ptr)) {
573 i++;
574 block = list.at(i);
575 }
576
577 Q_ASSERT(i < list.size());
578
579 block->deallocate();
580
581 if (!block->isInUse()) {
582 list.removeAt(i);
583 delete block;
584 // kDebug() << "block deleted, new size = " << list.size();
585 }
586}
587
588CompactHistoryBlockList::~CompactHistoryBlockList()
589{
590 qDeleteAll(list.begin(), list.end());
591 list.clear();
592}
593
594void *CompactHistoryLine::operator new(size_t size, CompactHistoryBlockList &blockList)
595{
596 return blockList.allocate(size);
597}
598
599CompactHistoryLine::CompactHistoryLine(const TextLine &line, CompactHistoryBlockList &bList)
600 : blockList(bList)
601 , formatLength(0)
602{
603 length = line.size();
604
605 if (!line.empty()) {
606 formatLength = 1;
607 int k = 1;
608
609 // count number of different formats in this text line
610 Character c = line[0];
611 while (k < length) {
612 if (!(line[k].equalsFormat(c))) {
613 formatLength++; // format change detected
614 c = line[k];
615 }
616 k++;
617 }
618
619 // kDebug() << "number of different formats in string: " << formatLength;
620 formatArray = (CharacterFormat *)blockList.allocate(sizeof(CharacterFormat) * formatLength);
621 Q_ASSERT(formatArray != nullptr);
622 text = (quint16 *)blockList.allocate(sizeof(quint16) * line.size());
623 Q_ASSERT(text != nullptr);
624
625 length = line.size();
626 wrapped = false;
627
628 // record formats and their positions in the format array
629 c = line[0];
630 formatArray[0].setFormat(c);
631 formatArray[0].startPos = 0; // there's always at least 1 format (for the entire line, unless a change happens)
632
633 k = 1; // look for possible format changes
634 int j = 1;
635 while (k < length && j < formatLength) {
636 if (!(line[k].equalsFormat(c))) {
637 c = line[k];
638 formatArray[j].setFormat(c);
639 formatArray[j].startPos = k;
640 // kDebug() << "format entry " << j << " at pos " << formatArray[j].startPos << " " << &(formatArray[j].startPos) ;
641 j++;
642 }
643 k++;
644 }
645
646 // copy character values
647 for (int i = 0; i < line.size(); i++) {
648 text[i] = line[i].character.unicode();
649 // kDebug() << "char " << i << " at mem " << &(text[i]);
650 }
651 }
652 // kDebug() << "line created, length " << length << " at " << &(length);
653}
654
655CompactHistoryLine::~CompactHistoryLine()
656{
657 // kDebug() << "~CHL";
658 if (length > 0) {
659 blockList.deallocate(text);
660 blockList.deallocate(formatArray);
661 }
662 blockList.deallocate(this);
663}
664
665void CompactHistoryLine::getCharacter(int index, Character &r)
666{
667 Q_ASSERT(index < length);
668 int formatPos = 0;
669 while ((formatPos + 1) < formatLength && index >= formatArray[formatPos + 1].startPos)
670 formatPos++;
671
672 r.character = text[index];
673 r.rendition = formatArray[formatPos].rendition;
674 r.foregroundColor = formatArray[formatPos].fgColor;
675 r.backgroundColor = formatArray[formatPos].bgColor;
676}
677
678void CompactHistoryLine::getCharacters(Character *array, int length, int startColumn)
679{
680 Q_ASSERT(startColumn >= 0 && length >= 0);
681 Q_ASSERT(startColumn + length <= (int)getLength());
682
683 for (int i = startColumn; i < length + startColumn; i++) {
684 getCharacter(i, array[i - startColumn]);
685 }
686}
687
688CompactHistoryScroll::CompactHistoryScroll(unsigned int maxLineCount)
689 : HistoryScroll(new CompactHistoryType(maxLineCount))
690 , lines()
691 , blockList()
692{
693 // kDebug() << "scroll of length " << maxLineCount << " created";
694 setMaxNbLines(maxLineCount);
695}
696
697CompactHistoryScroll::~CompactHistoryScroll()
698{
699 qDeleteAll(lines.begin(), lines.end());
700 lines.clear();
701}
702
703void CompactHistoryScroll::addCellsVector(const TextLine &cells)
704{
705 CompactHistoryLine *line;
706 line = new (blockList) CompactHistoryLine(cells, blockList);
707
708 if (lines.size() > (int)_maxLineCount) {
709 delete lines.takeAt(0);
710 }
711 lines.append(line);
712}
713
714void CompactHistoryScroll::addCells(std::span<const Character> a, int count)
715{
716 TextLine newLine(count);
717 std::copy(a.data(), a.subspan(count).data(), newLine.begin());
718 addCellsVector(newLine);
719}
720
721void CompactHistoryScroll::addLine(bool previousWrapped)
722{
723 CompactHistoryLine *line = lines.last();
724 // kDebug() << "last line at address " << line;
725 line->setWrapped(previousWrapped);
726}
727
728int CompactHistoryScroll::getLines()
729{
730 return lines.size();
731}
732
733int CompactHistoryScroll::getLineLen(int lineNumber)
734{
735 Q_ASSERT(lineNumber >= 0 && lineNumber < lines.size());
736 CompactHistoryLine *line = lines[lineNumber];
737 // kDebug() << "request for line at address " << line;
738 return line->getLength();
739}
740
741void CompactHistoryScroll::getCells(int lineNumber, int startColumn, int count, std::span<Character> buffer)
742{
743 if (count == 0)
744 return;
745 Q_ASSERT(lineNumber < lines.size());
746 CompactHistoryLine *line = lines[lineNumber];
747 Q_ASSERT(startColumn >= 0);
748 Q_ASSERT((unsigned int)startColumn <= line->getLength() - count);
749 line->getCharacters(buffer.data(), count, startColumn);
750}
751
752void CompactHistoryScroll::setMaxNbLines(unsigned int lineCount)
753{
754 _maxLineCount = lineCount;
755
756 while (lines.size() > (int)lineCount) {
757 delete lines.takeAt(0);
758 }
759 // kDebug() << "set max lines to: " << _maxLineCount;
760}
761
762bool CompactHistoryScroll::isWrappedLine(int lineNumber)
763{
764 Q_ASSERT(lineNumber < lines.size());
765 return lines[lineNumber]->isWrapped();
766}
767
768//////////////////////////////////////////////////////////////////////
769// History Types
770//////////////////////////////////////////////////////////////////////
771
772HistoryType::HistoryType()
773{
774}
775
776HistoryType::~HistoryType()
777{
778}
779
780//////////////////////////////
781
782HistoryTypeNone::HistoryTypeNone()
783{
784}
785
786bool HistoryTypeNone::isEnabled() const
787{
788 return false;
789}
790
791std::unique_ptr<HistoryScroll> HistoryTypeNone::scroll(std::unique_ptr<HistoryScroll> &&) const
792{
793 return std::make_unique<HistoryScrollNone>();
794}
795
796int HistoryTypeNone::maximumLineCount() const
797{
798 return 0;
799}
800
801//////////////////////////////
802
803HistoryTypeBlockArray::HistoryTypeBlockArray(size_t size)
804 : m_size(size)
805{
806}
807
808bool HistoryTypeBlockArray::isEnabled() const
809{
810 return true;
811}
812
813int HistoryTypeBlockArray::maximumLineCount() const
814{
815 return m_size;
816}
817
818std::unique_ptr<HistoryScroll> HistoryTypeBlockArray::scroll(std::unique_ptr<HistoryScroll> &&) const
819{
820 return std::make_unique<HistoryScrollBlockArray>(m_size);
821}
822
823//////////////////////////////
824
825HistoryTypeBuffer::HistoryTypeBuffer(unsigned int nbLines)
826 : m_nbLines(nbLines)
827{
828}
829
830bool HistoryTypeBuffer::isEnabled() const
831{
832 return true;
833}
834
835int HistoryTypeBuffer::maximumLineCount() const
836{
837 return m_nbLines;
838}
839
840std::unique_ptr<HistoryScroll> HistoryTypeBuffer::scroll(std::unique_ptr<HistoryScroll> &&old) const
841{
842 if (old) {
843 HistoryScrollBuffer *oldBuffer = dynamic_cast<HistoryScrollBuffer *>(old.get());
844 if (oldBuffer) {
845 oldBuffer->setMaxNbLines(m_nbLines);
846 return old;
847 }
848
849 auto newScroll = std::make_unique<HistoryScrollBuffer>(m_nbLines);
850 int lines = old->getLines();
851 int startLine = 0;
852 if (lines > (int)m_nbLines)
853 startLine = lines - m_nbLines;
854
855 Character line[LINE_SIZE];
856 for (int i = startLine; i < lines; i++) {
857 int size = old->getLineLen(i);
858 if (size > LINE_SIZE) {
859 auto tmp_line = std::vector<Character>(size);
860 old->getCells(i, 0, size, tmp_line);
861 newScroll->addCells(tmp_line, size);
862 newScroll->addLine(old->isWrappedLine(i));
863 } else {
864 old->getCells(i, 0, size, line);
865 newScroll->addCells(line, size);
866 newScroll->addLine(old->isWrappedLine(i));
867 }
868 }
869 return newScroll;
870 }
871 return std::make_unique<HistoryScrollBuffer>(m_nbLines);
872}
873
874//////////////////////////////
875
876HistoryTypeFile::HistoryTypeFile(const QString &fileName)
877 : m_fileName(fileName)
878{
879}
880
881bool HistoryTypeFile::isEnabled() const
882{
883 return true;
884}
885
886const QString &HistoryTypeFile::getFileName() const
887{
888 return m_fileName;
889}
890
891std::unique_ptr<HistoryScroll> HistoryTypeFile::scroll(std::unique_ptr<HistoryScroll> &&old) const
892{
893 if (dynamic_cast<HistoryFile *>(old.get()))
894 return old; // Unchanged.
895
896 auto newScroll = std::make_unique<HistoryScrollFile>(m_fileName);
897
898 Character line[LINE_SIZE];
899 int lines = (old != nullptr) ? old->getLines() : 0;
900 for (int i = 0; i < lines; i++) {
901 int size = old->getLineLen(i);
902 if (size > LINE_SIZE) {
903 auto tmp_line = std::vector<Character>(size);
904 old->getCells(i, 0, size, tmp_line);
905 newScroll->addCells(tmp_line, size);
906 newScroll->addLine(old->isWrappedLine(i));
907 } else {
908 old->getCells(i, 0, size, line);
909 newScroll->addCells(line, size);
910 newScroll->addLine(old->isWrappedLine(i));
911 }
912 }
913
914 return newScroll;
915}
916
917int HistoryTypeFile::maximumLineCount() const
918{
919 return 0;
920}
921
922//////////////////////////////
923
924CompactHistoryType::CompactHistoryType(unsigned int nbLines)
925 : m_nbLines(nbLines)
926{
927}
928
929bool CompactHistoryType::isEnabled() const
930{
931 return true;
932}
933
934int CompactHistoryType::maximumLineCount() const
935{
936 return m_nbLines;
937}
938
939std::unique_ptr<HistoryScroll> CompactHistoryType::scroll(std::unique_ptr<HistoryScroll> &&old) const
940{
941 if (old) {
942 CompactHistoryScroll *oldBuffer = dynamic_cast<CompactHistoryScroll *>(old.get());
943 if (oldBuffer) {
944 oldBuffer->setMaxNbLines(m_nbLines);
945 return old;
946 }
947 }
948 return std::make_unique<CompactHistoryScroll>(m_nbLines);
949}
A single character in the terminal which consists of a unicode character value, foreground and backgr...
Definition Character.h:63
QChar character
The unicode character value for this character.
Definition Character.h:86
CharacterColor foregroundColor
The foreground color used to draw this character.
Definition Character.h:101
CharacterColor backgroundColor
The color used to draw this character's background.
Definition Character.h:103
quint8 rendition
A combination of RENDITION flags which specify options for drawing the character.
Definition Character.h:98
QVariant read(const QByteArray &data, int versionOverride=0)
void resize(qsizetype size)
bool contains(const Key &key) const const
iterator insert(const Key &key, const T &value)
qsizetype size() const const
void append(QList< T > &&value)
const_reference at(qsizetype i) const const
iterator begin()
void clear()
bool empty() const const
iterator end()
bool isEmpty() const const
T & last()
void removeAt(qsizetype i)
qsizetype size() const const
T takeAt(qsizetype i)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Nov 29 2024 11:55:13 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.