]> git.lyx.org Git - features.git/blob - src/output_latex.cpp
Output a parbreak after a command.
[features.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 "Encoding.h"
18 #include "Font.h"
19 #include "InsetList.h"
20 #include "Language.h"
21 #include "Layout.h"
22 #include "LyXRC.h"
23 #include "OutputParams.h"
24 #include "Paragraph.h"
25 #include "ParagraphParameters.h"
26 #include "TextClass.h"
27 #include "TexRow.h"
28
29 #include "insets/InsetBibitem.h"
30 #include "insets/InsetArgument.h"
31
32 #include "support/lassert.h"
33 #include "support/convert.h"
34 #include "support/debug.h"
35 #include "support/lstrings.h"
36 #include "support/textutils.h"
37
38 #include <algorithm>
39 #include <boost/next_prior.hpp>
40 #include <list>
41
42 using namespace std;
43 using namespace lyx::support;
44
45
46 namespace lyx {
47
48 namespace {
49
50 enum OpenEncoding {
51         none,
52         inputenc,
53         CJK
54 };
55
56 // FIXME THREAD
57 // There could easily be a conflict here, with the export process
58 // setting this one way, and a View>Source process (possbily for
59 // another Buffer) resetting it.
60 static int open_encoding_ = none;
61 static int cjk_inherited_ = 0;
62 Language const * prev_env_language_ = 0;
63
64
65 string const getPolyglossiaEnvName(Language const * lang)
66 {
67         string result = lang->polyglossia();
68         if (result == "arabic")
69                 // exceptional spelling; see polyglossia docs.
70                 result = "Arabic";
71         return result;
72 }
73
74
75 struct TeXEnvironmentData
76 {
77         bool cjk_nested;
78         Layout const * style;
79         Language const * par_language;
80         Encoding const * prev_encoding;
81         bool leftindent_open;
82 };
83
84
85 static TeXEnvironmentData prepareEnvironment(Buffer const & buf,
86                                         Text const & text,
87                                         ParagraphList::const_iterator pit,
88                                         otexstream & os,
89                                         OutputParams const & runparams)
90 {
91         TeXEnvironmentData data;
92
93         BufferParams const & bparams = buf.params();
94
95         // FIXME This test should not be necessary.
96         // We should perhaps issue an error if it is.
97         Layout const & style = text.inset().forcePlainLayout() ?
98                 bparams.documentClass().plainLayout() : pit->layout();
99
100         ParagraphList const & paragraphs = text.paragraphs();
101         ParagraphList::const_iterator const priorpit =
102                 pit == paragraphs.begin() ? pit : boost::prior(pit);
103
104         bool const use_prev_env_language = prev_env_language_ != 0
105                         && priorpit->layout().isEnvironment()
106                         && (priorpit->getDepth() > pit->getDepth()
107                             || (priorpit->getDepth() == pit->getDepth()
108                                 && priorpit->layout() != pit->layout()));
109
110         data.prev_encoding = runparams.encoding;
111         data.par_language = pit->getParLanguage(bparams);
112         Language const * const doc_language = bparams.language;
113         Language const * const prev_par_language =
114                 (pit != paragraphs.begin())
115                 ? (use_prev_env_language ? prev_env_language_
116                                          : priorpit->getParLanguage(bparams))
117                 : doc_language;
118
119         bool const use_polyglossia = runparams.use_polyglossia;
120         string const par_lang = use_polyglossia ?
121                 getPolyglossiaEnvName(data.par_language) : data.par_language->babel();
122         string const prev_par_lang = use_polyglossia ?
123                 getPolyglossiaEnvName(prev_par_language) : prev_par_language->babel();
124         string const doc_lang = use_polyglossia ?
125                 getPolyglossiaEnvName(doc_language) : doc_language->babel();
126         string const lang_begin_command = use_polyglossia ?
127                 "\\begin{$$lang}" : lyxrc.language_command_begin;
128         string const lang_end_command = use_polyglossia ?
129                 "\\end{$$lang}" : lyxrc.language_command_end;
130
131         if (par_lang != prev_par_lang) {
132                 if (!lang_end_command.empty() &&
133                     prev_par_lang != doc_lang &&
134                     !prev_par_lang.empty()) {
135                         os << from_ascii(subst(
136                                 lang_end_command,
137                                 "$$lang",
138                                 prev_par_lang))
139                           // the '%' is necessary to prevent unwanted whitespace
140                           << "%\n";
141                 }
142
143                 if ((lang_end_command.empty() ||
144                     par_lang != doc_lang) &&
145                     !par_lang.empty()) {
146                         os << from_ascii(subst(
147                                 lang_begin_command,
148                                 "$$lang",
149                                 par_lang));
150                         if (use_polyglossia
151                             && !data.par_language->polyglossiaOpts().empty())
152                                         os << "["
153                                            << from_ascii(data.par_language->polyglossiaOpts())
154                                            << "]";
155                           // the '%' is necessary to prevent unwanted whitespace
156                         os << "%\n";
157                 }
158         }
159
160         data.leftindent_open = false;
161         if (!pit->params().leftIndent().zero()) {
162                 os << "\\begin{LyXParagraphLeftIndent}{"
163                    << from_ascii(pit->params().leftIndent().asLatexString())
164                    << "}\n";
165                 data.leftindent_open = true;
166         }
167
168         if (style.isEnvironment()) {
169                 os << "\\begin{" << from_ascii(style.latexname()) << '}';
170                 if (!style.latexargs().empty()) {
171                         OutputParams rp = runparams;
172                         rp.local_font = &pit->getFirstFontSettings(bparams);
173                         latexArgInsets(paragraphs, pit, os, rp, style.latexargs());
174                 }
175                 if (style.latextype == LATEX_LIST_ENVIRONMENT) {
176                         os << '{'
177                            << pit->params().labelWidthString()
178                            << "}\n";
179                 } else if (style.labeltype == LABEL_BIBLIO) {
180                         if (pit->params().labelWidthString().empty())
181                                 os << '{' << bibitemWidest(buf, runparams) << "}\n";
182                         else
183                                 os << '{'
184                                   << pit->params().labelWidthString()
185                                   << "}\n";
186                 } else
187                         os << from_ascii(style.latexparam()) << '\n';
188         }
189         data.style = &style;
190
191         // in multilingual environments, the CJK tags have to be nested properly
192         data.cjk_nested = false;
193         if (data.par_language->encoding()->package() == Encoding::CJK &&
194             open_encoding_ != CJK && pit->isMultiLingual(bparams)) {
195                 if (prev_par_language->encoding()->package() == Encoding::CJK)
196                         os << "\\begin{CJK}{" << from_ascii(data.par_language->encoding()->latexName())
197                            << "}{" << from_ascii(bparams.fonts_cjk) << "}%\n";
198                 open_encoding_ = CJK;
199                 data.cjk_nested = true;
200         }
201         return data;
202 }
203
204
205 static void finishEnvironment(otexstream & os, OutputParams const & runparams,
206                                TeXEnvironmentData const & data)
207 {
208         if (open_encoding_ == CJK && data.cjk_nested) {
209                 // We need to close the encoding even if it does not change
210                 // to do correct environment nesting
211                 os << "\\end{CJK}\n";
212                 open_encoding_ = none;
213         }
214
215         if (data.style->isEnvironment()) {
216                 os << breakln
217                    << "\\end{" << from_ascii(data.style->latexname()) << "}\n";
218                 prev_env_language_ = data.par_language;
219                 if (runparams.encoding != data.prev_encoding) {
220                         runparams.encoding = data.prev_encoding;
221                         if (!runparams.isFullUnicode())
222                                 os << setEncoding(data.prev_encoding->iconvName());
223                 }
224         }
225
226         if (data.leftindent_open) {
227                 os << breakln << "\\end{LyXParagraphLeftIndent}\n";
228                 prev_env_language_ = data.par_language;
229                 if (runparams.encoding != data.prev_encoding) {
230                         runparams.encoding = data.prev_encoding;
231                         if (!runparams.isFullUnicode())
232                                 os << setEncoding(data.prev_encoding->iconvName());
233                 }
234         }
235 }
236
237
238 void TeXEnvironment(Buffer const & buf, Text const & text,
239                     OutputParams const & runparams,
240                     pit_type & pit, otexstream & os)
241 {
242         ParagraphList const & paragraphs = text.paragraphs();
243         ParagraphList::const_iterator par = paragraphs.constIterator(pit);
244         LYXERR(Debug::LATEX, "TeXEnvironment for paragraph " << pit);
245
246         Layout const & current_layout = par->layout();
247         depth_type const current_depth = par->params().depth();
248         Length const & current_left_indent = par->params().leftIndent();
249
250         // This is for debugging purpose at the end.
251         pit_type const par_begin = pit;
252         for (; pit < runparams.par_end; ++pit) {
253                 ParagraphList::const_iterator par = paragraphs.constIterator(pit);
254
255                 // check first if this is an higher depth paragraph.
256                 bool go_out = (par->params().depth() < current_depth);
257                 if (par->params().depth() == current_depth) {
258                         // This environment is finished.
259                         go_out |= (par->layout() != current_layout);
260                         go_out |= (par->params().leftIndent() != current_left_indent);
261                 }
262                 if (go_out) {
263                         // nothing to do here, restore pit and go out.
264                         pit--;
265                         break;
266                 }
267
268                 if (par->layout() == current_layout
269                         && par->params().depth() == current_depth
270                         && par->params().leftIndent() == current_left_indent) {
271                         // We are still in the same environment so TeXOnePar and continue;
272                         TeXOnePar(buf, text, pit, os, runparams);
273                         continue;
274                 }
275
276                 // We are now in a deeper environment.
277                 // Either par->layout() != current_layout
278                 // Or     par->params().depth() > current_depth
279                 // Or     par->params().leftIndent() != current_left_indent)
280
281                 // FIXME This test should not be necessary.
282                 // We should perhaps issue an error if it is.
283                 bool const force_plain_layout = text.inset().forcePlainLayout();
284                 Layout const & style = force_plain_layout
285                         ? buf.params().documentClass().plainLayout()
286                         : par->layout();
287
288                 if (!style.isEnvironment()) {
289                         // This is a standard paragraph, no need to call TeXEnvironment.
290                         TeXOnePar(buf, text, pit, os, runparams);
291                         continue;
292                 }
293
294                 // This is a new environment.
295                 TeXEnvironmentData const data =
296                         prepareEnvironment(buf, text, par, os, runparams);
297                 // Recursive call to TeXEnvironment!
298                 TeXEnvironment(buf, text, runparams, pit, os);
299                 finishEnvironment(os, runparams, data);
300         }
301
302         if (pit != runparams.par_end)
303                 LYXERR(Debug::LATEX, "TeXEnvironment for paragraph " << par_begin << " done.");
304 }
305
306
307 void getArgInsets(otexstream & os, OutputParams const & runparams, Layout::LaTeXArgMap const & latexargs,
308                   map<int, lyx::InsetArgument const *> ilist, vector<string> required, string const & prefix)
309 {
310         unsigned int const argnr = latexargs.size();
311         if (argnr == 0)
312                 return;
313
314         for (unsigned int i = 1; i <= argnr; ++i) {
315                 map<int, InsetArgument const *>::const_iterator lit = ilist.find(i);
316                 bool inserted = false;
317                 if (lit != ilist.end()) {
318                         InsetArgument const * ins = (*lit).second;
319                         if (ins) {
320                                 Layout::LaTeXArgMap::const_iterator const lait =
321                                                 latexargs.find(ins->name());
322                                 if (lait != latexargs.end()) {
323                                         Layout::latexarg arg = (*lait).second;
324                                         docstring ldelim = arg.mandatory ?
325                                                         from_ascii("{") : from_ascii("[");
326                                         docstring rdelim = arg.mandatory ?
327                                                         from_ascii("}") : from_ascii("]");
328                                         if (!arg.ldelim.empty())
329                                                 ldelim = arg.ldelim;
330                                         if (!arg.rdelim.empty())
331                                                 rdelim = arg.rdelim;
332                                         ins->latexArgument(os, runparams, ldelim, rdelim, arg.presetarg);
333                                         inserted = true;
334                                 }
335                         }
336                 }
337                 if (!inserted) {
338                         Layout::LaTeXArgMap::const_iterator lait = latexargs.begin();
339                         Layout::LaTeXArgMap::const_iterator const laend = latexargs.end();
340                         for (; lait != laend; ++lait) {
341                                 string const name = prefix + convert<string>(i);
342                                 if ((*lait).first == name) {
343                                         Layout::latexarg arg = (*lait).second;
344                                         docstring preset = arg.presetarg;
345                                         if (!arg.defaultarg.empty()) {
346                                                 if (!preset.empty())
347                                                         preset += ",";
348                                                 preset += arg.defaultarg;
349                                         }
350                                         if (arg.mandatory) {
351                                                 docstring ldelim = arg.ldelim.empty() ?
352                                                                 from_ascii("{") : arg.ldelim;
353                                                 docstring rdelim = arg.rdelim.empty() ?
354                                                                 from_ascii("}") : arg.rdelim;
355                                                 os << ldelim << preset << rdelim;
356                                         } else if (!preset.empty()) {
357                                                 docstring ldelim = arg.ldelim.empty() ?
358                                                                 from_ascii("[") : arg.ldelim;
359                                                 docstring rdelim = arg.rdelim.empty() ?
360                                                                 from_ascii("]") : arg.rdelim;
361                                                 os << ldelim << preset << rdelim;
362                                         } else if (find(required.begin(), required.end(),
363                                                    (*lait).first) != required.end()) {
364                                                 docstring ldelim = arg.ldelim.empty() ?
365                                                                 from_ascii("[") : arg.ldelim;
366                                                 docstring rdelim = arg.rdelim.empty() ?
367                                                                 from_ascii("]") : arg.rdelim;
368                                                 os << ldelim << rdelim;
369                                         } else
370                                                 break;
371                                 }
372                         }
373                 }
374         }
375 }
376
377
378 } // namespace anon
379
380
381 void latexArgInsets(Paragraph const & par, otexstream & os,
382         OutputParams const & runparams, Layout::LaTeXArgMap const & latexargs, string const & prefix)
383 {
384         map<int, InsetArgument const *> ilist;
385         vector<string> required;
386
387         InsetList::const_iterator it = par.insetList().begin();
388         InsetList::const_iterator end = par.insetList().end();
389         for (; it != end; ++it) {
390                 if (it->inset->lyxCode() == ARG_CODE) {
391                         InsetArgument const * ins =
392                                 static_cast<InsetArgument const *>(it->inset);
393                         if (ins->name().empty())
394                                 LYXERR0("Error: Unnamed argument inset!");
395                         else {
396                                 string const name = prefix.empty() ? ins->name() : split(ins->name(), ':');
397                                 unsigned int const nr = convert<unsigned int>(name);
398                                 ilist[nr] = ins;
399                                 Layout::LaTeXArgMap::const_iterator const lit =
400                                                 latexargs.find(ins->name());
401                                 if (lit != latexargs.end()) {
402                                         Layout::latexarg const & arg = (*lit).second;
403                                         if (!arg.requires.empty()) {
404                                                 vector<string> req = getVectorFromString(arg.requires);
405                                                 required.insert(required.end(), req.begin(), req.end());
406                                         }
407                                 }
408                         }
409                 }
410         }
411         getArgInsets(os, runparams, latexargs, ilist, required, prefix);
412 }
413
414
415 void latexArgInsets(ParagraphList const & pars, ParagraphList::const_iterator pit,
416         otexstream & os, OutputParams const & runparams, Layout::LaTeXArgMap const & latexargs,
417         string const & prefix)
418 {
419         map<int, InsetArgument const *> ilist;
420         vector<string> required;
421
422         depth_type const current_depth = pit->params().depth();
423         Layout const current_layout = pit->layout();
424
425         // get the first paragraph in sequence with this layout and depth
426         pit_type offset = 0;
427         while (true) {
428                 if (boost::prior(pit, offset) == pars.begin())
429                         break;
430                 ParagraphList::const_iterator priorpit = boost::prior(pit, offset + 1);
431                 if (priorpit->layout() == current_layout
432                     && priorpit->params().depth() == current_depth)
433                         ++offset;
434                 else
435                         break;
436         }
437
438         ParagraphList::const_iterator spit = boost::prior(pit, offset);
439
440         for (; spit != pars.end(); ++spit) {
441                 if (spit->layout() != current_layout || spit->params().depth() < current_depth)
442                         break;
443                 if (spit->params().depth() > current_depth)
444                         continue;
445                 InsetList::const_iterator it = spit->insetList().begin();
446                 InsetList::const_iterator end = spit->insetList().end();
447                 for (; it != end; ++it) {
448                         if (it->inset->lyxCode() == ARG_CODE) {
449                                 InsetArgument const * ins =
450                                         static_cast<InsetArgument const *>(it->inset);
451                                 if (ins->name().empty())
452                                         LYXERR0("Error: Unnamed argument inset!");
453                                 else {
454                                         string const name = prefix.empty() ? ins->name() : split(ins->name(), ':');
455                                         unsigned int const nr = convert<unsigned int>(name);
456                                         if (ilist.find(nr) == ilist.end())
457                                                 ilist[nr] = ins;
458                                         Layout::LaTeXArgMap::const_iterator const lit =
459                                                         latexargs.find(ins->name());
460                                         if (lit != latexargs.end()) {
461                                                 Layout::latexarg const & arg = (*lit).second;
462                                                 if (!arg.requires.empty()) {
463                                                         vector<string> req = getVectorFromString(arg.requires);
464                                                         required.insert(required.end(), req.begin(), req.end());
465                                                 }
466                                         }
467                                 }
468                         }
469                 }
470         }
471         getArgInsets(os, runparams, latexargs, ilist, required, prefix);
472 }
473
474 namespace {
475
476 // output the proper paragraph start according to latextype.
477 void parStartCommand(Paragraph const & par, otexstream & os,
478                      OutputParams const & runparams, Layout const & style) 
479 {
480         switch (style.latextype) {
481         case LATEX_COMMAND:
482                 os << '\\' << from_ascii(style.latexname());
483
484                 // Command arguments
485                 if (!style.latexargs().empty())
486                         latexArgInsets(par, os, runparams, style.latexargs());
487                 os << from_ascii(style.latexparam());
488                 break;
489         case LATEX_ITEM_ENVIRONMENT:
490         case LATEX_LIST_ENVIRONMENT:
491                 os << "\\" + style.itemcommand();
492                 // Item arguments
493                 if (!style.itemargs().empty())
494                         latexArgInsets(par, os, runparams, style.itemargs(), "item:");
495                 os << " ";
496                 break;
497         case LATEX_BIB_ENVIRONMENT:
498                 // ignore this, the inset will write itself
499                 break;
500         default:
501                 break;
502         }
503 }
504
505 } // namespace anon
506
507 // FIXME: this should be anonymous
508 void TeXOnePar(Buffer const & buf,
509                Text const & text,
510                pit_type pit,
511                otexstream & os,
512                OutputParams const & runparams_in,
513                string const & everypar,
514                int start_pos, int end_pos)
515 {
516         BufferParams const & bparams = runparams_in.is_child
517                 ? buf.masterParams() : buf.params();
518         ParagraphList const & paragraphs = text.paragraphs();
519         Paragraph const & par = paragraphs.at(pit);
520         // FIXME This check should not really be needed.
521         // Perhaps we should issue an error if it is.
522         Layout const style = text.inset().forcePlainLayout() ?
523                 bparams.documentClass().plainLayout() : par.layout();
524
525         if (style.inpreamble)
526                 return;
527
528         LYXERR(Debug::LATEX, "TeXOnePar for paragraph " << pit << " ptr " << &par << " '"
529                 << everypar << "'");
530
531         OutputParams runparams = runparams_in;
532         runparams.isLastPar = (pit == pit_type(paragraphs.size() - 1));
533         // We reinitialze par begin and end to be on the safe side
534         // with embedded inset as we don't know if they set those
535         // value correctly.
536         runparams.par_begin = 0;
537         runparams.par_end = 0;
538
539         bool const maintext = text.isMainText();
540         // we are at the beginning of an inset and CJK is already open;
541         // we count inheritation levels to get the inset nesting right.
542         if (pit == 0 && !maintext
543             && (cjk_inherited_ > 0 || open_encoding_ == CJK)) {
544                 cjk_inherited_ += 1;
545                 open_encoding_ = none;
546         }
547
548         if (text.inset().isPassThru()) {
549                 Font const outerfont = text.outerFont(pit);
550
551                 // No newline before first paragraph in this lyxtext
552                 if (pit > 0) {
553                         os << '\n';
554                         if (!text.inset().getLayout().parbreakIsNewline())
555                                 os << '\n';
556                 }
557
558                 par.latex(bparams, outerfont, os, runparams, start_pos, end_pos);
559                 return;
560         }
561
562         Paragraph const * nextpar = runparams.isLastPar
563                 ? 0 : &paragraphs.at(pit + 1);
564
565         if (style.pass_thru) {
566                 Font const outerfont = text.outerFont(pit);
567                 parStartCommand(par, os, runparams, style);
568
569                 par.latex(bparams, outerfont, os, runparams, start_pos, end_pos);
570
571                 // I did not create a parEndCommand for this minuscule
572                 // task because in the other user of parStartCommand
573                 // the code is different (JMarc)
574                 if (style.isCommand())
575                         os << "}\n";
576                 else
577                         os << '\n';
578                 if (!style.parbreak_is_newline) {
579                         os << '\n';
580                 } else if (nextpar && !style.isEnvironment()) {
581                         Layout const nextstyle = text.inset().forcePlainLayout()
582                                 ? bparams.documentClass().plainLayout()
583                                 : nextpar->layout();
584                         if (nextstyle.name() != style.name())
585                                 os << '\n';
586                 }
587
588                 return;
589         }
590
591         // This paragraph's language
592         Language const * const par_language = par.getParLanguage(bparams);
593         // The document's language
594         Language const * const doc_language = bparams.language;
595         // The language that was in effect when the environment this paragraph is
596         // inside of was opened
597         Language const * const outer_language =
598                 (runparams.local_font != 0) ?
599                         runparams.local_font->language() : doc_language;
600
601         Paragraph const * priorpar = (pit == 0) ? 0 : &paragraphs.at(pit - 1);
602
603         // The previous language that was in effect is the language of the
604         // previous paragraph, unless the previous paragraph is inside an
605         // environment with nesting depth greater than (or equal to, but with
606         // a different layout) the current one. If there is no previous
607         // paragraph, the previous language is the outer language.
608         bool const use_prev_env_language = prev_env_language_ != 0
609                         && priorpar
610                         && priorpar->layout().isEnvironment()
611                         && (priorpar->getDepth() > par.getDepth()
612                             || (priorpar->getDepth() == par.getDepth()
613                                     && priorpar->layout() != par.layout()));
614         Language const * const prev_language =
615                 (pit != 0)
616                 ? (use_prev_env_language ? prev_env_language_
617                                          : priorpar->getParLanguage(bparams))
618                 : outer_language;
619
620
621         bool const use_polyglossia = runparams.use_polyglossia;
622         string const par_lang = use_polyglossia ?
623                 getPolyglossiaEnvName(par_language): par_language->babel();
624         string const prev_lang = use_polyglossia ?
625                 getPolyglossiaEnvName(prev_language) : prev_language->babel();
626         string const doc_lang = use_polyglossia ?
627                 getPolyglossiaEnvName(doc_language) : doc_language->babel();
628         string const outer_lang = use_polyglossia ?
629                 getPolyglossiaEnvName(outer_language) : outer_language->babel();
630         string lang_begin_command = use_polyglossia ?
631                 "\\begin{$$lang}" : lyxrc.language_command_begin;
632         string lang_end_command = use_polyglossia ?
633                 "\\end{$$lang}" : lyxrc.language_command_end;
634         // the '%' is necessary to prevent unwanted whitespace
635         string lang_command_termination = "%\n";
636
637         // In some insets (such as Arguments), we cannot use \selectlanguage
638         bool const localswitch = !use_polyglossia
639                 && text.inset().getLayout().forcelocalfontswitch();
640         if (localswitch) {
641                 lang_begin_command = lyxrc.language_command_local;
642                 lang_end_command = "}";
643                 lang_command_termination.clear();
644         }
645
646         if (par_lang != prev_lang
647                 // check if we already put language command in TeXEnvironment()
648                 && !(style.isEnvironment()
649                      && (pit == 0 || (priorpar->layout() != par.layout()
650                                           && priorpar->getDepth() <= par.getDepth())
651                                   || priorpar->getDepth() < par.getDepth())))
652         {
653                 if (!lang_end_command.empty() &&
654                     prev_lang != outer_lang &&
655                     !prev_lang.empty())
656                 {
657                         os << from_ascii(subst(lang_end_command,
658                                 "$$lang",
659                                 prev_lang))
660                            << lang_command_termination;
661                 }
662
663                 // We need to open a new language if we couldn't close the previous
664                 // one (because there's no language_command_end); and even if we closed
665                 // the previous one, if the current language is different than the
666                 // outer_language (which is currently in effect once the previous one
667                 // is closed).
668                 if ((lang_end_command.empty() || par_lang != outer_lang)
669                         && !par_lang.empty()) {
670                         // If we're inside an inset, and that inset is within an \L or \R
671                         // (or equivalents), then within the inset, too, any opposite
672                         // language paragraph should appear within an \L or \R (in addition
673                         // to, outside of, the normal language switch commands).
674                         // This behavior is not correct for ArabTeX, though.
675                         if (!use_polyglossia
676                             // not for ArabTeX
677                                 && par_language->lang() != "arabic_arabtex"
678                                 && outer_language->lang() != "arabic_arabtex"
679                             // are we in an inset?
680                             && runparams.local_font != 0
681                             // is the inset within an \L or \R?
682                             //
683                             // FIXME: currently, we don't check this; this means that
684                             // we'll have unnnecessary \L and \R commands, but that
685                             // doesn't seem to hurt (though latex will complain)
686                             //
687                             // is this paragraph in the opposite direction?
688                             && runparams.local_font->isRightToLeft() != par_language->rightToLeft()) {
689                                 // FIXME: I don't have a working copy of the Arabi package, so
690                                 // I'm not sure if the farsi and arabic_arabi stuff is correct
691                                 // or not...
692                                 if (par_language->lang() == "farsi")
693                                         os << "\\textFR{";
694                                 else if (outer_language->lang() == "farsi")
695                                         os << "\\textLR{";
696                                 else if (par_language->lang() == "arabic_arabi")
697                                         os << "\\textAR{";
698                                 else if (outer_language->lang() == "arabic_arabi")
699                                         os << "\\textLR{";
700                                 // remaining RTL languages currently is hebrew
701                                 else if (par_language->rightToLeft())
702                                         os << "\\R{";
703                                 else
704                                         os << "\\L{";
705                         }
706                         // With CJK, the CJK tag has to be closed first (see below)
707                         if (runparams.encoding->package() != Encoding::CJK
708                             && !par_lang.empty()) {
709                                 os << from_ascii(subst(
710                                         lang_begin_command,
711                                         "$$lang",
712                                         par_lang));
713                                 if (use_polyglossia
714                                     && !par_language->polyglossiaOpts().empty())
715                                                 os << "["
716                                                   << from_ascii(par_language->polyglossiaOpts())
717                                                   << "]";
718                                 os << lang_command_termination;
719                         }
720                 }
721         }
722
723         // Switch file encoding if necessary; no need to do this for "default"
724         // encoding, since this only affects the position of the outputted
725         // \inputencoding command; the encoding switch will occur when necessary
726         if (bparams.inputenc == "auto"
727                 && runparams.encoding->package() != Encoding::none) {
728                 // Look ahead for future encoding changes.
729                 // We try to output them at the beginning of the paragraph,
730                 // since the \inputencoding command is not allowed e.g. in
731                 // sections. For this reason we only set runparams.moving_arg
732                 // after checking for the encoding change, otherwise the
733                 // change would be always avoided by switchEncoding().
734                 for (pos_type i = 0; i < par.size(); ++i) {
735                         char_type const c = par.getChar(i);
736                         Encoding const * const encoding =
737                                 par.getFontSettings(bparams, i).language()->encoding();
738                         if (encoding->package() != Encoding::CJK
739                                 && runparams.encoding->package() == Encoding::inputenc
740                                 && isASCII(c))
741                                 continue;
742                         if (par.isInset(i))
743                                 break;
744                         // All characters before c are in the ASCII range, and
745                         // c is non-ASCII (but no inset), so change the
746                         // encoding to that required by the language of c.
747                         // With CJK, only add switch if we have CJK content at the beginning
748                         // of the paragraph
749                         if (i != 0 && encoding->package() == Encoding::CJK)
750                                 continue;
751
752                         pair<bool, int> enc_switch = switchEncoding(os.os(),
753                                                 bparams, runparams, *encoding);
754                         // the following is necessary after a CJK environment in a multilingual
755                         // context (nesting issue).
756                         if (par_language->encoding()->package() == Encoding::CJK
757                                 && open_encoding_ != CJK && cjk_inherited_ == 0) {
758                                 os << "\\begin{CJK}{" << from_ascii(par_language->encoding()->latexName())
759                                    << "}{" << from_ascii(bparams.fonts_cjk) << "}%\n";
760                                 open_encoding_ = CJK;
761                         }
762                         if (encoding->package() != Encoding::none && enc_switch.first) {
763                                 if (enc_switch.second > 0) {
764                                         // the '%' is necessary to prevent unwanted whitespace
765                                         os << "%\n";
766                                 }
767                                 // With CJK, the CJK tag had to be closed first (see above)
768                                 if (runparams.encoding->package() == Encoding::CJK
769                                     && !par_lang.empty()) {
770                                         os << from_ascii(subst(
771                                                 lang_begin_command,
772                                                 "$$lang",
773                                                 par_lang))
774                                         << lang_command_termination;
775                                 }
776                                 runparams.encoding = encoding;
777                         }
778                         break;
779                 }
780         }
781
782         runparams.moving_arg |= style.needprotect;
783         Encoding const * const prev_encoding = runparams.encoding;
784
785         bool const useSetSpace = bparams.documentClass().provides("SetSpace");
786         if (par.allowParagraphCustomization()) {
787                 if (par.params().startOfAppendix()) {
788                         os << "\\appendix\n";
789                 }
790
791                 if (!par.params().spacing().isDefault()
792                         && (pit == 0 || !priorpar->hasSameLayout(par)))
793                 {
794                         os << from_ascii(par.params().spacing().writeEnvirBegin(useSetSpace))
795                             << '\n';
796                 }
797
798                 if (style.isCommand()) {
799                         os << '\n';
800                 }
801         }
802
803         parStartCommand(par, os, runparams, style);
804         Font const outerfont = text.outerFont(pit);
805
806         // FIXME UNICODE
807         os << from_utf8(everypar);
808         par.latex(bparams, outerfont, os, runparams, start_pos, end_pos);
809
810         // Make sure that \\par is done with the font of the last
811         // character if this has another size as the default.
812         // This is necessary because LaTeX (and LyX on the screen)
813         // calculates the space between the baselines according
814         // to this font. (Matthias)
815         //
816         // Is this really needed ? (Dekel)
817         // We do not need to use to change the font for the last paragraph
818         // or for a command.
819
820         Font const font = par.empty()
821                  ? par.getLayoutFont(bparams, outerfont)
822                  : par.getFont(bparams, par.size() - 1, outerfont);
823
824         bool const is_command = style.isCommand();
825
826         if (style.resfont.size() != font.fontInfo().size()
827             && nextpar
828             && !is_command) {
829                 os << '{';
830                 os << "\\" << from_ascii(font.latexSize()) << " \\par}";
831         } else if (is_command) {
832                 os << '}';
833                 if (!style.postcommandargs().empty())
834                         latexArgInsets(par, os, runparams, style.postcommandargs(), "post:");
835                 if (runparams.encoding != prev_encoding) {
836                         runparams.encoding = prev_encoding;
837                         if (!runparams.isFullUnicode())
838                                 os << setEncoding(prev_encoding->iconvName());
839                 }
840         }
841
842         bool pending_newline = false;
843         bool unskip_newline = false;
844         switch (style.latextype) {
845         case LATEX_ITEM_ENVIRONMENT:
846         case LATEX_LIST_ENVIRONMENT:
847                 if (nextpar
848                     && (par.params().depth() < nextpar->params().depth())
849                     && !par.isEnvSeparator(par.size() - 1))
850                         pending_newline = true;
851                 break;
852         case LATEX_ENVIRONMENT: {
853                 // if its the last paragraph of the current environment
854                 // skip it otherwise fall through
855                 if (nextpar
856                         && (nextpar->layout() != par.layout()
857                         || nextpar->params().depth() != par.params().depth()))
858                         break;
859         }
860
861         // fall through possible
862         default:
863                 // we don't need it for the last paragraph!!!
864                 // or if the last thing is an environment separator
865                 if (nextpar && !par.isEnvSeparator(par.size() - 1))
866                         pending_newline = true;
867         }
868
869         if (par.allowParagraphCustomization()) {
870                 if (!par.params().spacing().isDefault()
871                         && (runparams.isLastPar || !nextpar->hasSameLayout(par))) {
872                         if (pending_newline)
873                                 os << '\n';
874
875                         string const endtag =
876                                 par.params().spacing().writeEnvirEnd(useSetSpace);
877                         if (prefixIs(endtag, "\\end{"))
878                                 os << breakln;
879
880                         os << from_ascii(endtag);
881                         pending_newline = true;
882                 }
883         }
884
885         // Closing the language is needed for the last paragraph; it is also
886         // needed if we're within an \L or \R that we may have opened above (not
887         // necessarily in this paragraph) and are about to close.
888         bool closing_rtl_ltr_environment = !use_polyglossia
889                 // not for ArabTeX
890                 && (par_language->lang() != "arabic_arabtex"
891                     && outer_language->lang() != "arabic_arabtex")
892                 // have we opened an \L or \R environment?
893                 && runparams.local_font != 0
894                 && runparams.local_font->isRightToLeft() != par_language->rightToLeft()
895                 // are we about to close the language?
896                 &&((nextpar && par_language->babel() != (nextpar->getParLanguage(bparams))->babel())
897                    || (runparams.isLastPar && par_language->babel() != outer_language->babel()));
898
899         if (closing_rtl_ltr_environment
900             || (runparams.isLastPar
901                 && ((!use_polyglossia && par_language->babel() != outer_language->babel())
902                     || (use_polyglossia && par_language->polyglossia() != outer_language->polyglossia())))) {
903                 // Since \selectlanguage write the language to the aux file,
904                 // we need to reset the language at the end of footnote or
905                 // float.
906
907                 if (pending_newline)
908                         os << '\n';
909
910                 // when the paragraph uses CJK, the language has to be closed earlier
911                 if (font.language()->encoding()->package() != Encoding::CJK) {
912                         if (lang_end_command.empty()) {
913                                 // If this is a child, we should restore the
914                                 // master language after the last paragraph.
915                                 Language const * const current_language =
916                                         (runparams.isLastPar && runparams.master_language)
917                                                 ? runparams.master_language
918                                                 : outer_language;
919                                 string const current_lang = use_polyglossia
920                                         ? getPolyglossiaEnvName(current_language)
921                                         : current_language->babel();
922                                 if (!current_lang.empty()) {
923                                         os << from_ascii(subst(
924                                                 lang_begin_command,
925                                                 "$$lang",
926                                                 current_lang));
927                                         pending_newline = !localswitch;
928                                         unskip_newline = !localswitch;
929                                 }
930                         } else if (!par_lang.empty()) {
931                                 os << from_ascii(subst(
932                                         lang_end_command,
933                                         "$$lang",
934                                         par_lang));
935                                 pending_newline = !localswitch;
936                                 unskip_newline = !localswitch;
937                         }
938                 }
939         }
940         if (closing_rtl_ltr_environment)
941                 os << "}";
942
943         if (pending_newline) {
944                 if (unskip_newline)
945                         // prevent unwanted whitespace
946                         os << '%';
947                 os << '\n';
948         }
949
950         // if this is a CJK-paragraph and the next isn't, close CJK
951         // also if the next paragraph is a multilingual environment (because of nesting)
952         if (nextpar
953                 && open_encoding_ == CJK
954                 && (nextpar->getParLanguage(bparams)->encoding()->package() != Encoding::CJK
955                    || (nextpar->layout().isEnvironment() && nextpar->isMultiLingual(bparams)))
956                 // inbetween environments, CJK has to be closed later (nesting!)
957                 && (!style.isEnvironment() || !nextpar->layout().isEnvironment())) {
958                 os << "\\end{CJK}\n";
959                 open_encoding_ = none;
960         }
961
962         // If this is the last paragraph, close the CJK environment
963         // if necessary. If it's an environment, we'll have to \end that first.
964         if (runparams.isLastPar && !style.isEnvironment()) {
965                 switch (open_encoding_) {
966                         case CJK: {
967                                 // do nothing at the end of child documents
968                                 if (maintext && buf.masterBuffer() != &buf)
969                                         break;
970                                 // end of main text
971                                 if (maintext) {
972                                         os << "\n\\end{CJK}\n";
973                                 // end of an inset
974                                 } else
975                                         os << "\\end{CJK}";
976                                 open_encoding_ = none;
977                                 break;
978                         }
979                         case inputenc: {
980                                 os << "\\egroup";
981                                 open_encoding_ = none;
982                                 break;
983                         }
984                         case none:
985                         default:
986                                 // do nothing
987                                 break;
988                 }
989         }
990
991         // If this is the last paragraph, and a local_font was set upon entering
992         // the inset, and we're using "auto" or "default" encoding, the encoding
993         // should be set back to that local_font's encoding.
994         // However, do not change the encoding when a fully unicode aware backend
995         // such as XeTeX is used.
996         if (runparams.isLastPar && runparams_in.local_font != 0
997             && runparams_in.encoding != runparams_in.local_font->language()->encoding()
998             && (bparams.inputenc == "auto" || bparams.inputenc == "default")
999             && (!runparams.isFullUnicode())) {
1000                 runparams_in.encoding = runparams_in.local_font->language()->encoding();
1001                 os << setEncoding(runparams_in.encoding->iconvName());
1002         }
1003         // Otherwise, the current encoding should be set for the next paragraph.
1004         else
1005                 runparams_in.encoding = runparams.encoding;
1006
1007
1008         // we don't need a newline for the last paragraph!!!
1009         // Note from JMarc: we will re-add a \n explicitly in
1010         // TeXEnvironment, because it is needed in this case
1011         if (nextpar && !par.isEnvSeparator(par.size() - 1)) {
1012                 // Make sure to start a new line
1013                 os << breakln;
1014                 Layout const & next_layout = nextpar->layout();
1015                 // A newline '\n' is always output before a command,
1016                 // so avoid doubling it.
1017                 if (!next_layout.isCommand()) {
1018                         // Here we now try to avoid spurious empty lines by
1019                         // outputting a paragraph break only if: (case 1) the
1020                         // paragraph style allows parbreaks and no \begin, \end
1021                         // or \item tags are going to follow (i.e., if the next
1022                         // isn't the first or the current isn't the last
1023                         // paragraph of an environment or itemize) and the
1024                         // depth and alignment of the following paragraph is
1025                         // unchanged, or (case 2) the following is a
1026                         // non-environment paragraph whose depth is increased
1027                         // but whose alignment is unchanged, or (case 3) the
1028                         // paragraph is a command not followed by an environment
1029                         // and the alignment of the current and next paragraph
1030                         // is unchanged.
1031                         if ((style == next_layout
1032                              && !style.parbreak_is_newline
1033                              && style.latextype != LATEX_ITEM_ENVIRONMENT
1034                              && style.latextype != LATEX_LIST_ENVIRONMENT
1035                              && style.align == par.getAlign()
1036                              && nextpar->getDepth() == par.getDepth()
1037                              && nextpar->getAlign() == par.getAlign())
1038                             || (!next_layout.isEnvironment()
1039                                 && nextpar->getDepth() > par.getDepth()
1040                                 && nextpar->getAlign() == par.getAlign())
1041                             || (style.isCommand()
1042                                 && !next_layout.isEnvironment()
1043                                 && style.align == par.getAlign()
1044                                 && next_layout.align == nextpar->getAlign())) {
1045                                 os << '\n';
1046                         }
1047                 }
1048         }
1049
1050         LYXERR(Debug::LATEX, "TeXOnePar for paragraph " << pit << " done; ptr "
1051                 << &par << " next " << nextpar);
1052
1053         return;
1054 }
1055
1056
1057 // LaTeX all paragraphs
1058 void latexParagraphs(Buffer const & buf,
1059                      Text const & text,
1060                      otexstream & os,
1061                      OutputParams const & runparams,
1062                      string const & everypar)
1063 {
1064         LASSERT(runparams.par_begin <= runparams.par_end,
1065                 { os << "% LaTeX Output Error\n"; return; } );
1066
1067         BufferParams const & bparams = buf.params();
1068
1069         bool const maintext = text.isMainText();
1070         bool const is_child = buf.masterBuffer() != &buf;
1071
1072         // Open a CJK environment at the beginning of the main buffer
1073         // if the document's language is a CJK language
1074         // (but not in child documents)
1075         if (maintext && !is_child
1076             && bparams.encoding().package() == Encoding::CJK) {
1077                 os << "\\begin{CJK}{" << from_ascii(bparams.encoding().latexName())
1078                 << "}{" << from_ascii(bparams.fonts_cjk) << "}%\n";
1079                 open_encoding_ = CJK;
1080         }
1081         // if "auto begin" is switched off, explicitly switch the
1082         // language on at start
1083         string const mainlang = runparams.use_polyglossia
1084                 ? getPolyglossiaEnvName(bparams.language)
1085                 : bparams.language->babel();
1086         string const lang_begin_command = runparams.use_polyglossia ?
1087                 "\\begin{$$lang}" : lyxrc.language_command_begin;
1088
1089         if (maintext && !lyxrc.language_auto_begin &&
1090             !mainlang.empty()) {
1091                 // FIXME UNICODE
1092                 os << from_utf8(subst(lang_begin_command,
1093                                         "$$lang",
1094                                         mainlang));
1095                 if (runparams.use_polyglossia
1096                     && !bparams.language->polyglossiaOpts().empty())
1097                         os << "["
1098                             << from_ascii(bparams.language->polyglossiaOpts())
1099                             << "]";
1100                 os << '\n';
1101         }
1102
1103         ParagraphList const & paragraphs = text.paragraphs();
1104
1105         if (runparams.par_begin == runparams.par_end) {
1106                 // The full doc will be exported but it is easier to just rely on
1107                 // runparams range parameters that will be passed TeXEnvironment.
1108                 runparams.par_begin = 0;
1109                 runparams.par_end = paragraphs.size();
1110         }
1111
1112         pit_type pit = runparams.par_begin;
1113         // lastpit is for the language check after the loop.
1114         pit_type lastpit = pit;
1115         // variables used in the loop:
1116         bool was_title = false;
1117         bool already_title = false;
1118         DocumentClass const & tclass = bparams.documentClass();
1119
1120         for (; pit < runparams.par_end; ++pit) {
1121                 lastpit = pit;
1122                 ParagraphList::const_iterator par = paragraphs.constIterator(pit);
1123
1124                 // FIXME This check should not be needed. We should
1125                 // perhaps issue an error if it is.
1126                 Layout const & layout = text.inset().forcePlainLayout() ?
1127                                 tclass.plainLayout() : par->layout();
1128
1129                 if (layout.intitle) {
1130                         if (already_title) {
1131                                 LYXERR0("Error in latexParagraphs: You"
1132                                         " should not mix title layouts"
1133                                         " with normal ones.");
1134                         } else if (!was_title) {
1135                                 was_title = true;
1136                                 if (tclass.titletype() == TITLE_ENVIRONMENT) {
1137                                         os << "\\begin{"
1138                                                         << from_ascii(tclass.titlename())
1139                                                         << "}\n";
1140                                 }
1141                         }
1142                 } else if (was_title && !already_title) {
1143                         if (tclass.titletype() == TITLE_ENVIRONMENT) {
1144                                 os << "\\end{" << from_ascii(tclass.titlename())
1145                                                 << "}\n";
1146                         }
1147                         else {
1148                                 os << "\\" << from_ascii(tclass.titlename())
1149                                                 << "\n";
1150                         }
1151                         already_title = true;
1152                         was_title = false;
1153                 }
1154
1155
1156                 if (!layout.isEnvironment() && par->params().leftIndent().zero()) {
1157                         // This is a standard top level paragraph, TeX it and continue.
1158                         TeXOnePar(buf, text, pit, os, runparams, everypar);
1159                         continue;
1160                 }
1161                 
1162                 TeXEnvironmentData const data =
1163                         prepareEnvironment(buf, text, par, os, runparams);
1164                 // pit can be changed in TeXEnvironment.
1165                 TeXEnvironment(buf, text, runparams, pit, os);
1166                 finishEnvironment(os, runparams, data);
1167         }
1168
1169         if (pit == runparams.par_end) {
1170                         // Make sure that the last paragraph is
1171                         // correctly terminated (because TeXOnePar does
1172                         // not add a \n in this case)
1173                         //os << '\n';
1174         }
1175
1176         // It might be that we only have a title in this document
1177         if (was_title && !already_title) {
1178                 if (tclass.titletype() == TITLE_ENVIRONMENT) {
1179                         os << "\\end{" << from_ascii(tclass.titlename())
1180                            << "}\n";
1181                 } else {
1182                         os << "\\" << from_ascii(tclass.titlename())
1183                            << "\n";
1184                 }
1185         }
1186
1187         // if "auto end" is switched off, explicitly close the language at the end
1188         // but only if the last par is in a babel language
1189         string const lang_end_command = runparams.use_polyglossia ?
1190                 "\\end{$$lang}" : lyxrc.language_command_end;
1191         if (maintext && !lyxrc.language_auto_end && !mainlang.empty() &&
1192                 paragraphs.at(lastpit).getParLanguage(bparams)->encoding()->package() != Encoding::CJK) {
1193                 os << from_utf8(subst(lang_end_command,
1194                                         "$$lang",
1195                                         mainlang))
1196                         << '\n';
1197         }
1198
1199         // If the last paragraph is an environment, we'll have to close
1200         // CJK at the very end to do proper nesting.
1201         if (maintext && !is_child && open_encoding_ == CJK) {
1202                 os << "\\end{CJK}\n";
1203                 open_encoding_ = none;
1204         }
1205
1206         // reset inherited encoding
1207         if (cjk_inherited_ > 0) {
1208                 cjk_inherited_ -= 1;
1209                 if (cjk_inherited_ == 0)
1210                         open_encoding_ = CJK;
1211         }
1212 }
1213
1214
1215 pair<bool, int> switchEncoding(odocstream & os, BufferParams const & bparams,
1216                    OutputParams const & runparams, Encoding const & newEnc,
1217                    bool force)
1218 {
1219         Encoding const & oldEnc = *runparams.encoding;
1220         bool moving_arg = runparams.moving_arg;
1221         // If we switch from/to CJK, we need to switch anyway, despite custom inputenc
1222         bool const from_to_cjk = 
1223                 (oldEnc.package() == Encoding::CJK && newEnc.package() != Encoding::CJK)
1224                 || (oldEnc.package() != Encoding::CJK && newEnc.package() == Encoding::CJK);
1225         if (!force && !from_to_cjk
1226             && ((bparams.inputenc != "auto" && bparams.inputenc != "default") || moving_arg))
1227                 return make_pair(false, 0);
1228
1229         // Do nothing if the encoding is unchanged.
1230         if (oldEnc.name() == newEnc.name())
1231                 return make_pair(false, 0);
1232
1233         // FIXME We ignore encoding switches from/to encodings that do
1234         // neither support the inputenc package nor the CJK package here.
1235         // This does of course only work in special cases (e.g. switch from
1236         // tis620-0 to latin1, but the text in latin1 contains ASCII only),
1237         // but it is the best we can do
1238         if (oldEnc.package() == Encoding::none
1239                 || newEnc.package() == Encoding::none)
1240                 return make_pair(false, 0);
1241
1242         LYXERR(Debug::LATEX, "Changing LaTeX encoding from "
1243                 << oldEnc.name() << " to " << newEnc.name());
1244         os << setEncoding(newEnc.iconvName());
1245         if (bparams.inputenc == "default")
1246                 return make_pair(true, 0);
1247
1248         docstring const inputenc_arg(from_ascii(newEnc.latexName()));
1249         switch (newEnc.package()) {
1250                 case Encoding::none:
1251                 case Encoding::japanese:
1252                         // shouldn't ever reach here, see above
1253                         return make_pair(true, 0);
1254                 case Encoding::inputenc: {
1255                         int count = inputenc_arg.length();
1256                         if (oldEnc.package() == Encoding::CJK &&
1257                             open_encoding_ == CJK) {
1258                                 os << "\\end{CJK}";
1259                                 open_encoding_ = none;
1260                                 count += 9;
1261                         }
1262                         else if (oldEnc.package() == Encoding::inputenc &&
1263                                  open_encoding_ == inputenc) {
1264                                 os << "\\egroup";
1265                                 open_encoding_ = none;
1266                                 count += 7;
1267                         }
1268                         if (runparams.local_font != 0
1269                             &&  oldEnc.package() == Encoding::CJK) {
1270                                 // within insets, \inputenc switches need
1271                                 // to be embraced within \bgroup...\egroup;
1272                                 // else CJK fails.
1273                                 os << "\\bgroup";
1274                                 count += 7;
1275                                 open_encoding_ = inputenc;
1276                         }
1277                         // with the japanese option, inputenc is omitted.
1278                         if (runparams.use_japanese)
1279                                 return make_pair(true, count);
1280                         os << "\\inputencoding{" << inputenc_arg << '}';
1281                         return make_pair(true, count + 16);
1282                 }
1283                 case Encoding::CJK: {
1284                         int count = inputenc_arg.length();
1285                         if (oldEnc.package() == Encoding::CJK &&
1286                             open_encoding_ == CJK) {
1287                                 os << "\\end{CJK}";
1288                                 count += 9;
1289                         }
1290                         if (oldEnc.package() == Encoding::inputenc &&
1291                             open_encoding_ == inputenc) {
1292                                 os << "\\egroup";
1293                                 count += 7;
1294                         }
1295                         os << "\\begin{CJK}{" << inputenc_arg << "}{"
1296                            << from_ascii(bparams.fonts_cjk) << "}";
1297                         open_encoding_ = CJK;
1298                         return make_pair(true, count + 15);
1299                 }
1300         }
1301         // Dead code to avoid a warning:
1302         return make_pair(true, 0);
1303
1304 }
1305
1306 } // namespace lyx