Fcitx
text.cpp
1 /*
2  * SPDX-FileCopyrightText: 2016-2016 CSSlayer <wengxt@gmail.com>
3  *
4  * SPDX-License-Identifier: LGPL-2.1-or-later
5  *
6  */
7 
8 #include "text.h"
9 #include <iterator>
10 #include <stdexcept>
11 #include <tuple>
12 #include <vector>
14 #include "fcitx-utils/utf8.h"
15 
16 namespace fcitx {
17 
18 class TextPrivate {
19 public:
20  TextPrivate() = default;
21  FCITX_INLINE_DEFINE_DEFAULT_DTOR_AND_COPY(TextPrivate)
22 
23  std::vector<std::tuple<std::string, TextFormatFlags>> texts_;
24  int cursor_ = -1;
25 };
26 
27 Text::Text() : d_ptr(std::make_unique<TextPrivate>()) {}
28 
29 Text::Text(std::string text, TextFormatFlags flag) : Text() {
30  append(std::move(text), flag);
31 }
32 
33 FCITX_DEFINE_DPTR_COPY_AND_DEFAULT_DTOR_AND_MOVE(Text)
34 
35 void Text::clear() {
36  FCITX_D();
37  d->texts_.clear();
38  setCursor();
39 }
40 
41 int Text::cursor() const {
42  FCITX_D();
43  return d->cursor_;
44 }
45 
46 void Text::setCursor(int pos) {
47  FCITX_D();
48  d->cursor_ = pos;
49 }
50 
51 void Text::append(std::string str, TextFormatFlags flag) {
52  FCITX_D();
53  if (!utf8::validate(str)) {
54  throw std::invalid_argument("Invalid utf8 string");
55  }
56  d->texts_.emplace_back(std::move(str), flag);
57 }
58 
59 void Text::append(Text text) {
60  FCITX_D();
61  std::copy(std::make_move_iterator(text.d_ptr->texts_.begin()),
62  std::make_move_iterator(text.d_ptr->texts_.end()),
63  std::back_inserter(d->texts_));
64 }
65 
66 const std::string &Text::stringAt(int idx) const {
67  FCITX_D();
68  return std::get<std::string>(d->texts_[idx]);
69 }
70 
71 TextFormatFlags Text::formatAt(int idx) const {
72  FCITX_D();
73  return std::get<TextFormatFlags>(d->texts_[idx]);
74 }
75 
76 size_t Text::size() const {
77  FCITX_D();
78  return d->texts_.size();
79 }
80 
81 bool Text::empty() const {
82  FCITX_D();
83  return d->texts_.empty();
84 }
85 
86 std::string Text::toString() const {
87  FCITX_D();
88  std::string result;
89  for (const auto &p : d->texts_) {
90  result += std::get<std::string>(p);
91  }
92 
93  return result;
94 }
95 
96 size_t Text::textLength() const {
97  FCITX_D();
98  size_t length = 0;
99  for (const auto &p : d->texts_) {
100  length += std::get<std::string>(p).size();
101  }
102 
103  return length;
104 }
105 
106 std::string Text::toStringForCommit() const {
107  FCITX_D();
108  std::string result;
109  for (const auto &p : d->texts_) {
110  if (!(std::get<TextFormatFlags>(p) & TextFormatFlag::DontCommit)) {
111  result += std::get<std::string>(p);
112  }
113  }
114 
115  return result;
116 }
117 
118 std::ostream &operator<<(std::ostream &os, const Text &text) {
119  os << "Text(";
120  for (size_t i = 0; i < text.size(); i++) {
121  os << "<" << text.stringAt(i) << ", flag=" << text.formatAt(i) << ">";
122  if (i + 1 != text.size()) {
123  os << ", ";
124  }
125  }
126  os << ", cursor=" << text.cursor() << ")";
127  return os;
128 }
129 
130 std::vector<Text> Text::splitByLine() const {
131  FCITX_D();
132  std::vector<Text> texts;
133  // Put first line.
134  texts.emplace_back();
135  for (const auto &p : d->texts_) {
136  if (std::get<std::string>(p).empty()) {
137  continue;
138  }
139  auto lines = stringutils::split(std::get<std::string>(p), "\n",
140  stringutils::SplitBehavior::KeepEmpty);
141  auto flag = std::get<TextFormatFlags>(p);
142  texts.back().append(lines[0], flag);
143  for (size_t i = 1; i < lines.size(); i++) {
144  texts.emplace_back();
145  texts.back().append(lines[i], flag);
146  }
147  }
148 
149  return texts;
150 }
151 
153  FCITX_D();
154 
155  Text normalized;
156  std::string curStr;
157  TextFormatFlags curFormat;
158  for (const auto &[str, format] : d->texts_) {
159  if (str.empty()) {
160  continue;
161  }
162  if (curFormat == format) {
163  curStr.append(str);
164  } else {
165  if (!curStr.empty()) {
166  normalized.append(std::move(curStr), curFormat);
167  }
168  curStr = str;
169  curFormat = format;
170  }
171  }
172  if (!curStr.empty()) {
173  normalized.append(std::move(curStr), curFormat);
174  }
175  normalized.setCursor(cursor());
176  return normalized;
177 }
178 
179 } // namespace fcitx
std::vector< Text > splitByLine() const
Split Text object into lines.
Definition: text.cpp:130
Formatted string commonly used in user interface.
size_t length(Iter start, Iter end)
Return the number UTF-8 characters in the string iterator range.
Definition: utf8.h:26
bool validate(Iter start, Iter end)
Check if the string iterator range is valid utf8 string.
Definition: utf8.h:67
Definition: action.cpp:12
C++ Utility functions for handling utf8 strings.
std::vector< std::string > split(std::string_view str, std::string_view delim, SplitBehavior behavior)
Split the string by delim.
A class represents a formatted string.
Definition: text.h:27
Text normalize() const
Remove empty string piece and merge the string with same format.
Definition: text.cpp:152
void setCursor(int pos=-1)
Set cursor by byte.
Definition: text.cpp:46
Class provides bit flag support for Enum.
Definition: flags.h:33
int cursor() const
Get cursor by byte.
Definition: text.cpp:41
String handle utilities.