]> git.lyx.org Git - lyx.git/blob - src/output_plaintext.cpp
Avoid full metrics computation with Update:FitCursor
[lyx.git] / src / output_plaintext.cpp
1 /**
2  * \file output_plaintext.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Lars Gullik Bjønnes
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12
13 #include "output_plaintext.h"
14
15 #include "Buffer.h"
16 #include "BufferParams.h"
17 #include "Layout.h"
18 #include "output.h"
19 #include "OutputParams.h"
20 #include "Paragraph.h"
21 #include "ParagraphList.h"
22 #include "ParagraphParameters.h"
23
24 #include "insets/Inset.h"
25
26 #include "support/debug.h"
27 #include "support/gettext.h"
28 #include "support/lstrings.h"
29
30 using namespace std;
31 using namespace lyx::support;
32
33 namespace lyx {
34
35
36 void writePlaintextFile(Buffer const & buf, FileName const & fname,
37         OutputParams const & runparams)
38 {
39         ofdocstream ofs;
40         if (!openFileWrite(ofs, fname))
41                 return;
42
43         // make sure we are ready to export
44         buf.updateBuffer();
45         buf.updateMacroInstances(OutputUpdate);
46         buf.makeCitationLabels();
47
48         writePlaintextFile(buf, ofs, runparams);
49 }
50
51
52 void writePlaintextFile(Buffer const & buf, odocstream & os,
53         OutputParams const & runparams)
54 {
55         bool ref_printed = false;
56         ParagraphList const & par = buf.paragraphs();
57         ParagraphList::const_iterator beg = par.begin();
58         ParagraphList::const_iterator end = par.end();
59         ParagraphList::const_iterator it = beg;
60         for (; it != end; ++it) {
61                 bool const merged_par = (*it).parEndChange().deleted();
62                 writePlaintextParagraph(buf, *it, os, runparams, ref_printed);
63                 if (!merged_par)
64                         os << "\n";
65                 if (runparams.linelen > 0 && !merged_par)
66                         os << "\n";
67         }
68 }
69
70
71 static pair<int, docstring> addDepth(int depth, int ldepth)
72 {
73         int d = depth * 2;
74         if (ldepth > depth)
75                 d += (ldepth - depth) * 2;
76         return make_pair(d, docstring(d, ' '));
77 }
78
79
80 void writePlaintextParagraph(Buffer const & buf,
81                     Paragraph const & par,
82                     odocstream & ods,
83                     OutputParams const & runparams,
84                     bool & ref_printed, size_t max_length)
85 {
86         int ltype = 0;
87         depth_type ltype_depth = 0;
88         depth_type depth = par.params().depth();
89
90         // First write the layout
91         string const tmp = to_utf8(par.layout().name());
92         if (compare_ascii_no_case(tmp, "itemize") == 0) {
93                 ltype = 1;
94                 ltype_depth = depth + 1;
95         } else if (compare_ascii_no_case(tmp, "enumerate") == 0) {
96                 ltype = 2;
97                 ltype_depth = depth + 1;
98         } else if (contains(ascii_lowercase(tmp), "ection")) {
99                 ltype = 3;
100                 ltype_depth = depth + 1;
101         } else if (contains(ascii_lowercase(tmp), "aragraph")) {
102                 ltype = 4;
103                 ltype_depth = depth + 1;
104         } else if (compare_ascii_no_case(tmp, "description") == 0) {
105                 ltype = 5;
106                 ltype_depth = depth + 1;
107         } else if (compare_ascii_no_case(tmp, "abstract") == 0) {
108                 ltype = 6;
109                 ltype_depth = 0;
110         } else if (compare_ascii_no_case(tmp, "bibliography") == 0) {
111                 ltype = 7;
112                 ltype_depth = 0;
113         } else {
114                 ltype = 0;
115                 ltype_depth = 0;
116         }
117
118         /* the labelwidthstring used in lists */
119
120         /* noindent ? */
121
122         /* what about the alignment */
123
124         // runparams.linelen == 0 is special and means we don't have paragraph breaks
125
126         string::size_type currlinelen = 0;
127
128         odocstringstream os;
129         os << docstring(depth * 2, ' ');
130         currlinelen += depth * 2;
131
132         //--
133         // we should probably change to the paragraph language in the
134         // support/gettext.here (if possible) so that strings are output in
135         // the correct language! (20012712 Jug)
136         //--
137         switch (ltype) {
138         case 0: // Standard
139         case 4: // (Sub)Paragraph
140         case 5: // Description
141                 break;
142
143         case 6: // Abstract
144                 if (runparams.linelen > 0) {
145                         os << buf.B_("Abstract") << "\n\n";
146                         currlinelen = 0;
147                 } else {
148                         docstring const abst = buf.B_("Abstract: ");
149                         os << abst;
150                         currlinelen += abst.length();
151                 }
152                 break;
153
154         case 7: // Bibliography
155                 if (!ref_printed) {
156                         if (runparams.linelen > 0) {
157                                 os << buf.B_("References") << "\n\n";
158                                 currlinelen = 0;
159                         } else {
160                                 docstring const refs = buf.B_("References: ");
161                                 os << refs;
162                                 currlinelen += refs.length();
163                         }
164                         ref_printed = true;
165                 }
166                 break;
167
168         default: {
169                 docstring const label = par.params().labelString();
170                 if (!label.empty()) {
171                         os << label << ' ';
172                         currlinelen += label.length() + 1;
173                 }
174                 break;
175         }
176
177         }
178
179         if (currlinelen == 0) {
180                 pair<int, docstring> p = addDepth(depth, ltype_depth);
181                 os << p.second;
182                 currlinelen += p.first;
183         }
184
185         docstring word;
186
187         for (pos_type i = 0; i < par.size(); ++i) {
188                 // deleted characters don't make much sense in plain text output
189                 if (par.isDeleted(i))
190                         continue;
191
192                 if (os.str().size() > max_length)
193                         break;
194
195                 char_type c = par.getUChar(buf.params(), runparams, i);
196
197                 if (par.isInset(i) || c == ' ') {
198                         if (runparams.linelen > 0 &&
199                             currlinelen + word.length() > runparams.linelen) {
200                                 os << '\n';
201                                 pair<int, docstring> p = addDepth(depth, ltype_depth);
202                                 os << p.second;
203                                 currlinelen = p.first;
204                         }
205                         os << word;
206                         currlinelen += word.length();
207                         word.erase();
208                 }
209
210                 if (par.isInset(i)) {
211                         OutputParams rp = runparams;
212                         rp.depth = par.params().depth();
213                         int len = par.getInset(i)->plaintext(os, rp, max_length);
214                         if (len >= Inset::PLAINTEXT_NEWLINE)
215                                 currlinelen = len - Inset::PLAINTEXT_NEWLINE;
216                         else
217                                 currlinelen += len;
218                         continue;
219                 }
220
221                 switch (c) {
222                 case ' ':
223                         os << ' ';
224                         ++currlinelen;
225                         break;
226
227                 case '\0':
228                         LYXERR(Debug::INFO, "writePlaintextFile: NUL char in structure.");
229                         break;
230
231                 default:
232                         word += c;
233                         break;
234                 }
235         }
236
237         // currlinelen may be greater than runparams.linelen!
238         // => check whether word is empty and do nothing in this case
239         if (!word.empty()) {
240                 if (runparams.linelen > 0 &&
241                     currlinelen + word.length() > runparams.linelen) {
242                         os << '\n';
243                         pair<int, docstring> p = addDepth(depth, ltype_depth);
244                         os << p.second;
245                         currlinelen = p.first;
246                 }
247                 os << word;
248         }
249         ods << os.str();
250 }
251
252
253 } // namespace lyx