2 * \file LaTeXFeatures.C
3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
7 * \author Lars Gullik Bjønnes
8 * \author Jean-Marc Lasgouttes
10 * \author André Pönitz
12 * Full author contact details are available in file CREDITS.
17 #include "LaTeXFeatures.h"
19 #include "bufferparams.h"
23 #include "FloatList.h"
29 #include "support/filetools.h"
33 using lyx::support::IsSGMLFilename;
34 using lyx::support::LibFileSearch;
35 using lyx::support::MakeRelPath;
36 using lyx::support::OnlyPath;
43 using std::ostringstream;
46 namespace biblio = lyx::biblio;
49 LaTeXFeatures::PackagesList LaTeXFeatures::packages_;
52 LaTeXFeatures::LaTeXFeatures(Buffer const & b, BufferParams const & p, bool n)
53 : buffer_(&b), params_(p), nice_(n)
57 bool LaTeXFeatures::useBabel() const
59 return lyxrc.language_use_babel ||
60 bufferParams().language->lang() != lyxrc.default_language ||
65 void LaTeXFeatures::require(string const & name)
70 features_.push_back(name);
74 void LaTeXFeatures::getAvailable()
77 string real_file = LibFileSearch("", "packages.lst");
79 if (real_file.empty())
82 lex.setFile(real_file);
87 bool finished = false;
89 while (lex.isOK() && !finished) {
91 case LyXLex::LEX_FEOF:
95 string const name = lex.getString();
96 PackagesList::const_iterator begin = packages_.begin();
97 PackagesList::const_iterator end = packages_.end();
98 if (find(begin, end, name) == end)
99 packages_.push_back(name);
107 void LaTeXFeatures::useLayout(string const & layoutname)
109 // Some code to avoid loops in dependency definition
110 static int level = 0;
111 const int maxlevel = 30;
112 if (level > maxlevel) {
113 lyxerr << "LaTeXFeatures::useLayout: maximum level of "
114 << "recursion attained by layout "
115 << layoutname << endl;
119 LyXTextClass const & tclass = params_.getLyXTextClass();
120 if (tclass.hasLayout(layoutname)) {
121 // Is this layout already in usedLayouts?
122 list<string>::const_iterator cit = usedLayouts_.begin();
123 list<string>::const_iterator end = usedLayouts_.end();
124 for (; cit != end; ++cit) {
125 if (layoutname == *cit)
129 LyXLayout_ptr const & lyt = tclass[layoutname];
130 if (!lyt->depends_on().empty()) {
132 useLayout(lyt->depends_on());
135 usedLayouts_.push_back(layoutname);
137 lyxerr << "LaTeXFeatures::useLayout: layout `"
138 << layoutname << "' does not exist in this class"
146 bool LaTeXFeatures::isRequired(string const & name) const
148 return find(features_.begin(), features_.end(), name) != features_.end();
152 bool LaTeXFeatures::isAvailable(string const & name) const
154 if (packages_.empty())
156 return find(packages_.begin(), packages_.end(), name) != packages_.end();
160 void LaTeXFeatures::addExternalPreamble(string const & preamble)
162 FeaturesList::const_iterator begin = preamble_snippets_.begin();
163 FeaturesList::const_iterator end = preamble_snippets_.end();
164 if (find(begin, end, preamble) == end)
165 preamble_snippets_.push_back(preamble);
169 void LaTeXFeatures::useFloat(string const & name)
171 usedFloats_.insert(name);
172 // We only need float.sty if we use non builtin floats, or if we
173 // use the "H" modifier. This includes modified table and
174 // figure floats. (Lgb)
175 Floating const & fl = params_.getLyXTextClass().floats().getType(name);
176 if (!fl.type().empty() && !fl.builtin()) {
182 void LaTeXFeatures::useLanguage(Language const * lang)
184 UsedLanguages_.insert(lang);
188 void LaTeXFeatures::includeFile(string const & key, string const & name)
190 IncludedFiles_[key] = name;
194 bool LaTeXFeatures::hasLanguages() const
196 return !UsedLanguages_.empty();
200 string LaTeXFeatures::getLanguages() const
202 ostringstream languages;
204 for (LanguageList::const_iterator cit =
205 UsedLanguages_.begin();
206 cit != UsedLanguages_.end();
208 languages << (*cit)->babel() << ',';
209 return languages.str();
213 set<string> LaTeXFeatures::getEncodingSet(string const & doc_encoding) const
215 set<string> encodings;
216 LanguageList::const_iterator it = UsedLanguages_.begin();
217 LanguageList::const_iterator end = UsedLanguages_.end();
218 for (; it != end; ++it)
219 if ((*it)->encoding()->LatexName() != doc_encoding)
220 encodings.insert((*it)->encoding()->LatexName());
226 char const * simplefeatures[] = {
244 int const nb_simplefeatures = sizeof(simplefeatures) / sizeof(char const *);
249 string const LaTeXFeatures::getPackages() const
251 ostringstream packages;
252 LyXTextClass const & tclass = params_.getLyXTextClass();
255 // These are all the 'simple' includes. i.e
256 // packages which we just \usepackage{package}
258 for (int i = 0; i < nb_simplefeatures; ++i) {
259 if (isRequired(simplefeatures[i]))
260 packages << "\\usepackage{"
261 << simplefeatures[i] << "}\n";
265 // The rest of these packages are somewhat more complicated
269 if (isRequired("amsmath")
270 && !tclass.provides(LyXTextClass::amsmath)
271 && params_.use_amsmath != BufferParams::AMS_OFF) {
272 packages << "\\usepackage{amsmath}\n";
276 if (isRequired("color")) {
277 if (params_.graphicsDriver == "default")
278 packages << "\\usepackage[usenames]{color}\n";
280 packages << "\\usepackage["
281 << params_.graphicsDriver
287 if (isRequired("makeidx")) {
288 if (! tclass.provides(LyXTextClass::makeidx))
289 packages << "\\usepackage{makeidx}\n";
290 packages << "\\makeindex\n";
294 if (isRequired("graphicx") && params_.graphicsDriver != "none") {
295 if (params_.graphicsDriver == "default")
296 packages << "\\usepackage{graphicx}\n";
298 packages << "\\usepackage["
299 << params_.graphicsDriver
304 // packages << "\\usepackage{algorithm}\n";
307 // lyxskak.sty --- newer chess support based on skak.sty
308 if (isRequired("chess")) {
309 packages << "\\usepackage[ps,mover]{lyxskak}\n";
313 if ((params_.spacing().getSpace() != Spacing::Single
314 && !params_.spacing().isDefault())
315 || isRequired("setspace")) {
316 packages << "\\usepackage{setspace}\n";
318 switch (params_.spacing().getSpace()) {
319 case Spacing::Default:
320 case Spacing::Single:
321 // we dont use setspace.sty so dont print anything
322 //packages += "\\singlespacing\n";
324 case Spacing::Onehalf:
325 packages << "\\onehalfspacing\n";
327 case Spacing::Double:
328 packages << "\\doublespacing\n";
331 packages << "\\setstretch{"
332 << params_.spacing().getValue() << "}\n";
337 if (isRequired("amssymb") || params_.use_amsmath == BufferParams::AMS_ON)
338 packages << "\\usepackage{amssymb}\n";
340 if (isRequired("url") && ! tclass.provides(LyXTextClass::url))
341 packages << "\\IfFileExists{url.sty}{\\usepackage{url}}\n"
342 " {\\newcommand{\\url}{\\texttt}}\n";
346 if (isRequired("natbib") && ! tclass.provides(LyXTextClass::natbib)) {
347 packages << "\\usepackage[";
348 if (params_.cite_engine == biblio::ENGINE_NATBIB_NUMERICAL) {
349 packages << "numbers";
351 packages << "authoryear";
353 packages << "]{natbib}\n";
356 // jurabib -- we need version 0.6 at least.
357 if (isRequired("jurabib")) {
358 packages << "\\usepackage{jurabib}[2004/01/25]\n";
361 // bibtopic -- the dot provides the aux file naming which
363 if (isRequired("bibtopic")) {
364 packages << "\\usepackage[dot]{bibtopic}\n";
367 return packages.str();
371 string const LaTeXFeatures::getMacros() const
373 ostringstream macros;
375 if (!preamble_snippets_.empty())
377 FeaturesList::const_iterator pit = preamble_snippets_.begin();
378 FeaturesList::const_iterator pend = preamble_snippets_.end();
379 for (; pit != pend; ++pit) {
380 macros << *pit << '\n';
383 if (isRequired("LyX"))
384 macros << lyx_def << '\n';
386 if (isRequired("lyxline"))
387 macros << lyxline_def << '\n';
389 if (isRequired("noun"))
390 macros << noun_def << '\n';
392 if (isRequired("lyxarrow"))
393 macros << lyxarrow_def << '\n';
396 if (isRequired("quotesinglbase"))
397 macros << quotesinglbase_def << '\n';
398 if (isRequired("quotedblbase"))
399 macros << quotedblbase_def << '\n';
400 if (isRequired("guilsinglleft"))
401 macros << guilsinglleft_def << '\n';
402 if (isRequired("guilsinglright"))
403 macros << guilsinglright_def << '\n';
404 if (isRequired("guillemotleft"))
405 macros << guillemotleft_def << '\n';
406 if (isRequired("guillemotright"))
407 macros << guillemotright_def << '\n';
410 if (isRequired("boldsymbol") && !isRequired("amsmath"))
411 macros << boldsymbol_def << '\n';
412 if (isRequired("binom") && !isRequired("amsmath"))
413 macros << binom_def << '\n';
414 if (isRequired("mathcircumflex"))
415 macros << mathcircumflex_def << '\n';
418 if (isRequired("ParagraphLeftIndent"))
419 macros << paragraphleftindent_def;
420 if (isRequired("NeedLyXFootnoteCode"))
421 macros << floatingfootnote_def;
423 // some problems with tex->html converters
424 if (isRequired("NeedTabularnewline"))
425 macros << tabularnewline_def;
427 // greyedout environment (note inset)
428 if (isRequired("lyxgreyedout"))
429 macros << lyxgreyedout_def;
431 if (isRequired("lyxdot"))
432 macros << lyxdot_def << '\n';
435 getFloatDefinitions(macros);
441 string const LaTeXFeatures::getBabelOptions() const
445 LanguageList::const_iterator it = UsedLanguages_.begin();
446 LanguageList::const_iterator end = UsedLanguages_.end();
447 for (; it != end; ++it)
448 if (!(*it)->latex_options().empty())
449 tmp << (*it)->latex_options() << '\n';
450 if (!params_.language->latex_options().empty())
451 tmp << params_.language->latex_options() << '\n';
457 string const LaTeXFeatures::getTClassPreamble() const
459 // the text class specific preamble
460 LyXTextClass const & tclass = params_.getLyXTextClass();
461 ostringstream tcpreamble;
463 tcpreamble << tclass.preamble();
465 list<string>::const_iterator cit = usedLayouts_.begin();
466 list<string>::const_iterator end = usedLayouts_.end();
467 for (; cit != end; ++cit) {
468 tcpreamble << tclass[*cit]->preamble();
471 CharStyles::iterator cs = tclass.charstyles().begin();
472 CharStyles::iterator csend = tclass.charstyles().end();
473 for (; cs != csend; ++cs) {
474 if (isRequired(cs->name))
475 tcpreamble << cs->preamble;
478 return tcpreamble.str();
482 string const LaTeXFeatures::getLyXSGMLEntities() const
484 // Definition of entities used in the document that are LyX related.
485 ostringstream entities;
487 if (isRequired("lyxarrow")) {
488 entities << "<!ENTITY lyxarrow \"->\">" << '\n';
491 return entities.str();
495 string const LaTeXFeatures::getIncludedFiles(string const & fname) const
497 ostringstream sgmlpreamble;
498 string const basename = OnlyPath(fname);
500 FileMap::const_iterator end = IncludedFiles_.end();
501 for (FileMap::const_iterator fi = IncludedFiles_.begin();
503 sgmlpreamble << "\n<!ENTITY " << fi->first
504 << (IsSGMLFilename(fi->second) ? " SYSTEM \"" : " \"")
505 << MakeRelPath(fi->second, basename) << "\">";
507 return sgmlpreamble.str();
511 void LaTeXFeatures::showStruct() const {
512 lyxerr << "LyX needs the following commands when LaTeXing:"
513 << "\n***** Packages:" << getPackages()
514 << "\n***** Macros:" << getMacros()
515 << "\n***** Textclass stuff:" << getTClassPreamble()
516 << "\n***** done." << endl;
520 Buffer const & LaTeXFeatures::buffer() const
526 void LaTeXFeatures::setBuffer(Buffer const & buffer)
532 BufferParams const & LaTeXFeatures::bufferParams() const
538 void LaTeXFeatures::getFloatDefinitions(ostream & os) const
540 FloatList const & floats = params_.getLyXTextClass().floats();
542 // Here we will output the code to create the needed float styles.
543 // We will try to do this as minimal as possible.
544 // \floatstyle{ruled}
545 // \newfloat{algorithm}{htbp}{loa}
546 // \floatname{algorithm}{Algorithm}
547 UsedFloats::const_iterator cit = usedFloats_.begin();
548 UsedFloats::const_iterator end = usedFloats_.end();
549 // ostringstream floats;
550 for (; cit != end; ++cit) {
551 Floating const & fl = floats.getType((*cit));
553 // For builtin floats we do nothing.
554 if (fl.builtin()) continue;
556 // We have to special case "table" and "figure"
557 if (fl.type() == "tabular" || fl.type() == "figure") {
558 // Output code to modify "table" or "figure"
559 // but only if builtin == false
560 // and that have to be true at this point in the
562 string const type = fl.type();
563 string const placement = fl.placement();
564 string const style = fl.style();
565 if (!style.empty()) {
566 os << "\\floatstyle{" << style << "}\n"
567 << "\\restylefloat{" << type << "}\n";
569 if (!placement.empty()) {
570 os << "\\floatplacement{" << type << "}{"
571 << placement << "}\n";
574 // The other non builtin floats.
576 string const type = fl.type();
577 string const placement = fl.placement();
578 string const ext = fl.ext();
579 string const within = fl.within();
580 string const style = fl.style();
581 string const name = fl.name();
582 os << "\\floatstyle{" << style << "}\n"
583 << "\\newfloat{" << type << "}{" << placement
584 << "}{" << ext << '}';
586 os << '[' << within << ']';
588 << "\\floatname{" << type << "}{"
591 // What missing here is to code to minimalize the code
592 // output so that the same floatstyle will not be
593 // used several times, when the same style is still in