]> git.lyx.org Git - lyx.git/blob - src/output_latex.cpp
Fulfill promise to Andre: TextClass_ptr --> TextClassPtr.
[lyx.git] / src / output_latex.cpp
1 /**
2  * \file output_latex.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_latex.h"
14
15 #include "Buffer.h"
16 #include "BufferParams.h"
17 #include "debug.h"
18 #include "Encoding.h"
19 #include "Language.h"
20 #include "LyXRC.h"
21 #include "OutputParams.h"
22 #include "Paragraph.h"
23 #include "paragraph_funcs.h"
24 #include "ParagraphParameters.h"
25 #include "TexRow.h"
26 #include "VSpace.h"
27
28 #include "insets/InsetBibitem.h"
29 #include "insets/InsetOptArg.h"
30
31 #include "support/lstrings.h"
32
33
34 namespace lyx {
35
36 using support::subst;
37
38 using std::endl;
39 using std::string;
40 using std::pair;
41 using std::make_pair;
42
43
44 namespace {
45
46 ParagraphList::const_iterator
47 TeXEnvironment(Buffer const & buf,
48                ParagraphList const & paragraphs,
49                ParagraphList::const_iterator pit,
50                odocstream & os, TexRow & texrow,
51                OutputParams const & runparams);
52
53 ParagraphList::const_iterator
54 TeXOnePar(Buffer const & buf,
55           ParagraphList const & paragraphs,
56           ParagraphList::const_iterator pit,
57           odocstream & os, TexRow & texrow,
58           OutputParams const & runparams,
59           string const & everypar = string());
60
61
62 ParagraphList::const_iterator
63 TeXDeeper(Buffer const & buf,
64           ParagraphList const & paragraphs,
65           ParagraphList::const_iterator pit,
66           odocstream & os, TexRow & texrow,
67           OutputParams const & runparams)
68 {
69         LYXERR(Debug::LATEX) << "TeXDeeper...     " << &*pit << endl;
70         ParagraphList::const_iterator par = pit;
71
72         while (par != paragraphs.end() &&
73                      par->params().depth() == pit->params().depth()) {
74                 if (par->layout()->isEnvironment()) {
75                         par = TeXEnvironment(buf, paragraphs, par,
76                                              os, texrow, runparams);
77                 } else {
78                         par = TeXOnePar(buf, paragraphs, par,
79                                              os, texrow, runparams);
80                 }
81         }
82         LYXERR(Debug::LATEX) << "TeXDeeper...done " << endl;
83
84         return par;
85 }
86
87
88 ParagraphList::const_iterator
89 TeXEnvironment(Buffer const & buf,
90                ParagraphList const & paragraphs,
91                ParagraphList::const_iterator pit,
92                odocstream & os, TexRow & texrow,
93                OutputParams const & runparams)
94 {
95         LYXERR(Debug::LATEX) << "TeXEnvironment...     " << &*pit << endl;
96
97         BufferParams const & bparams = buf.params();
98
99         LayoutPtr const & style = pit->layout();
100
101         Language const * const par_language = pit->getParLanguage(bparams);
102         Language const * const doc_language = bparams.language;
103         Language const * const prev_par_language =
104                 (pit != paragraphs.begin())
105                 ? boost::prior(pit)->getParLanguage(bparams)
106                 : doc_language;
107         if (par_language->babel() != prev_par_language->babel()) {
108
109                 if (!lyxrc.language_command_end.empty() &&
110                     prev_par_language->babel() != doc_language->babel() &&
111                     !prev_par_language->babel().empty()) {
112                         os << from_ascii(subst(
113                                 lyxrc.language_command_end,
114                                 "$$lang",
115                                 prev_par_language->babel()))
116                            << '\n';
117                         texrow.newline();
118                 }
119
120                 if ((lyxrc.language_command_end.empty() ||
121                      par_language->babel() != doc_language->babel()) &&
122                     !par_language->babel().empty()) {
123                         os << from_ascii(subst(
124                                 lyxrc.language_command_begin,
125                                 "$$lang",
126                                 par_language->babel()))
127                            << '\n';
128                         texrow.newline();
129                 }
130         }
131
132         bool leftindent_open = false;
133         if (!pit->params().leftIndent().zero()) {
134                 os << "\\begin{LyXParagraphLeftIndent}{"
135                    << from_ascii(pit->params().leftIndent().asLatexString())
136                    << "}\n";
137                 texrow.newline();
138                 leftindent_open = true;
139         }
140
141         if (style->isEnvironment()) {
142                 os << "\\begin{" << from_ascii(style->latexname()) << '}';
143                 if (style->optionalargs > 0) {
144                         int ret = latexOptArgInsets(buf, *pit, os, runparams,
145                                                     style->optionalargs);
146                         while (ret > 0) {
147                                 texrow.newline();
148                                 --ret;
149                         }
150                 }
151                 if (style->latextype == LATEX_LIST_ENVIRONMENT) {
152                         os << '{'
153                            << pit->params().labelWidthString()
154                            << "}\n";
155                 } else if (style->labeltype == LABEL_BIBLIO) {
156                         // ale970405
157                         os << '{' << bibitemWidest(buf) << "}\n";
158                 } else
159                         os << from_ascii(style->latexparam()) << '\n';
160                 texrow.newline();
161         }
162         ParagraphList::const_iterator par = pit;
163         do {
164                 par = TeXOnePar(buf, paragraphs, par, os, texrow, runparams);
165
166                 if (par == paragraphs.end()) {
167                         // Make sure that the last paragraph is
168                         // correctly terminated (because TeXOnePar does
169                         // not add a \n in this case)
170                         os << '\n';
171                         texrow.newline();
172                 } else if (par->params().depth() > pit->params().depth()) {
173                             if (par->layout()->isParagraph()) {
174
175                             // Thinko!
176                             // How to handle this? (Lgb)
177                             //&& !suffixIs(os, "\n\n")
178                                     //) {
179                                 // There should be at least one '\n' already
180                                 // but we need there to be two for Standard
181                                 // paragraphs that are depth-increment'ed to be
182                                 // output correctly.  However, tables can
183                                 // also be paragraphs so don't adjust them.
184                                 // ARRae
185                                 // Thinkee:
186                                 // Will it ever harm to have one '\n' too
187                                 // many? i.e. that we sometimes will have
188                                 // three in a row. (Lgb)
189                                 os << '\n';
190                                 texrow.newline();
191                         }
192                         par = TeXDeeper(buf, paragraphs, par, os, texrow,
193                                         runparams);
194                 }
195         } while (par != paragraphs.end()
196                  && par->layout() == pit->layout()
197                  && par->params().depth() == pit->params().depth()
198                  && par->params().leftIndent() == pit->params().leftIndent());
199
200         if (style->isEnvironment()) {
201                 os << "\\end{" << from_ascii(style->latexname()) << "}\n";
202                 texrow.newline();
203         }
204
205         if (leftindent_open) {
206                 os << "\\end{LyXParagraphLeftIndent}\n";
207                 texrow.newline();
208         }
209
210         if (par != paragraphs.end()) {
211                 LYXERR(Debug::LATEX) << "TeXEnvironment...done " << &*par << endl;
212         }
213         return par;
214 }
215
216 }
217
218
219 int latexOptArgInsets(Buffer const & buf, Paragraph const & par,
220                       odocstream & os, OutputParams const & runparams, int number)
221 {
222         int lines = 0;
223
224         InsetList::const_iterator it = par.insetlist.begin();
225         InsetList::const_iterator end = par.insetlist.end();
226         for (; it != end && number > 0 ; ++it) {
227                 if (it->inset->lyxCode() == Inset::OPTARG_CODE) {
228                         InsetOptArg * ins =
229                                 static_cast<InsetOptArg *>(it->inset);
230                         lines += ins->latexOptional(buf, os, runparams);
231                         --number;
232                 }
233         }
234         return lines;
235 }
236
237
238 namespace {
239
240 ParagraphList::const_iterator
241 TeXOnePar(Buffer const & buf,
242           ParagraphList const & paragraphs,
243           ParagraphList::const_iterator pit,
244           odocstream & os, TexRow & texrow,
245           OutputParams const & runparams_in,
246           string const & everypar)
247 {
248         LYXERR(Debug::LATEX) << "TeXOnePar...     " << &*pit << " '"
249                 << everypar << "'" << endl;
250         BufferParams const & bparams = buf.params();
251         LayoutPtr style;
252
253         // In an inset with unlimited length (all in one row),
254         // force layout to default
255         if (!pit->forceDefaultParagraphs())
256                 style = pit->layout();
257         else
258                 style = bparams.getTextClass().defaultLayout();
259
260         OutputParams runparams = runparams_in;
261         runparams.moving_arg |= style->needprotect;
262
263         // This paragraph's language
264         Language const * const par_language = pit->getParLanguage(bparams);
265         // The document's language
266         Language const * const doc_language = bparams.language;
267         // The language that was in effect when the environemnt this paragraph is 
268         // inside of was opened
269         Language const * const outer_language = 
270                 (runparams.local_font != 0) ?
271                         runparams.local_font->language() : doc_language;
272         // The previous language that was in effect is either the language of
273         // the previous paragraph, if there is one, or else the outer language
274         // if there is no previous paragraph
275         Language const * const prev_language =
276                 (pit != paragraphs.begin()) ?
277                         boost::prior(pit)->getParLanguage(bparams) : outer_language;
278
279         if (par_language->babel() != prev_language->babel()
280             // check if we already put language command in TeXEnvironment()
281             && !(style->isEnvironment()
282                  && (pit == paragraphs.begin() ||
283                      (boost::prior(pit)->layout() != pit->layout() &&
284                       boost::prior(pit)->getDepth() <= pit->getDepth())
285                      || boost::prior(pit)->getDepth() < pit->getDepth())))
286         {
287                 if (!lyxrc.language_command_end.empty() &&
288                     prev_language->babel() != outer_language->babel() &&
289                     !prev_language->babel().empty())
290                 {
291                         os << from_ascii(subst(lyxrc.language_command_end,
292                                 "$$lang",
293                                 prev_language->babel()))
294                            << '\n';
295                         texrow.newline();
296                 }
297
298                 // We need to open a new language if we couldn't close the previous 
299                 // one (because there's no language_command_end); and even if we closed
300                 // the previous one, if the current language is different than the
301                 // outer_language (which is currently in effect once the previous one
302                 // is closed).
303                 if ((lyxrc.language_command_end.empty() ||
304                      par_language->babel() != outer_language->babel()) &&
305                     !par_language->babel().empty()) {
306                         // If we're inside an inset, and that inset is within an \L or \R
307                         // (or equivalents), then within the inset, too, any opposite
308                         // language paragraph should appear within an \L or \R (in addition
309                         // to, outside of, the normal language switch commands).
310                         // This behavior is not correct for ArabTeX, though.
311                         if (    // not for ArabTeX
312                                         (par_language->lang() != "arabic_arabtex" &&
313                                          outer_language->lang() != "arabic_arabtex") &&
314                                         // are we in an inset?
315                                         runparams.local_font != 0 &&
316                                         // is the inset within an \L or \R?
317                                         // 
318                                         // FIXME: currently, we don't check this; this means that
319                                         // we'll have unnnecessary \L and \R commands, but that 
320                                         // doesn't seem to hurt (though latex will complain)
321                                         // 
322                                         // is this paragraph in the opposite direction?
323                                         runparams.local_font->isRightToLeft() !=
324                                                 par_language->rightToLeft()
325                                 ) {
326                                 // FIXME: I don't have a working copy of the Arabi package, so
327                                 // I'm not sure if the farsi and arabic_arabi stuff is correct
328                                 // or not...
329                                 if (par_language->lang() == "farsi")
330                                         os << "\\textFR{";
331                                 else if (outer_language->lang() == "farsi")
332                                         os << "\\textLR{";
333                                 else if (par_language->lang() == "arabic_arabi")
334                                         os << "\\textAR{";
335                                 else if (outer_language->lang() == "arabic_arabi")
336                                         os << "\\textLR{";
337                                 // remaining RTL languages currently is hebrew
338                                 else if (par_language->rightToLeft())
339                                         os << "\\R{";
340                                 else
341                                         os << "\\L{";
342                         }
343                         os << from_ascii(subst(
344                                 lyxrc.language_command_begin,
345                                 "$$lang",
346                                 par_language->babel()))
347                            << '\n';
348                         texrow.newline();
349                 }
350         }
351
352         // Switch file encoding if necessary; no need to do this for "default"
353         // encoding, since this only affects the position of the outputted
354         // \inputencoding command; the encoding switch will occur when necessary
355         if (bparams.inputenc == "auto" &&
356             runparams.encoding->package() == Encoding::inputenc) {
357                 // Look ahead for future encoding changes.
358                 // We try to output them at the beginning of the paragraph,
359                 // since the \inputencoding command is not allowed e.g. in
360                 // sections.
361                 for (pos_type i = 0; i < pit->size(); ++i) {
362                         char_type const c = pit->getChar(i);
363                         if (c < 0x80)
364                                 continue;
365                         if (pit->isInset(i))
366                                 break;
367                         // All characters before c are in the ASCII range, and
368                         // c is non-ASCII (but no inset), so change the
369                         // encoding to that required by the language of c.
370                         Encoding const * const encoding =
371                                 pit->getFontSettings(bparams, i).language()->encoding();
372                         pair<bool, int> enc_switch = switchEncoding(os, bparams, false,
373                                         *(runparams.encoding), *encoding);
374                         if (encoding->package() == Encoding::inputenc && enc_switch.first) {
375                                 runparams.encoding = encoding;
376                                 if (enc_switch.second > 0) {
377                                         os << '\n';
378                                         texrow.newline();
379                                 }
380                         }
381                         break;
382                 }
383         }
384
385         // In an inset with unlimited length (all in one row),
386         // don't allow any special options in the paragraph
387         if (!pit->forceDefaultParagraphs()) {
388                 if (pit->params().startOfAppendix()) {
389                         os << "\\appendix\n";
390                         texrow.newline();
391                 }
392
393                 if (!pit->params().spacing().isDefault()
394                         && (pit == paragraphs.begin()
395                             || !boost::prior(pit)->hasSameLayout(*pit)))
396                 {
397                         os << from_ascii(pit->params().spacing().writeEnvirBegin())
398                             << '\n';
399                         texrow.newline();
400                 }
401
402                 if (style->isCommand()) {
403                         os << '\n';
404                         texrow.newline();
405                 }
406         }
407
408         switch (style->latextype) {
409         case LATEX_COMMAND:
410                 os << '\\' << from_ascii(style->latexname());
411
412                 // Separate handling of optional argument inset.
413                 if (style->optionalargs > 0) {
414                         int ret = latexOptArgInsets(buf, *pit, os, runparams,
415                                                     style->optionalargs);
416                         while (ret > 0) {
417                                 texrow.newline();
418                                 --ret;
419                         }
420                 }
421                 else
422                         os << from_ascii(style->latexparam());
423                 break;
424         case LATEX_ITEM_ENVIRONMENT:
425         case LATEX_LIST_ENVIRONMENT:
426                 os << "\\item ";
427                 break;
428         case LATEX_BIB_ENVIRONMENT:
429                 // ignore this, the inset will write itself
430                 break;
431         default:
432                 break;
433         }
434
435         Font const outerfont =
436                 outerFont(std::distance(paragraphs.begin(), pit),
437                           paragraphs);
438
439         // FIXME UNICODE
440         os << from_utf8(everypar);
441         bool need_par = pit->simpleTeXOnePar(buf, bparams, outerfont,
442                                              os, texrow, runparams);
443
444         // Make sure that \\par is done with the font of the last
445         // character if this has another size as the default.
446         // This is necessary because LaTeX (and LyX on the screen)
447         // calculates the space between the baselines according
448         // to this font. (Matthias)
449         //
450         // Is this really needed ? (Dekel)
451         // We do not need to use to change the font for the last paragraph
452         // or for a command.
453
454         Font const font =
455                 (pit->empty()
456                  ? pit->getLayoutFont(bparams, outerfont)
457                  : pit->getFont(bparams, pit->size() - 1, outerfont));
458
459         bool is_command = style->isCommand();
460
461         if (style->resfont.size() != font.size()
462             && boost::next(pit) != paragraphs.end()
463             && !is_command) {
464                 if (!need_par)
465                         os << '{';
466                 os << "\\" << from_ascii(font.latexSize()) << " \\par}";
467         } else if (need_par) {
468                 os << "\\par}";
469         } else if (is_command)
470                 os << '}';
471
472         bool pending_newline = false;
473         switch (style->latextype) {
474         case LATEX_ITEM_ENVIRONMENT:
475         case LATEX_LIST_ENVIRONMENT:
476                 if (boost::next(pit) != paragraphs.end()
477                     && (pit->params().depth() < boost::next(pit)->params().depth()))
478                         pending_newline = true;
479                 break;
480         case LATEX_ENVIRONMENT: {
481                 // if its the last paragraph of the current environment
482                 // skip it otherwise fall through
483                 ParagraphList::const_iterator next = boost::next(pit);
484
485                 if (next != paragraphs.end()
486                     && (next->layout() != pit->layout()
487                         || next->params().depth() != pit->params().depth()))
488                         break;
489         }
490
491                 // fall through possible
492         default:
493                 // we don't need it for the last paragraph!!!
494                 if (boost::next(pit) != paragraphs.end())
495                         pending_newline = true;
496         }
497
498         if (!pit->forceDefaultParagraphs()) {
499                 if (!pit->params().spacing().isDefault()
500                         && (boost::next(pit) == paragraphs.end()
501                             || !boost::next(pit)->hasSameLayout(*pit)))
502                 {
503                         if (pending_newline) {
504                                 os << '\n';
505                                 texrow.newline();
506                         }
507                         os << from_ascii(pit->params().spacing().writeEnvirEnd());
508                         pending_newline = true;
509                 }
510         }
511
512         // Closing the language is needed for the last paragraph; it is also
513         // needed if we're within an \L or \R that we may have opened above (not
514         // necessarily in this paragraph) and are about to close.
515         bool closing_rtl_ltr_environment = 
516                 // not for ArabTeX
517                 (par_language->lang() != "arabic_arabtex" &&
518                  outer_language->lang() != "arabic_arabtex") &&
519                 // have we opened and \L or \R environment?
520                 runparams.local_font != 0 &&
521                 runparams.local_font->isRightToLeft() != par_language->rightToLeft() &&
522                 // are we about to close the language?
523                 ((boost::next(pit) != paragraphs.end() &&
524                   par_language->babel() != 
525                         (boost::next(pit)->getParLanguage(bparams))->babel()) ||
526                  (boost::next(pit) == paragraphs.end() &&
527                   par_language->babel() != outer_language->babel()));
528
529         if (closing_rtl_ltr_environment || (boost::next(pit) == paragraphs.end()
530             && par_language->babel() != outer_language->babel())) {
531                 // Since \selectlanguage write the language to the aux file,
532                 // we need to reset the language at the end of footnote or
533                 // float.
534
535                 if (pending_newline) {
536                         os << '\n';
537                         texrow.newline();
538                 }
539                 if (lyxrc.language_command_end.empty()) {
540                         if (!prev_language->babel().empty()) {
541                                 os << from_ascii(subst(
542                                         lyxrc.language_command_begin,
543                                         "$$lang",
544                                         prev_language->babel()));
545                                 pending_newline = true;
546                         }
547                 } else if (!par_language->babel().empty()) {
548                         os << from_ascii(subst(
549                                 lyxrc.language_command_end,
550                                 "$$lang",
551                                 par_language->babel()));
552                         pending_newline = true;
553                 }
554         }
555         if (closing_rtl_ltr_environment)
556                 os << "}";
557
558         if (pending_newline) {
559                 os << '\n';
560                 texrow.newline();
561         }
562
563         // If this is the last paragraph, and a local_font was set upon entering
564         // the inset, the encoding should be set back to that local_font's 
565         // encoding. We don't use switchEncoding(), because no explicit encoding
566         // switch command is needed, since latex will automatically revert to it
567         // when this inset closes.
568         // This switch is only necessary if we're using "auto" or "default" 
569         // encoding. 
570         if (boost::next(pit) == paragraphs.end() && runparams_in.local_font != 0) {
571                 runparams_in.encoding = runparams_in.local_font->language()->encoding();
572                 if (bparams.inputenc == "auto" || bparams.inputenc == "default")
573                         os << setEncoding(runparams_in.encoding->iconvName());
574
575         }
576         // Otherwise, the current encoding should be set for the next paragraph.
577         else
578                 runparams_in.encoding = runparams.encoding;
579
580
581         // we don't need it for the last paragraph!!!
582         // Note from JMarc: we will re-add a \n explicitely in
583         // TeXEnvironment, because it is needed in this case
584         if (boost::next(pit) != paragraphs.end()) {
585                 os << '\n';
586                 texrow.newline();
587         }
588
589         if (boost::next(pit) != paragraphs.end()) {
590                 LYXERR(Debug::LATEX) << "TeXOnePar...done " << &*boost::next(pit) << endl;
591         }
592
593         return ++pit;
594 }
595
596 } // anon namespace
597
598
599 // LaTeX all paragraphs
600 void latexParagraphs(Buffer const & buf,
601                      ParagraphList const & paragraphs,
602                      odocstream & os,
603                      TexRow & texrow,
604                      OutputParams const & runparams,
605                      string const & everypar)
606 {
607         bool was_title = false;
608         bool already_title = false;
609         TextClass const & tclass = buf.params().getTextClass();
610         ParagraphList::const_iterator par = paragraphs.begin();
611         ParagraphList::const_iterator endpar = paragraphs.end();
612
613         BOOST_ASSERT(runparams.par_begin <= runparams.par_end);
614         // if only part of the paragraphs will be outputed
615         if (runparams.par_begin !=  runparams.par_end) {
616                 par = boost::next(paragraphs.begin(), runparams.par_begin);
617                 endpar = boost::next(paragraphs.begin(), runparams.par_end);
618                 // runparams will be passed to nested paragraphs, so
619                 // we have to reset the range parameters.
620                 const_cast<OutputParams&>(runparams).par_begin = 0;
621                 const_cast<OutputParams&>(runparams).par_end = 0;
622         }
623
624         // if only_body
625         while (par != endpar) {
626                 ParagraphList::const_iterator lastpar = par;
627                 // well we have to check if we are in an inset with unlimited
628                 // length (all in one row) if that is true then we don't allow
629                 // any special options in the paragraph and also we don't allow
630                 // any environment other than the default layout of the
631                 // text class to be valid!
632                 if (!par->forceDefaultParagraphs()) {
633                         LayoutPtr const & layout = par->layout();
634
635                         if (layout->intitle) {
636                                 if (already_title) {
637                                         lyxerr << "Error in latexParagraphs: You"
638                                                 " should not mix title layouts"
639                                                 " with normal ones." << endl;
640                                 } else if (!was_title) {
641                                         was_title = true;
642                                         if (tclass.titletype() == TITLE_ENVIRONMENT) {
643                                                 os << "\\begin{"
644                                                     << from_ascii(tclass.titlename())
645                                                     << "}\n";
646                                                 texrow.newline();
647                                         }
648                                 }
649                         } else if (was_title && !already_title) {
650                                 if (tclass.titletype() == TITLE_ENVIRONMENT) {
651                                         os << "\\end{" << from_ascii(tclass.titlename())
652                                             << "}\n";
653                                 }
654                                 else {
655                                         os << "\\" << from_ascii(tclass.titlename())
656                                             << "\n";
657                                 }
658                                 texrow.newline();
659                                 already_title = true;
660                                 was_title = false;
661                         }
662
663                         if (layout->is_environment) {
664                                 par = TeXOnePar(buf, paragraphs, par, os, texrow,
665                                                 runparams, everypar);
666                         } else if (layout->isEnvironment() ||
667                                    !par->params().leftIndent().zero()) {
668                                 par = TeXEnvironment(buf, paragraphs, par, os,
669                                                      texrow, runparams);
670                         } else {
671                                 par = TeXOnePar(buf, paragraphs, par, os, texrow,
672                                                 runparams, everypar);
673                         }
674                 } else {
675                         par = TeXOnePar(buf, paragraphs, par, os, texrow,
676                                         runparams, everypar);
677                 }
678                 if (std::distance(lastpar, par) >= std::distance(lastpar, endpar))
679                         break;
680         }
681         // It might be that we only have a title in this document
682         if (was_title && !already_title) {
683                 if (tclass.titletype() == TITLE_ENVIRONMENT) {
684                         os << "\\end{" << from_ascii(tclass.titlename())
685                             << "}\n";
686                 }
687                 else {
688                         os << "\\" << from_ascii(tclass.titlename())
689                             << "\n";
690                                 }
691                 texrow.newline();
692         }
693 }
694
695
696 pair<bool, int> switchEncoding(odocstream & os, BufferParams const & bparams,
697                    bool moving_arg, Encoding const & oldEnc,
698                    Encoding const & newEnc)
699 {
700         if ((bparams.inputenc != "auto" && bparams.inputenc != "default")
701                 || moving_arg)
702                 return make_pair(false, 0);
703
704         // Do nothing if the encoding is unchanged.
705         if (oldEnc.name() == newEnc.name())
706                 return make_pair(false, 0);
707
708         // FIXME We ignore encoding switches from/to encodings that do
709         // neither support the inputenc package nor the CJK package here.
710         // This does of course only work in special cases (e.g. switch from
711         // tis620-0 to latin1, but the text in latin1 contains ASCII only),
712         // but it is the best we can do
713         if (oldEnc.package() == Encoding::none
714                 || newEnc.package() == Encoding::none)
715                 return make_pair(false, 0);
716
717         LYXERR(Debug::LATEX) << "Changing LaTeX encoding from "
718                 << oldEnc.name() << " to "
719                 << newEnc.name() << endl;
720         os << setEncoding(newEnc.iconvName());
721         if (bparams.inputenc == "default")
722                 return make_pair(true, 0);
723
724         docstring const inputenc(from_ascii(newEnc.latexName()));
725         switch (newEnc.package()) {
726                 case Encoding::none:
727                         // shouldn't ever reach here, see above
728                         return make_pair(true, 0);
729                 case Encoding::inputenc: {
730                         int count = inputenc.length();
731                         if (oldEnc.package() == Encoding::CJK) {
732                                 os << "\\end{CJK}";
733                                 count += 9;
734                         }
735                         os << "\\inputencoding{" << inputenc << '}';
736                         return make_pair(true, count + 16);
737                  }
738                 case Encoding::CJK: {
739                         int count = inputenc.length();
740                         if (oldEnc.package() == Encoding::CJK) {
741                                 os << "\\end{CJK}";
742                                 count += 9;
743                         }
744                         os << "\\begin{CJK}{" << inputenc << "}{}";
745                         return make_pair(true, count + 15);
746                 }
747         }
748         // Dead code to avoid a warning:
749         return make_pair(true, 0);
750 }
751
752 } // namespace lyx