]> git.lyx.org Git - lyx.git/blob - src/tex2lyx/text.C
06da035ca57b2cb14f71522727e0d2ddb0d23900
[lyx.git] / src / tex2lyx / text.C
1 /** The .tex to .lyx converter
2     \author André Pönitz (2003)
3  */
4
5 // {[(
6
7 #include <config.h>
8
9 #include "tex2lyx.h"
10 #include "FloatList.h"
11 #include "lyxtextclass.h"
12 #include "support/lstrings.h"
13 #include "support/tostr.h"
14
15 #include <iostream>
16 #include <map>
17 #include <sstream>
18 #include <vector>
19
20 using std::cerr;
21 using std::endl;
22 using std::map;
23 using std::ostream;
24 using std::ostringstream;
25 using std::string;
26 using std::vector;
27
28 using lyx::support::rtrim;
29 using lyx::support::suffixIs;
30
31 // Do we need to output some \begin_layout command before the next characters?
32 bool need_layout = true;
33 // We may need to add something after this \begin_layout command
34 string extra_stuff;
35 // Do we need to output some \end_layout command 
36 bool need_end_layout = false;
37
38 void check_end_layout(ostream & os) 
39 {
40         if (need_end_layout) {
41                 os << "\n\\end_layout\n";
42                 need_end_layout = false;
43         }
44 }
45
46
47 namespace {
48
49 char const * known_latex_commands[] = { "ref", "cite", "label", "index",
50 "printindex", "pageref", "url", 0 };
51
52 // LaTeX names for quotes
53 char const * known_quotes[] = { "glqq", "grqq", "quotedblbase",
54 "textquotedblleft", "quotesinglbase", "guilsinglleft", "guilsinglright", 0};
55
56 // the same as known_quotes with .lyx names
57 char const * known_coded_quotes[] = { "gld", "grd", "gld",
58 "grd", "gls", "fls", "frd", 0};
59
60 char const * known_sizes[] = { "tiny", "scriptsize", "footnotesize",
61 "small", "normalsize", "large", "Large", "LARGE", "huge", "Huge", 0};
62
63 char const * known_coded_sizes[] = { "tiny", "scriptsize", "footnotesize",
64 "small", "normal", "large", "larger", "largest",  "huge", "giant", 0};
65
66 string cap(string s)
67 {
68         if (s.size())
69                 s[0] = toupper(s[0]);
70         return s;
71 }
72
73
74 // splits "x=z, y=b" into a map
75 map<string, string> split_map(string const & s)
76 {
77         map<string, string> res;
78         vector<string> v;
79         split(s, v);
80         for (size_t i = 0; i < v.size(); ++i) {
81                 size_t const pos   = v[i].find('=');
82                 string const index = v[i].substr(0, pos);
83                 string const value = v[i].substr(pos + 1, string::npos);
84                 res[trim(index)] = trim(value);
85         }
86         return res;
87 }
88
89
90 void check_layout(ostream & os, LyXLayout_ptr layout)
91 {
92         if (need_layout) {
93                 check_end_layout(os);
94                 os << "\n\\begin_layout " << layout->name() << "\n\n";
95                 need_end_layout = true;
96                 need_layout=false;
97                 if (!extra_stuff.empty()) {
98                         os << extra_stuff;
99                         extra_stuff.erase();
100                 }
101         }
102 }
103
104
105 void begin_inset(ostream & os, string const & name)
106 {
107         os << "\n\\begin_inset " << name;
108 }
109
110
111 void end_inset(ostream & os)
112 {
113         os << "\n\\end_inset \n\n";
114 }
115
116
117 void skip_braces(Parser & p)
118 {
119         if (p.next_token().cat() != catBegin)
120                 return;
121         p.get_token();
122         if (p.next_token().cat() == catEnd) {
123                 p.get_token();
124                 return;
125         }
126         p.putback();
127 }
128
129
130 void handle_ert(ostream & os, string const & s)
131 {
132         begin_inset(os, "ERT");
133         os << "\nstatus Collapsed\n\n\\begin_layout Standard\n\n";
134         for (string::const_iterator it = s.begin(), et = s.end(); it != et; ++it) {
135                 if (*it == '\\')
136                         os << "\n\\backslash \n";
137                 else
138                         os << *it;
139         }
140         need_end_layout = true;
141         check_end_layout(os);
142         end_inset(os);
143 }
144
145
146 struct isLayout {
147         isLayout(string const name) : name_(name) {}
148         bool operator()(LyXLayout_ptr const & ptr) {
149                 return ptr.get() && ptr->latexname() == name_;
150         }
151 private:
152         string const name_;
153 };
154
155
156 LyXLayout_ptr findLayout(LyXTextClass const & textclass,
157                          string const & name) 
158 {
159         LyXTextClass::const_iterator it  = textclass.begin();
160         LyXTextClass::const_iterator end = textclass.end();
161         it = std::find_if(it, end, isLayout(name));
162         return (it == end) ? LyXLayout_ptr() : *it;
163 }
164
165
166 void output_command_layout(ostream & os, LyXLayout_ptr const & layout,
167                   Parser & p, bool outer, LyXTextClass const & textclass)
168 {
169         need_layout = true;
170         check_layout(os, layout);
171         if (layout->optionalargs > 0) {
172                 string s; 
173                 if (p.next_token().character() == '[') {
174                         p.get_token(); // eat '['
175                         begin_inset(os, "OptArg\n");
176                         os << "collapsed true\n";
177                         parse_text_in_inset(p, os, FLAG_BRACK_LAST, outer, textclass);
178                         end_inset(os);
179                 }
180         }
181         parse_text(p, os, FLAG_ITEM, outer, textclass, layout);
182         need_layout = true;
183 }
184
185
186 } // anonymous namespace
187
188
189 void parse_environment(Parser & p, ostream & os, bool outer,
190                        LyXTextClass const & textclass, LyXLayout_ptr layout)
191 {
192         LyXLayout_ptr newlayout;
193         string const name = p.getArg('{', '}');
194         const bool is_starred = suffixIs(name, '*');
195         string const unstarred_name = rtrim(name, "*");
196         active_environments.push_back(name);
197         if (is_math_env(name)) {
198                 check_layout(os, layout);
199                 begin_inset(os, "Formula ");
200                 os << "\\begin{" << name << "}";
201                 parse_math(p, os, FLAG_END, MATH_MODE);
202                 os << "\\end{" << name << "}";
203                 end_inset(os);
204         } else if (name == "tabular") {
205                 check_layout(os, layout);
206                 begin_inset(os, "Tabular ");
207                 handle_tabular(p, os, textclass);
208                 end_inset(os);
209         } else if (textclass.floats().typeExist(unstarred_name)) {
210                 check_layout(os, layout);
211                 begin_inset(os, "Float " + unstarred_name + "\n");
212                 if (p.next_token().asInput() == "[") {
213                         os << "placement " << p.getArg('[', ']') << '\n';
214                 }
215                 os << "wide " << tostr(is_starred)
216                    << "\ncollapsed false\n";
217                 parse_text_in_inset(p, os, FLAG_END, outer, textclass);
218                         end_inset(os);
219         } else if (name == "center") {
220                 parse_text(p, os, FLAG_END, outer, textclass);
221                 // The single '=' is meant here.
222         } else if ((newlayout = findLayout(textclass, name)).get() &&
223                    newlayout->isEnvironment()) {
224                 size_t const n = active_environments.size();
225                 string const s = active_environments[n - 2];
226                 bool const deeper = s == "enumerate" || s == "itemize"
227                         || s == "lyxlist";
228                 if (deeper)
229                         os << "\n\\begin_deeper";
230                 switch (newlayout->latextype) {
231                 case  LATEX_LIST_ENVIRONMENT:
232                         extra_stuff = "\\labelwidthstring "
233                                 + p.verbatim_item() + '\n';
234                         break;
235                 case  LATEX_BIB_ENVIRONMENT:
236                         p.verbatim_item(); // swallow next arg
237                         break;
238                 default:
239                         break;
240                 }
241                 need_layout = true;
242                 parse_text(p, os, FLAG_END, outer, textclass, newlayout);
243                 check_end_layout(os);
244                 if (deeper)
245                         os << "\n\\end_deeper\n";
246                 need_layout = true;
247         } else {
248                 cerr << "why are we here?" << endl;
249                 parse_text(p, os, FLAG_END, outer, textclass);
250         }
251 }
252
253
254 void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
255                 LyXTextClass const & textclass, LyXLayout_ptr layout)
256 {
257         if (!layout.get())
258                 layout = textclass.defaultLayout();
259         LyXLayout_ptr newlayout;
260         while (p.good()) {
261                 Token const & t = p.get_token();
262
263 #ifdef FILEDEBUG
264                 cerr << "t: " << t << " flags: " << flags << "\n";
265 #endif
266
267                 if (flags & FLAG_ITEM) {
268                         if (t.cat() == catSpace)
269                                 continue;
270
271                         flags &= ~FLAG_ITEM;
272                         if (t.cat() == catBegin) {
273                                 // skip the brace and collect everything to the next matching
274                                 // closing brace
275                                 flags |= FLAG_BRACE_LAST;
276                                 continue;
277                         }
278
279                         // handle only this single token, leave the loop if done
280                         flags |= FLAG_LEAVE;
281                 }
282
283                 if (t.character() == ']' && (flags & FLAG_BRACK_LAST)) 
284                         return;
285
286                 //
287                 // cat codes
288                 //
289                 if (t.cat() == catMath) {
290                         // we are inside some text mode thingy, so opening new math is allowed
291                         check_layout(os, layout);
292                         begin_inset(os, "Formula ");
293                         Token const & n = p.get_token();
294                         if (n.cat() == catMath && outer) {
295                                 // TeX's $$...$$ syntax for displayed math
296                                 os << "\\[";
297                                 parse_math(p, os, FLAG_SIMPLE, MATH_MODE);
298                                 os << "\\]";
299                                 p.get_token(); // skip the second '$' token
300                         } else {
301                                 // simple $...$  stuff
302                                 p.putback();
303                                 os << '$';
304                                 parse_math(p, os, FLAG_SIMPLE, MATH_MODE);
305                                 os << '$';
306                         }
307                         end_inset(os);
308                 }
309
310                 else if (t.cat() == catSuper || t.cat() == catSub)
311                         cerr << "catcode " << t << " illegal in text mode\n";
312
313                 // Basic support for english quotes. This should be
314                 // extended to other quotes, but is not so easy (a
315                 // left english quote is the same as a right german
316                 // quote...)
317                 else if (t.asInput() == "`" 
318                          && p.next_token().asInput() == "`") {
319                         check_layout(os, layout);
320                         begin_inset(os, "Quotes ");
321                         os << "eld";
322                         end_inset(os);
323                         p.get_token();
324                         skip_braces(p);
325                 }       
326                 else if (t.asInput() == "'" 
327                          && p.next_token().asInput() == "'") {
328                         check_layout(os, layout);
329                         begin_inset(os, "Quotes ");
330                         os << "erd";
331                         end_inset(os);
332                         p.get_token();
333                         skip_braces(p);
334                 }       
335
336
337                 else if (t.cat() == catLetter ||
338                                t.cat() == catSpace ||
339                                t.cat() == catOther ||
340                                t.cat() == catAlign ||
341                                t.cat() == catParameter) {
342                         check_layout(os, layout);
343                         os << t.character();
344                 }
345
346                 else if (t.cat() == catNewline) {
347                         if (p.next_token().cat() == catNewline) {
348                                 p.get_token();
349                                 need_layout = true;
350                         } else {
351                                 os << " "; // note the space
352                         }
353                 }
354
355                 else if (t.cat() == catActive) {
356                         check_layout(os, layout);
357                         if (t.character() == '~') {
358                                 if (layout->free_spacing)
359                                         os << ' ';
360                                 else 
361                                         os << "\\InsetSpace ~\n";
362                         } else
363                                 os << t.character();
364                 }
365
366                 else if (t.cat() == catBegin) {
367 // FIXME??? 
368                         // special handling of size changes
369                         check_layout(os, layout);
370                         bool const is_size = is_known(p.next_token().cs(), known_sizes);
371                         need_end_layout = false;
372                         string const s = parse_text(p, FLAG_BRACE_LAST, outer, textclass, layout);
373                         need_end_layout = true;
374                         if (s.empty() && p.next_token().character() == '`')
375                                 ; // ignore it in  {}``
376                         else if (is_size || s == "[" || s == "]" || s == "*")
377                                 os << s;
378                         else {
379                                 handle_ert(os, "{");
380                                 os << s;
381                                 handle_ert(os, "}");
382                         }
383                 }
384
385                 else if (t.cat() == catEnd) {
386                         if (flags & FLAG_BRACE_LAST) {
387                                 check_end_layout(os);
388                                 return;
389                         }
390                         cerr << "stray '}' in text\n";
391                         handle_ert(os, "}");
392                 }
393
394                 else if (t.cat() == catComment)
395                         handle_comment(p);
396
397                 //
398                 // control sequences
399                 //
400
401                 else if (t.cs() == "(") {
402                         check_layout(os, layout);
403                         begin_inset(os, "Formula");
404                         os << " \\(";
405                         parse_math(p, os, FLAG_SIMPLE2, MATH_MODE);
406                         os << "\\)";
407                         end_inset(os);
408                 }
409
410                 else if (t.cs() == "[") {
411                         check_layout(os, layout);
412                         begin_inset(os, "Formula");
413                         os << " \\[";
414                         parse_math(p, os, FLAG_EQUATION, MATH_MODE);
415                         os << "\\]";
416                         end_inset(os);
417                 }
418
419                 else if (t.cs() == "begin")
420                         parse_environment(p, os, outer, textclass, layout);
421
422                 else if (t.cs() == "end") {
423                         if (flags & FLAG_END) {
424                                 // eat environment name
425                                 string const name = p.getArg('{', '}');
426                                 if (name != active_environment())
427                                         cerr << "\\end{" + name + "} does not match \\begin{"
428                                                 + active_environment() + "}\n";
429                                 active_environments.pop_back();
430                                 return;
431                         }
432                         p.error("found 'end' unexpectedly");
433                 }
434
435                 else if (t.cs() == "item") {
436                         // should be done automatically by Parser::tokenize
437                         //p.skip_spaces();
438                         string s; 
439                         if (p.next_token().character() == '[') {
440                                 p.get_token(); // eat '['
441                                 s = parse_text(p, FLAG_BRACK_LAST, outer, textclass, layout);
442                         }
443                         need_layout = true;
444                         check_layout(os, layout);
445                         if (s.size())
446                                 os << s << ' ';
447                 }
448
449                 else if (t.cs() == "def") {
450                         string name = p.get_token().cs();
451                         while (p.next_token().cat() != catBegin)
452                                 name += p.get_token().asString();
453                         handle_ert(os, "\\def\\" + name + '{' + p.verbatim_item() + '}');
454                 }
455
456                 else if (t.cs() == "par") {
457                         p.skip_spaces();
458                         need_layout = true;
459 //                      if (p.next_token().cs() != "\\begin")
460 //                              handle_par(os);
461                         //cerr << "next token: '" << p.next_token().cs() << "'\n";
462                 }
463
464                 // Must attempt to parse "Section*" before "Section".
465                 else if ((p.next_token().asInput() == "*") &&
466                          // The single '=' is meant here.
467                          (newlayout = findLayout(textclass,
468                                                  t.cs() + '*')).get() &&
469                          newlayout->isCommand()) {
470                         p.get_token();
471                         output_command_layout(os, newlayout, p, outer, textclass);
472                 }
473
474                 // The single '=' is meant here.
475                 else if ((newlayout = findLayout(textclass, t.cs())).get() &&
476                          newlayout->isCommand()) {
477                         output_command_layout(os, newlayout, p, outer, textclass);
478                 }
479
480                 else if (t.cs() == "includegraphics") {
481                         map<string, string> opts = split_map(p.getArg('[', ']'));
482                         string name = p.verbatim_item();
483                         
484                         check_layout(os, layout);
485                         begin_inset(os, "Graphics ");
486                         os << "\n\tfilename " << name << '\n';
487                         if (opts.find("width") != opts.end())
488                                 os << "\twidth " << opts["width"] << '\n';
489                         if (opts.find("height") != opts.end())
490                                 os << "\theight " << opts["height"] << '\n';
491                         end_inset(os);
492                 }
493                 
494                 else if (t.cs() == "footnote") {
495                         check_layout(os, layout);
496                         begin_inset(os, "Foot\n");
497                         os << "collapsed true\n";
498                         parse_text_in_inset(p, os, FLAG_ITEM, false, textclass);
499                         end_inset(os);
500                 }
501
502                 else if (t.cs() == "ensuremath") {
503                         check_layout(os, layout);
504                         string s = parse_text(p, FLAG_ITEM, false, textclass);
505                         if (s == "±" || s == "³" || s == "²" || s == "µ")
506                                 os << s;
507                         else
508                                 handle_ert(os, "\\ensuremath{" + s + "}");
509                 }
510
511                 else if (t.cs() == "marginpar") {
512                         check_layout(os, layout);
513                         begin_inset(os, "Marginal\n");
514                         os << "collapsed true\n";
515                         need_layout = true;
516                         parse_text(p, os, FLAG_ITEM, false, textclass);
517                         end_inset(os);
518                         need_end_layout = true;
519                 }
520
521                 else if (t.cs() == "hfill") {
522                         check_layout(os, layout);
523                         os << "\n\\hfill\n";
524                         skip_braces(p);
525                 }
526
527                 else if (t.cs() == "makeindex" || t.cs() == "maketitle")
528                         skip_braces(p); // swallow this
529
530                 else if (t.cs() == "tableofcontents") {
531                         check_layout(os, layout);
532                         begin_inset(os, "LatexCommand ");
533                         os << '\\' << t.cs() << "{}\n";
534                         end_inset(os);
535                         skip_braces(p); // swallow this
536                 }
537
538
539                 else if (t.cs() == "textrm") {
540                         check_layout(os, layout);
541                         os << "\n\\family roman \n";
542                         parse_text(p, os, FLAG_ITEM, outer, textclass);
543                         os << "\n\\family default \n";
544                 }
545
546                 else if (t.cs() == "textsf") {
547                         check_layout(os, layout);
548                         os << "\n\\family sans \n";
549                         parse_text(p, os, FLAG_ITEM, outer, textclass);
550                         os << "\n\\family default \n";
551                 }
552
553                 else if (t.cs() == "texttt") {
554                         check_layout(os, layout);
555                         os << "\n\\family typewriter \n";
556                         parse_text(p, os, FLAG_ITEM, outer, textclass);
557                         os << "\n\\family default \n";
558                 }
559
560                 else if (t.cs() == "textit") {
561                         check_layout(os, layout);
562                         os << "\n\\shape italic \n";
563                         parse_text(p, os, FLAG_ITEM, outer, textclass);
564                         os << "\n\\shape default \n";
565                 }
566
567                 else if (t.cs() == "textsc") {
568                         check_layout(os, layout);
569                         os << "\n\\noun on \n";
570                         parse_text(p, os, FLAG_ITEM, outer, textclass);
571                         os << "\n\\noun default \n";
572                 }
573
574                 else if (t.cs() == "textbf") {
575                         check_layout(os, layout);
576                         os << "\n\\series bold \n";
577                         parse_text(p, os, FLAG_ITEM, outer, textclass);
578                         os << "\n\\series default \n";
579                 }
580
581                 else if (t.cs() == "underbar") {
582                         check_layout(os, layout);
583                         os << "\n\\bar under \n";
584                         parse_text(p, os, FLAG_ITEM, outer, textclass);
585                         os << "\n\\bar default \n";
586                 }
587
588                 else if (t.cs() == "emph" || t.cs() == "noun") {
589                         check_layout(os, layout);
590                         os << "\n\\" << t.cs() << " on \n";
591                         parse_text(p, os, FLAG_ITEM, outer, textclass);
592                         os << "\n\\" << t.cs() << " default \n";
593                 }
594
595                 else if (t.cs() == "bibitem") {
596                         check_layout(os, layout);
597                         os << "\\bibitem ";
598                         os << p.getOpt();
599                         os << '{' << p.verbatim_item() << '}' << "\n";
600                 }
601
602                 else if (is_known(t.cs(), known_latex_commands)) {
603                         check_layout(os, layout);
604                         begin_inset(os, "LatexCommand ");
605                         os << '\\' << t.cs();
606                         os << p.getOpt();
607                         os << p.getOpt();
608                         os << '{' << p.verbatim_item() << "}\n";
609                         end_inset(os);
610                 }
611
612                 else if (is_known(t.cs(), known_quotes)) {
613                   char const ** where = is_known(t.cs(), known_quotes);
614                         begin_inset(os, "Quotes ");
615                         os << known_coded_quotes[where - known_quotes];
616                         end_inset(os);
617                         skip_braces(p);
618                 }
619
620                 else if (is_known(t.cs(), known_sizes)) {
621                         char const ** where = is_known(t.cs(), known_sizes);
622                         check_layout(os, layout);
623                         os << "\n\\size " << known_coded_sizes[where - known_sizes] << "\n";
624                 }
625
626                 else if (t.cs() == "LyX" || t.cs() == "TeX" 
627                          || t.cs() == "LaTeX") {
628                         check_layout(os, layout);
629                         os << t.cs();
630                         skip_braces(p); // eat {}
631                 }
632
633                 else if (t.cs() == "LaTeXe") {
634                         check_layout(os, layout);
635                         os << "LaTeX2e";
636                         skip_braces(p); // eat {}
637                 }
638
639                 else if (t.cs() == "ldots") {
640                         check_layout(os, layout);
641                         skip_braces(p);
642                         os << "\\SpecialChar \\ldots{}\n";
643                 }
644
645                 else if (t.cs() == "lyxarrow") {
646                         check_layout(os, layout);
647                         os << "\\SpecialChar \\menuseparator\n";
648                         skip_braces(p);
649                 }
650
651                 else if (t.cs() == "ldots") {
652                         check_layout(os, layout);
653                         os << "\\SpecialChar \\ldots{}\n";
654                         skip_braces(p);
655                 }
656
657                 else if (t.cs() == "@" && p.next_token().asInput() == ".") {
658                         check_layout(os, layout);
659                         os << "\\SpecialChar \\@.\n";
660                         p.get_token();
661                 }
662
663                 else if (t.cs() == "-") {
664                         check_layout(os, layout);
665                         os << "\\SpecialChar \\-\n";
666                 }
667
668                 else if (t.cs() == "textasciitilde") {
669                         check_layout(os, layout);
670                         os << '~';
671                         skip_braces(p);
672                 }
673
674                 else if (t.cs() == "textasciicircum") {
675                         check_layout(os, layout);
676                         os << '^';
677                         skip_braces(p);
678                 }
679
680                 else if (t.cs() == "textbackslash") {
681                         check_layout(os, layout);
682                         os << "\n\\backslash \n";
683                         skip_braces(p);
684                 }
685
686                 else if (t.cs() == "_" || t.cs() == "&" || t.cs() == "#" 
687                             || t.cs() == "$" || t.cs() == "{" || t.cs() == "}" 
688                             || t.cs() == "%") {
689                         check_layout(os, layout);
690                         os << t.cs();
691                 }
692
693                 else if (t.cs() == "char") {
694                         check_layout(os, layout);
695                         if (p.next_token().character() == '`') {
696                                 p.get_token();
697                                 if (p.next_token().cs() == "\"") {
698                                         p.get_token();
699                                         os << '"';
700                                         skip_braces(p);
701                                 } else {
702                                         handle_ert(os, "\\char`");
703                                 }
704                         } else {
705                                 handle_ert(os, "\\char");
706                         }
707                 }
708
709                 else if (t.cs() == "\"") {
710                         check_layout(os, layout);
711                         string const name = p.verbatim_item();
712                              if (name == "a") os << 'ä';
713                         else if (name == "o") os << 'ö';
714                         else if (name == "u") os << 'ü';
715                         else if (name == "A") os << 'Ä';
716                         else if (name == "O") os << 'Ö';
717                         else if (name == "U") os << 'Ü';
718                         else handle_ert(os, "\"{" + name + "}");
719                 }
720
721                 else if (t.cs() == "=" || t.cs() == "H" || t.cs() == "c"
722                       || t.cs() == "^" || t.cs() == "'" || t.cs() == "~") {
723                         // we need the trim as the LyX parser chokes on such spaces
724                         check_layout(os, layout);
725                         os << "\n\\i \\" << t.cs() << "{"
726                            << trim(parse_text(p, FLAG_ITEM, outer, textclass), " ") << "}\n";
727                 }
728
729                 else if (t.cs() == "ss") {
730                         check_layout(os, layout);
731                         os << "ß";
732                 }
733
734                 else if (t.cs() == "i" || t.cs() == "j") {
735                         check_layout(os, layout);
736                         os << "\\" << t.cs() << ' ';
737                 }
738
739                 else if (t.cs() == "\\") {
740                         check_layout(os, layout);
741                         os << "\n\\newline \n";
742                 }
743         
744                 else if (t.cs() == "input") {
745                         check_layout(os, layout);
746                         handle_ert(os, "\\input{" + p.verbatim_item() + "}\n");
747                 }
748                 else if (t.cs() == "fancyhead") {
749                         check_layout(os, layout);
750                         ostringstream ss;
751                         ss << "\\fancyhead";
752                         ss << p.getOpt();
753                         ss << '{' << p.verbatim_item() << "}\n";
754                         handle_ert(os, ss.str());
755                 }
756
757                 else {
758                         //cerr << "#: " << t << " mode: " << mode << endl;
759                         // heuristic: read up to next non-nested space
760                         /*
761                         string s = t.asInput();
762                         string z = p.verbatim_item();
763                         while (p.good() && z != " " && z.size()) {
764                                 //cerr << "read: " << z << endl;
765                                 s += z;
766                                 z = p.verbatim_item();
767                         }
768                         cerr << "found ERT: " << s << endl;
769                         handle_ert(os, s + ' ');
770                         */
771                         check_layout(os, layout);
772                         handle_ert(os, t.asInput() + ' ');
773                 }
774
775                 if (flags & FLAG_LEAVE) {
776                         flags &= ~FLAG_LEAVE;
777                         break;
778                 }
779         }
780 }
781
782
783 string parse_text(Parser & p, unsigned flags, const bool outer,
784                   LyXTextClass const & textclass,
785                   LyXLayout_ptr layout)
786 {
787         ostringstream os;
788         parse_text(p, os, flags, outer, textclass, layout);
789         return os.str();
790 }
791
792 void parse_text_in_inset(Parser & p, ostream & os, unsigned flags, bool outer,
793                 LyXTextClass const & textclass, LyXLayout_ptr layout)
794 {
795                 need_layout = true;
796                 need_end_layout = false;
797                 parse_text(p, os, flags, outer, textclass, layout);
798                 check_end_layout(os);
799                 need_end_layout = true;
800 }
801 // }])