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