]> git.lyx.org Git - lyx.git/blob - src/LaTeXFeatures.C
hopefully fix tex2lyx linking.
[lyx.git] / src / LaTeXFeatures.C
1 /**
2  * \file LaTeXFeatures.C
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 "bufferparams.h"
20 #include "Color.h"
21 #include "debug.h"
22 #include "encoding.h"
23 #include "Floating.h"
24 #include "FloatList.h"
25 #include "LColor.h"
26 #include "language.h"
27 #include "lyxlex.h"
28 #include "lyx_sty.h"
29 #include "lyxrc.h"
30
31 #include "support/docstream.h"
32 #include "support/filetools.h"
33 #include <sstream>
34
35
36 namespace lyx {
37
38 using support::isSGMLFilename;
39 using support::libFileSearch;
40 using support::makeRelPath;
41 using support::onlyPath;
42
43 using std::endl;
44 using std::find;
45 using std::string;
46 using std::list;
47 using std::ostream;
48 using std::ostringstream;
49 using std::set;
50
51 LaTeXFeatures::PackagesList LaTeXFeatures::packages_;
52
53
54 LaTeXFeatures::LaTeXFeatures(Buffer const & b, BufferParams const & p,
55                              OutputParams const & r)
56         : buffer_(&b), params_(p), runparams_(r)
57 {}
58
59
60 bool LaTeXFeatures::useBabel() const
61 {
62         return lyxrc.language_use_babel ||
63                 bufferParams().language->lang() != lyxrc.default_language ||
64                 this->hasLanguages();
65 }
66
67
68 void LaTeXFeatures::require(string const & name)
69 {
70         if (isRequired(name))
71                 return;
72
73         features_.push_back(name);
74 }
75
76
77 void LaTeXFeatures::getAvailable()
78 {
79         LyXLex lex(0, 0);
80         string real_file = libFileSearch("", "packages.lst");
81
82         if (real_file.empty())
83                 return;
84
85         lex.setFile(real_file);
86
87         if (!lex.isOK())
88                 return;
89
90         // Make sure that we are clean
91         packages_.clear();
92
93         bool finished = false;
94         // Parse config-file
95         while (lex.isOK() && !finished) {
96                 switch (lex.lex()) {
97                 case LyXLex::LEX_FEOF:
98                         finished = true;
99                         break;
100                 default:
101                         string const name = lex.getString();
102                         PackagesList::const_iterator begin = packages_.begin();
103                         PackagesList::const_iterator end   = packages_.end();
104                         if (find(begin, end, name) == end)
105                                 packages_.push_back(name);
106                 }
107         }
108
109         return;
110 }
111
112
113 void LaTeXFeatures::useLayout(string const & layoutname)
114 {
115         // Some code to avoid loops in dependency definition
116         static int level = 0;
117         const int maxlevel = 30;
118         if (level > maxlevel) {
119                 lyxerr << "LaTeXFeatures::useLayout: maximum level of "
120                        << "recursion attained by layout "
121                        << layoutname << endl;
122                 return;
123         }
124
125         LyXTextClass const & tclass = params_.getLyXTextClass();
126         if (tclass.hasLayout(layoutname)) {
127                 // Is this layout already in usedLayouts?
128                 list<string>::const_iterator cit = usedLayouts_.begin();
129                 list<string>::const_iterator end = usedLayouts_.end();
130                 for (; cit != end; ++cit) {
131                         if (layoutname == *cit)
132                                 return;
133                 }
134
135                 LyXLayout_ptr const & lyt = tclass[layoutname];
136                 if (!lyt->depends_on().empty()) {
137                         ++level;
138                         useLayout(lyt->depends_on());
139                         --level;
140                 }
141                 usedLayouts_.push_back(layoutname);
142         } else {
143                 lyxerr << "LaTeXFeatures::useLayout: layout `"
144                        << layoutname << "' does not exist in this class"
145                        << endl;
146         }
147
148         --level;
149 }
150
151
152 bool LaTeXFeatures::isRequired(string const & name) const
153 {
154         return find(features_.begin(), features_.end(), name) != features_.end();
155 }
156
157
158 bool LaTeXFeatures::isAvailable(string const & name) const
159 {
160         if (packages_.empty())
161                 getAvailable();
162         return find(packages_.begin(), packages_.end(), name) != packages_.end();
163 }
164
165
166 void LaTeXFeatures::addExternalPreamble(string const & preamble)
167 {
168         FeaturesList::const_iterator begin = preamble_snippets_.begin();
169         FeaturesList::const_iterator end   = preamble_snippets_.end();
170         if (find(begin, end, preamble) == end)
171                 preamble_snippets_.push_back(preamble);
172 }
173
174
175 void LaTeXFeatures::useFloat(string const & name)
176 {
177         usedFloats_.insert(name);
178         // We only need float.sty if we use non builtin floats, or if we
179         // use the "H" modifier. This includes modified table and
180         // figure floats. (Lgb)
181         Floating const & fl = params_.getLyXTextClass().floats().getType(name);
182         if (!fl.type().empty() && !fl.builtin()) {
183                 require("float");
184         }
185 }
186
187
188 void LaTeXFeatures::useLanguage(Language const * lang)
189 {
190         UsedLanguages_.insert(lang);
191 }
192
193
194 void LaTeXFeatures::includeFile(docstring const & key, string const & name)
195 {
196         IncludedFiles_[key] = name;
197 }
198
199
200 bool LaTeXFeatures::hasLanguages() const
201 {
202         return !UsedLanguages_.empty();
203 }
204
205
206 string LaTeXFeatures::getLanguages() const
207 {
208         ostringstream languages;
209
210         for (LanguageList::const_iterator cit =
211                     UsedLanguages_.begin();
212              cit != UsedLanguages_.end();
213              ++cit)
214                 languages << (*cit)->babel() << ',';
215         return languages.str();
216 }
217
218
219 set<string> LaTeXFeatures::getEncodingSet(string const & doc_encoding) const
220 {
221         set<string> encodings;
222         LanguageList::const_iterator it  = UsedLanguages_.begin();
223         LanguageList::const_iterator end = UsedLanguages_.end();
224         for (; it != end; ++it)
225                 if ((*it)->encoding()->latexName() != doc_encoding)
226                         encodings.insert((*it)->encoding()->latexName());
227         return encodings;
228 }
229
230 namespace {
231
232 char const * simplefeatures[] = {
233         "array",
234         "verbatim",
235         "longtable",
236         "rotating",
237         "latexsym",
238         "pifont",
239         "subfigure",
240         "floatflt",
241         "varioref",
242         "prettyref",
243         "float",
244         "booktabs",
245         "dvipost",
246         "fancybox",
247         "calc",
248         "nicefrac",
249         "tipa",
250         "framed",
251 };
252
253 int const nb_simplefeatures = sizeof(simplefeatures) / sizeof(char const *);
254
255 }
256
257
258 string const LaTeXFeatures::getPackages() const
259 {
260         ostringstream packages;
261         LyXTextClass const & tclass = params_.getLyXTextClass();
262
263         //
264         //  These are all the 'simple' includes.  i.e
265         //  packages which we just \usepackage{package}
266         //
267         for (int i = 0; i < nb_simplefeatures; ++i) {
268                 if (isRequired(simplefeatures[i]))
269                         packages << "\\usepackage{"
270                                  << simplefeatures[i] << "}\n";
271         }
272
273         //
274         // The rest of these packages are somewhat more complicated
275         // than those above.
276         //
277
278         if (isRequired("amsmath")
279             && !tclass.provides(LyXTextClass::amsmath)
280             && params_.use_amsmath != BufferParams::package_off) {
281                 packages << "\\usepackage{amsmath}\n";
282         }
283
284         // wasysym is a simple feature, but it must be after amsmath if both
285         // are used
286         // wasysym redefines some integrals (e.g. iint) from amsmath. That
287         // leads to inconsistent integrals. We only load this package if
288         // esint is used, since esint redefines all relevant integral
289         // symbols from wasysym and amsmath.
290         // See http://bugzilla.lyx.org/show_bug.cgi?id=1942
291         if (isRequired("wasysym") && isRequired("esint") &&
292             params_.use_esint != BufferParams::package_off)
293                 packages << "\\usepackage{wasysym}\n";
294
295         // color.sty
296         if (isRequired("color")) {
297                 if (params_.graphicsDriver == "default")
298                         packages << "\\usepackage{color}\n";
299                 else
300                         packages << "\\usepackage["
301                                  << params_.graphicsDriver
302                                  << "]{color}\n";
303         }
304
305         // makeidx.sty
306         if (isRequired("makeidx")) {
307                 if (!tclass.provides(LyXTextClass::makeidx))
308                         packages << "\\usepackage{makeidx}\n";
309                 packages << "\\makeindex\n";
310         }
311
312         // graphicx.sty
313         if (isRequired("graphicx") && params_.graphicsDriver != "none") {
314                 if (params_.graphicsDriver == "default")
315                         packages << "\\usepackage{graphicx}\n";
316                 else
317                         packages << "\\usepackage["
318                                  << params_.graphicsDriver
319                                  << "]{graphicx}\n";
320         }
321         // shadecolor for shaded
322         if (isRequired("framed")) {
323                 RGBColor c = RGBColor(lcolor.getX11Name(LColor::shadedbg));
324                 packages << "\\definecolor{shadecolor}{rgb}{" 
325                         << c.r/255 << ',' << c.g/255 << ',' << c.b/255 << "}\n";
326         }
327
328         //if (algorithm) {
329         //      packages << "\\usepackage{algorithm}\n";
330         //}
331
332         // lyxskak.sty --- newer chess support based on skak.sty
333         if (isRequired("chess")) {
334                 packages << "\\usepackage[ps,mover]{lyxskak}\n";
335         }
336
337         // setspace.sty
338         if ((params_.spacing().getSpace() != Spacing::Single
339              && !params_.spacing().isDefault())
340             || isRequired("setspace")) {
341                 packages << "\\usepackage{setspace}\n";
342         }
343         switch (params_.spacing().getSpace()) {
344         case Spacing::Default:
345         case Spacing::Single:
346                 // we dont use setspace.sty so dont print anything
347                 //packages += "\\singlespacing\n";
348                 break;
349         case Spacing::Onehalf:
350                 packages << "\\onehalfspacing\n";
351                 break;
352         case Spacing::Double:
353                 packages << "\\doublespacing\n";
354                 break;
355         case Spacing::Other:
356                 packages << "\\setstretch{"
357                          << params_.spacing().getValue() << "}\n";
358                 break;
359         }
360
361         // amssymb.sty
362         if (isRequired("amssymb") || params_.use_amsmath == BufferParams::package_on)
363                 packages << "\\usepackage{amssymb}\n";
364
365         // esint must be after amsmath and wasysym, since it will redeclare
366         // inconsistent integral symbols
367         if (isRequired("esint") && params_.use_esint != BufferParams::package_off)
368                 packages << "\\usepackage{esint}\n";
369
370         // url.sty
371         if (isRequired("url") && ! tclass.provides(LyXTextClass::url))
372                 packages << "\\IfFileExists{url.sty}{\\usepackage{url}}\n"
373                             "                      {\\newcommand{\\url}{\\texttt}}\n";
374
375         // float.sty
376         // natbib.sty
377         if (isRequired("natbib") && ! tclass.provides(LyXTextClass::natbib)) {
378                 packages << "\\usepackage[";
379                 if (params_.cite_engine == biblio::ENGINE_NATBIB_NUMERICAL) {
380                         packages << "numbers";
381                 } else {
382                         packages << "authoryear";
383                 }
384                 packages << "]{natbib}\n";
385         }
386
387         // jurabib -- we need version 0.6 at least.
388         if (isRequired("jurabib")) {
389                 packages << "\\usepackage{jurabib}[2004/01/25]\n";
390         }
391
392         // bibtopic -- the dot provides the aux file naming which
393         // LyX can detect.
394         if (isRequired("bibtopic")) {
395                 packages << "\\usepackage[dot]{bibtopic}\n";
396         }
397
398         if (isRequired("xy"))
399                 packages << "\\usepackage[all]{xy}\n";
400
401         if (isRequired("nomencl")) {
402                 packages << "\\usepackage{nomencl}[2005/09/22]\n"
403                          << "\\makenomenclature\n";
404         }
405  
406         return packages.str();
407 }
408
409
410 string const LaTeXFeatures::getMacros() const
411 {
412         ostringstream macros;
413
414         if (!preamble_snippets_.empty())
415                 macros << '\n';
416         FeaturesList::const_iterator pit  = preamble_snippets_.begin();
417         FeaturesList::const_iterator pend = preamble_snippets_.end();
418         for (; pit != pend; ++pit) {
419                 macros << *pit << '\n';
420         }
421
422         if (isRequired("LyX"))
423                 macros << lyx_def << '\n';
424
425         if (isRequired("lyxline"))
426                 macros << lyxline_def << '\n';
427
428         if (isRequired("noun"))
429                 macros << noun_def << '\n';
430
431         if (isRequired("lyxarrow"))
432                 macros << lyxarrow_def << '\n';
433
434         // quotes.
435         if (isRequired("quotesinglbase"))
436                 macros << quotesinglbase_def << '\n';
437         if (isRequired("quotedblbase"))
438                 macros << quotedblbase_def << '\n';
439         if (isRequired("guilsinglleft"))
440                 macros << guilsinglleft_def << '\n';
441         if (isRequired("guilsinglright"))
442                 macros << guilsinglright_def << '\n';
443         if (isRequired("guillemotleft"))
444                 macros << guillemotleft_def << '\n';
445         if (isRequired("guillemotright"))
446                 macros << guillemotright_def << '\n';
447
448         // Math mode
449         if (isRequired("boldsymbol") && !isRequired("amsmath"))
450                 macros << boldsymbol_def << '\n';
451         if (isRequired("binom") && !isRequired("amsmath"))
452                 macros << binom_def << '\n';
453         if (isRequired("mathcircumflex"))
454                 macros << mathcircumflex_def << '\n';
455
456         // other
457         if (isRequired("ParagraphLeftIndent"))
458                 macros << paragraphleftindent_def;
459         if (isRequired("NeedLyXFootnoteCode"))
460                 macros << floatingfootnote_def;
461
462         // some problems with tex->html converters
463         if (isRequired("NeedTabularnewline"))
464                 macros << tabularnewline_def;
465
466         // greyedout environment (note inset)
467         if (isRequired("lyxgreyedout"))
468                 macros << lyxgreyedout_def;
469
470         if (isRequired("lyxdot"))
471                 macros << lyxdot_def << '\n';
472
473         // floats
474         getFloatDefinitions(macros);
475
476         return macros.str();
477 }
478
479
480 string const LaTeXFeatures::getBabelOptions() const
481 {
482         ostringstream tmp;
483
484         LanguageList::const_iterator it  = UsedLanguages_.begin();
485         LanguageList::const_iterator end =  UsedLanguages_.end();
486         for (; it != end; ++it)
487                 if (!(*it)->latex_options().empty())
488                         tmp << (*it)->latex_options() << '\n';
489         if (!params_.language->latex_options().empty())
490                 tmp << params_.language->latex_options() << '\n';
491
492         return tmp.str();
493 }
494
495
496 docstring const LaTeXFeatures::getTClassPreamble() const
497 {
498         // the text class specific preamble
499         LyXTextClass const & tclass = params_.getLyXTextClass();
500         odocstringstream tcpreamble;
501
502         tcpreamble << tclass.preamble();
503
504         list<string>::const_iterator cit = usedLayouts_.begin();
505         list<string>::const_iterator end = usedLayouts_.end();
506         for (; cit != end; ++cit) {
507                 tcpreamble << tclass[*cit]->preamble();
508         }
509
510         CharStyles::iterator cs = tclass.charstyles().begin();
511         CharStyles::iterator csend = tclass.charstyles().end();
512         for (; cs != csend; ++cs) {
513                 if (isRequired(cs->name))
514                         tcpreamble << cs->preamble;
515         }
516
517         return tcpreamble.str();
518 }
519
520
521 docstring const LaTeXFeatures::getLyXSGMLEntities() const
522 {
523         // Definition of entities used in the document that are LyX related.
524         odocstringstream entities;
525
526         if (isRequired("lyxarrow")) {
527                 entities << "<!ENTITY lyxarrow \"-&gt;\">" << '\n';
528         }
529
530         return entities.str();
531 }
532
533
534 docstring const LaTeXFeatures::getIncludedFiles(string const & fname) const
535 {
536         odocstringstream sgmlpreamble;
537         string const basename = onlyPath(fname);
538
539         FileMap::const_iterator end = IncludedFiles_.end();
540         for (FileMap::const_iterator fi = IncludedFiles_.begin();
541              fi != end; ++fi)
542                 sgmlpreamble << "\n<!ENTITY " << fi->first
543                              << (isSGMLFilename(fi->second) ? " SYSTEM \"" : " \"")
544                              << from_ascii(makeRelPath(fi->second, basename)) << "\">";
545
546         return sgmlpreamble.str();
547 }
548
549
550 void LaTeXFeatures::showStruct() const {
551         lyxerr << "LyX needs the following commands when LaTeXing:"
552                << "\n***** Packages:" << getPackages()
553                << "\n***** Macros:" << getMacros()
554                << "\n***** Textclass stuff:" << to_utf8(getTClassPreamble())
555                << "\n***** done." << endl;
556 }
557
558
559 Buffer const & LaTeXFeatures::buffer() const
560 {
561         return *buffer_;
562 }
563
564
565 void LaTeXFeatures::setBuffer(Buffer const & buffer)
566 {
567         buffer_ = &buffer;
568 }
569
570
571 BufferParams const & LaTeXFeatures::bufferParams() const
572 {
573         return params_;
574 }
575
576
577 void LaTeXFeatures::getFloatDefinitions(ostream & os) const
578 {
579         FloatList const & floats = params_.getLyXTextClass().floats();
580
581         // Here we will output the code to create the needed float styles.
582         // We will try to do this as minimal as possible.
583         // \floatstyle{ruled}
584         // \newfloat{algorithm}{htbp}{loa}
585         // \floatname{algorithm}{Algorithm}
586         UsedFloats::const_iterator cit = usedFloats_.begin();
587         UsedFloats::const_iterator end = usedFloats_.end();
588         // ostringstream floats;
589         for (; cit != end; ++cit) {
590                 Floating const & fl = floats.getType((*cit));
591
592                 // For builtin floats we do nothing.
593                 if (fl.builtin()) continue;
594
595                 // We have to special case "table" and "figure"
596                 if (fl.type() == "tabular" || fl.type() == "figure") {
597                         // Output code to modify "table" or "figure"
598                         // but only if builtin == false
599                         // and that have to be true at this point in the
600                         // function.
601                         string const type = fl.type();
602                         string const placement = fl.placement();
603                         string const style = fl.style();
604                         if (!style.empty()) {
605                                 os << "\\floatstyle{" << style << "}\n"
606                                    << "\\restylefloat{" << type << "}\n";
607                         }
608                         if (!placement.empty()) {
609                                 os << "\\floatplacement{" << type << "}{"
610                                    << placement << "}\n";
611                         }
612                 } else {
613                         // The other non builtin floats.
614
615                         string const type = fl.type();
616                         string const placement = fl.placement();
617                         string const ext = fl.ext();
618                         string const within = fl.within();
619                         string const style = fl.style();
620                         string const name = fl.name();
621                         os << "\\floatstyle{" << style << "}\n"
622                            << "\\newfloat{" << type << "}{" << placement
623                            << "}{" << ext << '}';
624                         if (!within.empty())
625                                 os << '[' << within << ']';
626                         os << '\n'
627                            << "\\floatname{" << type << "}{"
628                            << name << "}\n";
629
630                         // What missing here is to code to minimalize the code
631                         // output so that the same floatstyle will not be
632                         // used several times, when the same style is still in
633                         // effect. (Lgb)
634                 }
635         }
636 }
637
638
639 } // namespace lyx