]> git.lyx.org Git - lyx.git/blob - src/texstream.cpp
Avoid full metrics computation with Update:FitCursor
[lyx.git] / src / texstream.cpp
1 /**
2  * \file texstream.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Enrico Forestieri
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12
13 #include "texstream.h"
14
15 #include "TexRow.h"
16
17 #include "support/lstrings.h"
18 #include "support/unicode.h"
19
20 #include <algorithm>
21 #include <cerrno>
22 #include <cstdio>
23 #include <cstring>
24 #include <iconv.h>
25 #include <locale>
26
27 using namespace std;
28
29 using lyx::support::contains;
30 using lyx::support::split;
31
32
33 namespace lyx {
34
35
36 otexrowstream::otexrowstream(odocstream & os)
37         : os_(os), texrow_(make_unique<TexRow>())
38 {}
39
40
41 otexrowstream::~otexrowstream() = default;
42
43
44 unique_ptr<TexRow> otexrowstream::releaseTexRow()
45 {
46         auto p = make_unique<TexRow>();
47         swap(texrow_, p);
48         return p;
49 }
50
51
52 void otexrowstream::put(char_type const & c)
53 {
54         os_.put(c);
55         if (c == '\n')
56                 texrow_->newline();
57 }
58
59
60 void otexstream::put(char_type const & c)
61 {
62         bool isprotected = false;
63         if (protectspace_) {
64                 if (!canbreakline_ && c == ' ') {
65                         os() << "{}";
66                         isprotected = true;
67                 }
68                 protectspace_ = false;
69         }
70         if (terminate_command_) {
71                 if ((c == ' ' || c == '\0' || c == '\n') && !isprotected)
72                         // A space or line break follows. Terminate with brackets.
73                         os() << "{}";
74                 else if (c != '\\' && c != '{' && c != '}')
75                         // Non-terminating character follows. Terminate with space.
76                         os() << " ";
77                 terminate_command_ = false;
78         }
79         otexrowstream::put(c);
80         lastChar(c);
81 }
82
83
84 size_t otexstringstream::length()
85 {
86         auto pos = ods_.tellp();
87         return (pos >= 0) ? size_t(pos) : 0;
88 }
89
90
91 TexString otexstringstream::release()
92 {
93         TexString ts(ods_.str(), std::move(texrow()));
94         // reset this
95         texrow() = TexRow();
96         ods_.clear();
97         ods_.str(docstring());
98         return ts;
99 }
100
101
102 BreakLine breakln;
103 SafeBreakLine safebreakln;
104 TerminateCommand termcmd;
105
106
107 otexstream & operator<<(otexstream & ots, BreakLine)
108 {
109         if (ots.canBreakLine()) {
110                 if (ots.terminateCommand())
111                         ots << "{}";
112                 ots.otexrowstream::put('\n');
113                 ots.lastChar('\n');
114         }
115         ots.protectSpace(false);
116         ots.terminateCommand(false);
117         return ots;
118 }
119
120
121 otexstream & operator<<(otexstream & ots, SafeBreakLine)
122 {
123         otexrowstream & otrs = ots;
124         if (ots.canBreakLine()) {
125             if (ots.terminateCommand())
126                         otrs << "{}";
127                 otrs << "%\n";
128                 ots.lastChar('\n');
129         }
130         ots.protectSpace(false);
131         ots.terminateCommand(false);
132         return ots;
133 }
134
135
136 otexstream & operator<<(otexstream & ots, TerminateCommand)
137 {
138         ots.terminateCommand(true);
139         return ots;
140 }
141
142
143 otexrowstream & operator<<(otexrowstream & ots, odocstream_manip pf)
144 {
145         ots.os() << pf;
146         if (pf == static_cast<odocstream_manip>(endl)) {
147                 ots.texrow().newline();
148         }
149         return ots;
150 }
151
152
153 otexstream & operator<<(otexstream & ots, odocstream_manip pf)
154 {
155         otexrowstream & otrs = ots;
156         otrs << pf;
157         if (pf == static_cast<odocstream_manip>(endl)) {
158                 ots.lastChar('\n');
159         }
160         return ots;
161 }
162
163
164 otexrowstream & operator<<(otexrowstream & ots, TexString ts)
165 {
166         ts.validate();
167         ots.os() << std::move(ts.str);
168         ots.texrow().append(std::move(ts.texrow));
169         return ots;
170 }
171
172
173 otexstream & operator<<(otexstream & ots, TexString ts)
174 {
175         size_t const len = ts.str.length();
176         // Check whether there is something to output
177         if (len == 0)
178                 return ots;
179
180         otexrowstream & otrs = ots;
181         bool isprotected = false;
182         char_type const c = ts.str[0];
183         if (ots.protectSpace()) {
184                 if (!ots.canBreakLine() && c == ' ') {
185                         otrs << "{}";
186                         isprotected = true;
187                 }
188                 ots.protectSpace(false);
189         }
190         if (ots.terminateCommand()) {
191                 if ((c == ' ' || c == '\0' || c == '\n') && !isprotected)
192                         // A space or line break follows. Terminate with brackets.
193                         otrs << "{}";
194                 else if (c != '\\' && c != '{' && c != '}')
195                         // Non-terminating character follows. Terminate with space.
196                         otrs << " ";
197                 ots.terminateCommand(false);
198         }
199
200         if (len > 1)
201                 ots.canBreakLine(ts.str[len - 2] != '\n');
202         ots.lastChar(ts.str[len - 1]);
203
204         otrs << std::move(ts);
205         return ots;
206 }
207
208
209 otexrowstream & operator<<(otexrowstream & ots, docstring const & s)
210 {
211         ots.os() << s;
212         ots.texrow().newlines(count(s.begin(), s.end(), '\n'));
213         return ots;
214 }
215
216
217 otexstream & operator<<(otexstream & ots, docstring const & s)
218 {
219         size_t const len = s.length();
220
221         // Check whether there's something to output
222         if (len == 0)
223                 return ots;
224         otexrowstream & otrs = ots;
225         bool isprotected = false;
226         char_type const c = s[0];
227         if (ots.protectSpace()) {
228                 if (!ots.canBreakLine() && c == ' ') {
229                         otrs << "{}";
230                         isprotected = true;
231                 }
232                 ots.protectSpace(false);
233         }
234         if (ots.terminateCommand()) {
235                 if ((c == ' ' || c == '\0' || c == '\n') && !isprotected)
236                         // A space or line break follows. Terminate with brackets.
237                         otrs << "{}";
238                 else if (c != '\\' && c != '{' && c != '}')
239                         // Non-terminating character follows. Terminate with space.
240                         otrs << " ";
241                 ots.terminateCommand(false);
242         }
243
244         if (contains(s, 0xF0000)) {
245                 // Some encoding changes for the underlying stream are embedded
246                 // in the docstring. The encoding names to be used are enclosed
247                 // between the code points 0xF0000 and 0xF0001, the first two
248                 // characters of plane 15, which is a Private Use Area whose
249                 // codepoints don't have any associated glyph.
250                 docstring s1;
251                 docstring s2 = split(s, s1, 0xF0000);
252                 while (true) {
253                         if (!s1.empty())
254                                 otrs << s1;
255                         if (s2.empty())
256                                 break;
257                         docstring enc;
258                         docstring const s3 = split(s2, enc, 0xF0001);
259                         if (!contains(s2, 0xF0001))
260                                 s2 = split(enc, s1, 0xF0000);
261                         else {
262                                 otrs << setEncoding(to_ascii(enc));
263                                 s2 = split(s3, s1, 0xF0000);
264                         }
265                 }
266         } else
267                 otrs << s;
268
269         if (len > 1)
270                 ots.canBreakLine(s[len - 2] != '\n');
271         ots.lastChar(s[len - 1]);
272         return ots;
273 }
274
275
276 otexrowstream & operator<<(otexrowstream & ots, string const & s)
277 {
278         ots << from_utf8(s);
279         return ots;
280 }
281
282
283 otexstream & operator<<(otexstream & ots, string const & s)
284 {
285         ots << from_utf8(s);
286         return ots;
287 }
288
289
290 otexrowstream & operator<<(otexrowstream & ots, char const * s)
291 {
292         ots << from_utf8(s);
293         return ots;
294 }
295
296
297 otexstream & operator<<(otexstream & ots, char const * s)
298 {
299         ots << from_utf8(s);
300         return ots;
301 }
302
303
304 otexrowstream & operator<<(otexrowstream & ots, char c)
305 {
306         ots.put(c);
307         return ots;
308 }
309
310
311 otexstream & operator<<(otexstream & ots, char c)
312 {
313         ots.put(c);
314         return ots;
315 }
316
317
318 template <typename Type>
319 otexrowstream & operator<<(otexrowstream & ots, Type value)
320 {
321         ots.os() << value;
322         return ots;
323 }
324
325 template otexrowstream & operator<< <SetEnc>(otexrowstream & os, SetEnc);
326 template otexrowstream & operator<< <double>(otexrowstream &, double);
327 template otexrowstream & operator<< <int>(otexrowstream &, int);
328 template otexrowstream & operator<< <unsigned int>(otexrowstream &,
329                                                                                                    unsigned int);
330 template otexrowstream & operator<< <unsigned long>(otexrowstream &,
331                                                                                                         unsigned long);
332
333 #ifdef HAVE_LONG_LONG_INT
334 template otexrowstream & operator<< <unsigned long long>(otexrowstream &,
335                                                          unsigned long long);
336 #endif
337
338
339 template <typename Type>
340 otexstream & operator<<(otexstream & ots, Type value)
341 {
342         ots.os() << value;
343         ots.lastChar(0);
344         ots.protectSpace(false);
345         ots.terminateCommand(false);
346         return ots;
347 }
348
349 template otexstream & operator<< <SetEnc>(otexstream & os, SetEnc);
350 template otexstream & operator<< <double>(otexstream &, double);
351 template otexstream & operator<< <int>(otexstream &, int);
352 template otexstream & operator<< <unsigned int>(otexstream &, unsigned int);
353 template otexstream & operator<< <unsigned long>(otexstream &, unsigned long);
354 #ifdef HAVE_LONG_LONG_INT
355 template otexstream & operator<< <unsigned long long>(otexstream &, unsigned long long);
356 #endif
357
358 } // namespace lyx