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