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