]> git.lyx.org Git - lyx.git/blob - src/output_latex.cpp
Fixed some lines that were too long. It compiled afterwards.
[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         Layout_ptr 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         return par;
213 }
214
215 }
216
217
218 int latexOptArgInsets(Buffer const & buf, Paragraph const & par,
219                       odocstream & os, OutputParams const & runparams, int number)
220 {
221         int lines = 0;
222
223         InsetList::const_iterator it = par.insetlist.begin();
224         InsetList::const_iterator end = par.insetlist.end();
225         for (; it != end && number > 0 ; ++it) {
226                 if (it->inset->lyxCode() == Inset::OPTARG_CODE) {
227                         InsetOptArg * ins =
228                                 static_cast<InsetOptArg *>(it->inset);
229                         lines += ins->latexOptional(buf, os, runparams);
230                         --number;
231                 }
232         }
233         return lines;
234 }
235
236
237 namespace {
238
239 ParagraphList::const_iterator
240 TeXOnePar(Buffer const & buf,
241           ParagraphList const & paragraphs,
242           ParagraphList::const_iterator pit,
243           odocstream & os, TexRow & texrow,
244           OutputParams const & runparams_in,
245           string const & everypar)
246 {
247         LYXERR(Debug::LATEX) << "TeXOnePar...     " << &*pit << " '"
248                 << everypar << "'" << endl;
249         BufferParams const & bparams = buf.params();
250         Layout_ptr style;
251
252         // In an inset with unlimited length (all in one row),
253         // force layout to default
254         if (!pit->forceDefaultParagraphs())
255                 style = pit->layout();
256         else
257                 style = bparams.getTextClass().defaultLayout();
258
259         OutputParams runparams = runparams_in;
260         runparams.moving_arg |= style->needprotect;
261
262         // This paragraph's language
263         Language const * const par_language = pit->getParLanguage(bparams);
264         // The document's language
265         Language const * const doc_language = bparams.language;
266         // The language that was in effect when the environemnt this paragraph is 
267         // inside of was opened
268         Language const * const outer_language = 
269                 (runparams.local_font != 0) ?
270                         runparams.local_font->language() : doc_language;
271         // The previous language that was in effect is either the language of
272         // the previous paragraph, if there is one, or else the outer language
273         // if there is no previous paragraph
274         Language const * const prev_language =
275                 (pit != paragraphs.begin()) ?
276                         boost::prior(pit)->getParLanguage(bparams) : outer_language;
277
278         if (par_language->babel() != prev_language->babel()
279             // check if we already put language command in TeXEnvironment()
280             && !(style->isEnvironment()
281                  && (pit == paragraphs.begin() ||
282                      (boost::prior(pit)->layout() != pit->layout() &&
283                       boost::prior(pit)->getDepth() <= pit->getDepth())
284                      || boost::prior(pit)->getDepth() < pit->getDepth())))
285         {
286                 if (!lyxrc.language_command_end.empty() &&
287                     prev_language->babel() != outer_language->babel() &&
288                     !prev_language->babel().empty())
289                 {
290                         os << from_ascii(subst(lyxrc.language_command_end,
291                                 "$$lang",
292                                 prev_language->babel()))
293                            << '\n';
294                         texrow.newline();
295                 }
296
297                 // We need to open a new language if we couldn't close the previous 
298                 // one (because there's no language_command_end); and even if we closed
299                 // the previous one, if the current language is different than the
300                 // outer_language (which is currently in effect once the previous one
301                 // is closed).
302                 if ((lyxrc.language_command_end.empty() ||
303                      par_language->babel() != outer_language->babel()) &&
304                     !par_language->babel().empty()) {
305                         // If we're inside an inset, and that inset is within an \L or \R
306                         // (or equivalents), then within the inset, too, any opposite
307                         // language paragraph should appear within an \L or \R (in addition
308                         // to, outside of, the normal language switch commands).
309                         // This behavior is not correct for ArabTeX, though.
310                         if (    // not for ArabTeX
311                                         (par_language->lang() != "arabic_arabtex" &&
312                                          outer_language->lang() != "arabic_arabtex") &&
313                                         // are we in an inset?
314                                         runparams.local_font != 0 &&
315                                         // is the inset within an \L or \R?
316                                         // 
317                                         // FIXME: currently, we don't check this; this means that
318                                         // we'll have unnnecessary \L and \R commands, but that 
319                                         // doesn't seem to hurt (though latex will complain)
320                                         // 
321                                         // is this paragraph in the opposite direction?
322                                         runparams.local_font->isRightToLeft() !=
323                                                 par_language->rightToLeft()
324                                 ) {
325                                 // FIXME: I don't have a working copy of the Arabi package, so
326                                 // I'm not sure if the farsi and arabic_arabi stuff is correct
327                                 // or not...
328                                 if (par_language->lang() == "farsi")
329                                         os << "\\textFR{";
330                                 else if (outer_language->lang() == "farsi")
331                                         os << "\\textLR{";
332                                 else if (par_language->lang() == "arabic_arabi")
333                                         os << "\\textAR{";
334                                 else if (outer_language->lang() == "arabic_arabi")
335                                         os << "\\textLR{";
336                                 // remaining RTL languages currently is hebrew
337                                 else if (par_language->rightToLeft())
338                                         os << "\\R{";
339                                 else
340                                         os << "\\L{";
341                         }
342                         os << from_ascii(subst(
343                                 lyxrc.language_command_begin,
344                                 "$$lang",
345                                 par_language->babel()))
346                            << '\n';
347                         texrow.newline();
348                 }
349         }
350
351         // Switch file encoding if necessary; no need to do this for "default"
352         // encoding, since this only affects the position of the outputted
353         // \inputencoding command; the encoding switch will occur when necessary
354         if (bparams.inputenc == "auto" &&
355             runparams.encoding->package() == Encoding::inputenc) {
356                 // Look ahead for future encoding changes.
357                 // We try to output them at the beginning of the paragraph,
358                 // since the \inputencoding command is not allowed e.g. in
359                 // sections.
360                 for (pos_type i = 0; i < pit->size(); ++i) {
361                         char_type const c = pit->getChar(i);
362                         if (c < 0x80)
363                                 continue;
364                         if (pit->isInset(i))
365                                 break;
366                         // All characters before c are in the ASCII range, and
367                         // c is non-ASCII (but no inset), so change the
368                         // encoding to that required by the language of c.
369                         Encoding const * const encoding =
370                                 pit->getFontSettings(bparams, i).language()->encoding();
371                         pair<bool, int> enc_switch = switchEncoding(os, bparams, false,
372                                         *(runparams.encoding), *encoding);
373                         if (encoding->package() == Encoding::inputenc && enc_switch.first) {
374                                 runparams.encoding = encoding;
375                                 if (enc_switch.second > 0) {
376                                         os << '\n';
377                                         texrow.newline();
378                                 }
379                         }
380                         break;
381                 }
382         }
383
384         // In an inset with unlimited length (all in one row),
385         // don't allow any special options in the paragraph
386         if (!pit->forceDefaultParagraphs()) {
387                 if (pit->params().startOfAppendix()) {
388                         os << "\\appendix\n";
389                         texrow.newline();
390                 }
391
392                 if (!pit->params().spacing().isDefault()
393                         && (pit == paragraphs.begin()
394                             || !boost::prior(pit)->hasSameLayout(*pit)))
395                 {
396                         os << from_ascii(pit->params().spacing().writeEnvirBegin())
397                             << '\n';
398                         texrow.newline();
399                 }
400
401                 if (style->isCommand()) {
402                         os << '\n';
403                         texrow.newline();
404                 }
405         }
406
407         switch (style->latextype) {
408         case LATEX_COMMAND:
409                 os << '\\' << from_ascii(style->latexname());
410
411                 // Separate handling of optional argument inset.
412                 if (style->optionalargs > 0) {
413                         int ret = latexOptArgInsets(buf, *pit, os, runparams,
414                                                     style->optionalargs);
415                         while (ret > 0) {
416                                 texrow.newline();
417                                 --ret;
418                         }
419                 }
420                 else
421                         os << from_ascii(style->latexparam());
422                 break;
423         case LATEX_ITEM_ENVIRONMENT:
424         case LATEX_LIST_ENVIRONMENT:
425                 os << "\\item ";
426                 break;
427         case LATEX_BIB_ENVIRONMENT:
428                 // ignore this, the inset will write itself
429                 break;
430         default:
431                 break;
432         }
433
434         Font const outerfont =
435                 outerFont(std::distance(paragraphs.begin(), pit),
436                           paragraphs);
437
438         // FIXME UNICODE
439         os << from_utf8(everypar);
440         bool need_par = pit->simpleTeXOnePar(buf, bparams, outerfont,
441                                              os, texrow, runparams);
442
443         // Make sure that \\par is done with the font of the last
444         // character if this has another size as the default.
445         // This is necessary because LaTeX (and LyX on the screen)
446         // calculates the space between the baselines according
447         // to this font. (Matthias)
448         //
449         // Is this really needed ? (Dekel)
450         // We do not need to use to change the font for the last paragraph
451         // or for a command.
452
453         Font const font =
454                 (pit->empty()
455                  ? pit->getLayoutFont(bparams, outerfont)
456                  : pit->getFont(bparams, pit->size() - 1, outerfont));
457
458         bool is_command = style->isCommand();
459
460         if (style->resfont.size() != font.size()
461             && boost::next(pit) != paragraphs.end()
462             && !is_command) {
463                 if (!need_par)
464                         os << '{';
465                 os << "\\" << from_ascii(font.latexSize()) << " \\par}";
466         } else if (need_par) {
467                 os << "\\par}";
468         } else if (is_command)
469                 os << '}';
470
471         bool pending_newline = false;
472         switch (style->latextype) {
473         case LATEX_ITEM_ENVIRONMENT:
474         case LATEX_LIST_ENVIRONMENT:
475                 if (boost::next(pit) != paragraphs.end()
476                     && (pit->params().depth() < boost::next(pit)->params().depth()))
477                         pending_newline = true;
478                 break;
479         case LATEX_ENVIRONMENT: {
480                 // if its the last paragraph of the current environment
481                 // skip it otherwise fall through
482                 ParagraphList::const_iterator next = boost::next(pit);
483
484                 if (next != paragraphs.end()
485                     && (next->layout() != pit->layout()
486                         || next->params().depth() != pit->params().depth()))
487                         break;
488         }
489
490                 // fall through possible
491         default:
492                 // we don't need it for the last paragraph!!!
493                 if (boost::next(pit) != paragraphs.end())
494                         pending_newline = true;
495         }
496
497         if (!pit->forceDefaultParagraphs()) {
498                 if (!pit->params().spacing().isDefault()
499                         && (boost::next(pit) == paragraphs.end()
500                             || !boost::next(pit)->hasSameLayout(*pit)))
501                 {
502                         if (pending_newline) {
503                                 os << '\n';
504                                 texrow.newline();
505                         }
506                         os << from_ascii(pit->params().spacing().writeEnvirEnd());
507                         pending_newline = true;
508                 }
509         }
510
511         // Closing the language is needed for the last paragraph; it is also
512         // needed if we're within an \L or \R that we may have opened above (not
513         // necessarily in this paragraph) and are about to close.
514         bool closing_rtl_ltr_environment = 
515                 // not for ArabTeX
516                 (par_language->lang() != "arabic_arabtex" &&
517                  outer_language->lang() != "arabic_arabtex") &&
518                 // have we opened and \L or \R environment?
519                 runparams.local_font != 0 &&
520                 runparams.local_font->isRightToLeft() != par_language->rightToLeft() &&
521                 // are we about to close the language?
522                 ((boost::next(pit) != paragraphs.end() &&
523                   par_language->babel() != 
524                         (boost::next(pit)->getParLanguage(bparams))->babel()) ||
525                  (boost::next(pit) == paragraphs.end() &&
526                   par_language->babel() != outer_language->babel()));
527
528         if (closing_rtl_ltr_environment || (boost::next(pit) == paragraphs.end()
529             && par_language->babel() != outer_language->babel())) {
530                 // Since \selectlanguage write the language to the aux file,
531                 // we need to reset the language at the end of footnote or
532                 // float.
533
534                 if (pending_newline) {
535                         os << '\n';
536                         texrow.newline();
537                 }
538                 if (lyxrc.language_command_end.empty()) {
539                         if (!prev_language->babel().empty()) {
540                                 os << from_ascii(subst(
541                                         lyxrc.language_command_begin,
542                                         "$$lang",
543                                         prev_language->babel()));
544                                 pending_newline = true;
545                         }
546                 } else if (!par_language->babel().empty()) {
547                         os << from_ascii(subst(
548                                 lyxrc.language_command_end,
549                                 "$$lang",
550                                 par_language->babel()));
551                         pending_newline = true;
552                 }
553         }
554         if (closing_rtl_ltr_environment)
555                 os << "}";
556
557         if (pending_newline) {
558                 os << '\n';
559                 texrow.newline();
560         }
561
562         // If this is the last paragraph, and a local_font was set upon entering
563         // the inset, the encoding should be set back to that local_font's 
564         // encoding. We don't use switchEncoding(), because no explicit encoding
565         // switch command is needed, since latex will automatically revert to it
566         // when this inset closes.
567         // This switch is only necessary if we're using "auto" or "default" 
568         // encoding. 
569         if (boost::next(pit) == paragraphs.end() && runparams_in.local_font != 0) {
570                 runparams_in.encoding = runparams_in.local_font->language()->encoding();
571                 if (bparams.inputenc == "auto" || bparams.inputenc == "default")
572                         os << setEncoding(runparams_in.encoding->iconvName());
573
574         }
575         // Otherwise, the current encoding should be set for the next paragraph.
576         else
577                 runparams_in.encoding = runparams.encoding;
578
579
580         // we don't need it for the last paragraph!!!
581         // Note from JMarc: we will re-add a \n explicitely in
582         // TeXEnvironment, because it is needed in this case
583         if (boost::next(pit) != paragraphs.end()) {
584                 os << '\n';
585                 texrow.newline();
586         }
587
588         if (boost::next(pit) != paragraphs.end())
589                 LYXERR(Debug::LATEX) << "TeXOnePar...done " << &*boost::next(pit) << endl;
590
591         return ++pit;
592 }
593
594 } // anon namespace
595
596
597 // LaTeX all paragraphs
598 void latexParagraphs(Buffer const & buf,
599                      ParagraphList const & paragraphs,
600                      odocstream & os,
601                      TexRow & texrow,
602                      OutputParams const & runparams,
603                      string const & everypar)
604 {
605         bool was_title = false;
606         bool already_title = false;
607         TextClass const & tclass = buf.params().getTextClass();
608         ParagraphList::const_iterator par = paragraphs.begin();
609         ParagraphList::const_iterator endpar = paragraphs.end();
610
611         BOOST_ASSERT(runparams.par_begin <= runparams.par_end);
612         // if only part of the paragraphs will be outputed
613         if (runparams.par_begin !=  runparams.par_end) {
614                 par = boost::next(paragraphs.begin(), runparams.par_begin);
615                 endpar = boost::next(paragraphs.begin(), runparams.par_end);
616                 // runparams will be passed to nested paragraphs, so
617                 // we have to reset the range parameters.
618                 const_cast<OutputParams&>(runparams).par_begin = 0;
619                 const_cast<OutputParams&>(runparams).par_end = 0;
620         }
621
622         // if only_body
623         while (par != endpar) {
624                 ParagraphList::const_iterator lastpar = par;
625                 // well we have to check if we are in an inset with unlimited
626                 // length (all in one row) if that is true then we don't allow
627                 // any special options in the paragraph and also we don't allow
628                 // any environment other than the default layout of the
629                 // text class to be valid!
630                 if (!par->forceDefaultParagraphs()) {
631                         Layout_ptr const & layout = par->layout();
632
633                         if (layout->intitle) {
634                                 if (already_title) {
635                                         lyxerr << "Error in latexParagraphs: You"
636                                                 " should not mix title layouts"
637                                                 " with normal ones." << endl;
638                                 } else if (!was_title) {
639                                         was_title = true;
640                                         if (tclass.titletype() == TITLE_ENVIRONMENT) {
641                                                 os << "\\begin{"
642                                                     << from_ascii(tclass.titlename())
643                                                     << "}\n";
644                                                 texrow.newline();
645                                         }
646                                 }
647                         } else if (was_title && !already_title) {
648                                 if (tclass.titletype() == TITLE_ENVIRONMENT) {
649                                         os << "\\end{" << from_ascii(tclass.titlename())
650                                             << "}\n";
651                                 }
652                                 else {
653                                         os << "\\" << from_ascii(tclass.titlename())
654                                             << "\n";
655                                 }
656                                 texrow.newline();
657                                 already_title = true;
658                                 was_title = false;
659                         }
660
661                         if (layout->is_environment) {
662                                 par = TeXOnePar(buf, paragraphs, par, os, texrow,
663                                                 runparams, everypar);
664                         } else if (layout->isEnvironment() ||
665                                    !par->params().leftIndent().zero()) {
666                                 par = TeXEnvironment(buf, paragraphs, par, os,
667                                                      texrow, runparams);
668                         } else {
669                                 par = TeXOnePar(buf, paragraphs, par, os, texrow,
670                                                 runparams, everypar);
671                         }
672                 } else {
673                         par = TeXOnePar(buf, paragraphs, par, os, texrow,
674                                         runparams, everypar);
675                 }
676                 if (std::distance(lastpar, par) >= std::distance(lastpar, endpar))
677                         break;
678         }
679         // It might be that we only have a title in this document
680         if (was_title && !already_title) {
681                 if (tclass.titletype() == TITLE_ENVIRONMENT) {
682                         os << "\\end{" << from_ascii(tclass.titlename())
683                             << "}\n";
684                 }
685                 else {
686                         os << "\\" << from_ascii(tclass.titlename())
687                             << "\n";
688                                 }
689                 texrow.newline();
690         }
691 }
692
693
694 pair<bool, int> switchEncoding(odocstream & os, BufferParams const & bparams,
695                    bool moving_arg, Encoding const & oldEnc,
696                    Encoding const & newEnc)
697 {
698         if ((bparams.inputenc != "auto" && bparams.inputenc != "default")
699                 || moving_arg)
700                 return make_pair(false, 0);
701
702         // Do nothing if the encoding is unchanged.
703         if (oldEnc.name() == newEnc.name())
704                 return make_pair(false, 0);
705
706         // FIXME We ignore encoding switches from/to encodings that do
707         // neither support the inputenc package nor the CJK package here.
708         // This does of course only work in special cases (e.g. switch from
709         // tis620-0 to latin1, but the text in latin1 contains ASCII only),
710         // but it is the best we can do
711         if (oldEnc.package() == Encoding::none
712                 || newEnc.package() == Encoding::none)
713                 return make_pair(false, 0);
714
715         LYXERR(Debug::LATEX) << "Changing LaTeX encoding from "
716                 << oldEnc.name() << " to "
717                 << newEnc.name() << endl;
718         os << setEncoding(newEnc.iconvName());
719         if (bparams.inputenc == "default")
720                 return make_pair(true, 0);
721
722         docstring const inputenc(from_ascii(newEnc.latexName()));
723         switch (newEnc.package()) {
724                 case Encoding::none:
725                         // shouldn't ever reach here, see above
726                         return make_pair(true, 0);
727                 case Encoding::inputenc: {
728                         int count = inputenc.length();
729                         if (oldEnc.package() == Encoding::CJK) {
730                                 os << "\\end{CJK}";
731                                 count += 9;
732                         }
733                         os << "\\inputencoding{" << inputenc << '}';
734                         return make_pair(true, count + 16);
735                  }
736                 case Encoding::CJK: {
737                         int count = inputenc.length();
738                         if (oldEnc.package() == Encoding::CJK) {
739                                 os << "\\end{CJK}";
740                                 count += 9;
741                         }
742                         os << "\\begin{CJK}{" << inputenc << "}{}";
743                         return make_pair(true, count + 15);
744                 }
745         }
746         // Dead code to avoid a warning:
747         return make_pair(true, 0);
748 }
749
750 } // namespace lyx