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