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