]> git.lyx.org Git - lyx.git/blob - src/LaTeXFeatures.C
revert last accidental commit and do the intended one
[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/filetools.h"
32
33 #include <sstream>
34
35 using lyx::support::isSGMLFilename;
36 using lyx::support::libFileSearch;
37 using lyx::support::makeRelPath;
38 using lyx::support::onlyPath;
39
40 using std::endl;
41 using std::find;
42 using std::string;
43 using std::list;
44 using std::ostream;
45 using std::ostringstream;
46 using std::set;
47
48 namespace biblio = lyx::biblio;
49
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(string 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         "dvipost",
245         "fancybox",
246         "calc",
247         "nicefrac",
248         "tipa",
249         "framed",
250 };
251
252 int const nb_simplefeatures = sizeof(simplefeatures) / sizeof(char const *);
253
254 }
255
256
257 string const LaTeXFeatures::getPackages() const
258 {
259         ostringstream packages;
260         LyXTextClass const & tclass = params_.getLyXTextClass();
261
262         //
263         //  These are all the 'simple' includes.  i.e
264         //  packages which we just \usepackage{package}
265         //
266         for (int i = 0; i < nb_simplefeatures; ++i) {
267                 if (isRequired(simplefeatures[i]))
268                         packages << "\\usepackage{"
269                                  << simplefeatures[i] << "}\n";
270         }
271
272         //
273         // The rest of these packages are somewhat more complicated
274         // than those above.
275         //
276
277         if (isRequired("amsmath")
278             && !tclass.provides(LyXTextClass::amsmath)
279             && params_.use_amsmath != BufferParams::AMS_OFF) {
280                 packages << "\\usepackage{amsmath}\n";
281         }
282
283         // wasysym is a simple feature, but it must be after amsmath if both
284         // are used
285         if (isRequired("wasysym"))
286                 packages << "\\usepackage{wasysym}\n";
287
288         // color.sty
289         if (isRequired("color")) {
290                 if (params_.graphicsDriver == "default")
291                         packages << "\\usepackage{color}\n";
292                 else
293                         packages << "\\usepackage["
294                                  << params_.graphicsDriver
295                                  << "]{color}\n";
296         }
297
298         // makeidx.sty
299         if (isRequired("makeidx")) {
300                 if (!tclass.provides(LyXTextClass::makeidx))
301                         packages << "\\usepackage{makeidx}\n";
302                 packages << "\\makeindex\n";
303         }
304
305         // graphicx.sty
306         if (isRequired("graphicx") && params_.graphicsDriver != "none") {
307                 if (params_.graphicsDriver == "default")
308                         packages << "\\usepackage{graphicx}\n";
309                 else
310                         packages << "\\usepackage["
311                                  << params_.graphicsDriver
312                                  << "]{graphicx}\n";
313         }
314         // shadecolor for shaded
315         if (isRequired("framed")) {
316         lyx::RGBColor c = lyx::RGBColor(lcolor.getX11Name(LColor::shadedbg));
317                 packages << "\\definecolor{shadecolor}{rgb}{" 
318                         << c.r/255 << ',' << c.g/255 << ',' << c.b/255 << "}\n";
319         }
320
321         //if (algorithm) {
322         //      packages << "\\usepackage{algorithm}\n";
323         //}
324
325         // lyxskak.sty --- newer chess support based on skak.sty
326         if (isRequired("chess")) {
327                 packages << "\\usepackage[ps,mover]{lyxskak}\n";
328         }
329
330         // setspace.sty
331         if ((params_.spacing().getSpace() != Spacing::Single
332              && !params_.spacing().isDefault())
333             || isRequired("setspace")) {
334                 packages << "\\usepackage{setspace}\n";
335         }
336         switch (params_.spacing().getSpace()) {
337         case Spacing::Default:
338         case Spacing::Single:
339                 // we dont use setspace.sty so dont print anything
340                 //packages += "\\singlespacing\n";
341                 break;
342         case Spacing::Onehalf:
343                 packages << "\\onehalfspacing\n";
344                 break;
345         case Spacing::Double:
346                 packages << "\\doublespacing\n";
347                 break;
348         case Spacing::Other:
349                 packages << "\\setstretch{"
350                          << params_.spacing().getValue() << "}\n";
351                 break;
352         }
353
354         // amssymb.sty
355         if (isRequired("amssymb") || params_.use_amsmath == BufferParams::AMS_ON)
356                 packages << "\\usepackage{amssymb}\n";
357         // url.sty
358         if (isRequired("url") && ! tclass.provides(LyXTextClass::url))
359                 packages << "\\IfFileExists{url.sty}{\\usepackage{url}}\n"
360                             "                      {\\newcommand{\\url}{\\texttt}}\n";
361
362         // float.sty
363         // natbib.sty
364         if (isRequired("natbib") && ! tclass.provides(LyXTextClass::natbib)) {
365                 packages << "\\usepackage[";
366                 if (params_.cite_engine == biblio::ENGINE_NATBIB_NUMERICAL) {
367                         packages << "numbers";
368                 } else {
369                         packages << "authoryear";
370                 }
371                 packages << "]{natbib}\n";
372         }
373
374         // jurabib -- we need version 0.6 at least.
375         if (isRequired("jurabib")) {
376                 packages << "\\usepackage{jurabib}[2004/01/25]\n";
377         }
378
379         // bibtopic -- the dot provides the aux file naming which
380         // LyX can detect.
381         if (isRequired("bibtopic")) {
382                 packages << "\\usepackage[dot]{bibtopic}\n";
383         }
384
385         return packages.str();
386 }
387
388
389 string const LaTeXFeatures::getMacros() const
390 {
391         ostringstream macros;
392
393         if (!preamble_snippets_.empty())
394                 macros << '\n';
395         FeaturesList::const_iterator pit  = preamble_snippets_.begin();
396         FeaturesList::const_iterator pend = preamble_snippets_.end();
397         for (; pit != pend; ++pit) {
398                 macros << *pit << '\n';
399         }
400
401         if (isRequired("LyX"))
402                 macros << lyx_def << '\n';
403
404         if (isRequired("lyxline"))
405                 macros << lyxline_def << '\n';
406
407         if (isRequired("noun"))
408                 macros << noun_def << '\n';
409
410         if (isRequired("lyxarrow"))
411                 macros << lyxarrow_def << '\n';
412
413         // quotes.
414         if (isRequired("quotesinglbase"))
415                 macros << quotesinglbase_def << '\n';
416         if (isRequired("quotedblbase"))
417                 macros << quotedblbase_def << '\n';
418         if (isRequired("guilsinglleft"))
419                 macros << guilsinglleft_def << '\n';
420         if (isRequired("guilsinglright"))
421                 macros << guilsinglright_def << '\n';
422         if (isRequired("guillemotleft"))
423                 macros << guillemotleft_def << '\n';
424         if (isRequired("guillemotright"))
425                 macros << guillemotright_def << '\n';
426
427         // Math mode
428         if (isRequired("boldsymbol") && !isRequired("amsmath"))
429                 macros << boldsymbol_def << '\n';
430         if (isRequired("binom") && !isRequired("amsmath"))
431                 macros << binom_def << '\n';
432         if (isRequired("mathcircumflex"))
433                 macros << mathcircumflex_def << '\n';
434
435         // other
436         if (isRequired("ParagraphLeftIndent"))
437                 macros << paragraphleftindent_def;
438         if (isRequired("NeedLyXFootnoteCode"))
439                 macros << floatingfootnote_def;
440
441         // some problems with tex->html converters
442         if (isRequired("NeedTabularnewline"))
443                 macros << tabularnewline_def;
444
445         // greyedout environment (note inset)
446         if (isRequired("lyxgreyedout"))
447                 macros << lyxgreyedout_def;
448
449         if (isRequired("lyxdot"))
450                 macros << lyxdot_def << '\n';
451
452         // floats
453         getFloatDefinitions(macros);
454
455         return macros.str();
456 }
457
458
459 string const LaTeXFeatures::getBabelOptions() const
460 {
461         ostringstream tmp;
462
463         LanguageList::const_iterator it  = UsedLanguages_.begin();
464         LanguageList::const_iterator end =  UsedLanguages_.end();
465         for (; it != end; ++it)
466                 if (!(*it)->latex_options().empty())
467                         tmp << (*it)->latex_options() << '\n';
468         if (!params_.language->latex_options().empty())
469                 tmp << params_.language->latex_options() << '\n';
470
471         return tmp.str();
472 }
473
474
475 string const LaTeXFeatures::getTClassPreamble() const
476 {
477         // the text class specific preamble
478         LyXTextClass const & tclass = params_.getLyXTextClass();
479         ostringstream tcpreamble;
480
481         tcpreamble << tclass.preamble();
482
483         list<string>::const_iterator cit = usedLayouts_.begin();
484         list<string>::const_iterator end = usedLayouts_.end();
485         for (; cit != end; ++cit) {
486                 tcpreamble << tclass[*cit]->preamble();
487         }
488
489         CharStyles::iterator cs = tclass.charstyles().begin();
490         CharStyles::iterator csend = tclass.charstyles().end();
491         for (; cs != csend; ++cs) {
492                 if (isRequired(cs->name))
493                         tcpreamble << cs->preamble;
494         }
495
496         return tcpreamble.str();
497 }
498
499
500 string const LaTeXFeatures::getLyXSGMLEntities() const
501 {
502         // Definition of entities used in the document that are LyX related.
503         ostringstream entities;
504
505         if (isRequired("lyxarrow")) {
506                 entities << "<!ENTITY lyxarrow \"-&gt;\">" << '\n';
507         }
508
509         return entities.str();
510 }
511
512
513 string const LaTeXFeatures::getIncludedFiles(string const & fname) const
514 {
515         ostringstream sgmlpreamble;
516         string const basename = onlyPath(fname);
517
518         FileMap::const_iterator end = IncludedFiles_.end();
519         for (FileMap::const_iterator fi = IncludedFiles_.begin();
520              fi != end; ++fi)
521                 sgmlpreamble << "\n<!ENTITY " << fi->first
522                              << (isSGMLFilename(fi->second) ? " SYSTEM \"" : " \"")
523                              << makeRelPath(fi->second, basename) << "\">";
524
525         return sgmlpreamble.str();
526 }
527
528
529 void LaTeXFeatures::showStruct() const {
530         lyxerr << "LyX needs the following commands when LaTeXing:"
531                << "\n***** Packages:" << getPackages()
532                << "\n***** Macros:" << getMacros()
533                << "\n***** Textclass stuff:" << getTClassPreamble()
534                << "\n***** done." << endl;
535 }
536
537
538 Buffer const & LaTeXFeatures::buffer() const
539 {
540         return *buffer_;
541 }
542
543
544 void LaTeXFeatures::setBuffer(Buffer const & buffer)
545 {
546         buffer_ = &buffer;
547 }
548
549
550 BufferParams const & LaTeXFeatures::bufferParams() const
551 {
552         return params_;
553 }
554
555
556 void LaTeXFeatures::getFloatDefinitions(ostream & os) const
557 {
558         FloatList const & floats = params_.getLyXTextClass().floats();
559
560         // Here we will output the code to create the needed float styles.
561         // We will try to do this as minimal as possible.
562         // \floatstyle{ruled}
563         // \newfloat{algorithm}{htbp}{loa}
564         // \floatname{algorithm}{Algorithm}
565         UsedFloats::const_iterator cit = usedFloats_.begin();
566         UsedFloats::const_iterator end = usedFloats_.end();
567         // ostringstream floats;
568         for (; cit != end; ++cit) {
569                 Floating const & fl = floats.getType((*cit));
570
571                 // For builtin floats we do nothing.
572                 if (fl.builtin()) continue;
573
574                 // We have to special case "table" and "figure"
575                 if (fl.type() == "tabular" || fl.type() == "figure") {
576                         // Output code to modify "table" or "figure"
577                         // but only if builtin == false
578                         // and that have to be true at this point in the
579                         // function.
580                         string const type = fl.type();
581                         string const placement = fl.placement();
582                         string const style = fl.style();
583                         if (!style.empty()) {
584                                 os << "\\floatstyle{" << style << "}\n"
585                                    << "\\restylefloat{" << type << "}\n";
586                         }
587                         if (!placement.empty()) {
588                                 os << "\\floatplacement{" << type << "}{"
589                                    << placement << "}\n";
590                         }
591                 } else {
592                         // The other non builtin floats.
593
594                         string const type = fl.type();
595                         string const placement = fl.placement();
596                         string const ext = fl.ext();
597                         string const within = fl.within();
598                         string const style = fl.style();
599                         string const name = fl.name();
600                         os << "\\floatstyle{" << style << "}\n"
601                            << "\\newfloat{" << type << "}{" << placement
602                            << "}{" << ext << '}';
603                         if (!within.empty())
604                                 os << '[' << within << ']';
605                         os << '\n'
606                            << "\\floatname{" << type << "}{"
607                            << name << "}\n";
608
609                         // What missing here is to code to minimalize the code
610                         // output so that the same floatstyle will not be
611                         // used several times, when the same style is still in
612                         // effect. (Lgb)
613                 }
614         }
615 }