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