]> git.lyx.org Git - lyx.git/blob - src/LaTeXFeatures.cpp
9f65ed40eada01c5d73fc3cb91cc0d34ef208918
[lyx.git] / src / LaTeXFeatures.cpp
1 /**
2  * \file LaTeXFeatures.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author José Matos
7  * \author Lars Gullik Bjønnes
8  * \author Jean-Marc Lasgouttes
9  * \author Jürgen Vigna
10  * \author André Pönitz
11  *
12  * Full author contact details are available in file CREDITS.
13  */
14
15 #include <config.h>
16
17 #include "LaTeXFeatures.h"
18
19 #include "Buffer.h"
20 #include "BufferParams.h"
21 #include "ColorSet.h"
22 #include "Converter.h"
23 #include "Encoding.h"
24 #include "Floating.h"
25 #include "FloatList.h"
26 #include "Language.h"
27 #include "LaTeXFonts.h"
28 #include "LaTeXPackages.h"
29 #include "Layout.h"
30 #include "Lexer.h"
31 #include "LyXRC.h"
32 #include "TextClass.h"
33 #include "TexRow.h"
34 #include "texstream.h"
35
36 #include "insets/InsetLayout.h"
37
38 #include "support/debug.h"
39 #include "support/docstream.h"
40 #include "support/FileName.h"
41 #include "support/filetools.h"
42 #include "support/gettext.h"
43 #include "support/lstrings.h"
44 #include "support/regex.h"
45
46 #include <algorithm>
47
48
49 using namespace std;
50 using namespace lyx::support;
51
52
53 namespace lyx {
54
55 /////////////////////////////////////////////////////////////////////
56 //
57 // Strings
58 //
59 /////////////////////////////////////////////////////////////////////
60
61 //\NeedsTeXFormat{LaTeX2e}
62 //\ProvidesPackage{lyx}[1996/01/11 LLE v0.2 (LyX LaTeX Extensions)]
63 //\message{LyX LaTeX Extensions (LLE v0.2) of 11-Jan-1996.}
64
65 static docstring const lyx_def = from_ascii(
66         "{%\n  L\\kern-.1667em\\lower.25em\\hbox{Y}\\kern-.125emX\\@}");
67
68 static docstring const noun_def = from_ascii(
69         "\\newcommand{\\noun}[1]{\\textsc{#1}}");
70
71 static docstring const lyxarrow_def = from_ascii(
72         "\\DeclareRobustCommand*{\\lyxarrow}{%\n"
73         "\\@ifstar\n"
74         "{\\leavevmode\\,$\\triangleleft$\\,\\allowbreak}\n"
75         "{\\leavevmode\\,$\\triangleright$\\,\\allowbreak}}");
76
77 // ZERO WIDTH SPACE (ZWSP) is actually not a space character
78 // but marks a line break opportunity. Several commands provide a
79 // line break opportunity. They differ in side-effects:
80 // \allowbreak prevents hyphenation after hyphen or dash + ZWSP
81 // \linebreak[<n>] takes an optional argument denoting "urgency".
82 // The \LyXZeroWidthSpace wrapper allows customization in the preamble.
83 static docstring const lyxZWSP_def = from_ascii(
84         "\\newcommand*\\LyXZeroWidthSpace{\\hspace{0pt}}");
85
86 // for quotes without babel. This does not give perfect results, but
87 // anybody serious about non-english quotes should use babel (JMarc).
88
89 static docstring const quotedblbase_def = from_ascii(
90         "\\ProvideTextCommandDefault{\\quotedblbase}{%\n"
91         "  \\raisebox{-1.4ex}[1ex][.5ex]{\\textquotedblright}%\n"
92         "  \\penalty10000\\hskip0em\\relax%\n"
93         "}");
94
95 static docstring const quotesinglbase_def = from_ascii(
96         "\\ProvideTextCommandDefault{\\quotesinglbase}{%\n"
97         "  \\raisebox{-1.4ex}[1ex][.5ex]{\\textquoteright}%\n"
98         "  \\penalty10000\\hskip0em\\relax%\n"
99         "}");
100
101 static docstring const guillemotleft_def = from_ascii(
102         "\\ProvideTextCommandDefault{\\guillemotleft}{%\n"
103         "  {\\usefont{U}{lasy}{m}{n}\\char'50\\kern-.15em\\char'50}%\n"
104         "\\penalty10000\\hskip0pt\\relax%\n"
105         "}");
106
107 static docstring const guillemotright_def = from_ascii(
108         "\\ProvideTextCommandDefault{\\guillemotright}{%\n"
109         "  \\penalty10000\\hskip0pt%\n"
110         "  {\\usefont{U}{lasy}{m}{n}\\char'51\\kern-.15em\\char'51}%\n"
111         "}");
112
113 static docstring const guilsinglleft_def = from_ascii(
114         "\\ProvideTextCommandDefault{\\guilsinglleft}{%\n"
115         "  {\\usefont{U}{lasy}{m}{n}\\char'50}%\n"
116         "  \\penalty10000\\hskip0pt\\relax%\n"
117         "}");
118
119 static docstring const guilsinglright_def = from_ascii(
120         "\\ProvideTextCommandDefault{\\guilsinglright}{%\n"
121         "  \\penalty10000\\hskip0pt%\n"
122         "  {\\usefont{U}{lasy}{m}{n}\\char'51}%\n"
123         "}");
124
125 static docstring const textquotedbl_def = from_ascii(
126         "\\DeclareTextSymbolDefault{\\textquotedbl}{T1}");
127
128 static docstring const textquotedblp_xetex_def = from_ascii(
129         "\\providecommand\\textquotedblplain{%\n"
130         "  \\bgroup\\addfontfeatures{Mapping=}\\char34\\egroup}");
131
132 static docstring const textquotedblp_luatex_def = from_ascii(
133         "\\providecommand\\textquotedblplain{%\n"
134         "  \\bgroup\\addfontfeatures{RawFeature=-tlig}\\char34\\egroup}");
135
136 static docstring const textquotesinglep_xetex_def = from_ascii(
137         "\\providecommand\\textquotesingleplain{%\n"
138         "  \\bgroup\\addfontfeatures{Mapping=}\\char39\\egroup}");
139
140 static docstring const textquotesinglep_luatex_def = from_ascii(
141         "\\providecommand\\textquotesingleplain{%\n"
142         "  \\bgroup\\addfontfeatures{RawFeature=-tlig}\\char39\\egroup}");
143
144 static docstring const paragraphleftindent_def = from_ascii(
145         "\\newenvironment{LyXParagraphLeftIndent}[1]%\n"
146         "{\n"
147         "  \\begin{list}{}{%\n"
148         "    \\setlength{\\topsep}{0pt}%\n"
149         "    \\addtolength{\\leftmargin}{#1}\n"
150 // ho hum, yet more things commented out with no hint as to why they
151 // weren't just removed
152 //      "%%    \\addtolength{\\leftmargin}{#1\\textwidth}\n"
153 //      "%%    \\setlength{\\textwidth}{#2\\textwidth}\n"
154 //      "%%    \\setlength\\listparindent\\parindent%\n"
155 //      "%%    \\setlength\\itemindent\\parindent%\n"
156         "    \\setlength{\\parsep}{0pt plus 1pt}%\n"
157         "  }\n"
158         "  \\item[]\n"
159         "}\n"
160         "{\\end{list}}\n");
161
162 static docstring const floatingfootnote_def = from_ascii(
163         "%% Special footnote code from the package 'stblftnt.sty'\n"
164         "%% Author: Robin Fairbairns -- Last revised Dec 13 1996\n"
165         "\\let\\SF@@footnote\\footnote\n"
166         "\\def\\footnote{\\ifx\\protect\\@typeset@protect\n"
167         "    \\expandafter\\SF@@footnote\n"
168         "  \\else\n"
169         "    \\expandafter\\SF@gobble@opt\n"
170         "  \\fi\n"
171         "}\n"
172         "\\expandafter\\def\\csname SF@gobble@opt \\endcsname{\\@ifnextchar[%]\n"
173         "  \\SF@gobble@twobracket\n"
174         "  \\@gobble\n"
175         "}\n"
176         "\\edef\\SF@gobble@opt{\\noexpand\\protect\n"
177         "  \\expandafter\\noexpand\\csname SF@gobble@opt \\endcsname}\n"
178         "\\def\\SF@gobble@twobracket[#1]#2{}\n");
179
180 static docstring const binom_def = from_ascii(
181         "%% Binom macro for standard LaTeX users\n"
182         "\\newcommand{\\binom}[2]{{#1 \\choose #2}}\n");
183
184 static docstring const mathcircumflex_def = from_ascii(
185         "%% For printing a cirumflex inside a formula\n"
186         "\\newcommand{\\mathcircumflex}[0]{\\mbox{\\^{}}}\n");
187
188 static docstring const tabularnewline_def = from_ascii(
189         "%% Because html converters don't know tabularnewline\n"
190         "\\providecommand{\\tabularnewline}{\\\\}\n");
191
192 static docstring const lyxgreyedout_def = from_ascii(
193         "%% The greyedout annotation environment\n"
194         "\\newenvironment{lyxgreyedout}\n"
195         "  {\\textcolor{note_fontcolor}\\bgroup\\ignorespaces}\n"
196         "  {\\ignorespacesafterend\\egroup}\n");
197
198 static docstring const lyxgreyedout_rtl_def = from_ascii(
199         "%% The greyedout annotation environment (with RTL support)\n"
200         "\\NewEnviron{lyxgreyedout}{%\n"
201         "\\if@rl%\n"
202         "\\everypar{\\textcolor{note_fontcolor}\\beginL\\ignorespaces}%\n"
203         "\\BODY\\everypar{\\ignorespacesafterend\\endL}\n"
204         "\\else%\n"
205         "\\textcolor{note_fontcolor}\\bgroup\\ignorespaces%\n"
206         "\\BODY\\ignorespacesafterend\\egroup\n"
207         "\\fi}\n");
208
209 static docstring const lyxgreyedout_luartl_def = from_ascii(
210         "%% The greyedout annotation environment (with RTL support)\n"
211         "\\NewEnviron{lyxgreyedout}{%\n"
212         "\\if@RTL%\n"
213         "\\everypar{\\color{note_fontcolor}\\pardir TRT \\textdir TRT\\ignorespaces}%\n"
214         "\\BODY\\everypar{\\ignorespacesafterend}\n"
215         "\\else%\n"
216         "\\textcolor{note_fontcolor}\\bgroup\\ignorespaces%\n"
217         "\\BODY\\ignorespacesafterend\\egroup\n"
218         "\\fi}\n");
219
220 static docstring const lyxgreyedout_luartl_babel_def = from_ascii(
221         "%% The greyedout annotation environment (with RTL support)\n"
222         "\\NewEnviron{lyxgreyedout}{%\n"
223         "\\if@rl%\n"
224         "\\everypar{\\color{note_fontcolor}\\pardir TRT \\textdir TRT\\ignorespaces}%\n"
225         "\\BODY\\everypar{\\ignorespacesafterend}\n"
226         "\\else%\n"
227         "\\textcolor{note_fontcolor}\\bgroup\\ignorespaces%\n"
228         "\\BODY\\ignorespacesafterend\\egroup\n"
229         "\\fi}\n");
230
231 // We want to omit the file extension for includegraphics, but this does not
232 // work when the filename contains other dots.
233 // Idea from http://www.tex.ac.uk/cgi-bin/texfaq2html?label=unkgrfextn
234 static docstring const lyxdot_def = from_ascii(
235         "%% A simple dot to overcome graphicx limitations\n"
236         "\\newcommand{\\lyxdot}{.}\n");
237
238 static docstring const changetracking_dvipost_def = from_ascii(
239         "%% Change tracking with dvipost\n"
240         "\\dvipostlayout\n"
241         "\\dvipost{osstart color push Red}\n"
242         "\\dvipost{osend color pop}\n"
243         "\\dvipost{cbstart color push Blue}\n"
244         "\\dvipost{cbrule 0pt}\n"
245         "\\dvipost{cbend color pop}\n"
246         "\\DeclareRobustCommand{\\lyxadded}[4][]{\\changestart#4\\changeend}\n"
247         "\\DeclareRobustCommand{\\lyxdeleted}[4][]{%\n"
248         "\\changestart\\overstrikeon#4\\overstrikeoff\\changeend}\n");
249
250 static docstring const changetracking_dvipost_cb_def = from_ascii(
251         "%% Change tracking with dvipost\n"
252         "\\dvipostlayout\n"
253         "\\dvipost{osstart color push Red}\n"
254         "\\dvipost{osend color pop}\n"
255         "\\dvipost{cbstart color push Blue}\n"
256         "\\dvipost{cbend color pop}\n"
257         "\\DeclareRobustCommand{\\lyxadded}[4][]{\\changestart#4\\changeend}\n"
258         "\\DeclareRobustCommand{\\lyxdeleted}[4][]{%\n"
259         "\\changestart\\overstrikeon#4\\overstrikeoff\\changeend}\n");
260
261 static docstring const changetracking_xcolor_ulem_base_def = from_ascii(
262         "%% Change tracking with ulem and xcolor: base macros\n"
263         "\\DeclareRobustCommand{\\mklyxadded}[1]{\\bgroup\\color{lyxadded}{}#1\\egroup}\n"
264         "\\DeclareRobustCommand{\\mklyxdeleted}[1]{\\bgroup\\color{lyxdeleted}\\mklyxsout{#1}\\egroup}\n"
265         "\\DeclareRobustCommand{\\mklyxsout}[1]{\\ifx\\\\#1\\else\\sout{#1}\\fi}\n");
266
267 static docstring const changetracking_xcolor_ulem_def = from_ascii(
268         "%% Change tracking with ulem and xcolor: ct markup\n"
269         "\\DeclareRobustCommand{\\lyxadded}[4][]{\\mklyxadded{#4}}\n"
270         "\\DeclareRobustCommand{\\lyxdeleted}[4][]{\\mklyxdeleted{#4}}\n");
271
272 static docstring const changetracking_xcolor_ulem_cb_def = from_ascii(
273         "%% Change tracking with ulem, xcolor and changebars: ct markup\n"
274         "\\DeclareRobustCommand{\\lyxadded}[4][]{%\n"
275         "    \\protect\\cbstart\\mklyxadded{#4}%\n"
276         "    \\protect\\cbend%\n"
277         "}\n"
278         "\\DeclareRobustCommand{\\lyxdeleted}[4][]{%\n"
279         "    \\protect\\cbstart\\mklyxdeleted{#4}%\n"
280         "    \\protect\\cbend%\n"
281         "}\n");
282
283 static docstring const changetracking_xcolor_ulem_hyperref_def = from_ascii(
284         "%% Change tracking with ulem, xcolor, and hyperref: ct markup\n"
285         "\\DeclareRobustCommand{\\lyxadded}[4][]{\\texorpdfstring{\\mklyxadded{#4}}{#4}}\n"
286         "\\DeclareRobustCommand{\\lyxdeleted}[4][]{\\texorpdfstring{\\mklyxdeleted{#4}}{}}\n");
287
288 static docstring const changetracking_xcolor_ulem_hyperref_cb_def = from_ascii(
289         "%% Change tracking with ulem, xcolor, hyperref and changebars: ct markup\n"
290         "\\DeclareRobustCommand{\\lyxadded}[4][]{%\n"
291         "    \\texorpdfstring{\\protect\\cbstart\\mklyxadded{#4}%\n"
292         "    \\protect\\cbend}{#4}%\n"
293         "}\n"
294         "\\DeclareRobustCommand{\\lyxdeleted}[4][]{%\n"
295         "    \\texorpdfstring{\\protect\\cbstart\\mklyxdeleted{#4}%\n"
296         "    \\protect\\cbend}{}%\n"
297         "}\n");
298
299 static docstring const changetracking_tikz_object_sout_def = from_ascii(
300         "%% Strike out display math and text objects with tikz\n"
301         "\\usetikzlibrary{calc}\n"
302         "\\newcommand{\\lyxobjectsout}[1]{%\n"
303         "  \\bgroup%\n"
304         "  \\color{lyxdeleted}%\n"
305         "  \\tikz{\n"
306         "    \\node[inner sep=0pt,outer sep=0pt](lyxdelobj){#1};\n"
307         "    \\draw($(lyxdelobj.south west)+(2em,.5em)$)--($(lyxdelobj.north east)-(2em,.5em)$);\n"
308         "  }\n"
309         "  \\egroup%\n"
310         "}\n");
311
312 static docstring const changetracking_xcolor_ulem_object_def = from_ascii(
313         "%% Change tracking with ulem and xcolor: ct markup for complex objects\n"
314         "\\DeclareRobustCommand{\\lyxobjdeleted}[4][]{\\lyxobjectsout{#4}}\n"
315         "\\DeclareRobustCommand{\\lyxdisplayobjdeleted}[4][]{%\n"
316         "     \\leavevmode\\\\%\n"
317         "     \\lyxobjectsout{\\parbox{\\linewidth}{#4}}%\n"
318         "}\n"
319         "\\DeclareRobustCommand{\\lyxudisplayobjdeleted}[4][]{%\n"
320         "     \\leavevmode\\\\%\n"
321         "     \\raisebox{-\\belowdisplayshortskip}{%\n"
322         "                \\lyxobjectsout{\\parbox[b]{\\linewidth}{#4}}}%\n"
323         "}\n");
324
325 static docstring const changetracking_xcolor_ulem_cb_object_def = from_ascii(
326         "%% Change tracking with ulem, xcolor and changebars:ct markup for complex objects\n"
327         "\\DeclareRobustCommand{\\lyxobjdeleted}[4][]{%\n"
328         "    \\protect\\cbstart\\lyxobjectsout{#4}%\n"
329         "    \\protect\\cbend%\n"
330         "}\n"
331         "\\DeclareRobustCommand{\\lyxdisplayobjdeleted}[4][]{%\n"
332         "    \\leavevmode\\\\%\n"
333         "    \\protect\\cbstart%\n"
334         "    \\lyxobjectsout{\\parbox{\\linewidth}{#4}}%\n"
335         "    \\protect\\cbend%\n"
336         "}\n"
337         "\\DeclareRobustCommand{\\lyxudisplayobjdeleted}[4][]{%\n"
338         "    \\leavevmode\\\\%\n"
339         "    \\raisebox{-\\belowdisplayshortskip}{%\n"
340         "               \\protect\\cbstart%\n"
341         "               \\lyxobjectsout{\\parbox[b]{\\linewidth}{#4}}}%\n"
342         "               \\protect\\cbend%\n"
343         "}\n");
344
345 static docstring const changetracking_xcolor_ulem_hyperref_object_def = from_ascii(
346         "%% Change tracking with ulem, xcolor, and hyperref: ct markup for complex objects\n"
347         "\\DeclareRobustCommand{\\lyxobjdeleted}[4][]{\\texorpdfstring{\\lyxobjectsout{#4}}{}}\n"
348         "\\DeclareRobustCommand{\\lyxdisplayobjdeleted}[4][]{%\n"
349         "     \\texorpdfstring{\\leavevmode\\\\\\lyxobjectsout{\\parbox{\\linewidth}{#4}}}{}%\n"
350         "}\n"
351         "\\DeclareRobustCommand{\\lyxudisplayobjdeleted}[4][]{%\n"
352         "     \\texorpdfstring{\\leavevmode\\\\\\raisebox{-\\belowdisplayshortskip}{%\n"
353         "                \\lyxobjectsout{\\parbox[b]{\\linewidth}{#4}}}}{}%\n"
354         "}\n");
355
356 static docstring const changetracking_xcolor_ulem_hyperref_cb_object_def = from_ascii(
357         "%% Change tracking with ulem, xcolor, hyperref and changebars:\n"
358         "%% ct markup for complex objects\n"
359         "\\DeclareRobustCommand{\\lyxobjdeleted}[4][]{%\n"
360         "    \\texorpdfstring{\\protect\\cbstart\\lyxobjectsout{#4}%\n"
361         "    \\protect\\cbend}{}%\n"
362         "}\n"
363         "\\DeclareRobustCommand{\\lyxdisplayobjdeleted}[4][]{%\n"
364         "     \\texorpdfstring{\\leavevmode\\\\\\protect\\cbstart%\n"
365         "        \\lyxobjectsout{\\parbox{\\linewidth}{#4}}%\n"
366         "        \\protect\\cbend%\n"
367         "      }{}%\n"
368         "}\n"
369         "\\DeclareRobustCommand{\\lyxudisplayobjdeleted}[4][]{%\n"
370         "     \\texorpdfstring{\\leavevmode\\\\\\protect\\cbstart%\n"
371         "        \\raisebox{-\\belowdisplayshortskip}{%\n"
372         "                   \\lyxobjectsout{\\parbox[b]{\\linewidth}{#4}}%\n"
373         "        }%\n"
374         "     }{}%\n"
375         "}\n");
376
377 static docstring const changetracking_none_def = from_ascii(
378         "%% Change tracking: Disable markup in output\n"
379         "\\newcommand{\\lyxadded}[3]{#3}\n"
380         "\\newcommand{\\lyxdeleted}[3]{}\n"
381         "\\newcommand{\\lyxobjdeleted}[3]{}\n"
382         "\\newcommand{\\lyxdisplayobjdeleted}[3]{}\n"
383         "\\newcommand{\\lyxudisplayobjdeleted}[3]{}\n");
384
385 static docstring const textgreek_LGR_def = from_ascii(
386         "\\DeclareFontEncoding{LGR}{}{}\n");
387 static docstring const textgreek_def = from_ascii(
388         "\\DeclareRobustCommand{\\greektext}{%\n"
389         "  \\fontencoding{LGR}\\selectfont\\def\\encodingdefault{LGR}}\n"
390         "\\DeclareRobustCommand{\\textgreek}[1]{\\leavevmode{\\greektext #1}}\n");
391
392 static docstring const textcyr_T2A_def = from_ascii(
393         "\\InputIfFileExists{t2aenc.def}{}{%\n"
394         "  \\errmessage{File `t2aenc.def' not found: Cyrillic script not supported}}\n");
395 static docstring const textcyr_def = from_ascii(
396         "\\DeclareRobustCommand{\\cyrtext}{%\n"
397         "  \\fontencoding{T2A}\\selectfont\\def\\encodingdefault{T2A}}\n"
398         "\\DeclareRobustCommand{\\textcyrillic}[1]{\\leavevmode{\\cyrtext #1}}\n");
399
400 static docstring const lyxmathsym_def = from_ascii(
401         "\\newcommand{\\lyxmathsym}[1]{\\ifmmode\\begingroup\\def\\b@ld{bold}\n"
402         "  \\text{\\ifx\\math@version\\b@ld\\bfseries\\fi#1}\\endgroup\\else#1\\fi}\n");
403
404 static docstring const papersizedvi_def = from_ascii(
405         "\\special{papersize=\\the\\paperwidth,\\the\\paperheight}\n");
406
407 static docstring const papersizepdf_def = from_ascii(
408         "\\pdfpageheight\\paperheight\n"
409         "\\pdfpagewidth\\paperwidth\n");
410
411 static docstring const papersizepdflua_def = from_ascii(
412         "% Backwards compatibility for LuaTeX < 0.90\n"
413         "\\@ifundefined{pageheight}{\\let\\pageheight\\pdfpageheight}{}\n"
414         "\\@ifundefined{pagewidth}{\\let\\pagewidth\\pdfpagewidth}{}\n"
415         "\\pageheight\\paperheight\n"
416         "\\pagewidth\\paperwidth\n");
417
418 static docstring const cedilla_def = from_ascii(
419         "\\newcommand{\\docedilla}[2]{\\underaccent{#1\\mathchar'30}{#2}}\n"
420         "\\newcommand{\\cedilla}[1]{\\mathpalette\\docedilla{#1}}\n");
421
422 static docstring const subring_def = from_ascii(
423         "\\newcommand{\\dosubring}[2]{\\underaccent{#1\\mathchar'27}{#2}}\n"
424         "\\newcommand{\\subring}[1]{\\mathpalette\\dosubring{#1}}\n");
425
426 static docstring const subdot_def = from_ascii(
427         "\\newcommand{\\dosubdot}[2]{\\underaccent{#1.}{#2}}\n"
428         "\\newcommand{\\subdot}[1]{\\mathpalette\\dosubdot{#1}}\n");
429
430 static docstring const subhat_def = from_ascii(
431         "\\newcommand{\\dosubhat}[2]{\\underaccent{#1\\mathchar'136}{#2}}\n"
432         "\\newcommand{\\subhat}[1]{\\mathpalette\\dosubhat{#1}}\n");
433
434 static docstring const subtilde_def = from_ascii(
435         "\\newcommand{\\dosubtilde}[2]{\\underaccent{#1\\mathchar'176}{#2}}\n"
436         "\\newcommand{\\subtilde}[1]{\\mathpalette\\dosubtilde{#1}}\n");
437
438 static docstring const dacute_def = from_ascii(
439         "\\DeclareMathAccent{\\dacute}{\\mathalpha}{operators}{'175}\n");
440
441 static docstring const tipasymb_def = from_ascii(
442         "\\DeclareFontEncoding{T3}{}{}\n"
443         "\\DeclareSymbolFont{tipasymb}{T3}{cmr}{m}{n}\n");
444
445 static docstring const dgrave_def = from_ascii(
446         "\\DeclareMathAccent{\\dgrave}{\\mathord}{tipasymb}{'15}\n");
447
448 static docstring const rcap_def = from_ascii(
449         "\\DeclareMathAccent{\\rcap}{\\mathord}{tipasymb}{'20}\n");
450
451 static docstring const ogonek_def = from_ascii(
452         "\\newcommand{\\doogonek}[2]{\\setbox0=\\hbox{$#1#2$}\\underaccent{#1\\mkern-6mu\n"
453         "  \\ifx#2O\\hskip0.5\\wd0\\else\\ifx#2U\\hskip0.5\\wd0\\else\\hskip\\wd0\\fi\\fi\n"
454         "  \\ifx#2o\\mkern-2mu\\else\\ifx#2e\\mkern-1mu\\fi\\fi\n"
455         "  \\mathchar\"0\\hexnumber@\\symtipasymb0C}{#2}}\n"
456         "\\newcommand{\\ogonek}[1]{\\mathpalette\\doogonek{#1}}\n");
457
458 static docstring const lyxaccent_def = from_ascii(
459         "%% custom text accent \\LyxTextAccent[<rise value (length)>]{<accent>}{<base>}\n"
460         "\\newcommand*{\\LyxTextAccent}[3][0ex]{%\n"
461         "  \\hmode@bgroup\\ooalign{\\null#3\\crcr\\hidewidth\n"
462         "  \\raise#1\\hbox{#2}\\hidewidth}\\egroup}\n"
463         "%% select a font size smaller than the current font size:\n"
464         "\\newcommand{\\LyxAccentSize}[1][\\sf@size]{%\n"
465         "  \\check@mathfonts\\fontsize#1\\z@\\math@fontsfalse\\selectfont\n"
466         "}\n");
467
468 static docstring const textcommabelow_def = from_ascii(
469         "\\ProvideTextCommandDefault{\\textcommabelow}[1]{%%\n"
470         "  \\LyxTextAccent[-.31ex]{\\LyxAccentSize,}{#1}}\n");
471
472 static docstring const textcommaabove_def = from_ascii(
473         "\\ProvideTextCommandDefault{\\textcommaabove}[1]{%%\n"
474         "  \\LyxTextAccent[.5ex]{\\LyxAccentSize`}{#1}}\n");
475
476 static docstring const textcommaaboveright_def = from_ascii(
477         "\\ProvideTextCommandDefault{\\textcommaaboveright}[1]{%%\n"
478         "  \\LyxTextAccent[.5ex]{\\LyxAccentSize\\ '}{#1}}\n");
479
480 // Baltic languages use a comma-accent instead of a cedilla
481 static docstring const textbaltic_def = from_ascii(
482         "%% use comma accent instead of cedilla for these characters:\n"
483         "\\DeclareTextCompositeCommand{\\c}{T1}{g}{\\textcommaabove{g}}\n"
484         "\\DeclareTextCompositeCommand{\\c}{T1}{G}{\\textcommabelow{G}}\n"
485         "\\DeclareTextCompositeCommand{\\c}{T1}{k}{\\textcommabelow{k}}\n"
486         "\\DeclareTextCompositeCommand{\\c}{T1}{K}{\\textcommabelow{K}}\n"
487         "\\DeclareTextCompositeCommand{\\c}{T1}{l}{\\textcommabelow{l}}\n"
488         "\\DeclareTextCompositeCommand{\\c}{T1}{L}{\\textcommabelow{L}}\n"
489         "\\DeclareTextCompositeCommand{\\c}{T1}{n}{\\textcommabelow{n}}\n"
490         "\\DeclareTextCompositeCommand{\\c}{T1}{N}{\\textcommabelow{N}}\n"
491         "\\DeclareTextCompositeCommand{\\c}{T1}{r}{\\textcommabelow{r}}\n"
492         "\\DeclareTextCompositeCommand{\\c}{T1}{R}{\\textcommabelow{R}}\n");
493
494 // Use cyrillic fonts to provide letter schwa in text (see #11062)
495 static docstring const textschwa_def = from_ascii(
496         "%% letter schwa missing in Latin fonts, use Cyrillic schwa\n"
497         "\\DeclareTextSymbolDefault{\\CYRSCHWA}{T2A}\n"
498         "\\DeclareTextSymbolDefault{\\cyrschwa}{T2A}\n"
499         "\\ProvideTextCommandDefault{\\textSchwa}{\\CYRSCHWA}\n"
500         "\\ProvideTextCommandDefault{\\textschwa}{\\cyrschwa}\n");
501
502 // split-level fractions
503 static docstring const xfrac_def = from_ascii(
504            "\\usepackage{xfrac}\n");
505 static docstring const smallLetterFrac_def = from_ascii(
506         "\\DeclareCollectionInstance{smallLetterFrac}{xfrac}{default}{text}\n"
507         "  {phantom=c, scale-factor=1.0, slash-left-kern=-.05em}\n"
508         "\\DeclareCollectionInstance{smallLetterFrac}{xfrac}{lmr}{text}\n"
509         "  {slash-symbol-font=ptm, phantom=c, scale-factor=1, slash-left-kern=-.05em}\n"
510         "\\DeclareCollectionInstance{smallLetterFrac}{xfrac}{lmss}{text}\n"
511         "  {slash-symbol-font=ptm, phantom=c, scale-factor=1, slash-left-kern=-.05em}\n"
512         "\\DeclareCollectionInstance{smallLetterFrac}{xfrac}{cmr}{text}\n"
513         "  {slash-symbol-font=ptm, phantom=c, scale-factor=1, slash-left-kern=-.05em}\n"
514         "\\DeclareCollectionInstance{smallLetterFrac}{xfrac}{cmss}{text}\n"
515         "  {slash-symbol-font=ptm, phantom=c, scale-factor=1, slash-left-kern=-.05em}\n"
516         "\\newcommand{\\smallLetterFrac}[2]{%\n"
517         "  {\\UseCollection{xfrac}{smallLetterFrac}\\sfrac{#1}{#2}}}\n");
518
519 static docstring const lyxref_def = from_ascii(
520         "\\RS@ifundefined{subsecref}\n"
521         "  {\\newref{subsec}{name = \\RSsectxt}}\n"
522         "  {}\n"
523         "\\RS@ifundefined{thmref}\n"
524         "  {\\def\\RSthmtxt{theorem~}\\newref{thm}{name = \\RSthmtxt}}\n"
525         "  {}\n"
526         "\\RS@ifundefined{lemref}\n"
527         "  {\\def\\RSlemtxt{lemma~}\\newref{lem}{name = \\RSlemtxt}}\n"
528         "  {}\n");
529
530 // Make sure the columns are also outputed as rtl
531 static docstring const rtloutputdblcol_def = from_ascii(
532         "\\def\\@outputdblcol{%\n"
533         "  \\if@firstcolumn\n"
534         "    \\global \\@firstcolumnfalse\n"
535         "    \\global \\setbox\\@leftcolumn \\box\\@outputbox\n"
536         "  \\else\n"
537         "    \\global \\@firstcolumntrue\n"
538         "    \\setbox\\@outputbox \\vbox {%\n"
539         "      \\hb@xt@\\textwidth {%\n"
540         "      \\kern\\textwidth \\kern-\\columnwidth %**\n"
541         "      \\hb@xt@\\columnwidth {%\n"
542         "         \\box\\@leftcolumn \\hss}%\n"
543         "      \\kern-\\textwidth %**\n"
544         "      \\hfil\n"
545         "      {\\normalcolor\\vrule \\@width\\columnseprule}%\n"
546         "      \\hfil\n"
547         "      \\kern-\\textwidth  %**\n"
548         "      \\hb@xt@\\columnwidth {%\n"
549         "         \\box\\@outputbox \\hss}%\n"
550         "      \\kern-\\columnwidth \\kern\\textwidth %**\n"
551         "    }%\n"
552         "  }%\n"
553         "  \\@combinedblfloats\n"
554         "  \\@outputpage\n"
555         "  \\begingroup\n"
556         "  \\@dblfloatplacement\n"
557         "  \\@startdblcolumn\n"
558         "  \\@whilesw\\if@fcolmade \\fi\n"
559         "  {\\@outputpage\n"
560         "    \\@startdblcolumn}%\n"
561         "  \\endgroup\n"
562         "  \\fi\n"
563         "}\n"
564         "\\@mparswitchtrue\n");
565
566 static docstring const lyxmintcaption_def = from_ascii(
567         "\\long\\def\\lyxmintcaption[#1]#2{%\n"
568         "  \\ifx#1t\\vskip\\baselineskip\\fi%\n"
569         "  \\refstepcounter{listing}\\noindent%\n"
570         "  \\addcontentsline{lol}{listing}%\n"
571         "  {\\protect\\numberline{\\thelisting}{\\ignorespaces #2}}%\n"
572         "  \\setbox\\@tempboxa\\hbox{\\listingscaption~\\thelisting: #2}%\n"
573         "  \\ifdim \\wd\\@tempboxa >\\linewidth%\n"
574         "  \\parbox[t]{\\linewidth}{\\unhbox\\@tempboxa}\\else%\n"
575         "  \\hbox to\\linewidth{\\hfil\\box\\@tempboxa\\hfil}\\fi%\n"
576         "  \\ifx#1b\\vskip\\baselineskip\\fi\n"
577         "}\n");
578
579
580 /////////////////////////////////////////////////////////////////////
581 //
582 // LyXHTML strings
583 //
584 /////////////////////////////////////////////////////////////////////
585
586 static docstring const lyxnoun_style = from_ascii(
587         "dfn.lyxnoun {\n"
588         "  font-variant: small-caps;\n"
589         "}\n");
590
591
592 // this is how it normally renders, but it might not always do so.
593 static docstring const lyxstrikeout_style = from_ascii(
594         "del.strikeout {\n"
595         "  text-decoration: line-through;\n"
596         "}\n");
597
598
599 /////////////////////////////////////////////////////////////////////
600 //
601 // LaTeXFeatures
602 //
603 /////////////////////////////////////////////////////////////////////
604
605
606 LaTeXFeatures::LaTeXFeatures(Buffer const & b, BufferParams const & p,
607                                                          OutputParams const & r)
608         : buffer_(&b), params_(p), runparams_(r), in_float_(false),
609           in_deleted_inset_(false)
610 {}
611
612
613 LaTeXFeatures::LangPackage LaTeXFeatures::langPackage() const
614 {
615         string const local_lp = bufferParams().lang_package;
616
617         // Locally, custom is just stored as a string
618         // in bufferParams().lang_package.
619         if (local_lp != "auto"
620             && local_lp != "babel"
621             && local_lp != "default"
622             && local_lp != "none")
623                  return LANG_PACK_CUSTOM;
624
625         if (local_lp == "none")
626                 return LANG_PACK_NONE;
627
628         /* If "auto" is selected, we load polyglossia with non-TeX fonts,
629          * else we select babel.
630          * If babel is selected (either directly or via the "auto"
631          * mechanism), we really do only require it if we have
632          * a language that needs it.
633          */
634         bool const polyglossia_required =
635                 params_.useNonTeXFonts
636                 && isAvailable("polyglossia")
637                 && !isProvided("babel")
638                 && this->hasOnlyPolyglossiaLanguages();
639         bool const babel_required =
640                 !bufferParams().language->babel().empty()
641                 || !this->getBabelLanguages().empty();
642
643         if (local_lp == "auto") {
644                 // polyglossia requirement has priority over babel
645                 if (polyglossia_required)
646                         return LANG_PACK_POLYGLOSSIA;
647                 else if (babel_required)
648                         return LANG_PACK_BABEL;
649         }
650
651         if (local_lp == "babel") {
652                 if (babel_required)
653                         return LANG_PACK_BABEL;
654         }
655
656         if (local_lp == "default") {
657                 switch (lyxrc.language_package_selection) {
658                 case LyXRC::LP_AUTO:
659                         // polyglossia requirement has priority over babel
660                         if (polyglossia_required)
661                                 return LANG_PACK_POLYGLOSSIA;
662                         else if (babel_required)
663                                 return LANG_PACK_BABEL;
664                         break;
665                 case LyXRC::LP_BABEL:
666                         if (babel_required)
667                                 return LANG_PACK_BABEL;
668                         break;
669                 case LyXRC::LP_CUSTOM:
670                         return LANG_PACK_CUSTOM;
671                 case LyXRC::LP_NONE:
672                         return LANG_PACK_NONE;
673                 }
674         }
675
676         return LANG_PACK_NONE;
677 }
678
679
680 void LaTeXFeatures::require(string const & name)
681 {
682         features_.insert(name);
683 }
684
685
686 void LaTeXFeatures::require(set<string> const & names)
687 {
688         features_.insert(names.begin(), names.end());
689 }
690
691
692 void LaTeXFeatures::provide(string const & name)
693 {
694         provides_.insert(name);
695 }
696
697
698 void LaTeXFeatures::useLayout(docstring const & layoutname)
699 {
700         useLayout(layoutname, 0);
701 }
702
703
704 void LaTeXFeatures::useLayout(docstring const & layoutname, int level)
705 {
706         // Some code to avoid loops in dependency definition
707         const int maxlevel = 30;
708         if (level > maxlevel) {
709                 lyxerr << "LaTeXFeatures::useLayout: maximum level of "
710                        << "recursion attained by layout "
711                        << to_utf8(layoutname) << endl;
712                 return;
713         }
714
715         DocumentClass const & tclass = params_.documentClass();
716         if (tclass.hasLayout(layoutname)) {
717                 // Is this layout already in usedLayouts?
718                 if (find(usedLayouts_.begin(), usedLayouts_.end(), layoutname)
719                     != usedLayouts_.end())
720                         return;
721
722                 Layout const & layout = tclass[layoutname];
723                 require(layout.requires());
724
725                 if (!layout.depends_on().empty()) {
726                         useLayout(layout.depends_on(), level + 1);
727                 }
728                 usedLayouts_.push_back(layoutname);
729         } else {
730                 lyxerr << "LaTeXFeatures::useLayout: layout `"
731                        << to_utf8(layoutname) << "' does not exist in this class"
732                        << endl;
733         }
734 }
735
736
737 void LaTeXFeatures::useInsetLayout(InsetLayout const & lay)
738 {
739         docstring const & lname = lay.name();
740         DocumentClass const & tclass = params_.documentClass();
741
742         // this is a default inset layout, nothing useful here
743         if (!tclass.hasInsetLayout(lname))
744                 return;
745         // Is this layout already in usedInsetLayouts?
746         if (find(usedInsetLayouts_.begin(), usedInsetLayouts_.end(), lname)
747                         != usedInsetLayouts_.end())
748                 return;
749
750         require(lay.requires());
751         usedInsetLayouts_.push_back(lname);
752 }
753
754
755 bool LaTeXFeatures::isRequired(string const & name) const
756 {
757         return features_.find(name) != features_.end();
758 }
759
760
761 bool LaTeXFeatures::isProvided(string const & name) const
762 {
763         // Currently, this is only features provided by babel languages
764         // (such as textgreek)
765         if (provides_.find(name) != provides_.end())
766                 return true;
767
768         if (params_.useNonTeXFonts)
769                 return params_.documentClass().provides(name);
770
771         bool const ot1 = (params_.main_font_encoding() == "default"
772                 || params_.main_font_encoding() == "OT1");
773         bool const complete = (params_.fontsSans() == "default"
774                 && params_.fontsTypewriter() == "default");
775         bool const nomath = (params_.fontsMath() == "default");
776         return params_.documentClass().provides(name)
777                 || theLaTeXFonts().getLaTeXFont(
778                         from_ascii(params_.fontsRoman())).provides(name, ot1,
779                                                                   complete,
780                                                                   nomath)
781                 || theLaTeXFonts().getLaTeXFont(
782                         from_ascii(params_.fontsSans())).provides(name, ot1,
783                                                                  complete,
784                                                                  nomath)
785                 || theLaTeXFonts().getLaTeXFont(
786                         from_ascii(params_.fontsTypewriter())).provides(name, ot1,
787                                                                        complete,
788                                                                        nomath)
789                 || theLaTeXFonts().getLaTeXFont(
790                         from_ascii(params_.fontsMath())).provides(name, ot1,
791                                                                        complete,
792                                                                        nomath);
793 }
794
795
796 bool LaTeXFeatures::mustProvide(string const & name) const
797 {
798         return isRequired(name) && !isProvided(name);
799 }
800
801
802 bool LaTeXFeatures::isAvailable(string const & name)
803 {
804         string::size_type const i = name.find("->");
805         if (i != string::npos) {
806                 string const from = name.substr(0,i);
807                 string const to = name.substr(i+2);
808                 //LYXERR0("from=[" << from << "] to=[" << to << "]");
809                 return theConverters().isReachable(from, to);
810         }
811         return LaTeXPackages::isAvailable(name);
812 }
813
814
815 namespace {
816
817 void addSnippet(std::list<TexString> & list, TexString ts, bool allow_dupes)
818 {
819         if (allow_dupes ||
820             // test the absense of duplicates, i.e. elements with same str
821             none_of(list.begin(), list.end(), [&](TexString const & ts2){
822                             return ts.str == ts2.str;
823                     })
824             )
825                 list.push_back(move(ts));
826 }
827
828
829 TexString getSnippets(std::list<TexString> const & list)
830 {
831         otexstringstream snip;
832         for (TexString const & ts : list)
833                 snip << TexString(ts) << '\n';
834         return snip.release();
835 }
836
837 } // namespace
838
839
840 void LaTeXFeatures::addPreambleSnippet(TexString ts, bool allow_dupes)
841 {
842         addSnippet(preamble_snippets_, move(ts), allow_dupes);
843 }
844
845
846 void LaTeXFeatures::addPreambleSnippet(docstring const & str, bool allow_dupes)
847 {
848         addSnippet(preamble_snippets_, TexString(str), allow_dupes);
849 }
850
851
852 void LaTeXFeatures::addCSSSnippet(std::string const & snippet)
853 {
854         addSnippet(css_snippets_, TexString(from_ascii(snippet)), false);
855 }
856
857
858 TexString LaTeXFeatures::getPreambleSnippets() const
859 {
860         return getSnippets(preamble_snippets_);
861 }
862
863
864 docstring LaTeXFeatures::getCSSSnippets() const
865 {
866         return getSnippets(css_snippets_).str;
867 }
868
869
870
871 void LaTeXFeatures::useFloat(string const & name, bool subfloat)
872 {
873         if (!usedFloats_[name])
874                 usedFloats_[name] = subfloat;
875         if (subfloat)
876                 require("subfig");
877         // We only need float.sty if we use non builtin floats, or if we
878         // use the "H" modifier. This includes modified table and
879         // figure floats. (Lgb)
880         Floating const & fl = params_.documentClass().floats().getType(name);
881         if (!fl.floattype().empty()) {
882                 if (fl.usesFloatPkg())
883                         require("float");
884                 if (!fl.requires().empty()) {
885                         vector<string> reqs = getVectorFromString(fl.requires());
886                         for (auto const req : reqs)
887                                 require(req);
888                 }
889         }
890 }
891
892
893 void LaTeXFeatures::useLanguage(Language const * lang)
894 {
895         if (!lang->babel().empty() || !lang->polyglossia().empty())
896                 UsedLanguages_.insert(lang);
897         if (!lang->requires().empty())
898                 require(lang->requires());
899         // currently only supported for Babel
900         if (!lang->provides().empty() && useBabel())
901                 provide(lang->provides());
902         // CJK languages do not have a babel name.
903         // They use the CJK package
904         if (lang->encoding()->package() == Encoding::CJK)
905                 require("CJK");
906         // japanese babel language is special (tied to the pLaTeX engine).
907         if (lang->encoding()->package() == Encoding::japanese)
908                 require("japanese");
909 }
910
911
912 void LaTeXFeatures::includeFile(docstring const & key, string const & name)
913 {
914         IncludedFiles_[key] = name;
915 }
916
917
918 bool LaTeXFeatures::hasLanguages() const
919 {
920         return !UsedLanguages_.empty();
921 }
922
923
924 bool LaTeXFeatures::hasOnlyPolyglossiaLanguages() const
925 {
926         // first the main language
927         if (params_.language->polyglossia().empty())
928                 return false;
929         // now the secondary languages
930         LanguageList::const_iterator const begin = UsedLanguages_.begin();
931         for (LanguageList::const_iterator cit = begin;
932              cit != UsedLanguages_.end();
933              ++cit) {
934                 if ((*cit)->polyglossia().empty())
935                         return false;
936         }
937         return true;
938 }
939
940
941 bool LaTeXFeatures::hasPolyglossiaExclusiveLanguages() const
942 {
943         // first the main language
944         if (params_.language->isPolyglossiaExclusive())
945                 return true;
946         // now the secondary languages
947         LanguageList::const_iterator const begin = UsedLanguages_.begin();
948         for (LanguageList::const_iterator cit = begin;
949              cit != UsedLanguages_.end();
950              ++cit) {
951                 if ((*cit)->isPolyglossiaExclusive())
952                         return true;
953         }
954         return false;
955 }
956
957
958 vector<string> LaTeXFeatures::getPolyglossiaExclusiveLanguages() const
959 {
960         vector<string> result;
961         // first the main language
962         if (params_.language->isPolyglossiaExclusive())
963                 result.push_back(params_.language->display());
964         // now the secondary languages
965         LanguageList::const_iterator const begin = UsedLanguages_.begin();
966         for (LanguageList::const_iterator cit = begin;
967              cit != UsedLanguages_.end();
968              ++cit) {
969                 if ((*cit)->isPolyglossiaExclusive())
970                         result.push_back((*cit)->display());
971         }
972         return result;
973 }
974
975
976 vector<string> LaTeXFeatures::getBabelExclusiveLanguages() const
977 {
978         vector<string> result;
979         // first the main language
980         if (params_.language->isBabelExclusive())
981                 result.push_back(params_.language->display());
982         // now the secondary languages
983         LanguageList::const_iterator const begin = UsedLanguages_.begin();
984         for (LanguageList::const_iterator cit = begin;
985              cit != UsedLanguages_.end();
986              ++cit) {
987                 if ((*cit)->isBabelExclusive())
988                         result.push_back((*cit)->display());
989         }
990         return result;
991 }
992
993
994 string LaTeXFeatures::getBabelLanguages() const
995 {
996         ostringstream langs;
997
998         bool first = true;
999         LanguageList::const_iterator const begin = UsedLanguages_.begin();
1000         for (LanguageList::const_iterator cit = begin;
1001              cit != UsedLanguages_.end();
1002              ++cit) {
1003                 if ((*cit)->babel().empty())
1004                         continue;
1005                 if (!first)
1006                         langs << ',';
1007                 else
1008                         first = false;
1009                 langs << (*cit)->babel();
1010         }
1011         return langs.str();
1012 }
1013
1014
1015 set<string> LaTeXFeatures::getPolyglossiaLanguages() const
1016 {
1017         set<string> langs;
1018
1019         LanguageList::const_iterator const begin = UsedLanguages_.begin();
1020         for (LanguageList::const_iterator cit = begin;
1021              cit != UsedLanguages_.end();
1022              ++cit) {
1023                 // We do not need the variants here
1024                 langs.insert((*cit)->polyglossia());
1025         }
1026         return langs;
1027 }
1028
1029
1030 string LaTeXFeatures::getActiveChars() const
1031 {
1032         string res;
1033         // first the main language
1034         res += params_.language->activeChars();
1035         // now the secondary languages
1036         LanguageList::const_iterator const begin = UsedLanguages_.begin();
1037         for (LanguageList::const_iterator cit = begin;
1038              cit != UsedLanguages_.end(); ++cit)
1039                 res += ((*cit)->activeChars());
1040         return res;
1041 }
1042
1043
1044 set<string> LaTeXFeatures::getEncodingSet(string const & doc_encoding) const
1045 {
1046         // This does only find encodings of languages supported by babel, but
1047         // that does not matter since we don't have a language with an
1048         // encoding supported by inputenc but without babel support.
1049         set<string> encs;
1050         for (auto const & lang : UsedLanguages_)
1051                 if (lang->encoding()->latexName() != doc_encoding &&
1052                     lang->encoding()->package() == Encoding::inputenc)
1053                         encs.insert(lang->encoding()->latexName());
1054         return encs;
1055 }
1056
1057
1058 void LaTeXFeatures::getFontEncodings(vector<string> & encs, bool const onlylangs) const
1059 {
1060         if (!onlylangs) {
1061                 // these must be loaded if glyphs of this script are used
1062                 // unless a language providing them is used in the document
1063                 if (mustProvide("textgreek")
1064                     && find(encs.begin(), encs.end(), "LGR") == encs.end())
1065                         encs.insert(encs.begin(), "LGR");
1066                 if ((mustProvide("textcyrillic") || mustProvide("textschwa"))
1067                     && find(encs.begin(), encs.end(), "T2A") == encs.end())
1068                         encs.insert(encs.begin(), "T2A");
1069         }
1070
1071         for (auto const & lang : UsedLanguages_) {
1072                 vector<string> extraencs =
1073                         getVectorFromString(lang->fontenc(buffer().masterParams()));
1074                 for (auto const & extra : extraencs) {
1075                         if (extra != "none" && find(encs.begin(), encs.end(), extra) == encs.end())
1076                                 encs.insert(encs.begin(), extra);
1077                 }
1078         }
1079 }
1080
1081
1082 bool LaTeXFeatures::hasRTLLanguage() const
1083 {
1084         if (params_.language->rightToLeft())
1085                 return true;
1086         for (auto const & lang : UsedLanguages_)
1087                 if (lang->rightToLeft())
1088                         return true;
1089         return false;
1090 }
1091
1092
1093 namespace {
1094
1095 char const * simplefeatures[] = {
1096 // note that the package order here will be the same in the LaTeX-output
1097         "array",
1098         "verbatim",
1099         "cprotect",
1100         "longtable",
1101         "latexsym",
1102         "pifont",
1103         // subfig is handled in BufferParams.cpp
1104         "varioref",
1105         "prettyref",
1106         "refstyle",
1107         /*For a successful cooperation of the `wrapfig' package with the
1108           `float' package you should load the `wrapfig' package *after*
1109           the `float' package. See the caption package documentation
1110           for explanation.*/
1111         "float",
1112         "wrapfig",
1113         "booktabs",
1114         "dvipost",
1115         "fancybox",
1116         "calc",
1117         "units",
1118         "framed",
1119         "soul",
1120         "dingbat",
1121         "bbding",
1122         "ifsym",
1123         "txfonts",
1124         "pxfonts",
1125         "mathdesign",
1126         "mathrsfs",
1127         "mathabx",
1128         "mathtools",
1129         // "cancel",
1130         "ascii",
1131         "url",
1132         "csquotes",
1133         "enumitem",
1134         "endnotes",
1135         "enotez",
1136         "hhline",
1137         "ifthen",
1138         // listings is handled in BufferParams.cpp
1139         "bm",
1140         "pdfpages",
1141         "amscd",
1142         "slashed",
1143         "multicol",
1144         "multirow",
1145         "tfrupee",
1146         "shapepar",
1147         "rsphrase",
1148         "hpstatement",
1149         "algorithm2e",
1150         "sectionbox",
1151         "tcolorbox",
1152         "pdfcomment",
1153         "fixme",
1154         "todonotes",
1155         "forest",
1156         "varwidth",
1157         "tablefootnote",
1158         "afterpage",
1159         "tabularx",
1160         "tikz",
1161         "xltabular",
1162         "chessboard",
1163         "xskak",
1164         "pict2e",
1165         "drs",
1166         "environ"
1167 };
1168
1169 char const * bibliofeatures[] = {
1170         // Known bibliography packages (will be loaded before natbib)
1171         "achicago",
1172         "apacite",
1173         "apalike",
1174         "astron",
1175         "authordate1-4",
1176         "babelbib",
1177         "bibgerm",
1178         "chapterbib",
1179         "chicago",
1180         "chscite",
1181         "harvard",
1182         "mslapa",
1183         "named"
1184 };
1185
1186 int const nb_bibliofeatures = sizeof(bibliofeatures) / sizeof(char const *);
1187
1188 int const nb_simplefeatures = sizeof(simplefeatures) / sizeof(char const *);
1189
1190 } // namespace
1191
1192
1193 string const LaTeXFeatures::getColorOptions() const
1194 {
1195         ostringstream colors;
1196
1197         // Handling the color packages separately is needed to be able to load them
1198         // before babel when hyperref is loaded with the colorlinks option
1199         // for more info see Bufferparams.cpp
1200
1201         // [x]color.sty
1202         if (mustProvide("color") || mustProvide("xcolor")) {
1203                 string const package =
1204                         (mustProvide("xcolor") ? "xcolor" : "color");
1205                 if (params_.graphics_driver == "default"
1206                         || params_.graphics_driver == "none")
1207                         colors << "\\usepackage{" << package << "}\n";
1208                 else
1209                         colors << "\\usepackage["
1210                                  << params_.graphics_driver
1211                                  << "]{" << package << "}\n";
1212         }
1213
1214         // pdfcolmk must be loaded after color
1215         if (mustProvide("pdfcolmk"))
1216                 colors << "\\usepackage{pdfcolmk}\n";
1217
1218         // the following 3 color commands must be set after color
1219         // is loaded and before pdfpages, therefore add the command
1220         // here define the set color
1221         if (mustProvide("pagecolor")) {
1222                 colors << "\\definecolor{page_backgroundcolor}{rgb}{";
1223                 colors << outputLaTeXColor(params_.backgroundcolor) << "}\n";
1224                 // set the page color
1225                 colors << "\\pagecolor{page_backgroundcolor}\n";
1226         }
1227
1228         if (mustProvide("fontcolor")) {
1229                 colors << "\\definecolor{document_fontcolor}{rgb}{";
1230                 colors << outputLaTeXColor(params_.fontcolor) << "}\n";
1231                 // set the color
1232                 colors << "\\color{document_fontcolor}\n";
1233         }
1234
1235         if (mustProvide("lyxgreyedout")) {
1236                 colors << "\\definecolor{note_fontcolor}{rgb}{";
1237                 colors << outputLaTeXColor(params_.notefontcolor) << "}\n";
1238                 // the color will be set together with the definition of
1239                 // the lyxgreyedout environment (see lyxgreyedout_def)
1240         }
1241
1242         // color for shaded boxes
1243         if (isRequired("framed") && mustProvide("color")) {
1244                 colors << "\\definecolor{shadecolor}{rgb}{";
1245                 colors << outputLaTeXColor(params_.boxbgcolor) << "}\n";
1246                 // this color is automatically used by the LaTeX-package "framed"
1247         }
1248
1249         return colors.str();
1250 }
1251
1252
1253 string const LaTeXFeatures::getPackageOptions() const
1254 {
1255         ostringstream packageopts;
1256         // Output all the package option stuff we have been asked to do.
1257         map<string, string>::const_iterator it =
1258                 params_.documentClass().packageOptions().begin();
1259         map<string, string>::const_iterator en =
1260                 params_.documentClass().packageOptions().end();
1261         for (; it != en; ++it)
1262                 if (mustProvide(it->first))
1263                         packageopts << "\\PassOptionsToPackage{" << it->second << "}"
1264                                  << "{" << it->first << "}\n";
1265         return packageopts.str();
1266 }
1267
1268
1269 string const LaTeXFeatures::getPackages() const
1270 {
1271         ostringstream packages;
1272
1273         // FIXME: currently, we can only load packages and macros known
1274         // to LyX.
1275         // However, with the Require tag of layouts/custom insets,
1276         // also unknown packages can be requested. They are silently
1277         // swallowed now. We should change this eventually.
1278
1279         //  These are all the 'simple' includes.  i.e
1280         //  packages which we just \usepackage{package}
1281         for (int i = 0; i < nb_simplefeatures; ++i) {
1282                 if (mustProvide(simplefeatures[i]))
1283                         packages << "\\usepackage{" << simplefeatures[i] << "}\n";
1284         }
1285
1286         // The rest of these packages are somewhat more complicated
1287         // than those above.
1288
1289         if (mustProvide("changebar") && !mustProvide("ct-dvipost")) {
1290                 packages << "\\usepackage{changebar}\n";
1291         }
1292
1293         if (mustProvide("footnote")) {
1294                 if (isRequired("hyperref"))
1295                         packages << "\\usepackage{footnotehyper}\n";
1296                 else
1297                         packages << "\\usepackage{footnote}\n";
1298         }
1299
1300         // [pdf]lscape is used to rotate longtables
1301         if (mustProvide("lscape")) {
1302                 if (runparams_.flavor == OutputParams::LATEX
1303                     || runparams_.flavor == OutputParams::DVILUATEX)
1304                         packages << "\\usepackage{lscape}\n";
1305                 else
1306                         packages << "\\usepackage{pdflscape}\n";
1307         }
1308
1309         // The tipa package and its extensions (tipx, tone) must not
1310         // be loaded with non-TeX fonts, since fontspec includes the
1311         // respective macros
1312         if (mustProvide("tipa") && !params_.useNonTeXFonts)
1313                 packages << "\\usepackage{tipa}\n";
1314         if (mustProvide("tipx") && !params_.useNonTeXFonts)
1315                 packages << "\\usepackage{tipx}\n";
1316         if (mustProvide("extraipa") && !params_.useNonTeXFonts)
1317                 packages << "\\usepackage{extraipa}\n";
1318         if (mustProvide("tone") && !params_.useNonTeXFonts)
1319                 packages << "\\usepackage{tone}\n";
1320
1321         // if fontspec or newtxmath is used, AMS packages have to be loaded
1322         // before fontspec (in BufferParams)
1323         string const amsPackages = loadAMSPackages();
1324         bool const ot1 = (params_.main_font_encoding() == "default"
1325                           || params_.main_font_encoding() == "OT1");
1326         bool const use_newtxmath =
1327                 theLaTeXFonts().getLaTeXFont(from_ascii(params_.fontsMath())).getUsedPackage(
1328                         ot1, false, false) == "newtxmath";
1329
1330         if (!params_.useNonTeXFonts && !use_newtxmath && !amsPackages.empty())
1331                 packages << amsPackages;
1332
1333         if (mustProvide("cancel") &&
1334             params_.use_package("cancel") != BufferParams::package_off)
1335                 packages << "\\usepackage{cancel}\n";
1336
1337         // marvosym and bbding both define the \Cross macro
1338         if (mustProvide("marvosym")) {
1339             if (mustProvide("bbding"))
1340                 packages << "\\let\\Cross\\relax\n";
1341             packages << "\\usepackage{marvosym}\n";
1342         }
1343
1344         // accents must be loaded after amsmath
1345         if (mustProvide("accents") &&
1346             params_.use_package("accents") != BufferParams::package_off)
1347                 packages << "\\usepackage{accents}\n";
1348
1349         // mathdots must be loaded after amsmath
1350         if (mustProvide("mathdots") &&
1351                 params_.use_package("mathdots") != BufferParams::package_off)
1352                 packages << "\\usepackage{mathdots}\n";
1353
1354         // yhmath must be loaded after amsmath
1355         if (mustProvide("yhmath") &&
1356             params_.use_package("yhmath") != BufferParams::package_off)
1357                 packages << "\\usepackage{yhmath}\n";
1358
1359         // stmaryrd must be loaded after amsmath
1360         if (mustProvide("stmaryrd") &&
1361             params_.use_package("stmaryrd") != BufferParams::package_off)
1362                 packages << "\\usepackage{stmaryrd}\n";
1363
1364         if (mustProvide("stackrel") &&
1365             params_.use_package("stackrel") != BufferParams::package_off)
1366                 packages << "\\usepackage{stackrel}\n";
1367
1368         if (mustProvide("undertilde") &&
1369                 params_.use_package("undertilde") != BufferParams::package_off)
1370                 packages << "\\usepackage{undertilde}\n";
1371
1372         // [x]color and pdfcolmk are handled in getColorOptions() above
1373
1374         // makeidx.sty
1375         if (isRequired("makeidx") || isRequired("splitidx")) {
1376                 if (!isProvided("makeidx") && !isRequired("splitidx"))
1377                         packages << "\\usepackage{makeidx}\n";
1378                 if (mustProvide("splitidx"))
1379                         packages << "\\usepackage{splitidx}\n";
1380                 packages << "\\makeindex\n";
1381         }
1382
1383         // graphicx.sty
1384         if (mustProvide("graphicx") && params_.graphics_driver != "none") {
1385                 if (params_.graphics_driver == "default")
1386                         packages << "\\usepackage{graphicx}\n";
1387                 else
1388                         packages << "\\usepackage["
1389                                  << params_.graphics_driver
1390                                  << "]{graphicx}\n";
1391         }
1392
1393         // These must be loaded after graphicx, since they try
1394         // to load graphicx without options
1395         if (mustProvide("rotating"))
1396                 packages << "\\usepackage{rotating}\n";
1397         if (mustProvide("rotfloat"))
1398                 packages << "\\usepackage{rotfloat}\n";
1399
1400         // lyxskak.sty --- newer chess support based on skak.sty
1401         if (mustProvide("chess"))
1402                 packages << "\\usepackage[ps,mover]{lyxskak}\n";
1403
1404         // setspace.sty
1405         if (mustProvide("setspace") && !isProvided("SetSpace"))
1406                 packages << "\\usepackage{setspace}\n";
1407
1408         // we need to assure that mhchem is loaded before esint and every other
1409         // package that redefines command of amsmath because mhchem loads amlatex
1410         // (this info is from the author of mhchem from June 2013)
1411         if (mustProvide("mhchem") &&
1412             params_.use_package("mhchem") != BufferParams::package_off)
1413                 packages << "\\PassOptionsToPackage{version=3}{mhchem}\n"
1414                             "\\usepackage{mhchem}\n";
1415
1416         // wasysym is a simple feature, but it must be after amsmath if both
1417         // are used
1418         // wasysym redefines some integrals (e.g. iint) from amsmath. That
1419         // leads to inconsistent integrals. We only load this package if
1420         // the document does not contain integrals (then isRequired("esint")
1421         // is false) or if esint is used, since esint redefines all relevant
1422         // integral symbols from wasysym and amsmath.
1423         // See http://www.lyx.org/trac/ticket/1942
1424         if (mustProvide("wasysym") &&
1425             params_.use_package("wasysym") != BufferParams::package_off &&
1426             (params_.use_package("esint") != BufferParams::package_off || !isRequired("esint")))
1427                 packages << "\\usepackage{wasysym}\n";
1428
1429         // esint must be after amsmath (and packages requiring amsmath, like mhchem)
1430         // and wasysym, since it will redeclare inconsistent integral symbols
1431         if (mustProvide("esint") &&
1432             params_.use_package("esint") != BufferParams::package_off)
1433                 packages << "\\usepackage{esint}\n";
1434
1435         // Known bibliography packages (simple \usepackage{package})
1436         for (int i = 0; i < nb_bibliofeatures; ++i) {
1437                 if (mustProvide(bibliofeatures[i]))
1438                         packages << "\\usepackage{"
1439                                  << bibliofeatures[i] << "}\n";
1440         }
1441
1442         // Compatibility between achicago and natbib
1443         if (mustProvide("achicago") && mustProvide("natbib"))
1444                 packages << "\\let\\achicagobib\\thebibliography\n";
1445
1446         // natbib.sty
1447         // Some classes load natbib themselves, but still allow (or even require)
1448         // plain numeric citations (ReVTeX is such a case, see bug 5182).
1449         // This special case is indicated by the "natbib-internal" key.
1450         if (mustProvide("natbib")
1451             && !isProvided("natbib-internal")
1452             && !isProvided("biblatex")
1453             && !isProvided("biblatex-natbib")
1454             && !isProvided("jurabib")) {
1455                 packages << "\\usepackage[";
1456                 if (params_.citeEngineType() == ENGINE_TYPE_NUMERICAL)
1457                         packages << "numbers";
1458                 else
1459                         packages << "authoryear";
1460                 if (!params_.biblio_opts.empty())
1461                         packages << ',' << params_.biblio_opts;
1462                 packages << "]{natbib}\n";
1463         }
1464
1465         // Compatibility between achicago and natbib
1466         if (mustProvide("achicago") && mustProvide("natbib")) {
1467                 packages << "\\let\\thebibliography\\achicagobib\n";
1468                 packages << "\\let\\SCcite\\astroncite\n";
1469                 packages << "\\let\\UnexpandableProtect\\protect\n";
1470         }
1471
1472         // jurabib -- we need version 0.6 at least.
1473         if (mustProvide("jurabib")
1474             && !isProvided("natbib-internal")
1475             && !isProvided("natbib")
1476             && !isProvided("biblatex")
1477             && !isProvided("biblatex-natbib")) {
1478                 packages << "\\usepackage";
1479                 if (!params_.biblio_opts.empty())
1480                         packages << '[' << params_.biblio_opts << ']';
1481                 packages << "{jurabib}[2004/01/25]\n";
1482         }
1483
1484         // opcit -- we pass custombst as we output \bibliographystyle ourselves
1485         if (mustProvide("opcit")) {
1486                 if (isRequired("hyperref"))
1487                         packages << "\\usepackage[custombst,hyperref]{opcit}\n";
1488                 else
1489                         packages << "\\usepackage[custombst]{opcit}\n";
1490         }
1491
1492         // xargs -- we need version 1.09 at least
1493         if (mustProvide("xargs"))
1494                 packages << "\\usepackage{xargs}[2008/03/08]\n";
1495
1496         if (mustProvide("xy"))
1497                 packages << "\\usepackage[all]{xy}\n";
1498
1499         if (mustProvide("feyn"))
1500                 packages << "\\usepackage{feyn}\n"; //Diagram
1501
1502         if (mustProvide("ulem"))
1503                 packages << "\\PassOptionsToPackage{normalem}{ulem}\n"
1504                             "\\usepackage{ulem}\n";
1505
1506         if (mustProvide("nomencl")) {
1507                 // Make it work with the new and old version of the package,
1508                 // but don't use the compatibility option since it is
1509                 // incompatible to other packages.
1510                 packages << "\\usepackage{nomencl}\n"
1511                             "% the following is useful when we have the old nomencl.sty package\n"
1512                             "\\providecommand{\\printnomenclature}{\\printglossary}\n"
1513                             "\\providecommand{\\makenomenclature}{\\makeglossary}\n"
1514                             "\\makenomenclature\n";
1515         }
1516
1517         // fixltx2e provides subscript
1518         if (mustProvide("subscript") && !isRequired("fixltx2e"))
1519                 packages << "\\usepackage{subscript}\n";
1520
1521         // footmisc must be loaded after setspace
1522         // Set options here, load the package after the user preamble to
1523         // avoid problems with manual loaded footmisc.
1524         if (mustProvide("footmisc"))
1525                 packages << "\\PassOptionsToPackage{stable}{footmisc}\n";
1526
1527         if (mustProvide("microtype")){
1528                 packages << "\\usepackage{microtype}\n";
1529         }
1530
1531         return packages.str();
1532 }
1533
1534
1535 TexString LaTeXFeatures::getMacros() const
1536 {
1537         otexstringstream macros;
1538
1539         if (!preamble_snippets_.empty()) {
1540                 macros << '\n';
1541                 macros << getPreambleSnippets();
1542         }
1543
1544         if (mustProvide("xetexdashbreakstate"))
1545                 macros << "\\XeTeXdashbreakstate 0" << '\n';
1546
1547         if (mustProvide("papersize")) {
1548                 if (runparams_.flavor == OutputParams::LATEX
1549                     || runparams_.flavor == OutputParams::DVILUATEX)
1550                         macros << papersizedvi_def << '\n';
1551                 else if  (runparams_.flavor == OutputParams::LUATEX)
1552                         macros << papersizepdflua_def << '\n';
1553                 else
1554                         macros << papersizepdf_def << '\n';
1555         }
1556
1557         if (mustProvide("LyX")) {
1558                 macros << "\\providecommand{\\LyX}";
1559                 // open conditional wrappers
1560                 if (runparams_.use_polyglossia && hasRTLLanguage())
1561                         macros << "{\\@ensure@LTR";
1562                 if (isRequired("hyperref"))
1563                         macros << "{\\texorpdfstring";
1564                 if (useBabel())
1565                         macros << "{\\ensureascii";
1566                 // main definition
1567                 macros << lyx_def;
1568                 // close conditional wrappers
1569                 if (useBabel())
1570                         macros << '}';
1571                 if (isRequired("hyperref"))
1572                         macros << "{LyX}}";
1573                 if (runparams_.use_polyglossia && hasRTLLanguage())
1574                         macros << '}';
1575                 macros << '\n';
1576         }
1577
1578         if (mustProvide("noun"))
1579                 macros << noun_def << '\n';
1580
1581         if (mustProvide("lyxarrow"))
1582                 macros << lyxarrow_def << '\n';
1583
1584         if (mustProvide("lyxzerowidthspace"))
1585                 macros << lyxZWSP_def << '\n';
1586
1587         if (!usePolyglossia() && mustProvide("textgreek")) {
1588             // ensure LGR font encoding is defined also if fontenc is not loaded by LyX
1589                 if (params_.main_font_encoding() == "default")
1590                         macros << textgreek_LGR_def;
1591                 macros << textgreek_def << '\n';
1592         }
1593
1594         if (!usePolyglossia() && mustProvide("textcyrillic")) {
1595                 // ensure T2A font encoding is set up also if fontenc is not loaded by LyX
1596                 if (params_.main_font_encoding() == "default")
1597                         macros << textcyr_T2A_def;
1598                 macros << textcyr_def << '\n';
1599         }
1600
1601         // non-standard text accents:
1602         if (mustProvide("textcommaabove") || mustProvide("textcommaaboveright") ||
1603             mustProvide("textcommabelow") || mustProvide("textbaltic"))
1604                 macros << lyxaccent_def;
1605
1606         if (mustProvide("textcommabelow") || mustProvide("textbaltic"))
1607                 macros << textcommabelow_def << '\n';
1608
1609         if (mustProvide("textcommaabove") || mustProvide("textbaltic"))
1610                 macros << textcommaabove_def << '\n';
1611
1612         if (mustProvide("textcommaaboveright"))
1613                 macros << textcommaaboveright_def << '\n';
1614
1615         if (mustProvide("textbaltic"))
1616                 macros << textbaltic_def << '\n';
1617
1618         if (mustProvide("textschwa"))
1619                 macros << textschwa_def << '\n';
1620
1621         // split-level fractions
1622         if (mustProvide("xfrac") || mustProvide("smallLetterFrac"))
1623                 macros << xfrac_def << '\n';
1624
1625         if (mustProvide("smallLetterFrac"))
1626                 macros << smallLetterFrac_def << '\n';
1627
1628         if (mustProvide("lyxmathsym"))
1629                 macros << lyxmathsym_def << '\n';
1630
1631         if (mustProvide("cedilla"))
1632                 macros << cedilla_def << '\n';
1633
1634         if (mustProvide("subring"))
1635                 macros << subring_def << '\n';
1636
1637         if (mustProvide("subdot"))
1638                 macros << subdot_def << '\n';
1639
1640         if (mustProvide("subhat"))
1641                 macros << subhat_def << '\n';
1642
1643         if (mustProvide("subtilde"))
1644                 macros << subtilde_def << '\n';
1645
1646         if (mustProvide("dacute"))
1647                 macros << dacute_def << '\n';
1648
1649         if (mustProvide("tipasymb"))
1650                 macros << tipasymb_def << '\n';
1651
1652         if (mustProvide("dgrave"))
1653                 macros << dgrave_def << '\n';
1654
1655         if (mustProvide("rcap"))
1656                 macros << rcap_def << '\n';
1657
1658         if (mustProvide("ogonek"))
1659                 macros << ogonek_def << '\n';
1660
1661         // quotes.
1662         if (mustProvide("quotesinglbase"))
1663                 macros << quotesinglbase_def << '\n';
1664         if (mustProvide("quotedblbase"))
1665                 macros << quotedblbase_def << '\n';
1666         if (mustProvide("guilsinglleft"))
1667                 macros << guilsinglleft_def << '\n';
1668         if (mustProvide("guilsinglright"))
1669                 macros << guilsinglright_def << '\n';
1670         if (mustProvide("guillemotleft"))
1671                 macros << guillemotleft_def << '\n';
1672         if (mustProvide("guillemotright"))
1673                 macros << guillemotright_def << '\n';
1674         if (mustProvide("textquotedbl"))
1675                 macros << textquotedbl_def << '\n';
1676         if (mustProvide("textquotesinglep")) {
1677                 if (runparams_.flavor == OutputParams::XETEX)
1678                         macros << textquotesinglep_xetex_def << '\n';
1679                 else
1680                         macros << textquotesinglep_luatex_def << '\n';
1681         }
1682         if (mustProvide("textquotedblp")) {
1683                 if (runparams_.flavor == OutputParams::XETEX)
1684                         macros << textquotedblp_xetex_def << '\n';
1685                 else
1686                         macros << textquotedblp_luatex_def << '\n';
1687         }
1688
1689         // Math mode
1690         if (mustProvide("binom") && !isRequired("amsmath"))
1691                 macros << binom_def << '\n';
1692         if (mustProvide("mathcircumflex"))
1693                 macros << mathcircumflex_def << '\n';
1694
1695         // other
1696         if (mustProvide("ParagraphLeftIndent"))
1697                 macros << paragraphleftindent_def;
1698         if (mustProvide("NeedLyXFootnoteCode"))
1699                 macros << floatingfootnote_def;
1700
1701         // some problems with tex->html converters
1702         if (mustProvide("NeedTabularnewline"))
1703                 macros << tabularnewline_def;
1704
1705         // greyed-out environment (note inset)
1706         // the color is specified in the routine
1707         // getColorOptions() to avoid LaTeX-package clashes
1708         if (mustProvide("lyxgreyedout")) {
1709                 // We need different version for RTL (#8647)
1710                 if (hasRTLLanguage()) {
1711                         if (runparams_.flavor == OutputParams::LUATEX)
1712                                 if (useBabel())
1713                                         macros << lyxgreyedout_luartl_babel_def;
1714                                 else
1715                                         macros << lyxgreyedout_luartl_def;
1716                         else
1717                                 macros << lyxgreyedout_rtl_def;
1718                 } else
1719                         macros << lyxgreyedout_def;
1720         }
1721
1722         if (mustProvide("lyxdot"))
1723                 macros << lyxdot_def << '\n';
1724
1725         // floats
1726         getFloatDefinitions(macros);
1727
1728         if (mustProvide("refstyle"))
1729                 macros << lyxref_def << '\n';
1730
1731         // change tracking
1732         if (mustProvide("ct-dvipost")) {
1733                 if (isRequired("changebar"))
1734                         macros << changetracking_dvipost_cb_def;
1735                 else
1736                         macros << changetracking_dvipost_def;
1737         }
1738
1739         if (mustProvide("ct-xcolor-ulem")) {
1740                 streamsize const prec = macros.os().precision(2);
1741
1742                 RGBColor cadd = rgbFromHexName(lcolor.getX11Name(Color_addedtext));
1743                 macros << "\\providecolor{lyxadded}{rgb}{"
1744                        << cadd.r / 255.0 << ',' << cadd.g / 255.0 << ',' << cadd.b / 255.0 << "}\n";
1745
1746                 RGBColor cdel = rgbFromHexName(lcolor.getX11Name(Color_deletedtext));
1747                 macros << "\\providecolor{lyxdeleted}{rgb}{"
1748                        << cdel.r / 255.0 << ',' << cdel.g / 255.0 << ',' << cdel.b / 255.0 << "}\n";
1749
1750                 macros.os().precision(prec);
1751
1752                 macros << changetracking_xcolor_ulem_base_def;
1753
1754                 if (isRequired("changebar")) {
1755                         if (isRequired("hyperref"))
1756                                 macros << changetracking_xcolor_ulem_hyperref_cb_def;
1757                         else
1758                                 macros << changetracking_xcolor_ulem_cb_def;
1759                 } else {
1760                         if (isRequired("hyperref"))
1761                                 macros << changetracking_xcolor_ulem_hyperref_def;
1762                         else
1763                                 macros << changetracking_xcolor_ulem_def;
1764                 }
1765         }
1766
1767         if (mustProvide("ct-tikz-object-sout")) {
1768                 if (!mustProvide("ct-xcolor-ulem")) {
1769                         streamsize const prec = macros.os().precision(2);
1770
1771                         RGBColor cadd = rgbFromHexName(lcolor.getX11Name(Color_addedtext));
1772                         macros << "\\providecolor{lyxadded}{rgb}{"
1773                                << cadd.r / 255.0 << ',' << cadd.g / 255.0 << ',' << cadd.b / 255.0 << "}\n";
1774         
1775                         RGBColor cdel = rgbFromHexName(lcolor.getX11Name(Color_deletedtext));
1776                         macros << "\\providecolor{lyxdeleted}{rgb}{"
1777                                << cdel.r / 255.0 << ',' << cdel.g / 255.0 << ',' << cdel.b / 255.0 << "}\n";
1778         
1779                         macros.os().precision(prec);
1780                 }
1781                 
1782                 macros << changetracking_tikz_object_sout_def;
1783                 
1784                 if (isRequired("changebar")) {
1785                         if (isRequired("hyperref"))
1786                                 macros << changetracking_xcolor_ulem_hyperref_cb_object_def;
1787                         else
1788                                 macros << changetracking_xcolor_ulem_cb_object_def;
1789                 } else {
1790                         if (isRequired("hyperref"))
1791                                 macros << changetracking_xcolor_ulem_hyperref_object_def;
1792                         else
1793                                 macros << changetracking_xcolor_ulem_object_def;
1794                 }
1795         }
1796
1797         if (mustProvide("ct-none"))
1798                 macros << changetracking_none_def;
1799
1800         if (mustProvide("rtloutputdblcol"))
1801                 macros << rtloutputdblcol_def;
1802
1803         if (mustProvide("lyxmintcaption"))
1804                 macros << lyxmintcaption_def;
1805
1806         return macros.release();
1807 }
1808
1809
1810 docstring const LaTeXFeatures::getBabelPresettings() const
1811 {
1812         odocstringstream tmp;
1813
1814         for (Language const * lang : UsedLanguages_)
1815                 if (!lang->babel_presettings().empty())
1816                         tmp << lang->babel_presettings() << '\n';
1817         if (!params_.language->babel_presettings().empty())
1818                 tmp << params_.language->babel_presettings() << '\n';
1819
1820         if (!contains(tmp.str(), '@'))
1821                 return tmp.str();
1822
1823         return "\\makeatletter\n" + tmp.str() + "\\makeatother\n";
1824 }
1825
1826
1827 docstring const LaTeXFeatures::getBabelPostsettings() const
1828 {
1829         odocstringstream tmp;
1830
1831         for (Language const * lang : UsedLanguages_)
1832                 if (!lang->babel_postsettings().empty())
1833                         tmp << lang->babel_postsettings() << '\n';
1834         if (!params_.language->babel_postsettings().empty())
1835                 tmp << params_.language->babel_postsettings() << '\n';
1836
1837         if (!contains(tmp.str(), '@'))
1838                 return tmp.str();
1839
1840         return "\\makeatletter\n" + tmp.str() + "\\makeatother\n";
1841 }
1842
1843
1844 string const LaTeXFeatures::loadAMSPackages() const
1845 {
1846         ostringstream tmp;
1847
1848         if (mustProvide("amsmath")
1849             && params_.use_package("amsmath") != BufferParams::package_off) {
1850                 tmp << "\\usepackage{amsmath}\n";
1851         } else {
1852                 // amsbsy and amstext are already provided by amsmath
1853                 if (mustProvide("amsbsy"))
1854                         tmp << "\\usepackage{amsbsy}\n";
1855                 if (mustProvide("amstext"))
1856                         tmp << "\\usepackage{amstext}\n";
1857         }
1858
1859         if (mustProvide("amsthm"))
1860                 tmp << "\\usepackage{amsthm}\n";
1861
1862         if (mustProvide("amssymb")
1863             && params_.use_package("amssymb") != BufferParams::package_off)
1864                 tmp << "\\usepackage{amssymb}\n";
1865
1866         return tmp.str();
1867 }
1868
1869
1870 docstring const LaTeXFeatures::getTClassPreamble() const
1871 {
1872         // the text class specific preamble
1873         DocumentClass const & tclass = params_.documentClass();
1874         odocstringstream tcpreamble;
1875
1876         tcpreamble << tclass.preamble();
1877
1878         list<docstring>::const_iterator cit = usedLayouts_.begin();
1879         list<docstring>::const_iterator end = usedLayouts_.end();
1880         for (; cit != end; ++cit)
1881                 // For InPreamble layouts, we output the preamble stuff earlier
1882                 // (before the layouts). See Paragraph::Private::validate.
1883                 if (!tclass[*cit].inpreamble)
1884                         tcpreamble << tclass[*cit].preamble();
1885
1886         cit = usedInsetLayouts_.begin();
1887         end = usedInsetLayouts_.end();
1888         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
1889         for (; cit != end; ++cit) {
1890                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
1891                 if (it == ils.end())
1892                         continue;
1893                 tcpreamble << it->second.preamble();
1894         }
1895
1896         return tcpreamble.str();
1897 }
1898
1899
1900 docstring const LaTeXFeatures::getTClassHTMLPreamble() const
1901 {
1902         DocumentClass const & tclass = params_.documentClass();
1903         odocstringstream tcpreamble;
1904
1905         tcpreamble << tclass.htmlpreamble();
1906
1907         list<docstring>::const_iterator cit = usedLayouts_.begin();
1908         list<docstring>::const_iterator end = usedLayouts_.end();
1909         for (; cit != end; ++cit)
1910                 tcpreamble << tclass[*cit].htmlpreamble();
1911
1912         cit = usedInsetLayouts_.begin();
1913         end = usedInsetLayouts_.end();
1914         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
1915         for (; cit != end; ++cit) {
1916                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
1917                 if (it == ils.end())
1918                         continue;
1919                 tcpreamble << it->second.htmlpreamble();
1920         }
1921
1922         return tcpreamble.str();
1923 }
1924
1925
1926 docstring const LaTeXFeatures::getTClassHTMLStyles() const
1927 {
1928         DocumentClass const & tclass = params_.documentClass();
1929         odocstringstream tcpreamble;
1930
1931         if (mustProvide("noun"))
1932                 tcpreamble << lyxnoun_style;
1933         // this isn't exact, but it won't hurt that much if it
1934         // wasn't for this.
1935         if (mustProvide("ulem"))
1936                 tcpreamble << lyxstrikeout_style;
1937
1938         tcpreamble << tclass.htmlstyles();
1939
1940         list<docstring>::const_iterator cit = usedLayouts_.begin();
1941         list<docstring>::const_iterator end = usedLayouts_.end();
1942         for (; cit != end; ++cit)
1943                 tcpreamble << tclass[*cit].htmlstyle();
1944
1945         cit = usedInsetLayouts_.begin();
1946         end = usedInsetLayouts_.end();
1947         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
1948         for (; cit != end; ++cit) {
1949                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
1950                 if (it == ils.end())
1951                         continue;
1952                 tcpreamble << it->second.htmlstyle();
1953         }
1954
1955         return tcpreamble.str();
1956 }
1957
1958
1959 namespace {
1960
1961 docstring const getFloatI18nPreamble(docstring const & type,
1962                         docstring const & name, Language const * lang,
1963                         Encoding const & enc, bool const polyglossia)
1964 {
1965         // Check whether name can be encoded in the buffer encoding
1966         bool encodable = true;
1967         for (size_t i = 0; i < name.size(); ++i) {
1968                 if (!enc.encodable(name[i])) {
1969                         encodable = false;
1970                         break;
1971                 }
1972         }
1973
1974         docstring const language = polyglossia ? from_ascii(lang->polyglossia())
1975                                                : from_ascii(lang->babel());
1976         docstring const langenc = from_ascii(lang->encoding()->iconvName());
1977         docstring const texenc = from_ascii(lang->encoding()->latexName());
1978         docstring const bufenc = from_ascii(enc.iconvName());
1979         docstring const s1 = docstring(1, 0xF0000);
1980         docstring const s2 = docstring(1, 0xF0001);
1981         docstring const translated = encodable ? name
1982                 : from_ascii("\\inputencoding{") + texenc + from_ascii("}")
1983                         + s1 + langenc + s2 + name + s1 + bufenc + s2;
1984
1985         odocstringstream os;
1986         os << "\\addto\\captions" << language
1987            << "{\\renewcommand{\\" << type << "name}{" << translated << "}}\n";
1988         return os.str();
1989 }
1990
1991
1992 docstring const i18npreamble(docstring const & templ, Language const * lang,
1993                              Encoding const & enc, bool const polyglossia,
1994                              bool const need_fixedwidth)
1995 {
1996         if (templ.empty())
1997                 return templ;
1998
1999         string preamble = polyglossia ?
2000                 subst(to_utf8(templ), "$$lang", lang->polyglossia()) :
2001                 subst(to_utf8(templ), "$$lang", lang->babel());
2002
2003         string const langenc = lang->encoding()->iconvName();
2004         string const texenc = lang->encoding()->latexName();
2005         string const bufenc = enc.iconvName();
2006         Encoding const * testenc(&enc);
2007         bool lang_fallback = false;
2008         bool ascii_fallback = false;
2009         if (need_fixedwidth && !enc.hasFixedWidth()) {
2010                 if (lang->encoding()->hasFixedWidth()) {
2011                         testenc = lang->encoding();
2012                         lang_fallback = true;
2013                 } else {
2014                         // We need a fixed width encoding, but both the buffer
2015                         // encoding and the language encoding are variable
2016                         // width. As a last fallback, try to convert to pure
2017                         // ASCII using the LaTeX commands defined in unicodesymbols.
2018                         testenc = encodings.fromLyXName("ascii");
2019                         if (!testenc)
2020                                 return docstring();
2021                         ascii_fallback = true;
2022                 }
2023         }
2024         // First and second character of plane 15 (Private Use Area)
2025         string const s1 = "\xf3\xb0\x80\x80"; // U+F0000
2026         string const s2 = "\xf3\xb0\x80\x81"; // U+F0001
2027         // FIXME UNICODE
2028         // lyx::regex is not unicode-safe.
2029         // Should use QRegExp or (boost::u32regex, but that requires ICU)
2030         static regex const reg("_\\(([^\\)]+)\\)");
2031         smatch sub;
2032         while (regex_search(preamble, sub, reg)) {
2033                 string const key = sub.str(1);
2034                 docstring const name = lang->translateLayout(key);
2035                 // Check whether name can be encoded in the buffer encoding
2036                 bool encodable = true;
2037                 for (size_t i = 0; i < name.size() && encodable; ++i)
2038                         if (!testenc->encodable(name[i]))
2039                                 encodable = false;
2040                 string translated;
2041                 if (encodable && !lang_fallback)
2042                         translated = to_utf8(name);
2043                 else if (ascii_fallback)
2044                         translated = to_ascii(testenc->latexString(name).first);
2045                 else
2046                         translated = "\\inputencoding{" + texenc + "}"
2047                                 + s1 + langenc + s2 + to_utf8(name)
2048                                 + s1 + bufenc + s2;
2049                 preamble = subst(preamble, sub.str(), translated);
2050         }
2051         return from_utf8(preamble);
2052 }
2053
2054 } // namespace
2055
2056
2057 docstring const LaTeXFeatures::getTClassI18nPreamble(bool use_babel,
2058                                 bool use_polyglossia, bool use_minted) const
2059 {
2060         DocumentClass const & tclass = params_.documentClass();
2061         // collect preamble snippets in a set to prevent multiple identical
2062         // commands (would happen if e.g. both theorem and theorem* are used)
2063         set<docstring> snippets;
2064         typedef LanguageList::const_iterator lang_it;
2065         lang_it const lbeg = UsedLanguages_.begin();
2066         lang_it const lend =  UsedLanguages_.end();
2067         list<docstring>::const_iterator cit = usedLayouts_.begin();
2068         list<docstring>::const_iterator end = usedLayouts_.end();
2069         for (; cit != end; ++cit) {
2070                 // language dependent commands (once per document)
2071                 snippets.insert(i18npreamble(tclass[*cit].langpreamble(),
2072                                                 buffer().language(),
2073                                                 buffer().params().encoding(),
2074                                                 use_polyglossia, false));
2075                 // commands for language changing (for multilanguage documents)
2076                 if ((use_babel || use_polyglossia) && !UsedLanguages_.empty()) {
2077                         snippets.insert(i18npreamble(
2078                                                 tclass[*cit].babelpreamble(),
2079                                                 buffer().language(),
2080                                                 buffer().params().encoding(),
2081                                                 use_polyglossia, false));
2082                         for (lang_it lit = lbeg; lit != lend; ++lit)
2083                                 snippets.insert(i18npreamble(
2084                                                 tclass[*cit].babelpreamble(),
2085                                                 *lit,
2086                                                 buffer().params().encoding(),
2087                                                 use_polyglossia, false));
2088                 }
2089         }
2090         if ((use_babel || use_polyglossia) && !UsedLanguages_.empty()) {
2091                 FloatList const & floats = params_.documentClass().floats();
2092                 UsedFloats::const_iterator fit = usedFloats_.begin();
2093                 UsedFloats::const_iterator fend = usedFloats_.end();
2094                 for (; fit != fend; ++fit) {
2095                         Floating const & fl = floats.getType(fit->first);
2096                         // we assume builtin floats are translated
2097                         if (fl.isPredefined())
2098                                 continue;
2099                         docstring const type = from_ascii(fl.floattype());
2100                         docstring const flname = from_utf8(fl.name());
2101                         docstring name = buffer().language()->translateLayout(fl.name());
2102                         // only request translation if we have a real translation
2103                         // (that differs from the source)
2104                         if (flname != name)
2105                                 snippets.insert(getFloatI18nPreamble(
2106                                                 type, name, buffer().language(),
2107                                                 buffer().params().encoding(),
2108                                                 use_polyglossia));
2109                         for (lang_it lit = lbeg; lit != lend; ++lit) {
2110                                 string const code = (*lit)->code();
2111                                 name = (*lit)->translateLayout(fl.name());
2112                                 // we assume we have a suitable translation if
2113                                 // either the language is English (we need to
2114                                 // translate into English if English is a secondary
2115                                 // language) or if translateIfPossible returns
2116                                 // something different to the English source.
2117                                 bool const have_translation =
2118                                         (flname != name || contains(code, "en"));
2119                                 if (have_translation)
2120                                         snippets.insert(getFloatI18nPreamble(
2121                                                 type, name, *lit,
2122                                                 buffer().params().encoding(),
2123                                                 use_polyglossia));
2124                         }
2125                 }
2126         }
2127
2128         cit = usedInsetLayouts_.begin();
2129         end = usedInsetLayouts_.end();
2130         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
2131         for (; cit != end; ++cit) {
2132                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
2133                 if (it == ils.end())
2134                         continue;
2135                 // The listings package does not work with variable width
2136                 // encodings, only with fixed width encodings. Therefore we
2137                 // need to force a fixed width encoding for
2138                 // \lstlistlistingname and \lstlistingname (bug 9382).
2139                 // This needs to be consistent with InsetListings::latex()
2140                 // rsp. InsetListings::forcedEncoding().
2141                 bool const need_fixedwidth = !use_minted &&
2142                                         !runparams_.isFullUnicode() &&
2143                                         buffer().params().encoding().package() != Encoding::japanese &&
2144                                         it->second.fixedwidthpreambleencoding();
2145                 // language dependent commands (once per document)
2146                 snippets.insert(i18npreamble(it->second.langpreamble(),
2147                                                 buffer().language(),
2148                                                 buffer().params().encoding(),
2149                                                 use_polyglossia, need_fixedwidth));
2150                 // commands for language changing (for multilanguage documents)
2151                 if ((use_babel || use_polyglossia) && !UsedLanguages_.empty()) {
2152                         snippets.insert(i18npreamble(
2153                                                 it->second.babelpreamble(),
2154                                                 buffer().language(),
2155                                                 buffer().params().encoding(),
2156                                                 use_polyglossia, need_fixedwidth));
2157                         for (lang_it lit = lbeg; lit != lend; ++lit)
2158                                 snippets.insert(i18npreamble(
2159                                                 it->second.babelpreamble(),
2160                                                 *lit,
2161                                                 buffer().params().encoding(),
2162                                                 use_polyglossia, need_fixedwidth));
2163                 }
2164         }
2165
2166         odocstringstream tcpreamble;
2167         set<docstring>::const_iterator const send = snippets.end();
2168         set<docstring>::const_iterator it = snippets.begin();
2169         for (; it != send; ++it)
2170                 tcpreamble << *it;
2171         return tcpreamble.str();
2172 }
2173
2174
2175 docstring const LaTeXFeatures::getLyXSGMLEntities() const
2176 {
2177         // Definition of entities used in the document that are LyX related.
2178         odocstringstream entities;
2179
2180         if (mustProvide("lyxarrow")) {
2181                 entities << "<!ENTITY lyxarrow \"-&gt;\">" << '\n';
2182         }
2183
2184         return entities.str();
2185 }
2186
2187
2188 docstring const LaTeXFeatures::getIncludedFiles(string const & fname) const
2189 {
2190         odocstringstream sgmlpreamble;
2191         // FIXME UNICODE
2192         docstring const basename(from_utf8(onlyPath(fname)));
2193
2194         FileMap::const_iterator end = IncludedFiles_.end();
2195         for (FileMap::const_iterator fi = IncludedFiles_.begin();
2196              fi != end; ++fi)
2197                 // FIXME UNICODE
2198                 sgmlpreamble << "\n<!ENTITY " << fi->first
2199                              << (isSGMLFileName(fi->second) ? " SYSTEM \"" : " \"")
2200                              << makeRelPath(from_utf8(fi->second), basename) << "\">";
2201
2202         return sgmlpreamble.str();
2203 }
2204
2205
2206 void LaTeXFeatures::showStruct() const
2207 {
2208         lyxerr << "LyX needs the following commands when LaTeXing:"
2209                << "\n***** Packages:" << getPackages()
2210                << "\n***** Macros:" << to_utf8(getMacros().str)
2211                << "\n***** Textclass stuff:" << to_utf8(getTClassPreamble())
2212                << "\n***** done." << endl;
2213 }
2214
2215
2216 Buffer const & LaTeXFeatures::buffer() const
2217 {
2218         return *buffer_;
2219 }
2220
2221
2222 void LaTeXFeatures::setBuffer(Buffer const & buffer)
2223 {
2224         buffer_ = &buffer;
2225 }
2226
2227
2228 BufferParams const & LaTeXFeatures::bufferParams() const
2229 {
2230         return params_;
2231 }
2232
2233
2234 void LaTeXFeatures::getFloatDefinitions(otexstream & os) const
2235 {
2236         FloatList const & floats = params_.documentClass().floats();
2237
2238         // Here we will output the code to create the needed float styles.
2239         // We will try to do this as minimal as possible.
2240         // \floatstyle{ruled}
2241         // \newfloat{algorithm}{htbp}{loa}
2242         // \providecommand{\algorithmname}{Algorithm}
2243         // \floatname{algorithm}{\protect\algorithmname}
2244         UsedFloats::const_iterator cit = usedFloats_.begin();
2245         UsedFloats::const_iterator end = usedFloats_.end();
2246         for (; cit != end; ++cit) {
2247                 Floating const & fl = floats.getType(cit->first);
2248
2249                 // For builtin floats we do nothing.
2250                 if (fl.isPredefined())
2251                         continue;
2252
2253                 // We have to special case "table" and "figure"
2254                 if (fl.floattype() == "tabular" || fl.floattype() == "figure") {
2255                         // Output code to modify "table" or "figure"
2256                         // but only if builtin == false
2257                         // and that have to be true at this point in the
2258                         // function.
2259                         docstring const type = from_ascii(fl.floattype());
2260                         docstring const placement = from_ascii(fl.placement());
2261                         docstring const style = from_ascii(fl.style());
2262                         if (!style.empty()) {
2263                                 os << "\\floatstyle{" << style << "}\n"
2264                                    << "\\restylefloat{" << type << "}\n";
2265                         }
2266                         if (!placement.empty()) {
2267                                 os << "\\floatplacement{" << type << "}{"
2268                                    << placement << "}\n";
2269                         }
2270                 } else {
2271                         // The other non builtin floats.
2272
2273                         docstring const type = from_ascii(fl.floattype());
2274                         docstring const placement = from_ascii(fl.placement());
2275                         docstring const ext = from_ascii(fl.ext());
2276                         docstring const within = from_ascii(fl.within());
2277                         docstring const style = from_ascii(fl.style());
2278                         docstring const name =
2279                                 buffer().language()->translateLayout(fl.name());
2280                         os << "\\floatstyle{" << style << "}\n"
2281                            << "\\newfloat{" << type << "}{" << placement
2282                            << "}{" << ext << '}';
2283                         if (!within.empty())
2284                                 os << '[' << within << ']';
2285                         os << '\n'
2286                            << "\\providecommand{\\" << type << "name}{"
2287                            << name << "}\n"
2288                            << "\\floatname{" << type << "}{\\protect\\"
2289                            << type << "name}\n";
2290
2291                         // What missing here is to code to minimalize the code
2292                         // output so that the same floatstyle will not be
2293                         // used several times, when the same style is still in
2294                         // effect. (Lgb)
2295                 }
2296                 if (cit->second)
2297                         // The subfig package is loaded later
2298                         os << "\n\\AtBeginDocument{\\newsubfloat{" << from_ascii(fl.floattype()) << "}}\n";
2299         }
2300 }
2301
2302
2303 void LaTeXFeatures::resolveAlternatives()
2304 {
2305         for (Features::iterator it = features_.begin(); it != features_.end();) {
2306                 if (contains(*it, '|')) {
2307                         vector<string> const alternatives = getVectorFromString(*it, "|");
2308                         vector<string>::const_iterator const end = alternatives.end();
2309                         vector<string>::const_iterator ita = alternatives.begin();
2310                         // Is any alternative already required? => use that
2311                         for (; ita != end; ++ita) {
2312                                 if (isRequired(*ita))
2313                                         break;
2314                         }
2315                         // Is any alternative available? => use the first one
2316                         // (bug 9498)
2317                         if (ita == end) {
2318                                 for (ita = alternatives.begin(); ita != end; ++ita) {
2319                                         if (isAvailable(*ita)) {
2320                                                 require(*ita);
2321                                                 break;
2322                                         }
2323                                 }
2324                         }
2325                         // This will not work, but not requiring something
2326                         // would be more confusing
2327                         if (ita == end)
2328                                 require(alternatives.front());
2329                         features_.erase(it);
2330                         it = features_.begin();
2331                 } else
2332                         ++it;
2333         }
2334 }
2335
2336
2337 void LaTeXFeatures::expandMultiples()
2338 {
2339         for (Features::iterator it = features_.begin(); it != features_.end();) {
2340                 if (contains(*it, ',')) {
2341                         vector<string> const multiples = getVectorFromString(*it, ",");
2342                         vector<string>::const_iterator const end = multiples.end();
2343                         vector<string>::const_iterator itm = multiples.begin();
2344                         // Do nothing if any multiple is already required
2345                         for (; itm != end; ++itm) {
2346                                 if (!isRequired(*itm))
2347                                         require(*itm);
2348                         }
2349                         features_.erase(it);
2350                         it = features_.begin();
2351                 } else
2352                         ++it;
2353         }
2354 }
2355
2356
2357 } // namespace lyx