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