summaryrefslogtreecommitdiff
path: root/src/terminal/fqterm_text_line.h
blob: 07c3d624c66ceb96d42b9cf0ec481cc2f4184cea (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// SPDX-License-Identifier: GPL-2.0-or-later

#ifndef FQTERM_TEXTLINE_H
#define FQTERM_TEXTLINE_H

#include <vector>

#include "fqwcwidth.h"
#include "fqterm.h"
class QString;

namespace FQTerm {
/*
  A text line consists of several characters in a sequence of cells. A
  character may occupy some cells, e.g. each English letter occupies
  one cell, while a CJK character needs two.

  This class is used to manipolate a text line, delete/replace
  characters in a given cell range, insert characters before a cell,
  and retrieve characters/colors/attributs of a gaven cell range.
*/
class FQTermTextLine {
 public:
  FQTermTextLine(unsigned max_cell_count);
  ~FQTermTextLine();

  enum CHARSTATE{NORMAL = 0x00, FIRSTPART = 0x01, SECONDPART = 0x02};
  // Get the number of used cells.
  unsigned getWidth() const {return cells_.size();}

  void setMaxCellCount(unsigned max_cell_count);
  unsigned getMaxCellCount() const { return max_cell_count_; }
  
  // Whether this line of text contains blink characters.
  bool hasBlink() const;

  // Set/get the dirty flag, that indicates which cells have been
  // modified.
  void setDirtyFlag(unsigned cell_begin, unsigned cell_end);
  void safelySetDirtyFlag(unsigned cell_begin, unsigned cell_end);
  bool getDirtyCells(unsigned &cell_begin, unsigned &cell_end) const;
  void clearDirtyFlag();
  void setAllDirty() {setDirtyFlag(0, max_cell_count_);}

  const unsigned char *getColors() const {
    return cells_.size() == 0 ? NULL : &cell_colors_[0];
  }

  const unsigned char *getAttributes() const {
    return cells_.size() == 0 ? NULL : &cell_attrs_[0];
  }

  // Get plain text in [cell_begin, cell_end).
  void getPlainText(unsigned cell_begin, unsigned cell_end,
                    QString &result) const;

  void getAllPlainText(QString &result) const {
    getPlainText(0, getWidth(), result);
  }
  
  // Get text in cells [cell_begin, cell_end), with color and
  // attribute in ANSI format.
  void getAnsiText(unsigned cell_begin, unsigned cell_end,
                   QString &result,
                   const char *escape = "\x1b\x1b") const;

  void getAllAnsiText(QString &result, const char* escape = "\x1b\x1b") const {
    getAnsiText(0, getWidth(), result, escape);
  }

  void appendWhiteSpace(unsigned count,
                        unsigned char color = NO_COLOR,
                        unsigned char attr = NO_ATTR,
                        UTF16 space = ' ');

  void insertWhiteSpace(unsigned count, unsigned cell_begin,
                        unsigned char color = NO_COLOR,
                        unsigned char attr = NO_ATTR,
                        UTF16 space = ' ');

  void replaceWithWhiteSpace(unsigned count,
                             unsigned cell_begin, unsigned cell_end,
                             unsigned char color = NO_COLOR,
                             unsigned char attr = NO_ATTR,
                             UTF16 space = ' ');
  
  // insert string at specified cell,
  void insertText(const UTF16 *str, unsigned count,
                  unsigned cell_begin,
                  unsigned char color, unsigned char attr, int charstate = FQTermTextLine::NORMAL);
  void replaceText(const UTF16 *str, unsigned count,
                   unsigned cell_begin, unsigned cell_end,
                   unsigned char color, unsigned char attr, int charstate = FQTermTextLine::NORMAL);
  void deleteText(unsigned cell_begin, unsigned cell_end);
  void deleteAllText();

  // If cell_begin is a beginning of a readable character, return
  // cell_begin itself, otherwise return the previous cell which starts a
  // readable character.
  unsigned getCellBegin(unsigned cell_begin) const;

  // If cell_end is a ending of a readable character, return cell_end
  // itself, otherwise return the next cell which finishes a
  // readable character.
  unsigned getCellEnd(unsigned cell_end) const;

  unsigned getCharBegin(unsigned cell_begin) const;
  unsigned getCharEnd(unsigned cell_end) const;

 private:
  unsigned max_cell_count_; // max number of cells allowed.
  
  std::vector<uint16_t> cells_;  // store the index of character in this->chars_ for each cell.
  std::vector<unsigned char> cell_colors_; // store the color for each cell.
  std::vector<unsigned char> cell_attrs_; // store the attribute for each cell.
  std::vector<UTF16> chars_;  // store all the character.

  unsigned char stored_color_;
  unsigned char stored_attr_;

  // range of changed text.
  unsigned dirty_cell_begin_, dirty_cell_end_;

  // if the given cell isn't a beginning of characters, 
  // i.e is in the middle of a wide character,
  // break the character into several unicode replacement characters (URC)
  // to make the given cell be a beginning of character.
  bool breakCell(unsigned cell_begin);

  // calculate ANSI escape sequence with given color, attribute and escape strings.
  void getAnsiCtrlSeq(unsigned char color, unsigned char attr,
                      const char *escape, QString &result) const;

  // Two functions for debugging/testing.
  void verifyTextLine() const;
  void verifyCellRange(unsigned cell_begin, unsigned cell_end) const;
};

}  // namespace FQTerm

#endif  // FQTERM_TEXTLINE_H