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