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