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