]> git.lyx.org Git - lyx.git/blob - src/LaTeXFeatures.cpp
Support macros from hepnames and hepparticles packages
[lyx.git] / src / LaTeXFeatures.cpp
1 /**
2  * \file LaTeXFeatures.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author José Matos
7  * \author Lars Gullik Bjønnes
8  * \author Jean-Marc Lasgouttes
9  * \author Jürgen Vigna
10  * \author André Pönitz
11  *
12  * Full author contact details are available in file CREDITS.
13  */
14
15 #include <config.h>
16
17 #include "LaTeXFeatures.h"
18
19 #include "Buffer.h"
20 #include "BufferParams.h"
21 #include "ColorSet.h"
22 #include "Converter.h"
23 #include "Encoding.h"
24 #include "Floating.h"
25 #include "FloatList.h"
26 #include "Language.h"
27 #include "LaTeXFonts.h"
28 #include "LaTeXPackages.h"
29 #include "Layout.h"
30 #include "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         "hepparticles",
1166         "hepnames"
1167 };
1168
1169 char const * bibliofeatures[] = {
1170         // Known bibliography packages (will be loaded before natbib)
1171         "achicago",
1172         "apacite",
1173         "apalike",
1174         "astron",
1175         "authordate1-4",
1176         "babelbib",
1177         "bibgerm",
1178         "chapterbib",
1179         "chicago",
1180         "chscite",
1181         "harvard",
1182         "mslapa",
1183         "named"
1184 };
1185
1186 } // namespace
1187
1188
1189 string const LaTeXFeatures::getColorOptions() const
1190 {
1191         ostringstream colors;
1192
1193         // Handling the color packages separately is needed to be able to load them
1194         // before babel when hyperref is loaded with the colorlinks option
1195         // for more info see Bufferparams.cpp
1196
1197         // [x]color.sty
1198         if (mustProvide("color") || mustProvide("xcolor")) {
1199                 string const package =
1200                         (mustProvide("xcolor") ? "xcolor" : "color");
1201                 if (params_.graphics_driver == "default"
1202                         || params_.graphics_driver == "none")
1203                         colors << "\\usepackage{" << package << "}\n";
1204                 else
1205                         colors << "\\usepackage["
1206                                  << params_.graphics_driver
1207                                  << "]{" << package << "}\n";
1208         }
1209
1210         // pdfcolmk must be loaded after color
1211         if (mustProvide("pdfcolmk"))
1212                 colors << "\\usepackage{pdfcolmk}\n";
1213
1214         // the following 3 color commands must be set after color
1215         // is loaded and before pdfpages, therefore add the command
1216         // here define the set color
1217         if (mustProvide("pagecolor")) {
1218                 colors << "\\definecolor{page_backgroundcolor}{rgb}{";
1219                 colors << outputLaTeXColor(params_.backgroundcolor) << "}\n";
1220                 // set the page color
1221                 colors << "\\pagecolor{page_backgroundcolor}\n";
1222         }
1223
1224         if (mustProvide("fontcolor")) {
1225                 colors << "\\definecolor{document_fontcolor}{rgb}{";
1226                 colors << outputLaTeXColor(params_.fontcolor) << "}\n";
1227                 // set the color
1228                 colors << "\\color{document_fontcolor}\n";
1229         }
1230
1231         if (mustProvide("lyxgreyedout")) {
1232                 colors << "\\definecolor{note_fontcolor}{rgb}{";
1233                 colors << outputLaTeXColor(params_.notefontcolor) << "}\n";
1234                 // the color will be set together with the definition of
1235                 // the lyxgreyedout environment (see lyxgreyedout_def)
1236         }
1237
1238         // color for shaded boxes
1239         if (isRequired("framed") && mustProvide("color")) {
1240                 colors << "\\definecolor{shadecolor}{rgb}{";
1241                 colors << outputLaTeXColor(params_.boxbgcolor) << "}\n";
1242                 // this color is automatically used by the LaTeX-package "framed"
1243         }
1244
1245         return colors.str();
1246 }
1247
1248
1249 string const LaTeXFeatures::getPackageOptions() const
1250 {
1251         ostringstream packageopts;
1252         // Output all the package option stuff we have been asked to do.
1253         for (auto const & p : params_.documentClass().packageOptions())
1254                 if (mustProvide(p.first))
1255                         packageopts << "\\PassOptionsToPackage{" << p.second << "}"
1256                                  << "{" << p.first << "}\n";
1257         return packageopts.str();
1258 }
1259
1260
1261 string const LaTeXFeatures::getPackages() const
1262 {
1263         ostringstream packages;
1264
1265         // FIXME: currently, we can only load packages and macros known
1266         // to LyX.
1267         // However, with the Require tag of layouts/custom insets,
1268         // also unknown packages can be requested. They are silently
1269         // swallowed now. We should change this eventually.
1270
1271         //  These are all the 'simple' includes.  i.e
1272         //  packages which we just \usepackage{package}
1273         for (char const * feature : simplefeatures) {
1274                 if (mustProvide(feature))
1275                         packages << "\\usepackage{" << feature << "}\n";
1276         }
1277
1278         // The rest of these packages are somewhat more complicated
1279         // than those above.
1280
1281         if (mustProvide("changebar")) {
1282                 packages << "\\usepackage";
1283                 if (runparams_.flavor == Flavor::LaTeX
1284                     || runparams_.flavor == Flavor::DviLuaTeX)
1285                         packages << "[dvips]";
1286                 packages << "{changebar}\n";
1287         }
1288
1289         if (mustProvide("footnote")) {
1290                 if (isRequired("hyperref"))
1291                         packages << "\\usepackage{footnotehyper}\n";
1292                 else
1293                         packages << "\\usepackage{footnote}\n";
1294         }
1295
1296         // [pdf]lscape is used to rotate longtables
1297         if (mustProvide("lscape")) {
1298                 if (runparams_.flavor == Flavor::LaTeX
1299                     || runparams_.flavor == Flavor::DviLuaTeX)
1300                         packages << "\\usepackage{lscape}\n";
1301                 else
1302                         packages << "\\usepackage{pdflscape}\n";
1303         }
1304
1305         // The tipa package and its extensions (tipx, tone) must not
1306         // be loaded with non-TeX fonts, since fontspec includes the
1307         // respective macros
1308         if (mustProvide("tipa") && !params_.useNonTeXFonts)
1309                 packages << "\\usepackage{tipa}\n";
1310         if (mustProvide("tipx") && !params_.useNonTeXFonts)
1311                 packages << "\\usepackage{tipx}\n";
1312         if (mustProvide("extraipa") && !params_.useNonTeXFonts)
1313                 packages << "\\usepackage{extraipa}\n";
1314         if (mustProvide("tone") && !params_.useNonTeXFonts)
1315                 packages << "\\usepackage{tone}\n";
1316
1317         // if fontspec or newtxmath is used, AMS packages have to be loaded
1318         // before fontspec (in BufferParams)
1319         string const amsPackages = loadAMSPackages();
1320         bool const ot1 = (runparams().main_fontenc == "default"
1321                           || runparams().main_fontenc == "OT1");
1322         bool const use_newtxmath =
1323                 theLaTeXFonts().getLaTeXFont(from_ascii(params_.fontsMath())).getUsedPackage(
1324                         ot1, false, false) == "newtxmath";
1325
1326         if (!params_.useNonTeXFonts && !use_newtxmath && !amsPackages.empty())
1327                 packages << amsPackages;
1328
1329         if (mustProvide("cancel") &&
1330             params_.use_package("cancel") != BufferParams::package_off)
1331                 packages << "\\usepackage{cancel}\n";
1332
1333         // marvosym and bbding both define the \Cross macro
1334         if (mustProvide("marvosym")) {
1335             if (mustProvide("bbding"))
1336                 packages << "\\let\\Cross\\relax\n";
1337             packages << "\\usepackage{marvosym}\n";
1338         }
1339
1340         // accents must be loaded after amsmath
1341         if (mustProvide("accents") &&
1342             params_.use_package("accents") != BufferParams::package_off)
1343                 packages << "\\usepackage{accents}\n";
1344
1345         // mathdots must be loaded after amsmath
1346         if (mustProvide("mathdots") &&
1347                 params_.use_package("mathdots") != BufferParams::package_off)
1348                 packages << "\\usepackage{mathdots}\n";
1349
1350         // yhmath must be loaded after amsmath
1351         if (mustProvide("yhmath") &&
1352             params_.use_package("yhmath") != BufferParams::package_off)
1353                 packages << "\\usepackage{yhmath}\n";
1354
1355         // stmaryrd must be loaded after amsmath
1356         if (mustProvide("stmaryrd") &&
1357             params_.use_package("stmaryrd") != BufferParams::package_off)
1358                 packages << "\\usepackage{stmaryrd}\n";
1359
1360         if (mustProvide("stackrel") &&
1361             params_.use_package("stackrel") != BufferParams::package_off)
1362                 packages << "\\usepackage{stackrel}\n";
1363
1364         if (mustProvide("undertilde") &&
1365                 params_.use_package("undertilde") != BufferParams::package_off)
1366                 packages << "\\usepackage{undertilde}\n";
1367
1368         // [x]color and pdfcolmk are handled in getColorOptions() above
1369
1370         // makeidx.sty
1371         if (isRequired("makeidx") || isRequired("splitidx")) {
1372                 if (!isProvided("makeidx") && !isRequired("splitidx"))
1373                         packages << "\\usepackage{makeidx}\n";
1374                 if (mustProvide("splitidx"))
1375                         packages << "\\usepackage{splitidx}\n";
1376                 packages << "\\makeindex\n";
1377         }
1378
1379         // graphicx.sty
1380         if (mustProvide("graphicx") && params_.graphics_driver != "none") {
1381                 if (params_.graphics_driver == "default")
1382                         packages << "\\usepackage{graphicx}\n";
1383                 else
1384                         packages << "\\usepackage["
1385                                  << params_.graphics_driver
1386                                  << "]{graphicx}\n";
1387         }
1388
1389         // These must be loaded after graphicx, since they try
1390         // to load graphicx without options
1391         if (mustProvide("rotating"))
1392                 packages << "\\usepackage{rotating}\n";
1393         if (mustProvide("rotfloat"))
1394                 packages << "\\usepackage{rotfloat}\n";
1395         // and this must be loaded after rotating
1396         if (mustProvide("tablefootnote"))
1397                 packages << "\\usepackage{tablefootnote}\n";
1398
1399         // lyxskak.sty --- newer chess support based on skak.sty
1400         if (mustProvide("chess"))
1401                 packages << "\\usepackage[ps,mover]{lyxskak}\n";
1402
1403         // setspace.sty
1404         if (mustProvide("setspace") && !isProvided("SetSpace"))
1405                 packages << "\\usepackage{setspace}\n";
1406
1407         // we need to assure that mhchem is loaded before esint and every other
1408         // package that redefines command of amsmath because mhchem loads amlatex
1409         // (this info is from the author of mhchem from June 2013)
1410         if (mustProvide("mhchem") &&
1411             params_.use_package("mhchem") != BufferParams::package_off)
1412                 packages << "\\PassOptionsToPackage{version=3}{mhchem}\n"
1413                             "\\usepackage{mhchem}\n";
1414
1415         // wasysym is a simple feature, but it must be after amsmath if both
1416         // are used
1417         // wasysym redefines some integrals (e.g. iint) from amsmath. That
1418         // leads to inconsistent integrals. We only load this package if
1419         // the document does not contain integrals (then isRequired("esint")
1420         // is false) or if esint is used, since esint redefines all relevant
1421         // integral symbols from wasysym and amsmath.
1422         // See http://www.lyx.org/trac/ticket/1942
1423         if (mustProvide("wasysym") &&
1424             params_.use_package("wasysym") != BufferParams::package_off &&
1425             (params_.use_package("esint") != BufferParams::package_off || !isRequired("esint")))
1426                 packages << "\\usepackage{wasysym}\n";
1427
1428         // esint must be after amsmath (and packages requiring amsmath, like mhchem)
1429         // and wasysym, since it will redeclare inconsistent integral symbols
1430         if (mustProvide("esint") &&
1431             params_.use_package("esint") != BufferParams::package_off)
1432                 packages << "\\usepackage{esint}\n";
1433
1434         // Known bibliography packages (simple \usepackage{package})
1435         for (char const * feature : bibliofeatures) {
1436                 if (mustProvide(feature))
1437                         packages << "\\usepackage{" << feature << "}\n";
1438         }
1439
1440         // Compatibility between achicago and natbib
1441         if (mustProvide("achicago") && mustProvide("natbib"))
1442                 packages << "\\let\\achicagobib\\thebibliography\n";
1443
1444         // natbib.sty
1445         // Some classes load natbib themselves, but still allow (or even require)
1446         // plain numeric citations (ReVTeX is such a case, see bug 5182).
1447         // This special case is indicated by the "natbib-internal" key.
1448         if (mustProvide("natbib")
1449             && !isProvided("natbib-internal")
1450             && !isProvided("biblatex")
1451             && !isProvided("biblatex-natbib")
1452             && !isProvided("jurabib")) {
1453                 packages << "\\usepackage[";
1454                 if (params_.citeEngineType() == ENGINE_TYPE_NUMERICAL)
1455                         packages << "numbers";
1456                 else
1457                         packages << "authoryear";
1458                 if (!params_.biblio_opts.empty())
1459                         packages << ',' << params_.biblio_opts;
1460                 packages << "]{natbib}\n";
1461         }
1462
1463         // Compatibility between achicago and natbib
1464         if (mustProvide("achicago") && mustProvide("natbib")) {
1465                 packages << "\\let\\thebibliography\\achicagobib\n";
1466                 packages << "\\let\\SCcite\\astroncite\n";
1467                 packages << "\\let\\UnexpandableProtect\\protect\n";
1468         }
1469
1470         // jurabib -- we need version 0.6 at least.
1471         if (mustProvide("jurabib")
1472             && !isProvided("natbib-internal")
1473             && !isProvided("natbib")
1474             && !isProvided("biblatex")
1475             && !isProvided("biblatex-natbib")) {
1476                 packages << "\\usepackage";
1477                 if (!params_.biblio_opts.empty())
1478                         packages << '[' << params_.biblio_opts << ']';
1479                 packages << "{jurabib}[2004/01/25]\n";
1480         }
1481
1482         // opcit -- we pass custombst as we output \bibliographystyle ourselves
1483         if (mustProvide("opcit")) {
1484                 if (isRequired("hyperref"))
1485                         packages << "\\usepackage[custombst,hyperref]{opcit}\n";
1486                 else
1487                         packages << "\\usepackage[custombst]{opcit}\n";
1488         }
1489
1490         // xargs -- we need version 1.09 at least
1491         if (mustProvide("xargs"))
1492                 packages << "\\usepackage{xargs}[2008/03/08]\n";
1493
1494         if (mustProvide("xy"))
1495                 packages << "\\usepackage[all]{xy}\n";
1496
1497         if (mustProvide("feyn"))
1498                 packages << "\\usepackage{feyn}\n"; //Diagram
1499
1500         if (mustProvide("ulem"))
1501                 packages << "\\PassOptionsToPackage{normalem}{ulem}\n"
1502                             "\\usepackage{ulem}\n";
1503
1504         if (mustProvide("nomencl")) {
1505                 // Make it work with the new and old version of the package,
1506                 // but don't use the compatibility option since it is
1507                 // incompatible to other packages.
1508                 packages << "\\usepackage{nomencl}\n"
1509                             "% the following is useful when we have the old nomencl.sty package\n"
1510                             "\\providecommand{\\printnomenclature}{\\printglossary}\n"
1511                             "\\providecommand{\\makenomenclature}{\\makeglossary}\n"
1512                             "\\makenomenclature\n";
1513         }
1514
1515         // fixltx2e provides subscript
1516         if (mustProvide("subscript") && !isRequired("fixltx2e")
1517             && !isAvailable("LaTeX-2005/12/01"))
1518                 packages << "\\usepackage{subscript}\n";
1519
1520         // footmisc must be loaded after setspace
1521         // Set options here, load the package after the user preamble to
1522         // avoid problems with manual loaded footmisc.
1523         if (mustProvide("footmisc"))
1524                 packages << "\\PassOptionsToPackage{stable}{footmisc}\n";
1525
1526         if (mustProvide("microtype")){
1527                 packages << "\\usepackage{microtype}\n";
1528         }
1529
1530         return packages.str();
1531 }
1532
1533
1534 TexString LaTeXFeatures::getMacros() const
1535 {
1536         otexstringstream macros;
1537
1538         if (!preamble_snippets_.empty()) {
1539                 macros << '\n';
1540                 macros << getPreambleSnippets();
1541         }
1542
1543         if (mustProvide("xetexdashbreakstate"))
1544                 macros << "\\XeTeXdashbreakstate 0" << '\n';
1545
1546         if (mustProvide("papersize")) {
1547                 if (runparams_.flavor == Flavor::LaTeX
1548                     || runparams_.flavor == Flavor::DviLuaTeX)
1549                         macros << papersizedvi_def << '\n';
1550                 else if  (runparams_.flavor == Flavor::LuaTeX)
1551                         macros << papersizepdflua_def << '\n';
1552                 else
1553                         macros << papersizepdf_def << '\n';
1554         }
1555
1556         if (mustProvide("LyX")) {
1557                 macros << "\\providecommand{\\LyX}";
1558                 // open conditional wrappers
1559                 if (runparams_.use_polyglossia && hasRTLLanguage())
1560                         macros << "{\\@ensure@LTR";
1561                 if (isRequired("hyperref"))
1562                         macros << "{\\texorpdfstring";
1563                 if (useBabel())
1564                         macros << "{\\ensureascii";
1565                 // main definition
1566                 macros << lyx_def;
1567                 // close conditional wrappers
1568                 if (useBabel())
1569                         macros << '}';
1570                 if (isRequired("hyperref"))
1571                         macros << "{LyX}}";
1572                 if (runparams_.use_polyglossia && hasRTLLanguage())
1573                         macros << '}';
1574                 macros << '\n';
1575         }
1576
1577         if (mustProvide("noun"))
1578                 macros << noun_def << '\n';
1579
1580         if (mustProvide("lyxarrow"))
1581                 macros << lyxarrow_def << '\n';
1582
1583         if (mustProvide("aastex_case"))
1584                 macros << aastex_case_def << '\n';
1585
1586         if (mustProvide("lyxzerowidthspace"))
1587                 macros << lyxZWSP_def << '\n';
1588
1589         if (!usePolyglossia() && mustProvide("textgreek")) {
1590                 // ensure LGR font encoding is defined also if fontenc is not loaded by LyX
1591                 if (runparams().main_fontenc == "default")
1592                         macros << textgreek_LGR_def;
1593                 macros << textgreek_def << '\n';
1594         }
1595
1596         if (!usePolyglossia() && mustProvide("textcyrillic")) {
1597                 // ensure T2A font encoding is set up also if fontenc is not loaded by LyX
1598                 if (runparams().main_fontenc == "default")
1599                         macros << textcyr_T2A_def;
1600                 macros << textcyr_def << '\n';
1601         }
1602
1603         // non-standard text accents:
1604         if (mustProvide("textcommaabove") || mustProvide("textcommaaboveright") ||
1605             mustProvide("textcommabelow") || mustProvide("textbaltic"))
1606                 macros << lyxaccent_def;
1607
1608         if (mustProvide("textcommabelow") || mustProvide("textbaltic"))
1609                 macros << textcommabelow_def << '\n';
1610
1611         if (mustProvide("textcommaabove") || mustProvide("textbaltic"))
1612                 macros << textcommaabove_def << '\n';
1613
1614         if (mustProvide("textcommaaboveright"))
1615                 macros << textcommaaboveright_def << '\n';
1616
1617         if (mustProvide("textbaltic"))
1618                 macros << textbaltic_def << '\n';
1619
1620         if (mustProvide("textschwa"))
1621                 macros << textschwa_def << '\n';
1622
1623         // split-level fractions
1624         if (mustProvide("xfrac") || mustProvide("smallLetterFrac"))
1625                 macros << xfrac_def << '\n';
1626
1627         if (mustProvide("smallLetterFrac"))
1628                 macros << smallLetterFrac_def << '\n';
1629
1630         if (mustProvide("lyxmathsym"))
1631                 macros << lyxmathsym_def << '\n';
1632
1633         if (mustProvide("cedilla"))
1634                 macros << cedilla_def << '\n';
1635
1636         if (mustProvide("subring"))
1637                 macros << subring_def << '\n';
1638
1639         if (mustProvide("subdot"))
1640                 macros << subdot_def << '\n';
1641
1642         if (mustProvide("subhat"))
1643                 macros << subhat_def << '\n';
1644
1645         if (mustProvide("subtilde"))
1646                 macros << subtilde_def << '\n';
1647
1648         if (mustProvide("dacute"))
1649                 macros << dacute_def << '\n';
1650
1651         if (mustProvide("tipasymb"))
1652                 macros << tipasymb_def << '\n';
1653
1654         if (mustProvide("dgrave"))
1655                 macros << dgrave_def << '\n';
1656
1657         if (mustProvide("rcap"))
1658                 macros << rcap_def << '\n';
1659
1660         if (mustProvide("ogonek"))
1661                 macros << ogonek_def << '\n';
1662
1663         // quotes.
1664         if (mustProvide("quotesinglbase"))
1665                 macros << quotesinglbase_def << '\n';
1666         if (mustProvide("quotedblbase"))
1667                 macros << quotedblbase_def << '\n';
1668         if (mustProvide("guilsinglleft"))
1669                 macros << guilsinglleft_def << '\n';
1670         if (mustProvide("guilsinglright"))
1671                 macros << guilsinglright_def << '\n';
1672         if (mustProvide("guillemotleft"))
1673                 macros << guillemotleft_def << '\n';
1674         if (mustProvide("guillemotright"))
1675                 macros << guillemotright_def << '\n';
1676         if (mustProvide("textquotedbl"))
1677                 macros << textquotedbl_def << '\n';
1678         if (mustProvide("textquotesinglep")) {
1679                 if (runparams_.flavor == Flavor::XeTeX)
1680                         macros << textquotesinglep_xetex_def << '\n';
1681                 else
1682                         macros << textquotesinglep_luatex_def << '\n';
1683         }
1684         if (mustProvide("textquotedblp")) {
1685                 if (runparams_.flavor == Flavor::XeTeX)
1686                         macros << textquotedblp_xetex_def << '\n';
1687                 else
1688                         macros << textquotedblp_luatex_def << '\n';
1689         }
1690
1691         // Math mode
1692         if (mustProvide("binom") && !isRequired("amsmath"))
1693                 macros << binom_def << '\n';
1694         if (mustProvide("mathcircumflex"))
1695                 macros << mathcircumflex_def << '\n';
1696
1697         // other
1698         if (mustProvide("ParagraphLeftIndent"))
1699                 macros << paragraphleftindent_def;
1700         if (mustProvide("NeedLyXFootnoteCode"))
1701                 macros << floatingfootnote_def;
1702
1703         // some problems with tex->html converters
1704         if (mustProvide("NeedTabularnewline"))
1705                 macros << tabularnewline_def;
1706
1707         if (mustProvide("cellvarwidth"))
1708                 macros << cellvarwidth_def;
1709
1710         // greyed-out environment (note inset)
1711         // the color is specified in the routine
1712         // getColorOptions() to avoid LaTeX-package clashes
1713         if (mustProvide("lyxgreyedout"))
1714                 // We need different version for RTL (#8647), with change tracking (#12025)
1715                 // and for some specific engine/language package combinations
1716                 macros << lyxgreyedoutDef(hasRTLLanguage(), mustProvide("ct-xcolor-ulem"),
1717                                           (runparams_.flavor == Flavor::LuaTeX), useBabel());
1718
1719         if (mustProvide("lyxdot"))
1720                 macros << lyxdot_def << '\n';
1721
1722         // floats
1723         getFloatDefinitions(macros);
1724
1725         if (mustProvide("refstyle"))
1726                 macros << lyxref_def << '\n';
1727
1728         // change tracking
1729         if (mustProvide("ct-xcolor-ulem")) {
1730                 streamsize const prec = macros.os().precision(2);
1731
1732                 RGBColor cadd = rgbFromHexName(lcolor.getX11HexName(Color_addedtext_output));
1733                 macros << "\\providecolor{lyxadded}{rgb}{"
1734                        << cadd.r / 255.0 << ',' << cadd.g / 255.0 << ',' << cadd.b / 255.0 << "}\n";
1735
1736                 RGBColor cdel = rgbFromHexName(lcolor.getX11HexName(Color_deletedtext_output));
1737                 macros << "\\providecolor{lyxdeleted}{rgb}{"
1738                        << cdel.r / 255.0 << ',' << cdel.g / 255.0 << ',' << cdel.b / 255.0 << "}\n";
1739
1740                 macros.os().precision(prec);
1741
1742                 macros << changetracking_xcolor_ulem_base_def;
1743
1744                 if (isRequired("changebar")) {
1745                         if (isRequired("hyperref"))
1746                                 macros << changetracking_xcolor_ulem_hyperref_cb_def;
1747                         else
1748                                 macros << changetracking_xcolor_ulem_cb_def;
1749                 } else {
1750                         if (isRequired("hyperref"))
1751                                 macros << changetracking_xcolor_ulem_hyperref_def;
1752                         else
1753                                 macros << changetracking_xcolor_ulem_def;
1754                 }
1755         }
1756
1757         if (mustProvide("ct-tikz-object-sout")) {
1758                 if (!mustProvide("ct-xcolor-ulem")) {
1759                         streamsize const prec = macros.os().precision(2);
1760
1761                         RGBColor cadd = rgbFromHexName(lcolor.getX11HexName(Color_addedtext_output));
1762                         macros << "\\providecolor{lyxadded}{rgb}{"
1763                                << cadd.r / 255.0 << ',' << cadd.g / 255.0 << ',' << cadd.b / 255.0 << "}\n";
1764         
1765                         RGBColor cdel = rgbFromHexName(lcolor.getX11HexName(Color_deletedtext_output));
1766                         macros << "\\providecolor{lyxdeleted}{rgb}{"
1767                                << cdel.r / 255.0 << ',' << cdel.g / 255.0 << ',' << cdel.b / 255.0 << "}\n";
1768         
1769                         macros.os().precision(prec);
1770                 }
1771                 
1772                 macros << changetracking_tikz_object_sout_def;
1773                 
1774                 if (isRequired("changebar")) {
1775                         if (isRequired("hyperref"))
1776                                 macros << changetracking_xcolor_ulem_hyperref_cb_object_def;
1777                         else
1778                                 macros << changetracking_xcolor_ulem_cb_object_def;
1779                 } else {
1780                         if (isRequired("hyperref"))
1781                                 macros << changetracking_xcolor_ulem_hyperref_object_def;
1782                         else
1783                                 macros << changetracking_xcolor_ulem_object_def;
1784                 }
1785         }
1786
1787         if (mustProvide("ct-none"))
1788                 macros << changetracking_none_def;
1789
1790         if (mustProvide("rtloutputdblcol"))
1791                 macros << rtloutputdblcol_def;
1792
1793         if (mustProvide("lyxmintcaption"))
1794                 macros << lyxmintcaption_def;
1795
1796         return macros.release();
1797 }
1798
1799
1800 docstring const LaTeXFeatures::getBabelPresettings() const
1801 {
1802         odocstringstream tmp;
1803
1804         for (auto const & lang : UsedLanguages_)
1805                 if (!lang->babel_presettings().empty())
1806                         tmp << lang->babel_presettings() << '\n';
1807         if (!params_.language->babel_presettings().empty())
1808                 tmp << params_.language->babel_presettings() << '\n';
1809
1810         if (!contains(tmp.str(), '@'))
1811                 return tmp.str();
1812
1813         return "\\makeatletter\n" + tmp.str() + "\\makeatother\n";
1814 }
1815
1816
1817 docstring const LaTeXFeatures::getBabelPostsettings() const
1818 {
1819         odocstringstream tmp;
1820
1821         for (auto const & lang : UsedLanguages_)
1822                 if (!lang->babel_postsettings().empty())
1823                         tmp << lang->babel_postsettings() << '\n';
1824         if (!params_.language->babel_postsettings().empty())
1825                 tmp << params_.language->babel_postsettings() << '\n';
1826
1827         if (!contains(tmp.str(), '@'))
1828                 return tmp.str();
1829
1830         return "\\makeatletter\n" + tmp.str() + "\\makeatother\n";
1831 }
1832
1833
1834 string const LaTeXFeatures::loadAMSPackages() const
1835 {
1836         ostringstream tmp;
1837
1838         if (mustProvide("amsmath")
1839             && params_.use_package("amsmath") != BufferParams::package_off) {
1840                 tmp << "\\usepackage{amsmath}\n";
1841         } else {
1842                 // amsbsy and amstext are already provided by amsmath
1843                 if (mustProvide("amsbsy"))
1844                         tmp << "\\usepackage{amsbsy}\n";
1845                 if (mustProvide("amstext"))
1846                         tmp << "\\usepackage{amstext}\n";
1847         }
1848
1849         if (mustProvide("amsthm"))
1850                 tmp << "\\usepackage{amsthm}\n";
1851
1852         if (mustProvide("amssymb")
1853             && params_.use_package("amssymb") != BufferParams::package_off)
1854                 tmp << "\\usepackage{amssymb}\n";
1855
1856         return tmp.str();
1857 }
1858
1859
1860 docstring const LaTeXFeatures::getTClassPreamble() const
1861 {
1862         // the text class specific preamble
1863         DocumentClass const & tclass = params_.documentClass();
1864         odocstringstream tcpreamble;
1865
1866         tcpreamble << tclass.preamble();
1867
1868         list<docstring>::const_iterator cit = usedLayouts_.begin();
1869         list<docstring>::const_iterator end = usedLayouts_.end();
1870         for (; cit != end; ++cit)
1871                 // For InPreamble layouts, we output the preamble stuff earlier
1872                 // (before the layouts). See Paragraph::Private::validate.
1873                 if (!tclass[*cit].inpreamble)
1874                         tcpreamble << tclass[*cit].preamble();
1875
1876         cit = usedInsetLayouts_.begin();
1877         end = usedInsetLayouts_.end();
1878         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
1879         for (; cit != end; ++cit) {
1880                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
1881                 if (it == ils.end())
1882                         continue;
1883                 tcpreamble << it->second.preamble();
1884         }
1885
1886         return tcpreamble.str();
1887 }
1888
1889
1890 docstring const LaTeXFeatures::getTClassHTMLPreamble() const
1891 {
1892         DocumentClass const & tclass = params_.documentClass();
1893         odocstringstream tcpreamble;
1894
1895         tcpreamble << tclass.htmlpreamble();
1896
1897         list<docstring>::const_iterator cit = usedLayouts_.begin();
1898         list<docstring>::const_iterator end = usedLayouts_.end();
1899         for (; cit != end; ++cit)
1900                 tcpreamble << tclass[*cit].htmlpreamble();
1901
1902         cit = usedInsetLayouts_.begin();
1903         end = usedInsetLayouts_.end();
1904         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
1905         for (; cit != end; ++cit) {
1906                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
1907                 if (it == ils.end())
1908                         continue;
1909                 tcpreamble << it->second.htmlpreamble();
1910         }
1911
1912         return tcpreamble.str();
1913 }
1914
1915
1916 docstring const LaTeXFeatures::getTClassHTMLStyles() const
1917 {
1918         DocumentClass const & tclass = params_.documentClass();
1919         odocstringstream tcpreamble;
1920
1921         if (mustProvide("noun"))
1922                 tcpreamble << lyxnoun_style;
1923         // this isn't exact, but it won't hurt that much if it
1924         // wasn't for this.
1925         if (mustProvide("ulem"))
1926                 tcpreamble << lyxstrikeout_style;
1927
1928         tcpreamble << tclass.htmlstyles();
1929
1930         list<docstring>::const_iterator cit = usedLayouts_.begin();
1931         list<docstring>::const_iterator end = usedLayouts_.end();
1932         for (; cit != end; ++cit)
1933                 tcpreamble << tclass[*cit].htmlstyle();
1934
1935         cit = usedInsetLayouts_.begin();
1936         end = usedInsetLayouts_.end();
1937         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
1938         for (; cit != end; ++cit) {
1939                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
1940                 if (it == ils.end())
1941                         continue;
1942                 tcpreamble << it->second.htmlstyle();
1943         }
1944
1945         return tcpreamble.str();
1946 }
1947
1948
1949 namespace {
1950
1951 docstring const getFloatI18nPreamble(docstring const & type,
1952                         docstring const & name, Language const * lang,
1953                         Encoding const & enc, bool const polyglossia)
1954 {
1955         // Check whether name can be encoded in the buffer encoding
1956         bool encodable = true;
1957         for (char_type c : name) {
1958                 if (!enc.encodable(c)) {
1959                         encodable = false;
1960                         break;
1961                 }
1962         }
1963
1964         docstring const language = polyglossia ? from_ascii(lang->polyglossia())
1965                                                : from_ascii(lang->babel());
1966         docstring const langenc = from_ascii(lang->encoding()->iconvName());
1967         docstring const texenc = from_ascii(lang->encoding()->latexName());
1968         docstring const bufenc = from_ascii(enc.iconvName());
1969         docstring const s1 = docstring(1, 0xF0000);
1970         docstring const s2 = docstring(1, 0xF0001);
1971         docstring const translated = encodable ? name
1972                 : from_ascii("\\inputencoding{") + texenc + from_ascii("}")
1973                         + s1 + langenc + s2 + name + s1 + bufenc + s2;
1974
1975         odocstringstream os;
1976         os << "\\addto\\captions" << language
1977            << "{\\renewcommand{\\" << type << "name}{" << translated << "}}\n";
1978         return os.str();
1979 }
1980
1981
1982 docstring const i18npreamble(docstring const & templ, Language const * lang,
1983                              Encoding const & enc, bool const polyglossia,
1984                              bool const need_fixedwidth)
1985 {
1986         if (templ.empty())
1987                 return templ;
1988
1989         string preamble = polyglossia ?
1990                 subst(to_utf8(templ), "$$lang", lang->polyglossia()) :
1991                 subst(to_utf8(templ), "$$lang", lang->babel());
1992
1993         string const langenc = lang->encoding()->iconvName();
1994         string const texenc = lang->encoding()->latexName();
1995         string const bufenc = enc.iconvName();
1996         Encoding const * testenc(&enc);
1997         bool lang_fallback = false;
1998         bool ascii_fallback = false;
1999         if (need_fixedwidth && !enc.hasFixedWidth()) {
2000                 if (lang->encoding()->hasFixedWidth()) {
2001                         testenc = lang->encoding();
2002                         lang_fallback = true;
2003                 } else {
2004                         // We need a fixed width encoding, but both the buffer
2005                         // encoding and the language encoding are variable
2006                         // width. As a last fallback, try to convert to pure
2007                         // ASCII using the LaTeX commands defined in unicodesymbols.
2008                         testenc = encodings.fromLyXName("ascii");
2009                         if (!testenc)
2010                                 return docstring();
2011                         ascii_fallback = true;
2012                 }
2013         }
2014         // First and second character of plane 15 (Private Use Area)
2015         string const s1 = "\xf3\xb0\x80\x80"; // U+F0000
2016         string const s2 = "\xf3\xb0\x80\x81"; // U+F0001
2017         // FIXME UNICODE
2018         // lyx::regex is not unicode-safe.
2019         // Should use QRegExp or (boost::u32regex, but that requires ICU)
2020         static regex const reg("_\\(([^\\)]+)\\)");
2021         smatch sub;
2022         while (regex_search(preamble, sub, reg)) {
2023                 string const key = sub.str(1);
2024                 docstring const name = lang->translateLayout(key);
2025                 // Check whether name can be encoded in the buffer encoding
2026                 bool encodable = true;
2027                 for (size_t i = 0; i < name.size() && encodable; ++i)
2028                         if (!testenc->encodable(name[i]))
2029                                 encodable = false;
2030                 string translated;
2031                 if (encodable && !lang_fallback)
2032                         translated = to_utf8(name);
2033                 else if (ascii_fallback)
2034                         translated = to_ascii(testenc->latexString(name).first);
2035                 else
2036                         translated = "\\inputencoding{" + texenc + "}"
2037                                 + s1 + langenc + s2 + to_utf8(name)
2038                                 + s1 + bufenc + s2;
2039                 preamble = subst(preamble, sub.str(), translated);
2040         }
2041         return from_utf8(preamble);
2042 }
2043
2044 } // namespace
2045
2046
2047 docstring const LaTeXFeatures::getTClassI18nPreamble(bool use_babel,
2048                                 bool use_polyglossia, bool use_minted) const
2049 {
2050         DocumentClass const & tclass = params_.documentClass();
2051         // collect preamble snippets in a set to prevent multiple identical
2052         // commands (would happen if e.g. both theorem and theorem* are used)
2053         set<docstring> snippets;
2054         typedef LanguageList::const_iterator lang_it;
2055         lang_it const lbeg = UsedLanguages_.begin();
2056         lang_it const lend =  UsedLanguages_.end();
2057         list<docstring>::const_iterator cit = usedLayouts_.begin();
2058         list<docstring>::const_iterator end = usedLayouts_.end();
2059         for (; cit != end; ++cit) {
2060                 // language dependent commands (once per document)
2061                 snippets.insert(i18npreamble(tclass[*cit].langpreamble(),
2062                                                 buffer().language(),
2063                                                 buffer().params().encoding(),
2064                                                 use_polyglossia, false));
2065                 // commands for language changing (for multilanguage documents)
2066                 if ((use_babel || use_polyglossia) && !UsedLanguages_.empty()) {
2067                         snippets.insert(i18npreamble(
2068                                                 tclass[*cit].babelpreamble(),
2069                                                 buffer().language(),
2070                                                 buffer().params().encoding(),
2071                                                 use_polyglossia, false));
2072                         for (lang_it lit = lbeg; lit != lend; ++lit)
2073                                 snippets.insert(i18npreamble(
2074                                                 tclass[*cit].babelpreamble(),
2075                                                 *lit,
2076                                                 buffer().params().encoding(),
2077                                                 use_polyglossia, false));
2078                 }
2079         }
2080         if ((use_babel || use_polyglossia) && !UsedLanguages_.empty()) {
2081                 FloatList const & floats = params_.documentClass().floats();
2082                 UsedFloats::const_iterator fit = usedFloats_.begin();
2083                 UsedFloats::const_iterator fend = usedFloats_.end();
2084                 for (; fit != fend; ++fit) {
2085                         Floating const & fl = floats.getType(fit->first);
2086                         // we assume builtin floats are translated
2087                         if (fl.isPredefined())
2088                                 continue;
2089                         docstring const type = from_ascii(fl.floattype());
2090                         docstring const flname = from_utf8(fl.name());
2091                         docstring name = buffer().language()->translateLayout(fl.name());
2092                         // only request translation if we have a real translation
2093                         // (that differs from the source)
2094                         if (flname != name)
2095                                 snippets.insert(getFloatI18nPreamble(
2096                                                 type, name, buffer().language(),
2097                                                 buffer().params().encoding(),
2098                                                 use_polyglossia));
2099                         for (lang_it lit = lbeg; lit != lend; ++lit) {
2100                                 string const code = (*lit)->code();
2101                                 name = (*lit)->translateLayout(fl.name());
2102                                 // we assume we have a suitable translation if
2103                                 // either the language is English (we need to
2104                                 // translate into English if English is a secondary
2105                                 // language) or if translateIfPossible returns
2106                                 // something different to the English source.
2107                                 bool const have_translation =
2108                                         (flname != name || contains(code, "en"));
2109                                 if (have_translation)
2110                                         snippets.insert(getFloatI18nPreamble(
2111                                                 type, name, *lit,
2112                                                 buffer().params().encoding(),
2113                                                 use_polyglossia));
2114                         }
2115                 }
2116         }
2117
2118         cit = usedInsetLayouts_.begin();
2119         end = usedInsetLayouts_.end();
2120         TextClass::InsetLayouts const & ils = tclass.insetLayouts();
2121         for (; cit != end; ++cit) {
2122                 TextClass::InsetLayouts::const_iterator it = ils.find(*cit);
2123                 if (it == ils.end())
2124                         continue;
2125                 // The listings package does not work with variable width
2126                 // encodings, only with fixed width encodings. Therefore we
2127                 // need to force a fixed width encoding for
2128                 // \lstlistlistingname and \lstlistingname (bug 9382).
2129                 // This needs to be consistent with InsetListings::latex()
2130                 // rsp. InsetListings::forcedEncoding().
2131                 bool const need_fixedwidth = !use_minted &&
2132                                         !runparams_.isFullUnicode() &&
2133                                         buffer().params().encoding().package() != Encoding::japanese &&
2134                                         it->second.fixedwidthpreambleencoding();
2135                 // language dependent commands (once per document)
2136                 snippets.insert(i18npreamble(it->second.langpreamble(),
2137                                                 buffer().language(),
2138                                                 buffer().params().encoding(),
2139                                                 use_polyglossia, need_fixedwidth));
2140                 // commands for language changing (for multilanguage documents)
2141                 if ((use_babel || use_polyglossia) && !UsedLanguages_.empty()) {
2142                         snippets.insert(i18npreamble(
2143                                                 it->second.babelpreamble(),
2144                                                 buffer().language(),
2145                                                 buffer().params().encoding(),
2146                                                 use_polyglossia, need_fixedwidth));
2147                         for (lang_it lit = lbeg; lit != lend; ++lit)
2148                                 snippets.insert(i18npreamble(
2149                                                 it->second.babelpreamble(),
2150                                                 *lit,
2151                                                 buffer().params().encoding(),
2152                                                 use_polyglossia, need_fixedwidth));
2153                 }
2154         }
2155
2156         odocstringstream tcpreamble;
2157         set<docstring>::const_iterator const send = snippets.end();
2158         set<docstring>::const_iterator it = snippets.begin();
2159         for (; it != send; ++it)
2160                 tcpreamble << *it;
2161         return tcpreamble.str();
2162 }
2163
2164
2165 docstring const LaTeXFeatures::getLyXSGMLEntities() const
2166 {
2167         // Definition of entities used in the document that are LyX related.
2168         odocstringstream entities;
2169
2170         if (mustProvide("lyxarrow")) {
2171                 entities << "<!ENTITY lyxarrow \"-&gt;\">" << '\n';
2172         }
2173
2174         return entities.str();
2175 }
2176
2177
2178 docstring const LaTeXFeatures::getIncludedFiles(string const & fname) const
2179 {
2180         odocstringstream sgmlpreamble;
2181         // FIXME UNICODE
2182         docstring const basename(from_utf8(onlyPath(fname)));
2183
2184         FileMap::const_iterator end = IncludedFiles_.end();
2185         for (FileMap::const_iterator fi = IncludedFiles_.begin();
2186              fi != end; ++fi)
2187                 // FIXME UNICODE
2188                 sgmlpreamble << "\n<!ENTITY " << fi->first
2189                              << (isSGMLFileName(fi->second) ? " SYSTEM \"" : " \"")
2190                              << makeRelPath(from_utf8(fi->second), basename) << "\">";
2191
2192         return sgmlpreamble.str();
2193 }
2194
2195
2196 void LaTeXFeatures::showStruct() const
2197 {
2198         lyxerr << "LyX needs the following commands when LaTeXing:"
2199                << "\n***** Packages:" << getPackages()
2200                << "\n***** Macros:" << to_utf8(getMacros().str)
2201                << "\n***** Textclass stuff:" << to_utf8(getTClassPreamble())
2202                << "\n***** done." << endl;
2203 }
2204
2205
2206 Buffer const & LaTeXFeatures::buffer() const
2207 {
2208         return *buffer_;
2209 }
2210
2211
2212 void LaTeXFeatures::setBuffer(Buffer const & buffer)
2213 {
2214         buffer_ = &buffer;
2215 }
2216
2217
2218 BufferParams const & LaTeXFeatures::bufferParams() const
2219 {
2220         return params_;
2221 }
2222
2223
2224 void LaTeXFeatures::getFloatDefinitions(otexstream & os) const
2225 {
2226         FloatList const & floats = params_.documentClass().floats();
2227
2228         // Here we will output the code to create the needed float styles.
2229         // We will try to do this as minimal as possible.
2230         // \floatstyle{ruled}
2231         // \newfloat{algorithm}{htbp}{loa}
2232         // \providecommand{\algorithmname}{Algorithm}
2233         // \floatname{algorithm}{\protect\algorithmname}
2234         for (auto const & cit : usedFloats_) {
2235                 Floating const & fl = floats.getType(cit.first);
2236
2237                 // For builtin floats we do nothing.
2238                 if (fl.isPredefined())
2239                         continue;
2240
2241                 // We have to special case "table" and "figure"
2242                 if (fl.floattype() == "tabular" || fl.floattype() == "figure") {
2243                         // Output code to modify "table" or "figure"
2244                         // but only if builtin == false
2245                         // and that have to be true at this point in the
2246                         // function.
2247                         docstring const type = from_ascii(fl.floattype());
2248                         docstring const placement = from_ascii(fl.placement());
2249                         docstring const style = from_ascii(fl.style());
2250                         if (!style.empty()) {
2251                                 os << "\\floatstyle{" << style << "}\n"
2252                                    << "\\restylefloat{" << type << "}\n";
2253                         }
2254                         if (!placement.empty()) {
2255                                 os << "\\floatplacement{" << type << "}{"
2256                                    << placement << "}\n";
2257                         }
2258                 } else {
2259                         // The other non builtin floats.
2260
2261                         docstring const type = from_ascii(fl.floattype());
2262                         docstring const placement = from_ascii(fl.placement());
2263                         docstring const ext = from_ascii(fl.ext());
2264                         docstring const within = from_ascii(fl.within());
2265                         docstring const style = from_ascii(fl.style());
2266                         docstring const name =
2267                                 buffer().language()->translateLayout(fl.name());
2268                         os << "\\floatstyle{" << style << "}\n"
2269                            << "\\newfloat{" << type << "}{" << placement
2270                            << "}{" << ext << '}';
2271                         if (!within.empty())
2272                                 os << '[' << within << ']';
2273                         os << '\n'
2274                            << "\\providecommand{\\" << type << "name}{"
2275                            << name << "}\n"
2276                            << "\\floatname{" << type << "}{\\protect\\"
2277                            << type << "name}\n";
2278
2279                         // What missing here is to code to minimalize the code
2280                         // output so that the same floatstyle will not be
2281                         // used several times, when the same style is still in
2282                         // effect. (Lgb)
2283                 }
2284                 if (cit.second)
2285                         // The subfig package is loaded later
2286                         os << "\n\\AtBeginDocument{\\newsubfloat{" << from_ascii(fl.floattype()) << "}}\n";
2287         }
2288 }
2289
2290
2291 void LaTeXFeatures::resolveAlternatives()
2292 {
2293         for (Features::iterator it = features_.begin(); it != features_.end();) {
2294                 if (contains(*it, '|')) {
2295                         vector<string> const alternatives = getVectorFromString(*it, "|");
2296                         vector<string>::const_iterator const end = alternatives.end();
2297                         vector<string>::const_iterator ita = alternatives.begin();
2298                         // Is any alternative already required? => use that
2299                         for (; ita != end; ++ita) {
2300                                 if (isRequired(*ita))
2301                                         break;
2302                         }
2303                         // Is any alternative available? => use the first one
2304                         // (bug 9498)
2305                         if (ita == end) {
2306                                 for (ita = alternatives.begin(); ita != end; ++ita) {
2307                                         if (isAvailable(*ita)) {
2308                                                 require(*ita);
2309                                                 break;
2310                                         }
2311                                 }
2312                         }
2313                         // This will not work, but not requiring something
2314                         // would be more confusing
2315                         if (ita == end)
2316                                 require(alternatives.front());
2317                         features_.erase(it);
2318                         it = features_.begin();
2319                 } else
2320                         ++it;
2321         }
2322 }
2323
2324
2325 void LaTeXFeatures::expandMultiples()
2326 {
2327         for (Features::iterator it = features_.begin(); it != features_.end();) {
2328                 if (contains(*it, ',')) {
2329                         // Do nothing if any multiple is already required
2330                         for (string const & pkg : getVectorFromString(*it, ",")) {
2331                                 if (!isRequired(pkg))
2332                                         require(pkg);
2333                         }
2334                         features_.erase(it);
2335                         it = features_.begin();
2336                 } else
2337                         ++it;
2338         }
2339 }
2340
2341
2342 } // namespace lyx