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