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