Screen.cpp 46.5 KB
Newer Older
1
/*
2
3
4
5
   SPDX-FileCopyrightText: 2007-2008 Robert Knight <robert.knight@gmail.com>
   SPDX-FileCopyrightText: 1997, 1998 Lars Doelle <lars.doelle@on-line.de>

   SPDX-License-Identifier: GPL-2.0-or-later
6
   */
7

8
9
// Own
#include "Screen.h"
10

11
// Qt
12
#include <QSet>
13
#include <QTextStream>
14
#include <QDebug>
15

16
17
18
19
// Konsole decoders
#include <PlainTextDecoder.h>
#include <HTMLDecoder.h>

20
21
#include "history/HistoryType.h"
#include "history/HistoryScrollNone.h"
22
#include "characters/ExtendedCharTable.h"
23
#include "profile/Profile.h"
24
#include "EscapeSequenceUrlExtractor.h"
25

26
27
using namespace Konsole;

28
29
//Macro to convert x,y position on screen to position within an image.
//
Kurt Hindenburg's avatar
Kurt Hindenburg committed
30
//Originally the image was stored as one large contiguous block of
31
//memory, so a position within the image could be represented as an
32
//offset from the beginning of the block.  For efficiency reasons this
Kurt Hindenburg's avatar
Kurt Hindenburg committed
33
//is no longer the case.
34
//Many internal parts of this class still use this representation for parameters and so on,
35
36
//notably moveImage() and clearImage().
//This macro converts from an X,Y position into an image offset.
37
#ifndef loc
Jekyll Wu's avatar
Jekyll Wu committed
38
#define loc(X,Y) ((Y)*_columns+(X))
39
40
#endif

Jekyll Wu's avatar
Jekyll Wu committed
41
const Character Screen::DefaultChar = Character(' ',
Kurt Hindenburg's avatar
Kurt Hindenburg committed
42
43
44
45
                                      CharacterColor(COLOR_SPACE_DEFAULT, DEFAULT_FORE_COLOR),
                                      CharacterColor(COLOR_SPACE_DEFAULT, DEFAULT_BACK_COLOR),
                                      DEFAULT_RENDITION,
                                      false);
46

Jekyll Wu's avatar
Jekyll Wu committed
47
Screen::Screen(int lines, int columns):
48
    _currentTerminalDisplay(nullptr),
Jekyll Wu's avatar
Jekyll Wu committed
49
50
    _lines(lines),
    _columns(columns),
Carlos Alves's avatar
Carlos Alves committed
51
    _screenLines(_lines + 1),
52
    _screenLinesSize(_lines),
53
    _scrolledLines(0),
54
    _lastScrolledRegion(QRect()),
55
    _droppedLines(0),
56
    _lineProperties(QVarLengthArray<LineProperty, 64>()),
Jekyll Wu's avatar
Jekyll Wu committed
57
    _history(new HistoryScrollNone()),
Jekyll Wu's avatar
Jekyll Wu committed
58
59
    _cuX(0),
    _cuY(0),
60
61
    _currentForeground(CharacterColor()),
    _currentBackground(CharacterColor()),
Jekyll Wu's avatar
Jekyll Wu committed
62
63
64
    _currentRendition(DEFAULT_RENDITION),
    _topMargin(0),
    _bottomMargin(0),
65
    _tabStops(QBitArray()),
Jekyll Wu's avatar
Jekyll Wu committed
66
67
68
    _selBegin(0),
    _selTopLeft(0),
    _selBottomRight(0),
Jekyll Wu's avatar
Jekyll Wu committed
69
    _blockSelectionMode(false),
Jekyll Wu's avatar
Jekyll Wu committed
70
71
72
    _effectiveForeground(CharacterColor()),
    _effectiveBackground(CharacterColor()),
    _effectiveRendition(DEFAULT_RENDITION),
73
    _lastPos(-1),
74
75
    _lastDrawnChar(0),
    _escapeSequenceUrlExtractor(new EscapeSequenceUrlExtractor())
76
{
77
    _escapeSequenceUrlExtractor->setScreen(this);
Jekyll Wu's avatar
Jekyll Wu committed
78
    _lineProperties.resize(_lines + 1);
Kurt Hindenburg's avatar
Kurt Hindenburg committed
79
    for (int i = 0; i < _lines + 1; i++) {
Jekyll Wu's avatar
Jekyll Wu committed
80
        _lineProperties[i] = LINE_DEFAULT;
Kurt Hindenburg's avatar
Kurt Hindenburg committed
81
    }
82

83
84
85
    initTabStops();
    clearSelection();
    reset();
86
87
}

88
Screen::~Screen()
89
{
Jekyll Wu's avatar
Jekyll Wu committed
90
    delete _history;
91
    delete _escapeSequenceUrlExtractor;
92
93
}

94
void Screen::cursorUp(int n)
Kurt Hindenburg's avatar
Kurt Hindenburg committed
95
//=CUU
96
{
97
    if (n < 1) {
Kurt Hindenburg's avatar
Kurt Hindenburg committed
98
99
        n = 1; // Default
    }
Jekyll Wu's avatar
Jekyll Wu committed
100
101
    const int stop = _cuY < _topMargin ? 0 : _topMargin;
    _cuY = qMax(stop, _cuY - n);
102
103
}

104
void Screen::cursorDown(int n)
Kurt Hindenburg's avatar
Kurt Hindenburg committed
105
//=CUD
106
{
107
    if (n < 1) {
Kurt Hindenburg's avatar
Kurt Hindenburg committed
108
109
       n = 1; // Default
    }
110
111
112
    if (n > MAX_SCREEN_ARGUMENT) {
        n = MAX_SCREEN_ARGUMENT;
    }
Jekyll Wu's avatar
Jekyll Wu committed
113
114
    const int stop = _cuY > _bottomMargin ? _lines - 1 : _bottomMargin;
    _cuY = qMin(stop, _cuY + n);
115
116
}

117
void Screen::cursorLeft(int n)
Kurt Hindenburg's avatar
Kurt Hindenburg committed
118
//=CUB
119
{
120
    if (n < 1) {
Kurt Hindenburg's avatar
Kurt Hindenburg committed
121
122
        n = 1; // Default
    }
Jekyll Wu's avatar
Jekyll Wu committed
123
    _cuX = qMax(0, _cuX - n);
124
125
}

126
127
128
void Screen::cursorNextLine(int n)
//=CNL
{
129
    if (n < 1) {
130
131
        n = 1; // Default
    }
132
133
    if (n > MAX_SCREEN_ARGUMENT) {
        n = MAX_SCREEN_ARGUMENT;
134
    }
135
136
    _cuX = 0;
    _cuY = qMin(_cuY + n, _lines - 1);
137
138
139
140
141
}

void Screen::cursorPreviousLine(int n)
//=CPL
{
142
    if (n < 1) {
143
144
145
        n = 1; // Default
    }
    _cuX = 0;
146
    _cuY = qMax(0, _cuY - n);
147
148
}

149
void Screen::cursorRight(int n)
Kurt Hindenburg's avatar
Kurt Hindenburg committed
150
//=CUF
151
{
152
    if (n < 1) {
Kurt Hindenburg's avatar
Kurt Hindenburg committed
153
154
        n = 1; // Default
    }
155
156
157
    if (n > MAX_SCREEN_ARGUMENT) {
        n = MAX_SCREEN_ARGUMENT;
    }
Jekyll Wu's avatar
Jekyll Wu committed
158
    _cuX = qMin(_columns - 1, _cuX + n);
159
160
}

161
void Screen::setMargins(int top, int bot)
Kurt Hindenburg's avatar
Kurt Hindenburg committed
162
//=STBM
163
{
164
    if (top < 1) {
Kurt Hindenburg's avatar
Kurt Hindenburg committed
165
166
        top = 1;      // Default
    }
167
    if (bot < 1) {
Kurt Hindenburg's avatar
Kurt Hindenburg committed
168
169
        bot = _lines;  // Default
    }
170
171
    top = top - 1;              // Adjust to internal lineno
    bot = bot - 1;              // Adjust to internal lineno
Jekyll Wu's avatar
Jekyll Wu committed
172
    if (!(0 <= top && top < bot && bot < _lines)) {
Kurt Hindenburg's avatar
Kurt Hindenburg committed
173
        //Debug()<<" setRegion("<<top<<","<<bot<<") : bad range.";
174
175
176
177
        return;                   // Default error action: ignore
    }
    _topMargin = top;
    _bottomMargin = bot;
Jekyll Wu's avatar
Jekyll Wu committed
178
179
    _cuX = 0;
    _cuY = getMode(MODE_Origin) ? top : 0;
180
181
}

182
int Screen::topMargin() const
183
{
184
    return _topMargin;
185
}
186
int Screen::bottomMargin() const
187
{
188
    return _bottomMargin;
189
190
}

191
void Screen::index()
Kurt Hindenburg's avatar
Kurt Hindenburg committed
192
//=IND
193
{
Kurt Hindenburg's avatar
Kurt Hindenburg committed
194
    if (_cuY == _bottomMargin) {
195
        scrollUp(1);
Kurt Hindenburg's avatar
Kurt Hindenburg committed
196
    } else if (_cuY < _lines - 1) {
Jekyll Wu's avatar
Jekyll Wu committed
197
        _cuY += 1;
Kurt Hindenburg's avatar
Kurt Hindenburg committed
198
    }
199
200
}

201
void Screen::reverseIndex()
Kurt Hindenburg's avatar
Kurt Hindenburg committed
202
//=RI
203
{
Kurt Hindenburg's avatar
Kurt Hindenburg committed
204
    if (_cuY == _topMargin) {
Kurt Hindenburg's avatar
Kurt Hindenburg committed
205
        scrollDown(_topMargin, 1);
Kurt Hindenburg's avatar
Kurt Hindenburg committed
206
    } else if (_cuY > 0) {
Jekyll Wu's avatar
Jekyll Wu committed
207
        _cuY -= 1;
Kurt Hindenburg's avatar
Kurt Hindenburg committed
208
    }
209
210
}

211
void Screen::nextLine()
Kurt Hindenburg's avatar
Kurt Hindenburg committed
212
//=NEL
213
{
214
215
    toStartOfLine();
    index();
216
217
}

218
void Screen::eraseChars(int n)
219
{
220
    if (n < 1) {
Kurt Hindenburg's avatar
Kurt Hindenburg committed
221
222
        n = 1; // Default
    }
223
224
225
226
    if (n > MAX_SCREEN_ARGUMENT) {
        n = MAX_SCREEN_ARGUMENT;
    }
    const int p = qBound(0, _cuX + n - 1, _columns - 1);
Jekyll Wu's avatar
Jekyll Wu committed
227
    clearImage(loc(_cuX, _cuY), loc(p, _cuY), ' ');
228
229
}

230
void Screen::deleteChars(int n)
231
{
Kurt Hindenburg's avatar
Kurt Hindenburg committed
232
    Q_ASSERT(n >= 0);
233

234
    // always delete at least one char
235
    if (n < 1) {
Kurt Hindenburg's avatar
Kurt Hindenburg committed
236
        n = 1;
Kurt Hindenburg's avatar
Kurt Hindenburg committed
237
    }
238

239
    // if cursor is beyond the end of the line there is nothing to do
Kurt Hindenburg's avatar
Kurt Hindenburg committed
240
    if (_cuX >= _screenLines[_cuY].count()) {
241
        return;
Kurt Hindenburg's avatar
Kurt Hindenburg committed
242
    }
243

Kurt Hindenburg's avatar
Kurt Hindenburg committed
244
    if (_cuX + n > _screenLines[_cuY].count()) {
Jekyll Wu's avatar
Jekyll Wu committed
245
        n = _screenLines[_cuY].count() - _cuX;
Kurt Hindenburg's avatar
Kurt Hindenburg committed
246
    }
247

Kurt Hindenburg's avatar
Kurt Hindenburg committed
248
    Q_ASSERT(n >= 0);
Jekyll Wu's avatar
Jekyll Wu committed
249
    Q_ASSERT(_cuX + n <= _screenLines[_cuY].count());
250

Jekyll Wu's avatar
Jekyll Wu committed
251
    _screenLines[_cuY].remove(_cuX, n);
252
253
254
255
256
257

    // Append space(s) with current attributes
    Character spaceWithCurrentAttrs(' ', _effectiveForeground,
                                    _effectiveBackground,
                                    _effectiveRendition, false);

Kurt Hindenburg's avatar
Kurt Hindenburg committed
258
    for (int i = 0; i < n; i++) {
259
        _screenLines[_cuY].append(spaceWithCurrentAttrs);
Kurt Hindenburg's avatar
Kurt Hindenburg committed
260
    }
261
262
}

263
void Screen::insertChars(int n)
264
{
265
    if (n < 1) {
Kurt Hindenburg's avatar
Kurt Hindenburg committed
266
267
        n = 1; // Default
    }
268

Kurt Hindenburg's avatar
Kurt Hindenburg committed
269
    if (_screenLines[_cuY].size() < _cuX) {
Jekyll Wu's avatar
Jekyll Wu committed
270
        _screenLines[_cuY].resize(_cuX);
Kurt Hindenburg's avatar
Kurt Hindenburg committed
271
    }
272

Jekyll Wu's avatar
Jekyll Wu committed
273
    _screenLines[_cuY].insert(_cuX, n, Character(' '));
274

Kurt Hindenburg's avatar
Kurt Hindenburg committed
275
    if (_screenLines[_cuY].count() > _columns) {
Jekyll Wu's avatar
Jekyll Wu committed
276
        _screenLines[_cuY].resize(_columns);
Kurt Hindenburg's avatar
Kurt Hindenburg committed
277
    }
278
279
}

280
281
void Screen::repeatChars(int n)
{
282
    if (n < 1) {
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
        n = 1; // Default
    }

    // From ECMA-48 version 5, section 8.3.103:
    // "If the character preceding REP is a control function or part of a
    // control function, the effect of REP is not defined by this Standard."
    //
    // So, a "normal" program should always use REP immediately after a visible
    // character (those other than escape sequences). So, _lastDrawnChar can be
    // safely used.
    for (int i = 0; i < n; i++) {
        displayCharacter(_lastDrawnChar);
    }
}

298
void Screen::deleteLines(int n)
299
{
300
    if (n < 1) {
Kurt Hindenburg's avatar
Kurt Hindenburg committed
301
302
        n = 1; // Default
    }
Jekyll Wu's avatar
Jekyll Wu committed
303
    scrollUp(_cuY, n);
304
305
}

306
void Screen::insertLines(int n)
307
{
308
    if (n < 1) {
Kurt Hindenburg's avatar
Kurt Hindenburg committed
309
310
        n = 1; // Default
    }
Jekyll Wu's avatar
Jekyll Wu committed
311
    scrollDown(_cuY, n);
312
313
}

314
void Screen::setMode(int m)
315
{
316
    _currentModes[m] = 1;
Kurt Hindenburg's avatar
Kurt Hindenburg committed
317
    switch (m) {
Kurt Hindenburg's avatar
Kurt Hindenburg committed
318
319
320
321
    case MODE_Origin :
        _cuX = 0;
        _cuY = _topMargin;
        break; //FIXME: home
322
    }
323
324
}

325
void Screen::resetMode(int m)
326
{
327
    _currentModes[m] = 0;
Kurt Hindenburg's avatar
Kurt Hindenburg committed
328
    switch (m) {
Kurt Hindenburg's avatar
Kurt Hindenburg committed
329
330
331
332
    case MODE_Origin :
        _cuX = 0;
        _cuY = 0;
        break; //FIXME: home
333
    }
334
335
}

336
void Screen::saveMode(int m)
337
{
Jekyll Wu's avatar
Jekyll Wu committed
338
    _savedModes[m] = _currentModes[m];
339
340
}

341
void Screen::restoreMode(int m)
342
{
Jekyll Wu's avatar
Jekyll Wu committed
343
    _currentModes[m] = _savedModes[m];
344
345
}

Robert Knight's avatar
   
Robert Knight committed
346
bool Screen::getMode(int m) const
347
{
348
    return _currentModes[m] != 0;
349
350
}

351
void Screen::saveCursor()
352
{
Jekyll Wu's avatar
Jekyll Wu committed
353
354
355
356
357
    _savedState.cursorColumn = _cuX;
    _savedState.cursorLine  = _cuY;
    _savedState.rendition = _currentRendition;
    _savedState.foreground = _currentForeground;
    _savedState.background = _currentBackground;
358
359
}

360
void Screen::restoreCursor()
361
{
Jekyll Wu's avatar
Jekyll Wu committed
362
363
364
365
366
    _cuX     = qMin(_savedState.cursorColumn, _columns - 1);
    _cuY     = qMin(_savedState.cursorLine, _lines - 1);
    _currentRendition   = _savedState.rendition;
    _currentForeground   = _savedState.foreground;
    _currentBackground   = _savedState.background;
367
    updateEffectiveRendition();
368
369
}

370
void Screen::resizeImage(int new_lines, int new_columns)
371
{
Kurt Hindenburg's avatar
Kurt Hindenburg committed
372
373
374
    if ((new_lines == _lines) && (new_columns == _columns)) {
        return;
    }
375

376
377
378
    // First join everything.
    int currentPos = 0;
    int count_needed_lines = 0;
Carlos Alves's avatar
Carlos Alves committed
379
    while (currentPos < _screenLines.count() - 1) {
Carlos Alves's avatar
Carlos Alves committed
380
        // if the line have the 'LINE_WRAPPED' property, concat with the next line and remove it.
381
382
383
384
385
386
        if ((_lineProperties[currentPos] & LINE_WRAPPED) != 0) {
            _screenLines[currentPos].append(_screenLines[currentPos + 1]);
            _screenLines.remove(currentPos + 1);
            _lineProperties.remove(currentPos);
            _cuY--;
            continue;
387
        }
388
389
390
        count_needed_lines += _screenLines[currentPos].count() / (new_columns + 1);
        currentPos++;
    }
391

392
393
394
395
396
397
    // If it will need more lines than new_lines have, send lines to _history
    count_needed_lines += _cuY;
    if (count_needed_lines > new_lines - 1) {
        _lineProperties.resize(_lines + 1);
        for (int i = _screenLines.count(); (i > 0) && (i < new_lines + 1); i++) {
            _lineProperties[i] = LINE_DEFAULT;
398
        }
399
400
401
402
403
404
405
        _screenLines.resize(_lines + 1);
        // attempt to preserve focus and _lines
        _bottomMargin = _lines - 1; //FIXME: margin lost
        for (int i = 0; i < count_needed_lines - (new_lines - 1); i++) {
            addHistLine();
            scrollUp(0, 1);
            _cuY--;
406
        }
Kurt Hindenburg's avatar
Kurt Hindenburg committed
407
    }
408

409
410
    // Then move the data to lines below.
    currentPos = 0;
Carlos Alves's avatar
Carlos Alves committed
411
    while (currentPos != _screenLines.count() && currentPos != _cuY) {
412
413
414
415
416
        const bool shouldCopy = _screenLines[currentPos].size() > new_columns;

        // Copy from the current line, to the next one.
        if (shouldCopy) {
            _cuY++;
417

418
419
            auto values = _screenLines[currentPos].mid(new_columns);
            _screenLines[currentPos].remove(new_columns, values.size());
Carlos Alves's avatar
Carlos Alves committed
420
            _lineProperties.insert(currentPos + 1, _lineProperties[currentPos]);
421
            _screenLines.insert(currentPos + 1, values);
Carlos Alves's avatar
Carlos Alves committed
422
            _lineProperties[currentPos] |= LINE_WRAPPED;
423
424
425
        }
        currentPos += 1;
    }
Jekyll Wu's avatar
Jekyll Wu committed
426
    _lineProperties.resize(new_lines + 1);
427
    for (int i = _screenLines.count(); (i > 0) && (i < new_lines + 1); i++) {
Jekyll Wu's avatar
Jekyll Wu committed
428
        _lineProperties[i] = LINE_DEFAULT;
Kurt Hindenburg's avatar
Kurt Hindenburg committed
429
    }
430
    _screenLines.resize(new_lines + 1);
431

Carlos Alves's avatar
Carlos Alves committed
432
433
434
435
436
437
438
439
440
441
    // Check if _history need to change
    if (new_columns != _columns && _history->getLines()) {
        // Join next line history
        currentPos = 0;
        while (currentPos < _history->getLines() - 1) {
            // if it's true, join the line with next line
            if (_history->isWrappedLine(currentPos)) {
                int curr_linelen = _history->getLineLen(currentPos);
                int next_linelen = _history->getLineLen(currentPos + 1);
                auto *new_line = getCharacterBuffer(curr_linelen + next_linelen);
Carlos Alves's avatar
Carlos Alves committed
442
                bool new_line_property = _history->isWrappedLine(currentPos + 1);
Carlos Alves's avatar
Carlos Alves committed
443
444
445
446
447
448
449

                // Join the lines
                _history->getCells(currentPos, 0, curr_linelen, new_line);
                _history->getCells(currentPos + 1, 0, next_linelen, new_line + curr_linelen);

                // save the new_line in history and remove the next line
                _history->setCellsAt(currentPos, new_line, curr_linelen + next_linelen);
Carlos Alves's avatar
Carlos Alves committed
450
                _history->setLineAt(currentPos, new_line_property);
Carlos Alves's avatar
Carlos Alves committed
451
452
453
454
455
456
                _history->removeCells(currentPos + 1);
            }
            currentPos++;
        }
        // Move data to next line if needed
        currentPos = 0;
Carlos Alves's avatar
Carlos Alves committed
457
        while (currentPos < _history->getLines()) {
Carlos Alves's avatar
Carlos Alves committed
458
459
460
461
462
            int curr_linelen = _history->getLineLen(currentPos);

            // if the current line > new_columns it will need a new line
            if (curr_linelen > new_columns) {
                auto *curr_line = getCharacterBuffer(curr_linelen);
Carlos Alves's avatar
Carlos Alves committed
463
                bool curr_line_property = _history->isWrappedLine(currentPos);
Carlos Alves's avatar
Carlos Alves committed
464
465
466
467
468
                _history->getCells(currentPos, 0, curr_linelen, curr_line);
                
                _history->setCellsAt(currentPos, curr_line, new_columns);
                _history->setLineAt(currentPos, true);
                _history->insertCells(currentPos + 1, curr_line + new_columns, curr_linelen - new_columns);
Carlos Alves's avatar
Carlos Alves committed
469
                _history->setLineAt(currentPos + 1, curr_line_property);
Carlos Alves's avatar
Carlos Alves committed
470
471
472
473
            }
            currentPos++;
        }
    }
474
475
    clearSelection();
    _screenLinesSize = new_lines;
476

Jekyll Wu's avatar
Jekyll Wu committed
477
478
479
480
    _lines = new_lines;
    _columns = new_columns;
    _cuX = qMin(_cuX, _columns - 1);
    _cuY = qMin(_cuY, _lines - 1);
481
482

    // FIXME: try to keep values, evtl.
Kurt Hindenburg's avatar
Kurt Hindenburg committed
483
    _topMargin = 0;
Jekyll Wu's avatar
Jekyll Wu committed
484
    _bottomMargin = _lines - 1;
485
486
    initTabStops();
    clearSelection();
487
488
}

489
void Screen::setDefaultMargins()
490
{
491
    _topMargin = 0;
Jekyll Wu's avatar
Jekyll Wu committed
492
    _bottomMargin = _lines - 1;
493
494
}

495
/*
Robert Knight's avatar
   
Robert Knight committed
496
   Clarifying rendition here and in the display.
497

498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
   The rendition attributes are

   attribute
   --------------
   RE_UNDERLINE
   RE_BLINK
   RE_BOLD
   RE_REVERSE
   RE_TRANSPARENT
   RE_FAINT
   RE_STRIKEOUT
   RE_CONCEAL
   RE_OVERLINE

   Depending on settings, bold may be rendered as a heavier font
   in addition to a different color.
514
   */
515

Robert Knight's avatar
   
Robert Knight committed
516
void Screen::reverseRendition(Character& p) const
Kurt Hindenburg's avatar
Kurt Hindenburg committed
517
518
{
    CharacterColor f = p.foregroundColor;
519
    CharacterColor b = p.backgroundColor;
520

Kurt Hindenburg's avatar
Kurt Hindenburg committed
521
    p.foregroundColor = b;
522
    p.backgroundColor = f; //p->r &= ~RE_TRANSPARENT;
523
524
}

525
void Screen::updateEffectiveRendition()
526
{
Jekyll Wu's avatar
Jekyll Wu committed
527
    _effectiveRendition = _currentRendition;
528
    if ((_currentRendition & RE_REVERSE) != 0) {
Jekyll Wu's avatar
Jekyll Wu committed
529
530
        _effectiveForeground = _currentBackground;
        _effectiveBackground = _currentForeground;
Kurt Hindenburg's avatar
Kurt Hindenburg committed
531
    } else {
Jekyll Wu's avatar
Jekyll Wu committed
532
533
        _effectiveForeground = _currentForeground;
        _effectiveBackground = _currentBackground;
534
535
    }

536
537
538
539
540
541
    if ((_currentRendition & RE_BOLD) != 0) {
        if ((_currentRendition & RE_FAINT) == 0) {
            _effectiveForeground.setIntensive();
        }
    } else {
        if ((_currentRendition & RE_FAINT) != 0) {
542
            _effectiveForeground.setFaint();
543
        }
544
    }
545
546
}

Robert Knight's avatar
   
Robert Knight committed
547
void Screen::copyFromHistory(Character* dest, int startLine, int count) const
548
{
Jekyll Wu's avatar
Jekyll Wu committed
549
    Q_ASSERT(startLine >= 0 && count > 0 && startLine + count <= _history->getLines());
550

Kurt Hindenburg's avatar
Kurt Hindenburg committed
551
    for (int line = startLine; line < startLine + count; line++) {
Jekyll Wu's avatar
Jekyll Wu committed
552
553
        const int length = qMin(_columns, _history->getLineLen(line));
        const int destLineOffset  = (line - startLine) * _columns;
Robert Knight's avatar
   
Robert Knight committed
554

Jekyll Wu's avatar
Jekyll Wu committed
555
        _history->getCells(line, 0, length, dest + destLineOffset);
Robert Knight's avatar
   
Robert Knight committed
556

Kurt Hindenburg's avatar
Kurt Hindenburg committed
557
        for (int column = length; column < _columns; column++) {
Jekyll Wu's avatar
Jekyll Wu committed
558
            dest[destLineOffset + column] = Screen::DefaultChar;
Kurt Hindenburg's avatar
Kurt Hindenburg committed
559
        }
560
561

        // invert selected text
Jekyll Wu's avatar
Jekyll Wu committed
562
563
        if (_selBegin != -1) {
            for (int column = 0; column < _columns; column++) {
Kurt Hindenburg's avatar
Kurt Hindenburg committed
564
565
                if (isSelected(column, line)) {
                    reverseRendition(dest[destLineOffset + column]);
566
                }
567
            }
568
        }
569
    }
Robert Knight's avatar
   
Robert Knight committed
570
571
572
573
}

void Screen::copyFromScreen(Character* dest , int startLine , int count) const
{
Jekyll Wu's avatar
Jekyll Wu committed
574
    Q_ASSERT(startLine >= 0 && count > 0 && startLine + count <= _lines);
Robert Knight's avatar
   
Robert Knight committed
575

Kurt Hindenburg's avatar
Kurt Hindenburg committed
576
    for (int line = startLine; line < (startLine + count) ; line++) {
Jekyll Wu's avatar
Jekyll Wu committed
577
578
        int srcLineStartIndex  = line * _columns;
        int destLineStartIndex = (line - startLine) * _columns;
579

Jekyll Wu's avatar
Jekyll Wu committed
580
        for (int column = 0; column < _columns; column++) {
Kurt Hindenburg's avatar
Kurt Hindenburg committed
581
            int srcIndex = srcLineStartIndex + column;
582
            int destIndex = destLineStartIndex + column;
583

Jekyll Wu's avatar
Jekyll Wu committed
584
            dest[destIndex] = _screenLines[srcIndex / _columns].value(srcIndex % _columns, Screen::DefaultChar);
585

586
            // invert selected text
Kurt Hindenburg's avatar
Kurt Hindenburg committed
587
            if (_selBegin != -1 && isSelected(column, line + _history->getLines())) {
Kurt Hindenburg's avatar
Kurt Hindenburg committed
588
                reverseRendition(dest[destIndex]);
Kurt Hindenburg's avatar
Kurt Hindenburg committed
589
            }
590
        }
591
    }
Robert Knight's avatar
   
Robert Knight committed
592
593
}

Kurt Hindenburg's avatar
Kurt Hindenburg committed
594
void Screen::getImage(Character* dest, int size, int startLine, int endLine) const
Robert Knight's avatar
   
Robert Knight committed
595
{
Kurt Hindenburg's avatar
Kurt Hindenburg committed
596
    Q_ASSERT(startLine >= 0);
Jekyll Wu's avatar
Jekyll Wu committed
597
    Q_ASSERT(endLine >= startLine && endLine < _history->getLines() + _lines);
598
599

    const int mergedLines = endLine - startLine + 1;
Robert Knight's avatar
   
Robert Knight committed
600

Jekyll Wu's avatar
Jekyll Wu committed
601
    Q_ASSERT(size >= mergedLines * _columns);
602
    Q_UNUSED(size)
Robert Knight's avatar
   
Robert Knight committed
603

Jekyll Wu's avatar
Jekyll Wu committed
604
    const int linesInHistoryBuffer = qBound(0, _history->getLines() - startLine, mergedLines);
605
    const int linesInScreenBuffer = mergedLines - linesInHistoryBuffer;
Robert Knight's avatar
   
Robert Knight committed
606

Jekyll Wu's avatar
Jekyll Wu committed
607
    // copy _lines from history buffer
Kurt Hindenburg's avatar
Kurt Hindenburg committed
608
    if (linesInHistoryBuffer > 0) {
Kurt Hindenburg's avatar
Kurt Hindenburg committed
609
        copyFromHistory(dest, startLine, linesInHistoryBuffer);
Kurt Hindenburg's avatar
Kurt Hindenburg committed
610
    }
Robert Knight's avatar
   
Robert Knight committed
611

Jekyll Wu's avatar
Jekyll Wu committed
612
    // copy _lines from screen buffer
Kurt Hindenburg's avatar
Kurt Hindenburg committed
613
    if (linesInScreenBuffer > 0) {
Jekyll Wu's avatar
Jekyll Wu committed
614
615
        copyFromScreen(dest + linesInHistoryBuffer * _columns,
                       startLine + linesInHistoryBuffer - _history->getLines(),
Kurt Hindenburg's avatar
Kurt Hindenburg committed
616
                       linesInScreenBuffer);
Kurt Hindenburg's avatar
Kurt Hindenburg committed
617
    }
Robert Knight's avatar
   
Robert Knight committed
618

619
    // invert display when in screen mode
Kurt Hindenburg's avatar
Kurt Hindenburg committed
620
    if (getMode(MODE_Screen)) {
Kurt Hindenburg's avatar
Kurt Hindenburg committed
621
        for (int i = 0; i < mergedLines * _columns; i++) {
622
            reverseRendition(dest[i]); // for reverse display
Kurt Hindenburg's avatar
Kurt Hindenburg committed
623
        }
624
    }
625

626
    int visX = qMin(_cuX, _columns - 1);
627
    // mark the character at the current cursor position
628
    int cursorIndex = loc(visX, _cuY + linesInHistoryBuffer);
Kurt Hindenburg's avatar
Kurt Hindenburg committed
629
    if (getMode(MODE_Cursor) && cursorIndex < _columns * mergedLines) {
630
        dest[cursorIndex].rendition |= RE_CURSOR;
Kurt Hindenburg's avatar
Kurt Hindenburg committed
631
    }
632
633
}

Kurt Hindenburg's avatar
Kurt Hindenburg committed
634
QVector<LineProperty> Screen::getLineProperties(int startLine , int endLine) const
635
{
Kurt Hindenburg's avatar
Kurt Hindenburg committed
636
    Q_ASSERT(startLine >= 0);
Jekyll Wu's avatar
Jekyll Wu committed
637
    Q_ASSERT(endLine >= startLine && endLine < _history->getLines() + _lines);
638

Kurt Hindenburg's avatar
Kurt Hindenburg committed
639
    const int mergedLines = endLine - startLine + 1;
Jekyll Wu's avatar
Jekyll Wu committed
640
    const int linesInHistory = qBound(0, _history->getLines() - startLine, mergedLines);
641
    const int linesInScreen = mergedLines - linesInHistory;
642

643
644
    QVector<LineProperty> result(mergedLines);
    int index = 0;
645

Jekyll Wu's avatar
Jekyll Wu committed
646
    // copy properties for _lines in history
Kurt Hindenburg's avatar
Kurt Hindenburg committed
647
    for (int line = startLine; line < startLine + linesInHistory; line++) {
Jekyll Wu's avatar
Jekyll Wu committed
648
649
        //TODO Support for line properties other than wrapped _lines
        if (_history->isWrappedLine(line)) {
650
            result[index] = static_cast<LineProperty>(result[index] | LINE_WRAPPED);
651
652
653
654
        }
        index++;
    }

Jekyll Wu's avatar
Jekyll Wu committed
655
656
    // copy properties for _lines in screen buffer
    const int firstScreenLine = startLine + linesInHistory - _history->getLines();
Kurt Hindenburg's avatar
Kurt Hindenburg committed
657
    for (int line = firstScreenLine; line < firstScreenLine + linesInScreen; line++) {
Jekyll Wu's avatar
Jekyll Wu committed
658
        result[index] = _lineProperties[line];
659
        index++;
660
    }
661

662
    return result;
663
}
664

665
void Screen::reset()
666
{
667
668
669
670
    // Clear screen, but preserve the current line
    scrollUp(0, _cuY);
    _cuY = 0;

671
672
    _currentModes[MODE_Origin] = 0;
    _savedModes[MODE_Origin] = 0;
673

674
675
676
677
678
679
    setMode(MODE_Wrap);
    saveMode(MODE_Wrap);      // wrap at end of margin

    resetMode(MODE_Insert);
    saveMode(MODE_Insert);  // overstroke

680
    setMode(MODE_Cursor);                         // cursor visible
681
682
    resetMode(MODE_Screen);                         // screen not inverse
    resetMode(MODE_NewLine);
683

Kurt Hindenburg's avatar
Kurt Hindenburg committed
684
    _topMargin = 0;
Jekyll Wu's avatar
Jekyll Wu committed
685
    _bottomMargin = _lines - 1;
686

687
688
689
    // Other terminal emulators reset the entire scroll history during a reset
//    setScroll(getScroll(), false);

690
691
    setDefaultRendition();
    saveCursor();
692
693
}

694
void Screen::backspace()
695
{
Jekyll Wu's avatar
Jekyll Wu committed
696
    _cuX = qMax(0, _cuX - 1);
697

Kurt Hindenburg's avatar
Kurt Hindenburg committed
698
    if (_screenLines[_cuY].size() < _cuX + 1) {
Jekyll Wu's avatar
Jekyll Wu committed
699
        _screenLines[_cuY].resize(_cuX + 1);
Kurt Hindenburg's avatar
Kurt Hindenburg committed
700
    }
701
702
}

703
void Screen::tab(int n)
704
{
705
    // note that TAB is a format effector (does not write ' ');
706
    if (n < 1) {
Kurt Hindenburg's avatar
Kurt Hindenburg committed
707
708
        n = 1;
    }
Jekyll Wu's avatar
Jekyll Wu committed
709
    while ((n > 0) && (_cuX < _columns - 1)) {
Kurt Hindenburg's avatar
Kurt Hindenburg committed
710
        cursorRight(1);
Kurt Hindenburg's avatar
Kurt Hindenburg committed
711
        while ((_cuX < _columns - 1) && !_tabStops[_cuX]) {
712
            cursorRight(1);
Kurt Hindenburg's avatar
Kurt Hindenburg committed
713
        }
714
715
        n--;
    }
716
717
}

718
void Screen::backtab(int n)
719
{
720
    // note that TAB is a format effector (does not write ' ');
721
    if (n < 1) {
Kurt Hindenburg's avatar
Kurt Hindenburg committed
722
723
        n = 1;
    }
Jekyll Wu's avatar
Jekyll Wu committed
724
    while ((n > 0) && (_cuX > 0)) {
725
726
727
728
        cursorLeft(1);
        while ((_cuX > 0) && !_tabStops[_cuX]) {
            cursorLeft(1);
        }
729
730
        n--;
    }
731
732
}

733
void Screen::clearTabStops()
734
{
Kurt Hindenburg's avatar
Kurt Hindenburg committed
735
    for (int i = 0; i < _columns; i++) {
Jekyll Wu's avatar
Jekyll Wu committed
736
        _tabStops[i] = false;
Kurt Hindenburg's avatar
Kurt Hindenburg committed
737
    }
738
739
}

740
void Screen::changeTabStop(bool set)
741
{
Kurt Hindenburg's avatar
Kurt Hindenburg committed
742
    if (_cuX >= _columns) {
743
        return;
Kurt Hindenburg's avatar
Kurt Hindenburg committed
744
    }
745

Jekyll Wu's avatar
Jekyll Wu committed
746
    _tabStops[_cuX] = set;
747
748
}

749
void Screen::initTabStops()
750
{
Jekyll Wu's avatar
Jekyll Wu committed
751
    _tabStops.resize(_columns);
752

753
    // The 1st tabstop has to be one longer than the other.
754
755
    // i.e. the kids start counting from 0 instead of 1.
    // Other programs might behave correctly. Be aware.
Kurt Hindenburg's avatar
Kurt Hindenburg committed
756
    for (int i = 0; i < _columns; i++) {
Jekyll Wu's avatar
Jekyll Wu committed
757
        _tabStops[i] = (i % 8 == 0 && i != 0);
Kurt Hindenburg's avatar
Kurt Hindenburg committed
758
    }
759
760
}

761
void Screen::newLine()
762
{
Kurt Hindenburg's avatar
Kurt Hindenburg committed
763
    if (getMode(MODE_NewLine)) {
764
        toStartOfLine();
Kurt Hindenburg's avatar
Kurt Hindenburg committed
765
    }
766

767
    index();
768
769
}

770
void Screen::checkSelection(int from, int to)
771
{
Kurt Hindenburg's avatar
Kurt Hindenburg committed
772
    if (_selBegin == -1) {
773
        return;
Kurt Hindenburg's avatar
Kurt Hindenburg committed
774
    }