MauiKit Terminal

History.h
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#ifndef TEHISTORY_H
19#define TEHISTORY_H
20
21// Qt
22#include <QBitRef>
23#include <QHash>
24#include <QTemporaryFile>
25#include <QVector>
26
27// KDE
28// #include <ktemporaryfile.h>
29
30// Konsole
31#include "BlockArray.h"
32#include "Character.h"
33
34// map
35#include <memory>
36#include <sys/mman.h>
37
38namespace Konsole
39{
40
41#if 1
42/*
43 An extendable tmpfile(1) based buffer.
44*/
45
46class HistoryFile
47{
48public:
49 HistoryFile();
50 virtual ~HistoryFile();
51
52 virtual void add(const unsigned char *bytes, int len);
53 virtual void get(unsigned char *bytes, int len, int loc);
54 virtual int len();
55
56 // mmaps the file in read-only mode
57 void map();
58 // un-mmaps the file
59 void unmap();
60 // returns true if the file is mmap'ed
61 bool isMapped() const;
62
63private:
64 int ion;
65 int length;
66 QTemporaryFile tmpFile;
67
68 // pointer to start of mmap'ed file data, or 0 if the file is not mmap'ed
69 char *fileMap;
70
71 // incremented whenver 'add' is called and decremented whenever
72 //'get' is called.
73 // this is used to detect when a large number of lines are being read and processed from the history
74 // and automatically mmap the file for better performance (saves the overhead of many lseek-read calls).
75 int readWriteBalance;
76
77 // when readWriteBalance goes below this threshold, the file will be mmap'ed automatically
78 static const int MAP_THRESHOLD = -1000;
79};
80#endif
81
82//////////////////////////////////////////////////////////////////////
83
84//////////////////////////////////////////////////////////////////////
85// Abstract base class for file and buffer versions
86//////////////////////////////////////////////////////////////////////
87class HistoryType;
88
89class HistoryScroll
90{
91public:
92 HistoryScroll(HistoryType *);
93 virtual ~HistoryScroll();
94
95 virtual bool hasScroll();
96
97 // access to history
98 virtual int getLines() = 0;
99 virtual int getLineLen(int lineno) = 0;
100 virtual void getCells(int lineno, int colno, int count, std::span<Character> res) = 0;
101 virtual bool isWrappedLine(int lineno) = 0;
102
103 // backward compatibility (obsolete)
104 Character getCell(int lineno, int colno)
105 {
106 Character res;
107 getCells(lineno, colno, 1, std::span(&res, 1));
108 return res;
109 }
110
111 // adding lines.
112 virtual void addCells(std::span<const Character> a, int count) = 0;
113 // convenience method - this is virtual so that subclasses can take advantage
114 // of QVector's implicit copying
115 virtual void addCellsVector(const QVector<Character> &cells)
116 {
117 auto span = std::span<const Character>{cells.data(), size_t(cells.size())};
118 addCells(span, cells.size());
119 }
120
121 virtual void addLine(bool previousWrapped = false) = 0;
122
123 //
124 // FIXME: Passing around constant references to HistoryType instances
125 // is very unsafe, because those references will no longer
126 // be valid if the history scroll is deleted.
127 //
128 const HistoryType &getType()
129 {
130 return *m_histType;
131 }
132
133protected:
134 HistoryType *m_histType;
135};
136
137#if 1
138
139//////////////////////////////////////////////////////////////////////
140// File-based history (e.g. file log, no limitation in length)
141//////////////////////////////////////////////////////////////////////
142
143class HistoryScrollFile : public HistoryScroll
144{
145public:
146 HistoryScrollFile(const QString &logFileName);
147 ~HistoryScrollFile() override;
148
149 int getLines() override;
150 int getLineLen(int lineno) override;
151 void getCells(int lineno, int colno, int count, std::span<Character> res) override;
152 bool isWrappedLine(int lineno) override;
153
154 void addCells(std::span<const Character> a, int count) override;
155 void addLine(bool previousWrapped = false) override;
156
157private:
158 int startOfLine(int lineno);
159
160 QString m_logFileName;
161 HistoryFile index; // lines Row(int)
162 HistoryFile cells; // text Row(Character)
163 HistoryFile lineflags; // flags Row(unsigned char)
164};
165
166//////////////////////////////////////////////////////////////////////
167// Buffer-based history (limited to a fixed nb of lines)
168//////////////////////////////////////////////////////////////////////
169class HistoryScrollBuffer : public HistoryScroll
170{
171public:
172 typedef QVector<Character> HistoryLine;
173
174 HistoryScrollBuffer(unsigned int maxNbLines = 1000);
175 ~HistoryScrollBuffer() override;
176
177 int getLines() override;
178 int getLineLen(int lineno) override;
179 void getCells(int lineno, int colno, int count, std::span<Character> res) override;
180 bool isWrappedLine(int lineno) override;
181
182 void addCells(std::span<const Character> a, int count) override;
183 void addCellsVector(const QVector<Character> &cells) override;
184 void addLine(bool previousWrapped = false) override;
185
186 void setMaxNbLines(unsigned int nbLines);
187 unsigned int maxNbLines() const
188 {
189 return _maxLineCount;
190 }
191
192private:
193 int bufferIndex(int lineNumber) const;
194
195 HistoryLine *_historyBuffer;
196 QBitArray _wrappedLine;
197 int _maxLineCount;
198 int _usedLines;
199 int _head;
200
201 // QVector<histline*> m_histBuffer;
202 // QBitArray m_wrappedLine;
203 // unsigned int m_maxNbLines;
204 // unsigned int m_nbLines;
205 // unsigned int m_arrayIndex;
206 // bool m_buffFilled;
207};
208
209/*class HistoryScrollBufferV2 : public HistoryScroll
210{
211public:
212 virtual int getLines();
213 virtual int getLineLen(int lineno);
214 virtual void getCells(int lineno, int colno, int count, Character res[]);
215 virtual bool isWrappedLine(int lineno);
216
217 virtual void addCells(const Character a[], int count);
218 virtual void addCells(const QVector<Character>& cells);
219 virtual void addLine(bool previousWrapped=false);
220
221};*/
222
223#endif
224
225//////////////////////////////////////////////////////////////////////
226// Nothing-based history (no history :-)
227//////////////////////////////////////////////////////////////////////
228class HistoryScrollNone : public HistoryScroll
229{
230public:
231 HistoryScrollNone();
232 ~HistoryScrollNone() override;
233
234 bool hasScroll() override;
235
236 int getLines() override;
237 int getLineLen(int lineno) override;
238 void getCells(int lineno, int colno, int count, std::span<Character> res) override;
239 bool isWrappedLine(int lineno) override;
240
241 void addCells(std::span<const Character> a, int count) override;
242 void addLine(bool previousWrapped = false) override;
243};
244
245//////////////////////////////////////////////////////////////////////
246// BlockArray-based history
247//////////////////////////////////////////////////////////////////////
248class HistoryScrollBlockArray : public HistoryScroll
249{
250public:
251 HistoryScrollBlockArray(size_t size);
252 ~HistoryScrollBlockArray() override;
253
254 int getLines() override;
255 int getLineLen(int lineno) override;
256 void getCells(int lineno, int colno, int count, std::span<Character> res) override;
257 bool isWrappedLine(int lineno) override;
258
259 void addCells(std::span<const Character> a, int count) override;
260 void addLine(bool previousWrapped = false) override;
261
262protected:
263 BlockArray m_blockArray;
264 QHash<int, size_t> m_lineLengths;
265};
266
267//////////////////////////////////////////////////////////////////////
268// History using compact storage
269// This implementation uses a list of fixed-sized blocks
270// where history lines are allocated in (avoids heap fragmentation)
271//////////////////////////////////////////////////////////////////////
272typedef QVector<Character> TextLine;
273
274class CharacterFormat
275{
276public:
277 bool equalsFormat(const CharacterFormat &other) const
278 {
279 return other.rendition == rendition && other.fgColor == fgColor && other.bgColor == bgColor;
280 }
281
282 bool equalsFormat(const Character &c) const
283 {
284 return c.rendition == rendition && c.foregroundColor == fgColor && c.backgroundColor == bgColor;
285 }
286
287 void setFormat(const Character &c)
288 {
289 rendition = c.rendition;
290 fgColor = c.foregroundColor;
291 bgColor = c.backgroundColor;
292 }
293
294 CharacterColor fgColor, bgColor;
295 quint16 startPos;
296 quint8 rendition;
297};
298
299class CompactHistoryBlock
300{
301public:
302 CompactHistoryBlock()
303 {
304 blockLength = 4096 * 64; // 256kb
305 head = (quint8 *)mmap(nullptr, blockLength, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
306 // head = (quint8*) malloc(blockLength);
307 Q_ASSERT(head != MAP_FAILED);
308 tail = blockStart = head;
309 allocCount = 0;
310 }
311
312 virtual ~CompactHistoryBlock()
313 {
314 // free(blockStart);
315 munmap(blockStart, blockLength);
316 }
317
318 virtual unsigned int remaining()
319 {
320 return blockStart + blockLength - tail;
321 }
322 virtual unsigned length()
323 {
324 return blockLength;
325 }
326 virtual void *allocate(size_t length);
327 virtual bool contains(void *addr)
328 {
329 return addr >= blockStart && addr < (blockStart + blockLength);
330 }
331 virtual void deallocate();
332 virtual bool isInUse()
333 {
334 return allocCount != 0;
335 };
336
337private:
338 size_t blockLength;
339 quint8 *head;
340 quint8 *tail;
341 quint8 *blockStart;
342 int allocCount;
343};
344
345class CompactHistoryBlockList
346{
347public:
348 CompactHistoryBlockList(){};
349 ~CompactHistoryBlockList();
350
351 void *allocate(size_t size);
352 void deallocate(void *);
353 int length()
354 {
355 return list.size();
356 }
357
358private:
360};
361
362class CompactHistoryLine
363{
364public:
365 CompactHistoryLine(const TextLine &, CompactHistoryBlockList &blockList);
366 virtual ~CompactHistoryLine();
367
368 // custom new operator to allocate memory from custom pool instead of heap
369 static void *operator new(size_t size, CompactHistoryBlockList &blockList);
370 static void operator delete(void *){/* do nothing, deallocation from pool is done in destructor*/};
371
372 virtual void getCharacters(Character *array, int length, int startColumn);
373 virtual void getCharacter(int index, Character &r);
374 virtual bool isWrapped() const
375 {
376 return wrapped;
377 };
378 virtual void setWrapped(bool isWrapped)
379 {
380 wrapped = isWrapped;
381 };
382 virtual unsigned int getLength() const
383 {
384 return length;
385 };
386
387protected:
388 CompactHistoryBlockList &blockList;
389 CharacterFormat *formatArray;
390 quint16 length;
391 quint16 *text;
392 quint16 formatLength;
393 bool wrapped;
394};
395
396class CompactHistoryScroll : public HistoryScroll
397{
398 typedef QList<CompactHistoryLine *> HistoryArray;
399
400public:
401 CompactHistoryScroll(unsigned int maxNbLines = 1000);
402 ~CompactHistoryScroll() override;
403
404 int getLines() override;
405 int getLineLen(int lineno) override;
406 void getCells(int lineno, int colno, int count, std::span<Character> res) override;
407 bool isWrappedLine(int lineno) override;
408
409 void addCells(std::span<const Character> a, int count) override;
410 void addCellsVector(const TextLine &cells) override;
411 void addLine(bool previousWrapped = false) override;
412
413 void setMaxNbLines(unsigned int nbLines);
414 unsigned int maxNbLines() const
415 {
416 return _maxLineCount;
417 }
418
419private:
420 bool hasDifferentColors(const TextLine &line) const;
421 HistoryArray lines;
422 CompactHistoryBlockList blockList;
423
424 unsigned int _maxLineCount;
425};
426
427//////////////////////////////////////////////////////////////////////
428// History type
429//////////////////////////////////////////////////////////////////////
430
431class HistoryType
432{
433public:
434 HistoryType();
435 virtual ~HistoryType();
436
437 /**
438 * Returns true if the history is enabled ( can store lines of output )
439 * or false otherwise.
440 */
441 virtual bool isEnabled() const = 0;
442 /**
443 * Returns true if the history size is unlimited.
444 */
445 bool isUnlimited() const
446 {
447 return maximumLineCount() == 0;
448 }
449 /**
450 * Returns the maximum number of lines which this history type
451 * can store or 0 if the history can store an unlimited number of lines.
452 */
453 virtual int maximumLineCount() const = 0;
454
455 virtual std::unique_ptr<HistoryScroll> scroll(std::unique_ptr<HistoryScroll> &&) const = 0;
456};
457
458class HistoryTypeNone : public HistoryType
459{
460public:
461 HistoryTypeNone();
462
463 bool isEnabled() const override;
464 int maximumLineCount() const override;
465
466 std::unique_ptr<HistoryScroll> scroll(std::unique_ptr<HistoryScroll> &&) const override;
467};
468
469class HistoryTypeBlockArray : public HistoryType
470{
471public:
472 HistoryTypeBlockArray(size_t size);
473
474 bool isEnabled() const override;
475 int maximumLineCount() const override;
476
477 std::unique_ptr<HistoryScroll> scroll(std::unique_ptr<HistoryScroll> &&) const override;
478
479protected:
480 size_t m_size;
481};
482
483#if 1
484class HistoryTypeFile : public HistoryType
485{
486public:
487 HistoryTypeFile(const QString &fileName = QString());
488
489 bool isEnabled() const override;
490 virtual const QString &getFileName() const;
491 int maximumLineCount() const override;
492
493 std::unique_ptr<HistoryScroll> scroll(std::unique_ptr<HistoryScroll> &&) const override;
494
495protected:
496 QString m_fileName;
497};
498
499class HistoryTypeBuffer : public HistoryType
500{
501 friend class HistoryScrollBuffer;
502
503public:
504 HistoryTypeBuffer(unsigned int nbLines);
505
506 bool isEnabled() const override;
507 int maximumLineCount() const override;
508
509 std::unique_ptr<HistoryScroll> scroll(std::unique_ptr<HistoryScroll> &&) const override;
510
511protected:
512 unsigned int m_nbLines;
513};
514
515class CompactHistoryType : public HistoryType
516{
517public:
518 CompactHistoryType(unsigned int size);
519
520 bool isEnabled() const override;
521 int maximumLineCount() const override;
522
523 std::unique_ptr<HistoryScroll> scroll(std::unique_ptr<HistoryScroll> &&) const override;
524
525protected:
526 unsigned int m_nbLines;
527};
528
529#endif
530
531}
532
533#endif // TEHISTORY_H
pointer data()
qsizetype size() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Jul 26 2024 11:57:30 by doxygen 1.11.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.