Euphoria
ui_text.cc
Go to the documentation of this file.
1 #include "core/ui_text.h"
2 
3 #include "log/log.h"
4 
5 #include "base/stringbuilder.h"
6 
7 
8 namespace eu::core
9 {
10  namespace textparser
11  {
12  NodeText::NodeText(const std::string& t) : text(t) {}
13 
14  void
15  NodeText::accept(Visitor* visitor) const
16  {
17  visitor->on_text(text);
18  }
19 
20  NodeImage::NodeImage(const std::string& t) : image(t) {}
21 
22  void
23  NodeImage::accept(Visitor* visitor) const
24  {
25  visitor->on_image(image);
26  }
27 
29 
30  void
32  {
33  if(begin)
34  {
35  visitor->on_begin();
36  }
37  else
38  {
39  visitor->on_end();
40  }
41  }
42  }
43 
45 
46  namespace textparser
47  {
48  void
49  VisitorDebugString::on_text(const std::string& text)
50  {
51  ss.add_string(fmt::format("{{text {}}}", text));
52  }
53 
54  void
55  VisitorDebugString::on_image(const std::string& img)
56  {
57  ss.add_string(fmt::format("{{image {}}}", img));
58  }
59 
60  void
62  {
63  ss.add_view("{begin}");
64  }
65 
66  void
68  {
69  ss.add_view("{end}");
70  }
71 
72  std::string
74  {
76  visitor->accept(&str);
77  return str.ss.to_string();
78  }
79  }
80 
82 
83  void
85  {
86  nodes.resize(0);
87  }
88 
89  void
90  UiText::add_text(const std::string& str)
91  {
92  nodes.emplace_back(std::make_shared<textparser::NodeText>(str));
93  }
94 
95  void
96  UiText::add_image(const std::string& img)
97  {
98  nodes.emplace_back(std::make_shared<textparser::NodeImage>(img));
99  }
100 
101  void
103  {
104  nodes.emplace_back(std::make_shared<textparser::NodeBeginOrEnd>(true));
105  }
106 
107  void
109  {
110  nodes.emplace_back(std::make_shared<textparser::NodeBeginOrEnd>(false));
111  }
112 
113  void
114  UiText::init_with_text(const std::string& str)
115  {
116  clear();
117  add_text(str);
118  }
119 
120  namespace
121  {
122  enum class ParserState
123  {
124  text,
125  image
126  };
127 
128 
129  // todo(Gustav): this parser looks shitty... improve?
130  struct Parser
131  {
132  UiText* nodes = nullptr;
133 
134  ParserState state = ParserState::text;
135  bool escape = false;
136  StringBuilder buff;
137  bool ok = true;
138 
139  void
140  close()
141  {
142  const std::string data = buff.to_string();
143  buff.clear();
144  switch(state)
145  {
146  case ParserState::text:
147  if(!data.empty())
148  {
149  nodes->add_text(data);
150  }
151  break;
152  case ParserState::image:
153  if(!data.empty())
154  {
155  nodes->add_image(data);
156  }
157  else
158  {
159  LOG_ERROR("Tried to create a empty @image");
160  ok = false;
161  }
162  break;
163  }
164  }
165 
166  void
167  on_char(char c)
168  {
169  switch(state)
170  {
171  case ParserState::text:
172  if(escape)
173  {
174  buff.add_char(c);
175  escape = false;
176  }
177  else
178  {
179  switch(c)
180  {
181  case '@':
182  close();
183  state = ParserState::image;
184  break;
185  case '{':
186  close();
187  nodes->add_begin();
188  break;
189  case '}':
190  close();
191  nodes->add_end();
192  break;
193  case '\\': escape = true; break;
194  default: buff.add_char(c); break;
195  }
196  }
197  break;
198  case ParserState::image:
199  if(('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')
200  || c == '-' || c == '_')
201  {
202  buff.add_char(c);
203  }
204  else
205  {
206  close();
207  state = ParserState::text;
208  if(c == ' ')
209  {
210  // nop
211  }
212  else
213  {
214  on_char(c);
215  return;
216  }
217  }
218  break;
219  }
220  }
221  };
222  }
223 
224  bool
225  UiText::init_by_parsing_source(const std::string& str)
226  {
227  nodes.resize(0);
228  Parser parser;
229  parser.nodes = this;
230 
231  for(char c: str)
232  {
233  parser.on_char(c);
234  if(!parser.ok)
235  {
236  return false;
237  }
238  }
239 
240  parser.close();
241  if(!parser.ok)
242  {
243  return false;
244  }
245  if(parser.escape)
246  {
247  LOG_ERROR("Ending with escape");
248  return false;
249  }
250  return true;
251  }
252 
253  UiText
254  UiText::create_from_text(const std::string& str)
255  {
256  UiText text;
257  text.init_with_text(str);
258  return text;
259  }
260 
261  void
263  {
264  for(auto& node: nodes)
265  {
266  node->accept(visitor);
267  }
268  }
269 
270  void
272  {
273  for(const auto& node: nodes)
274  {
275  node->accept(visitor);
276  }
277  }
278 
279 }
#define LOG_ERROR(...)
Definition: log.h:9
std::string to_string()
Complete the builder and return the resulting string.
StringBuilder & add_view(const std::string_view &str)
StringBuilder & add_string(const std::string &str)
Represents displayed text.
Definition: ui_text.h:107
bool init_by_parsing_source(const std::string &str)
Definition: ui_text.cc:225
void clear()
Definition: ui_text.cc:84
std::vector< std::shared_ptr< textparser::Node > > nodes
Definition: ui_text.h:108
static UiText create_from_text(const std::string &str)
Definition: ui_text.cc:254
void add_begin()
Definition: ui_text.cc:102
void init_with_text(const std::string &str)
Definition: ui_text.cc:114
void accept(textparser::Visitor *visitor)
Definition: ui_text.cc:262
void add_image(const std::string &img)
Definition: ui_text.cc:96
void add_end()
Definition: ui_text.cc:108
void add_text(const std::string &str)
Definition: ui_text.cc:90
void accept(Visitor *visitor) const override
Definition: ui_text.cc:31
void accept(Visitor *visitor) const override
Definition: ui_text.cc:23
NodeImage(const std::string &t)
Definition: ui_text.cc:20
NodeText(const std::string &t)
Definition: ui_text.cc:12
void accept(Visitor *visitor) const override
Definition: ui_text.cc:15
static std::string accept_all_nodes(UiText *visitor)
Definition: ui_text.cc:73
void on_image(const std::string &img) override
Definition: ui_text.cc:55
void on_text(const std::string &text) override
Definition: ui_text.cc:49
virtual void on_text(const std::string &text)=0
virtual void on_image(const std::string &image)=0
bool escape
Definition: ui_text.cc:135
bool ok
Definition: ui_text.cc:137
ParserState state
Definition: ui_text.cc:134
StringBuilder buff
Definition: ui_text.cc:136
UiText * nodes
Definition: ui_text.cc:132