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