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