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