set(LINKED_sources ${TOP_SRC_DIR}/src/lengthcommon.cpp)
set(LINKED_headers)
-foreach(_src insets/InsetLayout Color Counters
- Encoding FloatList Floating FontInfo
+foreach(_src insets/InsetLayout Author Color Counters
+ Encoding FloatList Floating FontInfo LaTeXPackages
Layout LayoutFile LayoutModuleList Lexer ModuleList TextClass
Spacing version)
list(APPEND LINKED_sources ${TOP_SRC_DIR}/src/${_src}.cpp)
src_tex2lyx_header_files = Split('''
Context.h
Parser.h
+ Preamble.h
tex2lyx.h
''')
Context.cpp
math.cpp
Parser.cpp
- preamble.cpp
+ Preamble.cpp
table.cpp
tex2lyx.cpp
text.cpp
src_tex2lyx_copied_files = Split('''
+ Author.cpp
Color.cpp
Counters.cpp
Encoding.cpp
FloatList.cpp
Floating.cpp
FontInfo.cpp
+ LaTeXPackages.cpp
Layout.cpp
LayoutFile.cpp
LayoutModuleList.cpp
% is some code that may occur in a .tex file created by LyX. The re-import
% works only because the first argument of \texorpdfstring is specified as
% translatable in this file.
+% If a command puts the contents of an argument inside an own group, use
+% "group" instead of "translate". Otherwise things like font changes would
+% survive the end of the group in LyX (bug 3036).
\abstractname
\Acrobatmenu{}{} % from the hyperref package
\makelabels
\maketitle
\MakeShortVerb{} % from doc.sty, argument must be verbatim
-\markboth{}{translate}
-\markright{translate}
+\markboth{group}{group}
+\markright{group}
\mathversion{}
\mbox{translate}
\mddefault
% Environments that start math mode.
% $...$, $$...$$, \(...\) and \[...\] are hardcoded in tex2lyx.
-% The arguments are currently ignored.
+% The arguments are currently ignored (apart from displaymath).
\begin{mathenvironments}
-equation
-equation*
-eqnarray
-eqnarray*
-align
-align*
-gather
-gather*
-multline
-multline*
-math
-displaymath
-flalign
-flalign
+equation{displaymath}
+equation*{displaymath}
+eqnarray{displaymath}
+eqnarray*{displaymath}
+align{displaymath}
+align*{displaymath}
+gather{displaymath}
+gather*{displaymath}
+multline{displaymath}
+multline*{displaymath}
+math{}
+displaymath{displaymath}
+flalign{displaymath}
+flalign{displaymath}
% These require extra args
-alignat
-alignat*
-xalignat
-xalignat*
-xxalignat
+alignat{}{displaymath}
+alignat*{displaymath}
+xalignat{}{displaymath}
+xalignat*{}{displaymath}
+xxalignat{}{displaymath}
% These are not known by LyX but work nevertheless:
-empheq
+empheq[]{}{displaymath}
\end{mathenvironments}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DELETED // deleted text
};
- explicit Change(Type t = UNCHANGED, int a = 0, time_t ct = current_time())
+ explicit Change(Type t = UNCHANGED, int a = 0, time_t ct = support::current_time())
: type(t), author(a), changetime(ct) {}
/// is the change similar to the given change such that both can be merged?
#include "Floating.h"
#include "FloatList.h"
#include "Language.h"
+#include "LaTeXPackages.h"
#include "Layout.h"
#include "Lexer.h"
#include "LyXRC.h"
//
/////////////////////////////////////////////////////////////////////
-LaTeXFeatures::Packages LaTeXFeatures::packages_;
-
LaTeXFeatures::LaTeXFeatures(Buffer const & b, BufferParams const & p,
OutputParams const & r)
}
-void LaTeXFeatures::getAvailable()
-{
- Lexer lex;
- support::FileName const real_file = libFileSearch("", "packages.lst");
-
- if (real_file.empty())
- return;
-
- lex.setFile(real_file);
-
- if (!lex.isOK())
- return;
-
- // Make sure that we are clean
- packages_.clear();
-
- bool finished = false;
- // Parse config-file
- while (lex.isOK() && !finished) {
- switch (lex.lex()) {
- case Lexer::LEX_FEOF:
- finished = true;
- break;
- default:
- packages_.insert(lex.getString());
- }
- }
-}
-
-
void LaTeXFeatures::useLayout(docstring const & layoutname)
{
// Some code to avoid loops in dependency definition
//LYXERR0("from=[" << from << "] to=[" << to << "]");
return theConverters().isReachable(from, to);
}
-
- if (packages_.empty())
- getAvailable();
- string n = name;
- if (suffixIs(n, ".sty"))
- n.erase(name.length() - 4);
- return packages_.find(n) != packages_.end();
+ return LaTeXPackages::isAvailable(name);
}
void require(std::string const & name);
/// Add a set of feature names requirements
void require(std::set<std::string> const & names);
- /// Which of the required packages are installed?
- static void getAvailable();
/// Is the (required) package available?
static bool isAvailable(std::string const & name);
/// Has the package been required?
typedef std::list<std::string> SnippetList;
///
SnippetList preamble_snippets_;
- /// The available (required) packages
- typedef std::set<std::string> Packages;
- ///
- static Packages packages_;
///
typedef std::set<Language const *> LanguageList;
/// used languages (only those that are supported by babel)
--- /dev/null
+/**
+ * \file LaTeXPackages.cpp
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author José Matos
+ * \author Lars Gullik Bjønnes
+ * \author Jean-Marc Lasgouttes
+ * \author Jürgen Vigna
+ * \author André Pönitz
+ *
+ * Full author contact details are available in file CREDITS.
+ */
+
+#include <config.h>
+
+#include "LaTeXPackages.h"
+
+#include "Lexer.h"
+
+#include "support/FileName.h"
+#include "support/filetools.h"
+#include "support/lstrings.h"
+
+
+using namespace std;
+using namespace lyx::support;
+
+
+namespace lyx {
+
+LaTeXPackages::Packages LaTeXPackages::packages_;
+
+
+void LaTeXPackages::getAvailable()
+{
+ Lexer lex;
+ support::FileName const real_file = libFileSearch("", "packages.lst");
+
+ if (real_file.empty())
+ return;
+
+ lex.setFile(real_file);
+
+ if (!lex.isOK())
+ return;
+
+ // Make sure that we are clean
+ packages_.clear();
+
+ bool finished = false;
+ // Parse config-file
+ while (lex.isOK() && !finished) {
+ switch (lex.lex()) {
+ case Lexer::LEX_FEOF:
+ finished = true;
+ break;
+ default:
+ packages_.insert(lex.getString());
+ }
+ }
+}
+
+
+bool LaTeXPackages::isAvailable(string const & name)
+{
+ if (packages_.empty())
+ getAvailable();
+ string n = name;
+ if (suffixIs(n, ".sty"))
+ n.erase(name.length() - 4);
+ return packages_.find(n) != packages_.end();
+}
+
+} // namespace lyx
--- /dev/null
+// -*- C++ -*-
+/**
+ * \file LaTeXPackages.h
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author Lars Gullik Bjønnes
+ * \author Jean-Marc Lasgouttes
+ *
+ * Full author contact details are available in file CREDITS.
+ */
+
+#ifndef LATEXPACKAGES_H
+#define LATEXPACKAGES_H
+
+#include <string>
+#include <set>
+
+
+namespace lyx {
+
+
+/** The list of avilable LaTeX packages
+ */
+class LaTeXPackages {
+public:
+ /// Which of the required packages are installed?
+ static void getAvailable();
+ /// Is the (required) package available?
+ static bool isAvailable(std::string const & name);
+private:
+ /// The available (required) packages
+ typedef std::set<std::string> Packages;
+ ///
+ static Packages packages_;
+};
+
+
+} // namespace lyx
+
+#endif
Language.cpp \
LaTeX.cpp \
LaTeXFeatures.cpp \
+ LaTeXPackages.cpp \
LayoutFile.cpp \
LayoutModuleList.cpp \
Length.cpp \
KeySequence.h \
Language.h \
LaTeXFeatures.h \
+ LaTeXPackages.h \
LaTeX.h \
Layout.h \
LayoutEnums.h \
#define SPELL_BASE_H
#include "support/strfwd.h"
-#include "support/lyxtime.h"
namespace lyx {
#include "Intl.h"
#include "KeyMap.h"
#include "Language.h"
-#include "LaTeXFeatures.h"
+#include "LaTeXPackages.h"
#include "Lexer.h"
#include "LyX.h"
#include "LyXAction.h"
current_view_->message(_("Reloading configuration..."));
lyxrc.read(libFileSearch(QString(), "lyxrc.defaults"), false);
// Re-read packages.lst
- LaTeXFeatures::getAvailable();
+ LaTeXPackages::getAvailable();
if (ret)
Alert::information(_("System reconfiguration failed"),
namespace frontend {
using support::bformat;
+using support::formatted_time;
GuiChanges::GuiChanges(GuiView & lv)
: GuiDialog(lv, "changes", qt_("Merge Changes"))
#include "support/lyxtime.h"
+#include "support/debug.h"
+#include "support/environment.h"
+#include "support/lstrings.h"
+#include "support/qstring_helpers.h"
+
+#include <QDateTime>
+#include <QLocale>
+
using namespace std;
namespace lyx {
+namespace support {
time_t current_time()
{
return string(date);
}
+
+time_t from_ctime(string t)
+{
+ // Example for the format: "Sun Nov 6 10:39:39 2011\n"
+ // Generously remove trailing '\n' (and other whitespace if needed)
+ t = trim(t, " \t\r\n");
+#if QT_VERSION >= 0x040400
+ // toDateTime() is too stupid to recognize variable amounts of
+ // whitespace (needed because ctime() outputs double spaces before
+ // single digit day numbers and hours)
+ t = subst(t, " ", " ");
+ QString const format("ddd MMM d H:mm:ss yyyy");
+ QLocale loc("C");
+ QDateTime loc_dt = loc.toDateTime(toqstr(t), format);
+ if (!loc_dt.isValid()) {
+ LYXERR(Debug::LOCALE, "Could not parse `" << t
+ << "´ (invalid format)");
+ return static_cast<time_t>(-1);
+ }
+ return loc_dt.toTime_t();
+#elif defined(_WIN32)
+#error "The minimum required Qt version on windows is Qt 4.4."
+#else
+ // strptime() is not available on windows (defined by POSIX)
+
+ // strptime() uses the current locale, so we need to switch to "C"
+ LYXERR(Debug::LOCALE, "Setting LC_ALL and LC_TIME to C");
+ string oldLC_ALL = getEnv("LC_ALL");
+ string oldLC_TIME = getEnv("LC_TIME");
+ if (!setEnv("LC_ALL", "C"))
+ LYXERR(Debug::LOCALE, "\t... LC_ALL failed!");
+ if (!setEnv("LC_TIME", "C"))
+ LYXERR(Debug::LOCALE, "\t... LC_TIME failed!");
+
+ struct tm loc_tm;
+ char const * const format = "%a%n%b%n%d%n%T%n%Y";
+ char * remainder = strptime(t.c_str(), format, &loc_tm);
+
+ LYXERR(Debug::LOCALE, "Resetting LC_ALL and LC_TIME");
+ if(!setEnv("LC_TIME", oldLC_TIME))
+ LYXERR(Debug::LOCALE, "\t... LC_TIME failed!");
+ if (!setEnv("LC_ALL", oldLC_ALL))
+ LYXERR(Debug::LOCALE, "\t... LC_ALL failed!");
+
+ if (!remainder) {
+ LYXERR(Debug::LOCALE, "Could not parse `" << t
+ << "´ (invalid format)");
+ return static_cast<time_t>(-1);
+ }
+ if (*remainder != '\0') {
+ LYXERR(Debug::LOCALE, "Could not parse `" << t
+ << "´ (excess characters)");
+ return static_cast<time_t>(-1);
+ }
+ return mktime(&loc_tm);
+#endif
+}
+
+} // namespace support
} // namespace lyx
namespace lyx {
+namespace support {
time_t current_time();
*/
std::string const formatted_time(time_t t, std::string const & fmt);
+/**
+ * Inverse of ctime().
+ * Since ctime() outputs the local time, the caller needs to ensure that the
+ * time zone and daylight saving time are the same as when \p t was created
+ * by ctime().
+ */
+time_t from_ctime(std::string t);
+
+} // namespace support
} // namespace lyx
#endif // LYXTIME_H
test/test-structure.tex
LINKED_FILES = \
+ ../Author.cpp \
../Color.cpp \
../Counters.cpp \
../Encoding.cpp \
../Floating.cpp \
../FontInfo.cpp \
../insets/InsetLayout.cpp \
+ ../LaTeXPackages.cpp \
../Layout.cpp \
../LayoutFile.cpp \
../LayoutModuleList.cpp \
math.cpp \
Parser.cpp \
Parser.h \
- preamble.cpp \
+ Preamble.cpp \
+ Preamble.h \
table.cpp \
tex2lyx.cpp \
tex2lyx.h \
}
+// We return a copy here because the tokens_ vector may get reallocated
+Token const Parser::next_next_token()
+{
+ static const Token dummy;
+ // If good() has not been called after the last get_token() we need
+ // to tokenize two more tokens.
+ if (pos_ + 1 >= tokens_.size()) {
+ tokenize_one();
+ tokenize_one();
+ }
+ return pos_ + 1 < tokens_.size() ? tokens_[pos_ + 1] : dummy;
+}
+
+
// We return a copy here because the tokens_ vector may get reallocated
Token const Parser::get_token()
{
if (curr_token().cat() == catNewline &&
(curr_token().cs().size() > 1 ||
(next_token().cat() == catSpace &&
- pos_ < tokens_.size() - 1 &&
- tokens_[pos_ + 1].cat() == catNewline)))
+ next_next_token().cat() == catNewline)))
return true;
if (curr_token().cat() == catEscape && curr_token().cs() == "par")
return true;
Token const curr_token() const;
/// The next token.
Token const next_token();
+ /// The next but one token.
+ Token const next_next_token();
/// Make the next token current and return that.
Token const get_token();
/// \return whether the current token starts a new paragraph
--- /dev/null
+/**
+ * \file Preamble.cpp
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author André Pönitz
+ * \author Uwe Stöhr
+ *
+ * Full author contact details are available in file CREDITS.
+ */
+
+// {[(
+
+#include <config.h>
+
+#include "Preamble.h"
+#include "tex2lyx.h"
+
+#include "LayoutFile.h"
+#include "Layout.h"
+#include "Lexer.h"
+#include "TextClass.h"
+
+#include "support/convert.h"
+#include "support/FileName.h"
+#include "support/filetools.h"
+#include "support/lstrings.h"
+
+#include "support/regex.h"
+
+#include <algorithm>
+#include <iostream>
+
+using namespace std;
+using namespace lyx::support;
+
+
+namespace lyx {
+
+// special columntypes
+extern map<char, int> special_columns;
+
+Preamble preamble;
+
+namespace {
+
+//add this to known_languages when updating to lyxformat 266:
+// "armenian" (needs special handling since not supported by standard babel)
+//add these to known_languages when updating to lyxformat 268:
+//"chinese-simplified", "chinese-traditional", "japanese", "korean"
+// Both changes require first that support for non-babel languages (CJK,
+// armtex) is added.
+/**
+ * known babel language names (including synonyms)
+ * not in standard babel: arabic, arabtex, armenian, belarusian, serbian-latin, thai
+ * not yet supported by LyX: kurmanji
+ * please keep this in sync with known_coded_languages line by line!
+ */
+const char * const known_languages[] = {"acadian", "afrikaans", "albanian",
+"american", "arabic", "arabtex", "austrian", "bahasa", "bahasai", "bahasam",
+"basque", "belarusian", "brazil", "brazilian", "breton", "british", "bulgarian",
+"canadian", "canadien", "catalan", "croatian", "czech", "danish", "dutch",
+"english", "esperanto", "estonian", "farsi", "finnish", "francais", "french",
+"frenchb", "frenchle", "frenchpro", "galician", "german", "germanb", "greek",
+"hebrew", "hungarian", "icelandic", "indon", "indonesian", "interlingua",
+"irish", "italian", "kazakh", "latin", "latvian", "lithuanian", "lowersorbian",
+"lsorbian", "magyar", "malay", "meyalu", "mongolian", "naustrian", "newzealand",
+"ngerman", "ngermanb", "norsk", "nynorsk", "polutonikogreek", "polish",
+"portuges", "portuguese", "romanian", "russian", "russianb", "samin",
+"scottish", "serbian", "serbian-latin", "slovak", "slovene", "spanish",
+"swedish", "thai", "turkish", "turkmen", "ukraineb", "ukrainian",
+"uppersorbian", "UKenglish", "USenglish", "usorbian", "vietnam", "welsh",
+0};
+
+/**
+ * the same as known_languages with .lyx names
+ * please keep this in sync with known_languages line by line!
+ */
+const char * const known_coded_languages[] = {"french", "afrikaans", "albanian",
+"american", "arabic_arabi", "arabic_arabtex", "austrian", "bahasa", "bahasa", "bahasam",
+"basque", "belarusian", "brazilian", "brazilian", "breton", "british", "bulgarian",
+"canadian", "canadien", "catalan", "croatian", "czech", "danish", "dutch",
+"english", "esperanto", "estonian", "farsi", "finnish", "french", "french",
+"french", "french", "french", "galician", "german", "german", "greek",
+"hebrew", "magyar", "icelandic", "bahasa", "bahasa", "interlingua",
+"irish", "italian", "kazakh", "latin", "latvian", "lithuanian", "lowersorbian",
+"lowersorbian", "magyar", "bahasam", "bahasam", "mongolian", "naustrian", "english",
+"ngerman", "ngerman", "norsk", "nynorsk", "polutonikogreek", "polish",
+"portuguese", "portuguese", "romanian", "russian", "russian", "samin",
+"scottish", "serbian", "serbian-latin", "slovak", "slovene", "spanish",
+"swedish", "thai", "turkish", "turkmen", "ukrainian", "ukrainian",
+"uppersorbian", "uppersorbian", "english", "english", "vietnamese", "welsh",
+0};
+
+/// languages with english quotes (.lyx names)
+const char * const known_english_quotes_languages[] = {"american", "bahasa",
+"bahasam", "brazilian", "canadian", "chinese-simplified", "english",
+"esperanto", "hebrew", "irish", "korean", "portuguese", "scottish", "thai", 0};
+
+/// languages with french quotes (.lyx names)
+const char * const known_french_quotes_languages[] = {"albanian",
+"arabic_arabi", "arabic_arabtex", "basque", "canadien", "catalan", "french",
+"galician", "greek", "italian", "norsk", "nynorsk", "polutonikogreek",
+"russian", "spanish", "spanish-mexico", "turkish", "turkmen", "ukrainian",
+"vietnamese", 0};
+
+/// languages with german quotes (.lyx names)
+const char * const known_german_quotes_languages[] = {"austrian", "bulgarian",
+"czech", "german", "icelandic", "lithuanian", "lowersorbian", "naustrian",
+"ngerman", "serbian", "serbian-latin", "slovak", "slovene", "uppersorbian", 0};
+
+/// languages with polish quotes (.lyx names)
+const char * const known_polish_quotes_languages[] = {"afrikaans", "croatian",
+"dutch", "estonian", "magyar", "polish", "romanian", 0};
+
+/// languages with swedish quotes (.lyx names)
+const char * const known_swedish_quotes_languages[] = {"finnish",
+"swedish", 0};
+
+/// known language packages from the times before babel
+const char * const known_old_language_packages[] = {"french", "frenchle",
+"frenchpro", "german", "ngerman", "pmfrench", 0};
+
+char const * const known_fontsizes[] = { "10pt", "11pt", "12pt", 0 };
+
+const char * const known_roman_fonts[] = { "ae", "beraserif", "bookman",
+"ccfonts", "chancery", "charter", "cmr", "fourier", "lmodern", "mathpazo",
+"mathptmx", "newcent", "utopia", 0};
+
+const char * const known_sans_fonts[] = { "avant", "berasans", "cmbr", "cmss",
+"helvet", "lmss", 0};
+
+const char * const known_typewriter_fonts[] = { "beramono", "cmtl", "cmtt",
+"courier", "lmtt", "luximono", "fourier", "lmodern", "mathpazo", "mathptmx",
+"newcent", 0};
+
+const char * const known_paper_sizes[] = { "a0paper", "b0paper", "c0paper",
+"a1paper", "b1paper", "c1paper", "a2paper", "b2paper", "c2paper", "a3paper",
+"b3paper", "c3paper", "a4paper", "b4paper", "c4paper", "a5paper", "b5paper",
+"c5paper", "a6paper", "b6paper", "c6paper", "executivepaper", "legalpaper",
+"letterpaper", "b0j", "b1j", "b2j", "b3j", "b4j", "b5j", "b6j", 0};
+
+const char * const known_class_paper_sizes[] = { "a4paper", "a5paper",
+"executivepaper", "legalpaper", "letterpaper", 0};
+
+const char * const known_paper_margins[] = { "lmargin", "tmargin", "rmargin",
+"bmargin", "headheight", "headsep", "footskip", "columnsep", 0};
+
+const char * const known_coded_paper_margins[] = { "leftmargin", "topmargin",
+"rightmargin", "bottommargin", "headheight", "headsep", "footskip",
+"columnsep", 0};
+
+/// commands that can start an \if...\else...\endif sequence
+const char * const known_if_commands[] = {"if", "ifarydshln", "ifbraket",
+"ifcancel", "ifcolortbl", "ifeurosym", "ifmarginnote", "ifmmode", "ifpdf",
+"ifsidecap", "ifupgreek", 0};
+
+const char * const known_basic_colors[] = {"blue", "black", "cyan", "green",
+"magenta", "red", "white", "yellow", 0};
+
+const char * const known_basic_color_codes[] = {"#0000ff", "#000000", "#00ffff", "#00ff00",
+"#ff00ff", "#ff0000", "#ffffff", "#ffff00", 0};
+
+/// conditional commands with three arguments like \@ifundefined{}{}{}
+const char * const known_if_3arg_commands[] = {"@ifundefined", "IfFileExists",
+0};
+
+/// packages that work only in xetex
+const char * const known_xetex_packages[] = {"arabxetex", "fixlatvian",
+"fontbook", "fontwrap", "mathspec", "philokalia", "polyglossia", "unisugar",
+"xeCJK", "xecolor", "xecyr", "xeindex", "xepersian", "xunicode", 0};
+
+// codes used to remove packages that are loaded automatically by LyX.
+// Syntax: package_beg_sep<name>package_mid_sep<package loading code>package_end_sep
+const char package_beg_sep = '\001';
+const char package_mid_sep = '\002';
+const char package_end_sep = '\003';
+
+
+// returns true if at least one of the options in what has been found
+bool handle_opt(vector<string> & opts, char const * const * what, string & target)
+{
+ if (opts.empty())
+ return false;
+
+ bool found = false;
+ // the last language option is the document language (for babel and LyX)
+ // the last size option is the document font size
+ vector<string>::iterator it;
+ vector<string>::iterator position = opts.begin();
+ for (; *what; ++what) {
+ it = find(opts.begin(), opts.end(), *what);
+ if (it != opts.end()) {
+ if (it >= position) {
+ found = true;
+ target = *what;
+ position = it;
+ }
+ }
+ }
+ return found;
+}
+
+
+void delete_opt(vector<string> & opts, char const * const * what)
+{
+ if (opts.empty())
+ return;
+
+ // remove found options from the list
+ // do this after handle_opt to avoid potential memory leaks
+ vector<string>::iterator it;
+ for (; *what; ++what) {
+ it = find(opts.begin(), opts.end(), *what);
+ if (it != opts.end())
+ opts.erase(it);
+ }
+}
+
+
+/*!
+ * Split a package options string (keyval format) into a vector.
+ * Example input:
+ * authorformat=smallcaps,
+ * commabeforerest,
+ * titleformat=colonsep,
+ * bibformat={tabular,ibidem,numbered}
+ */
+vector<string> split_options(string const & input)
+{
+ vector<string> options;
+ string option;
+ Parser p(input);
+ while (p.good()) {
+ Token const & t = p.get_token();
+ if (t.asInput() == ",") {
+ options.push_back(trim(option));
+ option.erase();
+ } else if (t.asInput() == "=") {
+ option += '=';
+ p.skip_spaces(true);
+ if (p.next_token().asInput() == "{")
+ option += '{' + p.getArg('{', '}') + '}';
+ } else if (t.cat() != catSpace)
+ option += t.asInput();
+ }
+
+ if (!option.empty())
+ options.push_back(trim(option));
+
+ return options;
+}
+
+
+/*!
+ * Retrieve a keyval option "name={value with=sign}" named \p name from
+ * \p options and return the value.
+ * The found option is also removed from \p options.
+ */
+string process_keyval_opt(vector<string> & options, string name)
+{
+ for (size_t i = 0; i < options.size(); ++i) {
+ vector<string> option;
+ split(options[i], option, '=');
+ if (option.size() < 2)
+ continue;
+ if (option[0] == name) {
+ options.erase(options.begin() + i);
+ option.erase(option.begin());
+ return join(option, "=");
+ }
+ }
+ return "";
+}
+
+} // anonymous namespace
+
+
+bool Preamble::indentParagraphs() const
+{
+ return h_paragraph_separation == "indent";
+}
+
+
+bool Preamble::isPackageUsed(string const & package) const
+{
+ return used_packages.find(package) != used_packages.end();
+}
+
+
+vector<string> Preamble::getPackageOptions(string const & package) const
+{
+ map<string, vector<string> >::const_iterator it = used_packages.find(package);
+ if (it != used_packages.end())
+ return it->second;
+ return vector<string>();
+}
+
+
+void Preamble::registerAutomaticallyLoadedPackage(std::string const & package)
+{
+ auto_packages.insert(package);
+}
+
+
+void Preamble::addModule(string const & module)
+{
+ used_modules.push_back(module);
+}
+
+
+void Preamble::suppressDate(bool suppress)
+{
+ if (suppress)
+ h_suppress_date = "true";
+ else
+ h_suppress_date = "false";
+}
+
+
+void Preamble::registerAuthor(std::string const & name)
+{
+ Author author(from_utf8(name), empty_docstring());
+ author.setUsed(true);
+ authors_.record(author);
+ h_tracking_changes = "true";
+ h_output_changes = "true";
+}
+
+
+Author const & Preamble::getAuthor(std::string const & name) const
+{
+ Author author(from_utf8(name), empty_docstring());
+ for (AuthorList::Authors::const_iterator it = authors_.begin();
+ it != authors_.end(); it++)
+ if (*it == author)
+ return *it;
+ static Author const dummy;
+ return dummy;
+}
+
+
+void Preamble::add_package(string const & name, vector<string> & options)
+{
+ // every package inherits the global options
+ if (used_packages.find(name) == used_packages.end())
+ used_packages[name] = split_options(h_options);
+
+ vector<string> & v = used_packages[name];
+ v.insert(v.end(), options.begin(), options.end());
+ if (name == "jurabib") {
+ // Don't output the order argument (see the cite command
+ // handling code in text.cpp).
+ vector<string>::iterator end =
+ remove(options.begin(), options.end(), "natbiborder");
+ end = remove(options.begin(), end, "jurabiborder");
+ options.erase(end, options.end());
+ }
+}
+
+
+namespace {
+
+// Given is a string like "scaled=0.9", return 0.9 * 100
+string const scale_as_percentage(string const & scale)
+{
+ string::size_type pos = scale.find('=');
+ if (pos != string::npos) {
+ string value = scale.substr(pos + 1);
+ if (isStrDbl(value))
+ return convert<string>(100 * convert<double>(value));
+ }
+ // If the input string didn't match our expectations.
+ // return the default value "100"
+ return "100";
+}
+
+
+string remove_braces(string const & value)
+{
+ if (value.empty())
+ return value;
+ if (value[0] == '{' && value[value.length()-1] == '}')
+ return value.substr(1, value.length()-2);
+ return value;
+}
+
+} // anonymous namespace
+
+
+Preamble::Preamble() : one_language(true)
+{
+ //h_backgroundcolor;
+ //h_boxbgcolor;
+ h_cite_engine = "basic";
+ h_defskip = "medskip";
+ //h_float_placement;
+ //h_fontcolor;
+ h_fontencoding = "default";
+ h_font_roman = "default";
+ h_font_sans = "default";
+ h_font_typewriter = "default";
+ h_font_default_family = "default";
+ h_font_sc = "false";
+ h_font_osf = "false";
+ h_font_sf_scale = "100";
+ h_font_tt_scale = "100";
+ h_graphics = "default";
+ h_html_be_strict = "false";
+ h_html_css_as_file = "0";
+ h_html_math_output = "0";
+ h_inputencoding = "auto";
+ h_language = "english";
+ h_language_package = "none";
+ //h_listings_params;
+ //h_margins;
+ //h_notefontcolor;
+ //h_options;
+ h_output_changes = "false";
+ h_papercolumns = "1";
+ h_paperfontsize = "default";
+ h_paperorientation = "portrait";
+ h_paperpagestyle = "default";
+ //h_papersides;
+ h_papersize = "default";
+ h_paragraph_indentation = "default";
+ h_paragraph_separation = "indent";
+ //h_pdf_title;
+ //h_pdf_author;
+ //h_pdf_subject;
+ //h_pdf_keywords;
+ h_pdf_bookmarks = "1";
+ h_pdf_bookmarksnumbered = "0";
+ h_pdf_bookmarksopen = "0";
+ h_pdf_bookmarksopenlevel = "1";
+ h_pdf_breaklinks = "0";
+ h_pdf_pdfborder = "0";
+ h_pdf_colorlinks = "0";
+ h_pdf_backref = "section";
+ h_pdf_pdfusetitle = "1";
+ //h_pdf_pagemode;
+ //h_pdf_quoted_options;
+ h_quotes_language = "english";
+ h_secnumdepth = "3";
+ h_spacing = "single";
+ h_suppress_date = "false";
+ h_textclass = "article";
+ h_tocdepth = "3";
+ h_tracking_changes = "false";
+ h_use_bibtopic = "false";
+ h_use_indices = "false";
+ h_use_geometry = "false";
+ h_use_amsmath = "1";
+ h_use_default_options = "false";
+ h_use_esint = "1";
+ h_use_hyperref = "0";
+ h_use_mhchem = "0";
+ h_use_mathdots = "0";
+ h_use_refstyle = "0";
+}
+
+
+void Preamble::handle_hyperref(vector<string> & options)
+{
+ // FIXME swallow inputencoding changes that might surround the
+ // hyperref setup if it was written by LyX
+ h_use_hyperref = "1";
+ // swallow "unicode=true", since LyX does always write that
+ vector<string>::iterator it =
+ find(options.begin(), options.end(), "unicode=true");
+ if (it != options.end())
+ options.erase(it);
+ it = find(options.begin(), options.end(), "pdfusetitle");
+ if (it != options.end()) {
+ h_pdf_pdfusetitle = "1";
+ options.erase(it);
+ }
+ string bookmarks = process_keyval_opt(options, "bookmarks");
+ if (bookmarks == "true")
+ h_pdf_bookmarks = "1";
+ else if (bookmarks == "false")
+ h_pdf_bookmarks = "0";
+ if (h_pdf_bookmarks == "1") {
+ string bookmarksnumbered =
+ process_keyval_opt(options, "bookmarksnumbered");
+ if (bookmarksnumbered == "true")
+ h_pdf_bookmarksnumbered = "1";
+ else if (bookmarksnumbered == "false")
+ h_pdf_bookmarksnumbered = "0";
+ string bookmarksopen =
+ process_keyval_opt(options, "bookmarksopen");
+ if (bookmarksopen == "true")
+ h_pdf_bookmarksopen = "1";
+ else if (bookmarksopen == "false")
+ h_pdf_bookmarksopen = "0";
+ if (h_pdf_bookmarksopen == "1") {
+ string bookmarksopenlevel =
+ process_keyval_opt(options, "bookmarksopenlevel");
+ if (!bookmarksopenlevel.empty())
+ h_pdf_bookmarksopenlevel = bookmarksopenlevel;
+ }
+ }
+ string breaklinks = process_keyval_opt(options, "breaklinks");
+ if (breaklinks == "true")
+ h_pdf_breaklinks = "1";
+ else if (breaklinks == "false")
+ h_pdf_breaklinks = "0";
+ string pdfborder = process_keyval_opt(options, "pdfborder");
+ if (pdfborder == "{0 0 0}")
+ h_pdf_pdfborder = "1";
+ else if (pdfborder == "{0 0 1}")
+ h_pdf_pdfborder = "0";
+ string backref = process_keyval_opt(options, "backref");
+ if (!backref.empty())
+ h_pdf_backref = backref;
+ string colorlinks = process_keyval_opt(options, "colorlinks");
+ if (colorlinks == "true")
+ h_pdf_colorlinks = "1";
+ else if (colorlinks == "false")
+ h_pdf_colorlinks = "0";
+ string pdfpagemode = process_keyval_opt(options, "pdfpagemode");
+ if (!pdfpagemode.empty())
+ h_pdf_pagemode = pdfpagemode;
+ string pdftitle = process_keyval_opt(options, "pdftitle");
+ if (!pdftitle.empty()) {
+ h_pdf_title = remove_braces(pdftitle);
+ }
+ string pdfauthor = process_keyval_opt(options, "pdfauthor");
+ if (!pdfauthor.empty()) {
+ h_pdf_author = remove_braces(pdfauthor);
+ }
+ string pdfsubject = process_keyval_opt(options, "pdfsubject");
+ if (!pdfsubject.empty())
+ h_pdf_subject = remove_braces(pdfsubject);
+ string pdfkeywords = process_keyval_opt(options, "pdfkeywords");
+ if (!pdfkeywords.empty())
+ h_pdf_keywords = remove_braces(pdfkeywords);
+ if (!options.empty()) {
+ if (!h_pdf_quoted_options.empty())
+ h_pdf_quoted_options += ',';
+ h_pdf_quoted_options += join(options, ",");
+ options.clear();
+ }
+}
+
+
+void Preamble::handle_geometry(vector<string> & options)
+{
+ h_use_geometry = "true";
+ vector<string>::iterator it;
+ // paper orientation
+ if ((it = find(options.begin(), options.end(), "landscape")) != options.end()) {
+ h_paperorientation = "landscape";
+ options.erase(it);
+ }
+ // paper size
+ // keyval version: "paper=letter"
+ string paper = process_keyval_opt(options, "paper");
+ if (!paper.empty())
+ h_papersize = paper + "paper";
+ // alternative version: "letterpaper"
+ handle_opt(options, known_paper_sizes, h_papersize);
+ delete_opt(options, known_paper_sizes);
+ // page margins
+ char const * const * margin = known_paper_margins;
+ for (; *margin; ++margin) {
+ string value = process_keyval_opt(options, *margin);
+ if (!value.empty()) {
+ int k = margin - known_paper_margins;
+ string name = known_coded_paper_margins[k];
+ h_margins += '\\' + name + ' ' + value + '\n';
+ }
+ }
+}
+
+
+void Preamble::handle_package(Parser &p, string const & name,
+ string const & opts, bool in_lyx_preamble)
+{
+ vector<string> options = split_options(opts);
+ add_package(name, options);
+ string scale;
+
+ if (is_known(name, known_xetex_packages))
+ xetex = true;
+
+ // roman fonts
+ if (is_known(name, known_roman_fonts)) {
+ h_font_roman = name;
+ p.skip_spaces();
+ }
+
+ if (name == "fourier") {
+ h_font_roman = "utopia";
+ // when font uses real small capitals
+ if (opts == "expert")
+ h_font_sc = "true";
+ }
+
+ if (name == "mathpazo")
+ h_font_roman = "palatino";
+
+ if (name == "mathptmx")
+ h_font_roman = "times";
+
+ // sansserif fonts
+ if (is_known(name, known_sans_fonts)) {
+ h_font_sans = name;
+ if (!opts.empty()) {
+ scale = opts;
+ h_font_sf_scale = scale_as_percentage(scale);
+ }
+ }
+
+ // typewriter fonts
+ if (is_known(name, known_typewriter_fonts)) {
+ // fourier can be set as roman font _only_
+ // fourier as typewriter is handled in handling of \ttdefault
+ if (name != "fourier") {
+ h_font_typewriter = name;
+ if (!opts.empty()) {
+ scale = opts;
+ h_font_tt_scale = scale_as_percentage(scale);
+ }
+ }
+ }
+
+ // font uses old-style figure
+ if (name == "eco")
+ h_font_osf = "true";
+
+ // after the detection and handling of special cases, we can remove the
+ // fonts, otherwise they would appear in the preamble, see bug #7856
+ if (is_known(name, known_roman_fonts) || is_known(name, known_sans_fonts)
+ || is_known(name, known_typewriter_fonts))
+ ;
+
+ else if (name == "amsmath" || name == "amssymb")
+ h_use_amsmath = "2";
+
+ else if (name == "esint")
+ h_use_esint = "2";
+
+ else if (name == "mhchem")
+ h_use_mhchem = "2";
+
+ else if (name == "mathdots")
+ h_use_mathdots = "2";
+
+ else if (name == "babel") {
+ h_language_package = "default";
+ // One might think we would have to do nothing if babel is loaded
+ // without any options to prevent pollution of the preamble with this
+ // babel call in every roundtrip.
+ // But the user could have defined babel-specific things afterwards. So
+ // we need to keep it in the preamble to prevent cases like bug #7861.
+ if (!opts.empty()) {
+ // check if more than one option was used - used later for inputenc
+ if (options.begin() != options.end() - 1)
+ one_language = false;
+ // babel takes the last language of the option of its \usepackage
+ // call as document language. If there is no such language option, the
+ // last language in the documentclass options is used.
+ handle_opt(options, known_languages, h_language);
+ // If babel is called with options, LyX puts them by default into the
+ // document class options. This works for most languages, except
+ // for Latvian, Lithuanian, Mongolian, Turkmen and Vietnamese and
+ // perhaps in future others.
+ // Therefore keep the babel call as it is as the user might have
+ // reasons for it.
+ h_preamble << "\\usepackage[" << opts << "]{babel}\n";
+ delete_opt(options, known_languages);
+ }
+ else
+ h_preamble << "\\usepackage{babel}\n";
+ }
+
+ else if (name == "fontenc") {
+ h_fontencoding = getStringFromVector(options, ",");
+ /* We could do the following for better round trip support,
+ * but this makes the document less portable, so I skip it:
+ if (h_fontencoding == lyxrc.fontenc)
+ h_fontencoding = "global";
+ */
+ options.clear();
+ }
+
+ else if (name == "inputenc" || name == "luainputenc") {
+ // h_inputencoding is only set when there is not more than one
+ // inputenc option because otherwise h_inputencoding must be
+ // set to "auto" (the default encoding of the document language)
+ // Therefore check for the "," character.
+ // It is also only set when there is not more than one babel
+ // language option.
+ if (opts.find(",") == string::npos && one_language == true)
+ h_inputencoding = opts;
+ if (!options.empty())
+ p.setEncoding(options.back());
+ options.clear();
+ }
+
+ else if (is_known(name, known_old_language_packages)) {
+ // known language packages from the times before babel
+ // if they are found and not also babel, they will be used as
+ // custom language package
+ h_language_package = "\\usepackage{" + name + "}";
+ }
+
+ else if (name == "prettyref")
+ ; // ignore this FIXME: Use the package separator mechanism instead
+
+ else if (name == "varioref")
+ ; // ignore this FIXME: Use the package separator mechanism instead
+
+ else if (name == "verbatim")
+ ; // ignore this FIXME: Use the package separator mechanism instead
+
+ else if (name == "textcomp")
+ ; // ignore this FIXME: Use the package separator mechanism instead
+
+ else if (name == "lyxskak") {
+ // ignore this and its options
+ if (!options.empty())
+ options.clear();
+ }
+
+ else if (name == "array" || name == "booktabs" || name == "float" ||
+ name == "color" || name == "hhline" || name == "longtable" ||
+ name == "makeidx" || name == "nomencl" || name == "splitidx" ||
+ name == "setspace" || name == "subscript" || name == "ulem" ||
+ name == "url") {
+ if (!in_lyx_preamble)
+ h_preamble << package_beg_sep << name
+ << package_mid_sep << "\\usepackage{"
+ << name << '}' << package_end_sep;
+ }
+
+ else if (name == "graphicx")
+ ; // ignore this FIXME: Use the package separator mechanism instead
+
+ else if (name == "geometry")
+ handle_geometry(options);
+
+ else if (name == "rotfloat")
+ ; // ignore this FIXME: Use the package separator mechanism instead
+
+ else if (name == "wrapfig")
+ ; // ignore this FIXME: Use the package separator mechanism instead
+
+ else if (name == "subfig")
+ ; // ignore this FIXME: Use the package separator mechanism instead
+
+ else if (is_known(name, known_languages))
+ h_language = name;
+
+ else if (name == "natbib") {
+ h_cite_engine = "natbib_authoryear";
+ vector<string>::iterator it =
+ find(options.begin(), options.end(), "authoryear");
+ if (it != options.end())
+ options.erase(it);
+ else {
+ it = find(options.begin(), options.end(), "numbers");
+ if (it != options.end()) {
+ h_cite_engine = "natbib_numerical";
+ options.erase(it);
+ }
+ }
+ }
+
+ else if (name == "jurabib")
+ h_cite_engine = "jurabib";
+
+ else if (name == "hyperref")
+ handle_hyperref(options);
+
+ else if (!in_lyx_preamble) {
+ if (options.empty())
+ h_preamble << "\\usepackage{" << name << "}";
+ else {
+ h_preamble << "\\usepackage[" << opts << "]{"
+ << name << "}";
+ options.clear();
+ }
+ }
+
+ // We need to do something with the options...
+ if (!options.empty())
+ cerr << "Ignoring options '" << join(options, ",")
+ << "' of package " << name << '.' << endl;
+
+ // remove the whitespace
+ p.skip_spaces();
+}
+
+
+void Preamble::handle_if(Parser & p, bool in_lyx_preamble)
+{
+ while (p.good()) {
+ Token t = p.get_token();
+ if (t.cat() == catEscape &&
+ is_known(t.cs(), known_if_commands))
+ handle_if(p, in_lyx_preamble);
+ else {
+ if (!in_lyx_preamble)
+ h_preamble << t.asInput();
+ if (t.cat() == catEscape && t.cs() == "fi")
+ return;
+ }
+ }
+}
+
+
+bool Preamble::writeLyXHeader(ostream & os, bool subdoc)
+{
+ // translate from babel to LyX names
+ h_language = babel2lyx(h_language);
+
+ // set the quote language
+ // LyX only knows the following quotes languages:
+ // english, swedish, german, polish, french and danish
+ // (quotes for "japanese" and "chinese-traditional" are missing because
+ // they wouldn't be useful: http://www.lyx.org/trac/ticket/6383)
+ // conversion list taken from
+ // http://en.wikipedia.org/wiki/Quotation_mark,_non-English_usage
+ // (quotes for kazakh and interlingua are unknown)
+ // danish
+ if (h_language == "danish")
+ h_quotes_language = "danish";
+ // french
+ else if (is_known(h_language, known_french_quotes_languages))
+ h_quotes_language = "french";
+ // german
+ else if (is_known(h_language, known_german_quotes_languages))
+ h_quotes_language = "german";
+ // polish
+ else if (is_known(h_language, known_polish_quotes_languages))
+ h_quotes_language = "polish";
+ // swedish
+ else if (is_known(h_language, known_swedish_quotes_languages))
+ h_quotes_language = "swedish";
+ //english
+ else if (is_known(h_language, known_english_quotes_languages))
+ h_quotes_language = "english";
+
+ if (contains(h_float_placement, "H"))
+ registerAutomaticallyLoadedPackage("float");
+ if (h_spacing != "single" && h_spacing != "default")
+ registerAutomaticallyLoadedPackage("setspace");
+
+ // output the LyX file settings
+ os << "#LyX file created by tex2lyx " << PACKAGE_VERSION << "\n"
+ << "\\lyxformat " << LYX_FORMAT << '\n'
+ << "\\begin_document\n"
+ << "\\begin_header\n"
+ << "\\textclass " << h_textclass << "\n";
+ string const raw = subdoc ? empty_string() : h_preamble.str();
+ if (!raw.empty()) {
+ os << "\\begin_preamble\n";
+ for (string::size_type i = 0; i < raw.size(); ++i) {
+ if (raw[i] == package_beg_sep) {
+ // Here follows some package loading code that
+ // must be skipped if the package is loaded
+ // automatically.
+ string::size_type j = raw.find(package_mid_sep, i);
+ if (j == string::npos)
+ return false;
+ string::size_type k = raw.find(package_end_sep, j);
+ if (k == string::npos)
+ return false;
+ string const package = raw.substr(i + 1, j - i - 1);
+ string const replacement = raw.substr(j + 1, k - j - 1);
+ if (auto_packages.find(package) == auto_packages.end())
+ os << replacement;
+ i = k;
+ } else
+ os.put(raw[i]);
+ }
+ os << "\n\\end_preamble\n";
+ }
+ if (!h_options.empty())
+ os << "\\options " << h_options << "\n";
+ os << "\\use_default_options " << h_use_default_options << "\n";
+ if (!used_modules.empty()) {
+ os << "\\begin_modules\n";
+ vector<string>::const_iterator const end = used_modules.end();
+ vector<string>::const_iterator it = used_modules.begin();
+ for (; it != end; it++)
+ os << *it << '\n';
+ os << "\\end_modules\n";
+ }
+ os << "\\language " << h_language << "\n"
+ << "\\language_package " << h_language_package << "\n"
+ << "\\inputencoding " << h_inputencoding << "\n"
+ << "\\fontencoding " << h_fontencoding << "\n"
+ << "\\font_roman " << h_font_roman << "\n"
+ << "\\font_sans " << h_font_sans << "\n"
+ << "\\font_typewriter " << h_font_typewriter << "\n"
+ << "\\font_default_family " << h_font_default_family << "\n"
+ << "\\font_sc " << h_font_sc << "\n"
+ << "\\font_osf " << h_font_osf << "\n"
+ << "\\font_sf_scale " << h_font_sf_scale << "\n"
+ << "\\font_tt_scale " << h_font_tt_scale << "\n"
+ << "\\graphics " << h_graphics << "\n";
+ if (!h_float_placement.empty())
+ os << "\\float_placement " << h_float_placement << "\n";
+ os << "\\paperfontsize " << h_paperfontsize << "\n"
+ << "\\spacing " << h_spacing << "\n"
+ << "\\use_hyperref " << h_use_hyperref << '\n';
+ if (h_use_hyperref == "1") {
+ if (!h_pdf_title.empty())
+ os << "\\pdf_title \"" << h_pdf_title << "\"\n";
+ if (!h_pdf_author.empty())
+ os << "\\pdf_author \"" << h_pdf_author << "\"\n";
+ if (!h_pdf_subject.empty())
+ os << "\\pdf_subject \"" << h_pdf_subject << "\"\n";
+ if (!h_pdf_keywords.empty())
+ os << "\\pdf_keywords \"" << h_pdf_keywords << "\"\n";
+ os << "\\pdf_bookmarks " << h_pdf_bookmarks << "\n"
+ "\\pdf_bookmarksnumbered " << h_pdf_bookmarksnumbered << "\n"
+ "\\pdf_bookmarksopen " << h_pdf_bookmarksopen << "\n"
+ "\\pdf_bookmarksopenlevel " << h_pdf_bookmarksopenlevel << "\n"
+ "\\pdf_breaklinks " << h_pdf_breaklinks << "\n"
+ "\\pdf_pdfborder " << h_pdf_pdfborder << "\n"
+ "\\pdf_colorlinks " << h_pdf_colorlinks << "\n"
+ "\\pdf_backref " << h_pdf_backref << "\n"
+ "\\pdf_pdfusetitle " << h_pdf_pdfusetitle << '\n';
+ if (!h_pdf_pagemode.empty())
+ os << "\\pdf_pagemode " << h_pdf_pagemode << '\n';
+ if (!h_pdf_quoted_options.empty())
+ os << "\\pdf_quoted_options \"" << h_pdf_quoted_options << "\"\n";
+ }
+ os << "\\papersize " << h_papersize << "\n"
+ << "\\use_geometry " << h_use_geometry << "\n"
+ << "\\use_amsmath " << h_use_amsmath << "\n"
+ << "\\use_esint " << h_use_esint << "\n"
+ << "\\use_mhchem " << h_use_mhchem << "\n"
+ << "\\use_mathdots " << h_use_mathdots << "\n"
+ << "\\cite_engine " << h_cite_engine << "\n"
+ << "\\use_bibtopic " << h_use_bibtopic << "\n"
+ << "\\use_indices " << h_use_indices << "\n"
+ << "\\paperorientation " << h_paperorientation << '\n'
+ << "\\suppress_date " << h_suppress_date << '\n'
+ << "\\use_refstyle " << h_use_refstyle << '\n';
+ if (!h_fontcolor.empty())
+ os << "\\fontcolor " << h_fontcolor << '\n';
+ if (!h_notefontcolor.empty())
+ os << "\\notefontcolor " << h_notefontcolor << '\n';
+ if (!h_backgroundcolor.empty())
+ os << "\\backgroundcolor " << h_backgroundcolor << '\n';
+ if (!h_boxbgcolor.empty())
+ os << "\\boxbgcolor " << h_boxbgcolor << '\n';
+ os << h_margins
+ << "\\secnumdepth " << h_secnumdepth << "\n"
+ << "\\tocdepth " << h_tocdepth << "\n"
+ << "\\paragraph_separation " << h_paragraph_separation << "\n";
+ if (h_paragraph_separation == "skip")
+ os << "\\defskip " << h_defskip << "\n";
+ else
+ os << "\\paragraph_indentation " << h_paragraph_indentation << "\n";
+ os << "\\quotes_language " << h_quotes_language << "\n"
+ << "\\papercolumns " << h_papercolumns << "\n"
+ << "\\papersides " << h_papersides << "\n"
+ << "\\paperpagestyle " << h_paperpagestyle << "\n";
+ if (!h_listings_params.empty())
+ os << "\\listings_params " << h_listings_params << "\n";
+ os << "\\tracking_changes " << h_tracking_changes << "\n"
+ << "\\output_changes " << h_output_changes << "\n"
+ << "\\html_math_output " << h_html_math_output << "\n"
+ << "\\html_css_as_file " << h_html_css_as_file << "\n"
+ << "\\html_be_strict " << h_html_be_strict << "\n"
+ << authors_
+ << "\\end_header\n\n"
+ << "\\begin_body\n";
+ return true;
+}
+
+
+void Preamble::parse(Parser & p, string const & forceclass,
+ TeX2LyXDocClass & tc)
+{
+ // initialize fixed types
+ special_columns['D'] = 3;
+ bool is_full_document = false;
+ bool is_lyx_file = false;
+ bool in_lyx_preamble = false;
+
+ // determine whether this is a full document or a fragment for inclusion
+ while (p.good()) {
+ Token const & t = p.get_token();
+
+ if (t.cat() == catEscape && t.cs() == "documentclass") {
+ is_full_document = true;
+ break;
+ }
+ }
+ p.reset();
+
+ while (is_full_document && p.good()) {
+ Token const & t = p.get_token();
+
+#ifdef FILEDEBUG
+ cerr << "t: " << t << "\n";
+#endif
+
+ //
+ // cat codes
+ //
+ if (!in_lyx_preamble &&
+ (t.cat() == catLetter ||
+ t.cat() == catSuper ||
+ t.cat() == catSub ||
+ t.cat() == catOther ||
+ t.cat() == catMath ||
+ t.cat() == catActive ||
+ t.cat() == catBegin ||
+ t.cat() == catEnd ||
+ t.cat() == catAlign ||
+ t.cat() == catParameter))
+ h_preamble << t.cs();
+
+ else if (!in_lyx_preamble &&
+ (t.cat() == catSpace || t.cat() == catNewline))
+ h_preamble << t.asInput();
+
+ else if (t.cat() == catComment) {
+ static regex const islyxfile("%% LyX .* created this file");
+ static regex const usercommands("User specified LaTeX commands");
+
+ string const comment = t.asInput();
+
+ // magically switch encoding default if it looks like XeLaTeX
+ static string const magicXeLaTeX =
+ "% This document must be compiled with XeLaTeX ";
+ if (comment.size() > magicXeLaTeX.size()
+ && comment.substr(0, magicXeLaTeX.size()) == magicXeLaTeX
+ && h_inputencoding == "auto") {
+ cerr << "XeLaTeX comment found, switching to UTF8\n";
+ h_inputencoding = "utf8";
+ }
+ smatch sub;
+ if (regex_search(comment, sub, islyxfile)) {
+ is_lyx_file = true;
+ in_lyx_preamble = true;
+ } else if (is_lyx_file
+ && regex_search(comment, sub, usercommands))
+ in_lyx_preamble = false;
+ else if (!in_lyx_preamble)
+ h_preamble << t.asInput();
+ }
+
+ else if (t.cs() == "pagestyle")
+ h_paperpagestyle = p.verbatim_item();
+
+ else if (t.cs() == "date") {
+ string argument = p.getArg('{', '}');
+ if (argument.empty())
+ h_suppress_date = "true";
+ else
+ h_preamble << t.asInput() << '{' << argument << '}';
+ }
+
+ else if (t.cs() == "color") {
+ string const space =
+ (p.hasOpt() ? p.getOpt() : string());
+ string argument = p.getArg('{', '}');
+ // check the case that a standard color is used
+ if (space.empty() && is_known(argument, known_basic_colors)) {
+ h_fontcolor = rgbcolor2code(argument);
+ preamble.registerAutomaticallyLoadedPackage("color");
+ } else if (space.empty() && argument == "document_fontcolor")
+ preamble.registerAutomaticallyLoadedPackage("color");
+ // check the case that LyX's document_fontcolor is defined
+ // but not used for \color
+ else {
+ h_preamble << t.asInput();
+ if (!space.empty())
+ h_preamble << space;
+ h_preamble << '{' << argument << '}';
+ // the color might already be set because \definecolor
+ // is parsed before this
+ h_fontcolor = "";
+ }
+ }
+
+ else if (t.cs() == "pagecolor") {
+ string argument = p.getArg('{', '}');
+ // check the case that a standard color is used
+ if (is_known(argument, known_basic_colors)) {
+ h_backgroundcolor = rgbcolor2code(argument);
+ } else if (argument == "page_backgroundcolor")
+ preamble.registerAutomaticallyLoadedPackage("color");
+ // check the case that LyX's page_backgroundcolor is defined
+ // but not used for \pagecolor
+ else {
+ h_preamble << t.asInput() << '{' << argument << '}';
+ // the color might already be set because \definecolor
+ // is parsed before this
+ h_backgroundcolor = "";
+ }
+ }
+
+ else if (t.cs() == "makeatletter") {
+ // LyX takes care of this
+ p.setCatCode('@', catLetter);
+ }
+
+ else if (t.cs() == "makeatother") {
+ // LyX takes care of this
+ p.setCatCode('@', catOther);
+ }
+
+ else if (t.cs() == "newcommand" || t.cs() == "newcommandx"
+ || t.cs() == "renewcommand" || t.cs() == "renewcommandx"
+ || t.cs() == "providecommand" || t.cs() == "providecommandx"
+ || t.cs() == "DeclareRobustCommand"
+ || t.cs() == "DeclareRobustCommandx"
+ || t.cs() == "ProvideTextCommandDefault"
+ || t.cs() == "DeclareMathAccent") {
+ bool star = false;
+ if (p.next_token().character() == '*') {
+ p.get_token();
+ star = true;
+ }
+ string const name = p.verbatim_item();
+ string const opt1 = p.getFullOpt();
+ string const opt2 = p.getFullOpt();
+ string const body = p.verbatim_item();
+ // font settings
+ if (name == "\\rmdefault")
+ if (is_known(body, known_roman_fonts))
+ h_font_roman = body;
+ if (name == "\\sfdefault")
+ if (is_known(body, known_sans_fonts))
+ h_font_sans = body;
+ if (name == "\\ttdefault")
+ if (is_known(body, known_typewriter_fonts))
+ h_font_typewriter = body;
+ if (name == "\\familydefault") {
+ string family = body;
+ // remove leading "\"
+ h_font_default_family = family.erase(0,1);
+ }
+
+ // remove the lyxdot definition that is re-added by LyX
+ // if necessary
+ if (name == "\\lyxdot")
+ in_lyx_preamble = true;
+
+ // Add the command to the known commands
+ add_known_command(name, opt1, !opt2.empty(), from_utf8(body));
+
+ // only non-lyxspecific stuff
+ if (!in_lyx_preamble) {
+ ostringstream ss;
+ ss << '\\' << t.cs();
+ if (star)
+ ss << '*';
+ ss << '{' << name << '}' << opt1 << opt2
+ << '{' << body << "}";
+ h_preamble << ss.str();
+/*
+ ostream & out = in_preamble ? h_preamble : os;
+ out << "\\" << t.cs() << "{" << name << "}"
+ << opts << "{" << body << "}";
+*/
+ }
+ }
+
+ else if (t.cs() == "documentclass") {
+ vector<string>::iterator it;
+ vector<string> opts = split_options(p.getArg('[', ']'));
+ handle_opt(opts, known_fontsizes, h_paperfontsize);
+ delete_opt(opts, known_fontsizes);
+ // delete "pt" at the end
+ string::size_type i = h_paperfontsize.find("pt");
+ if (i != string::npos)
+ h_paperfontsize.erase(i);
+ // The documentclass options are always parsed before the options
+ // of the babel call so that a language cannot overwrite the babel
+ // options.
+ handle_opt(opts, known_languages, h_language);
+ delete_opt(opts, known_languages);
+
+ // paper orientation
+ if ((it = find(opts.begin(), opts.end(), "landscape")) != opts.end()) {
+ h_paperorientation = "landscape";
+ opts.erase(it);
+ }
+ // paper sides
+ if ((it = find(opts.begin(), opts.end(), "oneside"))
+ != opts.end()) {
+ h_papersides = "1";
+ opts.erase(it);
+ }
+ if ((it = find(opts.begin(), opts.end(), "twoside"))
+ != opts.end()) {
+ h_papersides = "2";
+ opts.erase(it);
+ }
+ // paper columns
+ if ((it = find(opts.begin(), opts.end(), "onecolumn"))
+ != opts.end()) {
+ h_papercolumns = "1";
+ opts.erase(it);
+ }
+ if ((it = find(opts.begin(), opts.end(), "twocolumn"))
+ != opts.end()) {
+ h_papercolumns = "2";
+ opts.erase(it);
+ }
+ // paper sizes
+ // some size options are known to any document classes, other sizes
+ // are handled by the \geometry command of the geometry package
+ handle_opt(opts, known_class_paper_sizes, h_papersize);
+ delete_opt(opts, known_class_paper_sizes);
+ // the remaining options
+ h_options = join(opts, ",");
+ // FIXME This does not work for classes that have a
+ // different name in LyX than in LaTeX
+ h_textclass = p.getArg('{', '}');
+ }
+
+ else if (t.cs() == "usepackage") {
+ string const options = p.getArg('[', ']');
+ string const name = p.getArg('{', '}');
+ vector<string> vecnames;
+ split(name, vecnames, ',');
+ vector<string>::const_iterator it = vecnames.begin();
+ vector<string>::const_iterator end = vecnames.end();
+ for (; it != end; ++it)
+ handle_package(p, trim(*it), options,
+ in_lyx_preamble);
+ }
+
+ else if (t.cs() == "inputencoding") {
+ string const encoding = p.getArg('{','}');
+ h_inputencoding = encoding;
+ p.setEncoding(encoding);
+ }
+
+ else if (t.cs() == "newenvironment") {
+ string const name = p.getArg('{', '}');
+ string const opt1 = p.getFullOpt();
+ string const opt2 = p.getFullOpt();
+ string const beg = p.verbatim_item();
+ string const end = p.verbatim_item();
+ if (!in_lyx_preamble) {
+ h_preamble << "\\newenvironment{" << name
+ << '}' << opt1 << opt2 << '{'
+ << beg << "}{" << end << '}';
+ }
+ add_known_environment(name, opt1, !opt2.empty(),
+ from_utf8(beg), from_utf8(end));
+
+ }
+
+ else if (t.cs() == "def") {
+ string name = p.get_token().cs();
+ while (p.next_token().cat() != catBegin)
+ name += p.get_token().cs();
+ if (!in_lyx_preamble)
+ h_preamble << "\\def\\" << name << '{'
+ << p.verbatim_item() << "}";
+ }
+
+ else if (t.cs() == "newcolumntype") {
+ string const name = p.getArg('{', '}');
+ trim(name);
+ int nargs = 0;
+ string opts = p.getOpt();
+ if (!opts.empty()) {
+ istringstream is(string(opts, 1));
+ is >> nargs;
+ }
+ special_columns[name[0]] = nargs;
+ h_preamble << "\\newcolumntype{" << name << "}";
+ if (nargs)
+ h_preamble << "[" << nargs << "]";
+ h_preamble << "{" << p.verbatim_item() << "}";
+ }
+
+ else if (t.cs() == "setcounter") {
+ string const name = p.getArg('{', '}');
+ string const content = p.getArg('{', '}');
+ if (name == "secnumdepth")
+ h_secnumdepth = content;
+ else if (name == "tocdepth")
+ h_tocdepth = content;
+ else
+ h_preamble << "\\setcounter{" << name << "}{" << content << "}";
+ }
+
+ else if (t.cs() == "setlength") {
+ string const name = p.verbatim_item();
+ string const content = p.verbatim_item();
+ // the paragraphs are only not indented when \parindent is set to zero
+ if (name == "\\parindent" && content != "") {
+ if (content[0] == '0')
+ h_paragraph_separation = "skip";
+ else
+ h_paragraph_indentation = translate_len(content);
+ } else if (name == "\\parskip") {
+ if (content == "\\smallskipamount")
+ h_defskip = "smallskip";
+ else if (content == "\\medskipamount")
+ h_defskip = "medskip";
+ else if (content == "\\bigskipamount")
+ h_defskip = "bigskip";
+ else
+ h_defskip = content;
+ } else
+ h_preamble << "\\setlength{" << name << "}{" << content << "}";
+ }
+
+ else if (t.cs() == "onehalfspacing")
+ h_spacing = "onehalf";
+
+ else if (t.cs() == "doublespacing")
+ h_spacing = "double";
+
+ else if (t.cs() == "setstretch")
+ h_spacing = "other " + p.verbatim_item();
+
+ else if (t.cs() == "begin") {
+ string const name = p.getArg('{', '}');
+ if (name == "document")
+ break;
+ h_preamble << "\\begin{" << name << "}";
+ }
+
+ else if (t.cs() == "geometry") {
+ vector<string> opts = split_options(p.getArg('{', '}'));
+ handle_geometry(opts);
+ }
+
+ else if (t.cs() == "definecolor") {
+ string const color = p.getArg('{', '}');
+ string const space = p.getArg('{', '}');
+ string const value = p.getArg('{', '}');
+ if (color == "document_fontcolor" && space == "rgb") {
+ RGBColor c(RGBColorFromLaTeX(value));
+ h_fontcolor = X11hexname(c);
+ } else if (color == "note_fontcolor" && space == "rgb") {
+ RGBColor c(RGBColorFromLaTeX(value));
+ h_notefontcolor = X11hexname(c);
+ } else if (color == "page_backgroundcolor" && space == "rgb") {
+ RGBColor c(RGBColorFromLaTeX(value));
+ h_backgroundcolor = X11hexname(c);
+ } else if (color == "shadecolor" && space == "rgb") {
+ RGBColor c(RGBColorFromLaTeX(value));
+ h_boxbgcolor = X11hexname(c);
+ } else {
+ h_preamble << "\\definecolor{" << color
+ << "}{" << space << "}{" << value
+ << '}';
+ }
+ }
+
+ else if (t.cs() == "jurabibsetup") {
+ // FIXME p.getArg('{', '}') is most probably wrong (it
+ // does not handle nested braces).
+ // Use p.verbatim_item() instead.
+ vector<string> jurabibsetup =
+ split_options(p.getArg('{', '}'));
+ // add jurabibsetup to the jurabib package options
+ add_package("jurabib", jurabibsetup);
+ if (!jurabibsetup.empty()) {
+ h_preamble << "\\jurabibsetup{"
+ << join(jurabibsetup, ",") << '}';
+ }
+ }
+
+ else if (t.cs() == "hypersetup") {
+ vector<string> hypersetup =
+ split_options(p.verbatim_item());
+ // add hypersetup to the hyperref package options
+ handle_hyperref(hypersetup);
+ if (!hypersetup.empty()) {
+ h_preamble << "\\hypersetup{"
+ << join(hypersetup, ",") << '}';
+ }
+ }
+
+ else if (is_known(t.cs(), known_if_3arg_commands)) {
+ // prevent misparsing of \usepackage if it is used
+ // as an argument (see e.g. our own output of
+ // \@ifundefined above)
+ string const arg1 = p.verbatim_item();
+ string const arg2 = p.verbatim_item();
+ string const arg3 = p.verbatim_item();
+ // test case \@ifundefined{date}{}{\date{}}
+ if (t.cs() == "@ifundefined" && arg1 == "date" &&
+ arg2.empty() && arg3 == "\\date{}") {
+ h_suppress_date = "true";
+ // older tex2lyx versions did output
+ // \@ifundefined{definecolor}{\usepackage{color}}{}
+ } else if (t.cs() == "@ifundefined" &&
+ arg1 == "definecolor" &&
+ arg2 == "\\usepackage{color}" &&
+ arg3.empty()) {
+ if (!in_lyx_preamble)
+ h_preamble << package_beg_sep
+ << "color"
+ << package_mid_sep
+ << "\\@ifundefined{definecolor}{color}{}"
+ << package_end_sep;
+ // test for case
+ //\@ifundefined{showcaptionsetup}{}{%
+ // \PassOptionsToPackage{caption=false}{subfig}}
+ // that LyX uses for subfloats
+ } else if (t.cs() == "@ifundefined" &&
+ arg1 == "showcaptionsetup" && arg2.empty()
+ && arg3 == "%\n \\PassOptionsToPackage{caption=false}{subfig}") {
+ ; // do nothing
+ } else if (!in_lyx_preamble) {
+ h_preamble << t.asInput()
+ << '{' << arg1 << '}'
+ << '{' << arg2 << '}'
+ << '{' << arg3 << '}';
+ }
+ }
+
+ else if (is_known(t.cs(), known_if_commands)) {
+ // must not parse anything in conditional code, since
+ // LyX would output the parsed contents unconditionally
+ if (!in_lyx_preamble)
+ h_preamble << t.asInput();
+ handle_if(p, in_lyx_preamble);
+ }
+
+ else if (!t.cs().empty() && !in_lyx_preamble)
+ h_preamble << '\\' << t.cs();
+ }
+
+ // remove the whitespace
+ p.skip_spaces();
+
+ // Force textclass if the user wanted it
+ if (!forceclass.empty())
+ h_textclass = forceclass;
+ if (noweb_mode && !prefixIs(h_textclass, "literate-"))
+ h_textclass.insert(0, "literate-");
+ tc.setName(h_textclass);
+ if (!tc.load()) {
+ cerr << "Error: Could not read layout file for textclass \"" << h_textclass << "\"." << endl;
+ exit(EXIT_FAILURE);
+ }
+ if (h_papersides.empty()) {
+ ostringstream ss;
+ ss << tc.sides();
+ h_papersides = ss.str();
+ }
+}
+
+
+string babel2lyx(string const & language)
+{
+ char const * const * where = is_known(language, known_languages);
+ if (where)
+ return known_coded_languages[where - known_languages];
+ return language;
+}
+
+
+string rgbcolor2code(string const & name)
+{
+ char const * const * where = is_known(name, known_basic_colors);
+ if (where) {
+ // "red", "green" etc
+ return known_basic_color_codes[where - known_basic_colors];
+ }
+ // "255,0,0", "0,255,0" etc
+ RGBColor c(RGBColorFromLaTeX(name));
+ return X11hexname(c);
+}
+
+// }])
+
+
+} // namespace lyx
--- /dev/null
+/**
+ * \file Preamble.h
+ * This file is part of LyX, the document processor.
+ * Licence details can be found in the file COPYING.
+ *
+ * \author André Pönitz
+ * \author Uwe Stöhr
+ *
+ * Full author contact details are available in file CREDITS.
+ */
+
+// {[(
+
+#ifndef LYX_PREAMBLE_H
+#define LYX_PREAMBLE_H
+
+#include "Author.h"
+
+#include <iosfwd>
+#include <sstream>
+#include <string>
+#include <vector>
+#include <map>
+#include <set>
+
+
+namespace lyx {
+
+class Parser;
+class TeX2LyXDocClass;
+
+class Preamble
+{
+public:
+ Preamble();
+
+ ///
+ std::string inputencoding() const { return h_inputencoding; }
+ ///
+ std::string notefontcolor() const { return h_notefontcolor; }
+ ///
+ std::string use_indices() const { return h_use_indices; }
+ ///
+ bool indentParagraphs() const;
+ ///
+ bool isPackageUsed(std::string const & package) const;
+ ///
+ std::vector<std::string>
+ getPackageOptions(std::string const & package) const;
+ /// Tell that \p package will be loaded automatically by LyX.
+ /// This has only an effect if \p package is prepared for
+ /// autoloading in parse().
+ void registerAutomaticallyLoadedPackage(std::string const & package);
+ ///
+ void addModule(std::string const & module);
+ ///
+ void suppressDate(bool suppress);
+ /// Register an author named \p name in the author list
+ void registerAuthor(std::string const & name);
+ /// Get author named \p name (must be registered first)
+ Author const & getAuthor(std::string const & name) const;
+
+
+ /// Parses the LaTeX preamble into internal data
+ void parse(Parser & p, std::string const & forceclass,
+ TeX2LyXDocClass & tc);
+ /// Writes the LyX file header from internal data
+ bool writeLyXHeader(std::ostream & os, bool subdoc);
+
+private:
+ ///
+ std::map<std::string, std::vector<std::string> > used_packages;
+ /// Packages that will be loaded automatically by LyX
+ std::set<std::string> auto_packages;
+ ///
+ std::vector<std::string> used_modules;
+
+ /// needed to handle encodings with babel
+ bool one_language;
+
+ std::ostringstream h_preamble;
+ std::string h_backgroundcolor;
+ std::string h_boxbgcolor;
+ std::string h_cite_engine;
+ std::string h_defskip;
+ std::string h_float_placement;
+ std::string h_fontcolor;
+ std::string h_fontencoding;
+ std::string h_font_roman;
+ std::string h_font_sans;
+ std::string h_font_typewriter;
+ std::string h_font_default_family;
+ std::string h_font_sc;
+ std::string h_font_osf;
+ std::string h_font_sf_scale;
+ std::string h_font_tt_scale;
+ std::string h_graphics;
+ std::string h_html_be_strict;
+ std::string h_html_css_as_file;
+ std::string h_html_math_output;
+ std::string h_inputencoding;
+ std::string h_language;
+ std::string h_language_package;
+ std::string h_listings_params;
+ std::string h_margins;
+ std::string h_notefontcolor;
+ std::string h_options;
+ std::string h_output_changes;
+ std::string h_papercolumns;
+ std::string h_paperfontsize;
+ std::string h_paperorientation;
+ std::string h_paperpagestyle;
+ std::string h_papersides;
+ std::string h_papersize;
+ std::string h_paragraph_indentation;
+ /// necessary to set the separation when \setlength is parsed
+ std::string h_paragraph_separation;
+ std::string h_pdf_title;
+ std::string h_pdf_author;
+ std::string h_pdf_subject;
+ std::string h_pdf_keywords;
+ std::string h_pdf_bookmarks;
+ std::string h_pdf_bookmarksnumbered;
+ std::string h_pdf_bookmarksopen;
+ std::string h_pdf_bookmarksopenlevel;
+ std::string h_pdf_breaklinks;
+ std::string h_pdf_pdfborder;
+ std::string h_pdf_colorlinks;
+ std::string h_pdf_backref;
+ std::string h_pdf_pdfusetitle;
+ std::string h_pdf_pagemode;
+ std::string h_pdf_quoted_options;
+ std::string h_quotes_language;
+ std::string h_secnumdepth;
+ std::string h_spacing;
+ std::string h_suppress_date;
+ std::string h_textclass;
+ std::string h_tocdepth;
+ std::string h_tracking_changes;
+ std::string h_use_bibtopic;
+ std::string h_use_indices;
+ std::string h_use_geometry;
+ std::string h_use_amsmath;
+ std::string h_use_default_options;
+ std::string h_use_esint;
+ std::string h_use_hyperref;
+ std::string h_use_mhchem;
+ std::string h_use_mathdots;
+ std::string h_use_refstyle;
+
+ /*!
+ * Add package \p name with options \p options to used_packages.
+ * Remove options from \p options that we don't want to output.
+ */
+ void add_package(std::string const & name,
+ std::vector<std::string> & options);
+ ///
+ void handle_hyperref(std::vector<std::string> & options);
+ ///
+ void handle_geometry(std::vector<std::string> & options);
+ ///
+ void handle_package(Parser &p, std::string const & name,
+ std::string const & opts, bool in_lyx_preamble);
+ ///
+ void handle_if(Parser & p, bool in_lyx_preamble);
+
+ AuthorList authors_;
+};
+
+
+extern Preamble preamble;
+
+// }])
+
+
+} // namespace lyx
+
+#endif
Format LaTeX feature LyX feature
-222 change tracking change tracking
224 external insets defined in InsetExternal
- lib/external_templates. This is
- quite difficult to recognize.
+ lib/external_templates.
+ (Date and RasterImage cannot be supported
+ (Chess diagram and Spreadsheet are supported)
+ (Xfig figure, Lilypond, Dia diagram can be supported by looking at the file extension)
+ (for PDFpages work is in progress by uwestoehr)
226 nothing (impossible to import) InsetBranch, \branch...\end_branch
226 transformations InsetExternal
228 draft InsetExternal
232 bibtopic InsetBibTeX
-248 booktabs.sty InsetTabular
254 esint.sty \use_esint
266 armenian \language, \lang
267 XeTeX utf8 encoding
363 horizontal longtable alignment InsetTabular
364 branch file name suffix \filename_suffix
366 relative lengths for parskip \defskip
-367 relative lengths for h and v space InsetHSpace, InsetVSpace
-368 glue lengths InsetHSpace
-369 author id \author
-370 \date{} \suppress_date
- (partly supported, see bug #7844)
+367 relative lengths for h and v space InsetSpace, InsetVSpace
+368 glue lengths InsetSpace
371 automatic mhchem loading \use_mhchem
375 \includeonly \{begin,end}_includeonly
376 update .aux of unincluded children \maintain_unincluded_children
401 feyn.sty InsetMathDiagram
402 \addcontentsline InsetBibtex bibtotoc option
404 refstyle.sty InsetRef
-405 author hash \author
407 vertical offset for multirows InsetTabular
409 XeTeX \use_non_tex_fonts
411 support for polyglossia \language_package (the cases of no package, of babel and of custom package is supported)
-412 tabular* InsetTabular
}
+bool is_display_math_env(string const & name)
+{
+ CommandMap::const_iterator it = known_math_environments.find(name);
+ if (it != known_math_environments.end())
+ if (!it->second.empty())
+ return it->second.back() == displaymath;
+ return false;
+}
+
+
void parse_math(Parser & p, ostream & os, unsigned flags, const mode_type mode)
{
while (p.good()) {
+++ /dev/null
-/**
- * \file preamble.cpp
- * This file is part of LyX, the document processor.
- * Licence details can be found in the file COPYING.
- *
- * \author André Pönitz
- * \author Uwe Stöhr
- *
- * Full author contact details are available in file CREDITS.
- */
-
-// {[(
-
-#include <config.h>
-
-#include "tex2lyx.h"
-
-#include "LayoutFile.h"
-#include "Layout.h"
-#include "Lexer.h"
-#include "TextClass.h"
-
-#include "support/convert.h"
-#include "support/FileName.h"
-#include "support/filetools.h"
-#include "support/lstrings.h"
-
-#include "support/regex.h"
-
-#include <algorithm>
-#include <iostream>
-#include <sstream>
-#include <string>
-#include <vector>
-#include <map>
-
-using namespace std;
-using namespace lyx::support;
-
-
-namespace lyx {
-
-// special columntypes
-extern map<char, int> special_columns;
-
-map<string, vector<string> > used_packages;
-const char * const modules_placeholder = "\001modules\001";
-
-// needed to handle encodings with babel
-bool one_language = true;
-string h_inputencoding = "auto";
-string h_paragraph_separation = "indent";
-
-namespace {
-
-//add this to known_languages when updating to lyxformat 266:
-// "armenian" (needs special handling since not supported by standard babel)
-//add these to known_languages when updating to lyxformat 268:
-//"chinese-simplified", "chinese-traditional", "japanese", "korean"
-// Both changes require first that support for non-babel languages (CJK,
-// armtex) is added.
-/**
- * known babel language names (including synonyms)
- * not in standard babel: arabic, arabtex, armenian, belarusian, serbian-latin, thai
- * not yet supported by LyX: kurmanji
- * please keep this in sync with known_coded_languages line by line!
- */
-const char * const known_languages[] = {"acadian", "afrikaans", "albanian",
-"american", "arabic", "arabtex", "austrian", "bahasa", "bahasai", "bahasam",
-"basque", "belarusian", "brazil", "brazilian", "breton", "british", "bulgarian",
-"canadian", "canadien", "catalan", "croatian", "czech", "danish", "dutch",
-"english", "esperanto", "estonian", "farsi", "finnish", "francais", "french",
-"frenchb", "frenchle", "frenchpro", "galician", "german", "germanb", "greek",
-"hebrew", "hungarian", "icelandic", "indon", "indonesian", "interlingua",
-"irish", "italian", "kazakh", "latin", "latvian", "lithuanian", "lowersorbian",
-"lsorbian", "magyar", "malay", "meyalu", "mongolian", "naustrian", "newzealand",
-"ngerman", "ngermanb", "norsk", "nynorsk", "polutonikogreek", "polish",
-"portuges", "portuguese", "romanian", "russian", "russianb", "samin",
-"scottish", "serbian", "serbian-latin", "slovak", "slovene", "spanish",
-"swedish", "thai", "turkish", "turkmen", "ukraineb", "ukrainian",
-"uppersorbian", "UKenglish", "USenglish", "usorbian", "vietnam", "welsh",
-0};
-
-/**
- * the same as known_languages with .lyx names
- * please keep this in sync with known_languages line by line!
- */
-const char * const known_coded_languages[] = {"french", "afrikaans", "albanian",
-"american", "arabic_arabi", "arabic_arabtex", "austrian", "bahasa", "bahasa", "bahasam",
-"basque", "belarusian", "brazilian", "brazilian", "breton", "british", "bulgarian",
-"canadian", "canadien", "catalan", "croatian", "czech", "danish", "dutch",
-"english", "esperanto", "estonian", "farsi", "finnish", "french", "french",
-"french", "french", "french", "galician", "german", "german", "greek",
-"hebrew", "magyar", "icelandic", "bahasa", "bahasa", "interlingua",
-"irish", "italian", "kazakh", "latin", "latvian", "lithuanian", "lowersorbian",
-"lowersorbian", "magyar", "bahasam", "bahasam", "mongolian", "naustrian", "english",
-"ngerman", "ngerman", "norsk", "nynorsk", "polutonikogreek", "polish",
-"portuguese", "portuguese", "romanian", "russian", "russian", "samin",
-"scottish", "serbian", "serbian-latin", "slovak", "slovene", "spanish",
-"swedish", "thai", "turkish", "turkmen", "ukrainian", "ukrainian",
-"uppersorbian", "uppersorbian", "english", "english", "vietnamese", "welsh",
-0};
-
-/// languages with english quotes (.lyx names)
-const char * const known_english_quotes_languages[] = {"american", "bahasa",
-"bahasam", "brazilian", "canadian", "chinese-simplified", "english",
-"esperanto", "hebrew", "irish", "korean", "portuguese", "scottish", "thai", 0};
-
-/// languages with french quotes (.lyx names)
-const char * const known_french_quotes_languages[] = {"albanian",
-"arabic_arabi", "arabic_arabtex", "basque", "canadien", "catalan", "french",
-"galician", "greek", "italian", "norsk", "nynorsk", "polutonikogreek",
-"russian", "spanish", "spanish-mexico", "turkish", "turkmen", "ukrainian",
-"vietnamese", 0};
-
-/// languages with german quotes (.lyx names)
-const char * const known_german_quotes_languages[] = {"austrian", "bulgarian",
-"czech", "german", "icelandic", "lithuanian", "lowersorbian", "naustrian",
-"ngerman", "serbian", "serbian-latin", "slovak", "slovene", "uppersorbian", 0};
-
-/// languages with polish quotes (.lyx names)
-const char * const known_polish_quotes_languages[] = {"afrikaans", "croatian",
-"dutch", "estonian", "magyar", "polish", "romanian", 0};
-
-/// languages with swedish quotes (.lyx names)
-const char * const known_swedish_quotes_languages[] = {"finnish",
-"swedish", 0};
-
-/// known language packages from the times before babel
-const char * const known_old_language_packages[] = {"french", "frenchle",
-"frenchpro", "german", "ngerman", "pmfrench", 0};
-
-char const * const known_fontsizes[] = { "10pt", "11pt", "12pt", 0 };
-
-const char * const known_roman_fonts[] = { "ae", "beraserif", "bookman",
-"ccfonts", "chancery", "charter", "cmr", "fourier", "lmodern", "mathpazo",
-"mathptmx", "newcent", "utopia", 0};
-
-const char * const known_sans_fonts[] = { "avant", "berasans", "cmbr", "cmss",
-"helvet", "lmss", 0};
-
-const char * const known_typewriter_fonts[] = { "beramono", "cmtl", "cmtt",
-"courier", "lmtt", "luximono", "fourier", "lmodern", "mathpazo", "mathptmx",
-"newcent", 0};
-
-const char * const known_paper_sizes[] = { "a0paper", "b0paper", "c0paper",
-"a1paper", "b1paper", "c1paper", "a2paper", "b2paper", "c2paper", "a3paper",
-"b3paper", "c3paper", "a4paper", "b4paper", "c4paper", "a5paper", "b5paper",
-"c5paper", "a6paper", "b6paper", "c6paper", "executivepaper", "legalpaper",
-"letterpaper", "b0j", "b1j", "b2j", "b3j", "b4j", "b5j", "b6j", 0};
-
-const char * const known_class_paper_sizes[] = { "a4paper", "a5paper",
-"executivepaper", "legalpaper", "letterpaper", 0};
-
-const char * const known_paper_margins[] = { "lmargin", "tmargin", "rmargin",
-"bmargin", "headheight", "headsep", "footskip", "columnsep", 0};
-
-const char * const known_coded_paper_margins[] = { "leftmargin", "topmargin",
-"rightmargin", "bottommargin", "headheight", "headsep", "footskip",
-"columnsep", 0};
-
-/// commands that can start an \if...\else...\endif sequence
-const char * const known_if_commands[] = {"if", "ifarydshln", "ifbraket",
-"ifcancel", "ifcolortbl", "ifeurosym", "ifmarginnote", "ifmmode", "ifpdf",
-"ifsidecap", "ifupgreek", 0};
-
-const char * const known_basic_colors[] = {"blue", "black", "cyan", "green",
-"magenta", "red", "white", "yellow", 0};
-
-const char * const known_basic_color_codes[] = {"#0000ff", "#000000", "#00ffff", "#00ff00",
-"#ff00ff", "#ff0000", "#ffffff", "#ffff00", 0};
-
-/// conditional commands with three arguments like \@ifundefined{}{}{}
-const char * const known_if_3arg_commands[] = {"@ifundefined", "IfFileExists",
-0};
-
-// default settings
-ostringstream h_preamble;
-string h_textclass = "article";
-string h_use_default_options = "false";
-string h_options;
-string h_language = "english";
-string h_language_package = "none";
-string h_fontencoding = "default";
-string h_font_roman = "default";
-string h_font_sans = "default";
-string h_font_typewriter = "default";
-string h_font_default_family = "default";
-string h_font_sc = "false";
-string h_font_osf = "false";
-string h_font_sf_scale = "100";
-string h_font_tt_scale = "100";
-string h_graphics = "default";
-string h_float_placement;
-string h_paperfontsize = "default";
-string h_spacing = "single";
-string h_use_hyperref = "0";
-string h_pdf_title;
-string h_pdf_author;
-string h_pdf_subject;
-string h_pdf_keywords;
-string h_pdf_bookmarks = "1";
-string h_pdf_bookmarksnumbered = "0";
-string h_pdf_bookmarksopen = "0";
-string h_pdf_bookmarksopenlevel = "1";
-string h_pdf_breaklinks = "0";
-string h_pdf_pdfborder = "0";
-string h_pdf_colorlinks = "0";
-string h_pdf_backref = "section";
-string h_pdf_pdfusetitle = "1";
-string h_pdf_pagemode;
-string h_pdf_quoted_options;
-string h_papersize = "default";
-string h_use_geometry = "false";
-string h_use_amsmath = "1";
-string h_use_esint = "1";
-string h_use_mhchem = "0";
-string h_use_mathdots = "0";
-string h_cite_engine = "basic";
-string h_use_bibtopic = "false";
-string h_paperorientation = "portrait";
-string h_suppress_date = "false";
-string h_use_refstyle = "0";
-string h_backgroundcolor;
-string h_boxbgcolor;
-string h_fontcolor;
-string h_notefontcolor;
-string h_secnumdepth = "3";
-string h_tocdepth = "3";
-string h_defskip = "medskip";
-string h_paragraph_indentation = "default";
-string h_quotes_language = "english";
-string h_papercolumns = "1";
-string h_papersides;
-string h_paperpagestyle = "default";
-string h_listings_params;
-string h_tracking_changes = "false";
-string h_output_changes = "false";
-string h_html_math_output = "0";
-string h_html_css_as_file = "0";
-string h_html_be_strict = "false";
-string h_margins;
-
-
-// returns true if at least one of the options in what has been found
-bool handle_opt(vector<string> & opts, char const * const * what, string & target)
-{
- if (opts.empty())
- return false;
-
- bool found = false;
- // the last language option is the document language (for babel and LyX)
- // the last size option is the document font size
- vector<string>::iterator it;
- vector<string>::iterator position = opts.begin();
- for (; *what; ++what) {
- it = find(opts.begin(), opts.end(), *what);
- if (it != opts.end()) {
- if (it >= position) {
- found = true;
- target = *what;
- position = it;
- }
- }
- }
- return found;
-}
-
-
-void delete_opt(vector<string> & opts, char const * const * what)
-{
- if (opts.empty())
- return;
-
- // remove found options from the list
- // do this after handle_opt to avoid potential memory leaks
- vector<string>::iterator it;
- for (; *what; ++what) {
- it = find(opts.begin(), opts.end(), *what);
- if (it != opts.end())
- opts.erase(it);
- }
-}
-
-
-/*!
- * Split a package options string (keyval format) into a vector.
- * Example input:
- * authorformat=smallcaps,
- * commabeforerest,
- * titleformat=colonsep,
- * bibformat={tabular,ibidem,numbered}
- */
-vector<string> split_options(string const & input)
-{
- vector<string> options;
- string option;
- Parser p(input);
- while (p.good()) {
- Token const & t = p.get_token();
- if (t.asInput() == ",") {
- options.push_back(trim(option));
- option.erase();
- } else if (t.asInput() == "=") {
- option += '=';
- p.skip_spaces(true);
- if (p.next_token().asInput() == "{")
- option += '{' + p.getArg('{', '}') + '}';
- } else if (t.cat() != catSpace)
- option += t.asInput();
- }
-
- if (!option.empty())
- options.push_back(trim(option));
-
- return options;
-}
-
-
-/*!
- * Retrieve a keyval option "name={value with=sign}" named \p name from
- * \p options and return the value.
- * The found option is also removed from \p options.
- */
-string process_keyval_opt(vector<string> & options, string name)
-{
- for (size_t i = 0; i < options.size(); ++i) {
- vector<string> option;
- split(options[i], option, '=');
- if (option.size() < 2)
- continue;
- if (option[0] == name) {
- options.erase(options.begin() + i);
- option.erase(option.begin());
- return join(option, "=");
- }
- }
- return "";
-}
-
-
-/*!
- * Add package \p name with options \p options to used_packages.
- * Remove options from \p options that we don't want to output.
- */
-void add_package(string const & name, vector<string> & options)
-{
- // every package inherits the global options
- if (used_packages.find(name) == used_packages.end())
- used_packages[name] = split_options(h_options);
-
- vector<string> & v = used_packages[name];
- v.insert(v.end(), options.begin(), options.end());
- if (name == "jurabib") {
- // Don't output the order argument (see the cite command
- // handling code in text.cpp).
- vector<string>::iterator end =
- remove(options.begin(), options.end(), "natbiborder");
- end = remove(options.begin(), end, "jurabiborder");
- options.erase(end, options.end());
- }
-}
-
-
-// Given is a string like "scaled=0.9", return 0.9 * 100
-string const scale_as_percentage(string const & scale)
-{
- string::size_type pos = scale.find('=');
- if (pos != string::npos) {
- string value = scale.substr(pos + 1);
- if (isStrDbl(value))
- return convert<string>(100 * convert<double>(value));
- }
- // If the input string didn't match our expectations.
- // return the default value "100"
- return "100";
-}
-
-
-string remove_braces(string const & value)
-{
- if (value.empty())
- return value;
- if (value[0] == '{' && value[value.length()-1] == '}')
- return value.substr(1, value.length()-2);
- return value;
-}
-
-
-void handle_hyperref(vector<string> & options)
-{
- // FIXME swallow inputencoding changes that might surround the
- // hyperref setup if it was written by LyX
- h_use_hyperref = "1";
- // swallow "unicode=true", since LyX does always write that
- vector<string>::iterator it =
- find(options.begin(), options.end(), "unicode=true");
- if (it != options.end())
- options.erase(it);
- it = find(options.begin(), options.end(), "pdfusetitle");
- if (it != options.end()) {
- h_pdf_pdfusetitle = "1";
- options.erase(it);
- }
- string bookmarks = process_keyval_opt(options, "bookmarks");
- if (bookmarks == "true")
- h_pdf_bookmarks = "1";
- else if (bookmarks == "false")
- h_pdf_bookmarks = "0";
- if (h_pdf_bookmarks == "1") {
- string bookmarksnumbered =
- process_keyval_opt(options, "bookmarksnumbered");
- if (bookmarksnumbered == "true")
- h_pdf_bookmarksnumbered = "1";
- else if (bookmarksnumbered == "false")
- h_pdf_bookmarksnumbered = "0";
- string bookmarksopen =
- process_keyval_opt(options, "bookmarksopen");
- if (bookmarksopen == "true")
- h_pdf_bookmarksopen = "1";
- else if (bookmarksopen == "false")
- h_pdf_bookmarksopen = "0";
- if (h_pdf_bookmarksopen == "1") {
- string bookmarksopenlevel =
- process_keyval_opt(options, "bookmarksopenlevel");
- if (!bookmarksopenlevel.empty())
- h_pdf_bookmarksopenlevel = bookmarksopenlevel;
- }
- }
- string breaklinks = process_keyval_opt(options, "breaklinks");
- if (breaklinks == "true")
- h_pdf_breaklinks = "1";
- else if (breaklinks == "false")
- h_pdf_breaklinks = "0";
- string pdfborder = process_keyval_opt(options, "pdfborder");
- if (pdfborder == "{0 0 0}")
- h_pdf_pdfborder = "1";
- else if (pdfborder == "{0 0 1}")
- h_pdf_pdfborder = "0";
- string backref = process_keyval_opt(options, "backref");
- if (!backref.empty())
- h_pdf_backref = backref;
- string colorlinks = process_keyval_opt(options, "colorlinks");
- if (colorlinks == "true")
- h_pdf_colorlinks = "1";
- else if (colorlinks == "false")
- h_pdf_colorlinks = "0";
- string pdfpagemode = process_keyval_opt(options, "pdfpagemode");
- if (!pdfpagemode.empty())
- h_pdf_pagemode = pdfpagemode;
- string pdftitle = process_keyval_opt(options, "pdftitle");
- if (!pdftitle.empty()) {
- h_pdf_title = remove_braces(pdftitle);
- }
- string pdfauthor = process_keyval_opt(options, "pdfauthor");
- if (!pdfauthor.empty()) {
- h_pdf_author = remove_braces(pdfauthor);
- }
- string pdfsubject = process_keyval_opt(options, "pdfsubject");
- if (!pdfsubject.empty())
- h_pdf_subject = remove_braces(pdfsubject);
- string pdfkeywords = process_keyval_opt(options, "pdfkeywords");
- if (!pdfkeywords.empty())
- h_pdf_keywords = remove_braces(pdfkeywords);
- if (!options.empty()) {
- if (!h_pdf_quoted_options.empty())
- h_pdf_quoted_options += ',';
- h_pdf_quoted_options += join(options, ",");
- options.clear();
- }
-}
-
-
-void handle_package(Parser &p, string const & name, string const & opts,
- bool in_lyx_preamble)
-{
- vector<string> options = split_options(opts);
- add_package(name, options);
- string scale;
-
- // roman fonts
- if (is_known(name, known_roman_fonts)) {
- h_font_roman = name;
- p.skip_spaces();
- }
-
- if (name == "fourier") {
- h_font_roman = "utopia";
- // when font uses real small capitals
- if (opts == "expert")
- h_font_sc = "true";
- }
-
- if (name == "mathpazo")
- h_font_roman = "palatino";
-
- if (name == "mathptmx")
- h_font_roman = "times";
-
- // sansserif fonts
- if (is_known(name, known_sans_fonts)) {
- h_font_sans = name;
- if (!opts.empty()) {
- scale = opts;
- h_font_sf_scale = scale_as_percentage(scale);
- }
- }
-
- // typewriter fonts
- if (is_known(name, known_typewriter_fonts)) {
- // fourier can be set as roman font _only_
- // fourier as typewriter is handled in handling of \ttdefault
- if (name != "fourier") {
- h_font_typewriter = name;
- if (!opts.empty()) {
- scale = opts;
- h_font_tt_scale = scale_as_percentage(scale);
- }
- }
- }
-
- // font uses old-style figure
- if (name == "eco")
- h_font_osf = "true";
-
- // after the detection and handling of special cases, we can remove the
- // fonts, otherwise they would appear in the preamble, see bug #7856
- if (is_known(name, known_roman_fonts) || is_known(name, known_sans_fonts)
- || is_known(name, known_typewriter_fonts))
- ;
-
- else if (name == "amsmath" || name == "amssymb")
- h_use_amsmath = "2";
-
- else if (name == "esint")
- h_use_esint = "2";
-
- else if (name == "mhchem")
- h_use_mhchem = "2";
-
- else if (name == "mathdots")
- h_use_mathdots = "2";
-
- else if (name == "babel") {
- h_language_package = "default";
- // One might think we would have to do nothing if babel is loaded
- // without any options to prevent pollution of the preamble with this
- // babel call in every roundtrip.
- // But the user could have defined babel-specific things afterwards. So
- // we need to keep it in the preamble to prevent cases like bug #7861.
- if (!opts.empty()) {
- // check if more than one option was used - used later for inputenc
- if (options.begin() != options.end() - 1)
- one_language = false;
- // babel takes the last language of the option of its \usepackage
- // call as document language. If there is no such language option, the
- // last language in the documentclass options is used.
- handle_opt(options, known_languages, h_language);
- // If babel is called with options, LyX puts them by default into the
- // document class options. This works for most languages, except
- // for Latvian, Lithuanian, Mongolian, Turkmen and Vietnamese and
- // perhaps in future others.
- // Therefore keep the babel call as it is as the user might have
- // reasons for it.
- h_preamble << "\\usepackage[" << opts << "]{babel}\n";
- delete_opt(options, known_languages);
- }
- else
- h_preamble << "\\usepackage{babel}\n";
- }
-
- else if (name == "fontenc") {
- h_fontencoding = getStringFromVector(options, ",");
- /* We could do the following for better round trip support,
- * but this makes the document less portable, so I skip it:
- if (h_fontencoding == lyxrc.fontenc)
- h_fontencoding = "global";
- */
- options.clear();
- }
-
- else if (name == "inputenc" || name == "luainputenc") {
- // h_inputencoding is only set when there is not more than one
- // inputenc option because otherwise h_inputencoding must be
- // set to "auto" (the default encoding of the document language)
- // Therefore check for the "," character.
- // It is also only set when there is not more than one babel
- // language option.
- if (opts.find(",") == string::npos && one_language == true)
- h_inputencoding = opts;
- if (!options.empty())
- p.setEncoding(options.back());
- options.clear();
- }
-
- else if (is_known(name, known_old_language_packages)) {
- // known language packages from the times before babel
- // if they are found and not also babel, they will be used as
- // cutom language package
- h_language_package = "\\usepackage{" + name + "}";
- }
-
- else if (name == "makeidx")
- ; // ignore this
-
- else if (name == "prettyref")
- ; // ignore this
-
- else if (name == "varioref")
- ; // ignore this
-
- else if (name == "verbatim")
- ; // ignore this
-
- else if (name == "nomencl")
- ; // ignore this
-
- else if (name == "textcomp")
- ; // ignore this
-
- else if (name == "url")
- ; // ignore this
-
- else if (name == "subscript")
- ; // ignore this
-
- else if (name == "color") {
- // with the following command this package is only loaded when needed for
- // undefined colors, since we only support the predefined colors
- h_preamble << "\\@ifundefined{definecolor}\n {\\usepackage{color}}{}\n";
- }
-
- else if (name == "graphicx")
- ; // ignore this
-
- else if (name == "setspace")
- ; // ignore this
-
-#if 0
- // do not ignore as long as we don't support all commands (e.g. \xout is missing)
- else if (name == "ulem")
- ; // ignore this
-#endif
-
- else if (name == "geometry")
- ; // Ignore this, the geometry settings are made by the \geometry
- // command. This command is handled below.
-
- else if (name == "rotfloat")
- ; // ignore this
-
- else if (name == "wrapfig")
- ; // ignore this
-
- else if (name == "subfig")
- ; // ignore this
-
- else if (is_known(name, known_languages))
- h_language = name;
-
- else if (name == "natbib") {
- h_cite_engine = "natbib_authoryear";
- vector<string>::iterator it =
- find(options.begin(), options.end(), "authoryear");
- if (it != options.end())
- options.erase(it);
- else {
- it = find(options.begin(), options.end(), "numbers");
- if (it != options.end()) {
- h_cite_engine = "natbib_numerical";
- options.erase(it);
- }
- }
- }
-
- else if (name == "jurabib")
- h_cite_engine = "jurabib";
-
- else if (name == "hyperref")
- handle_hyperref(options);
-
- else if (!in_lyx_preamble) {
- if (options.empty())
- h_preamble << "\\usepackage{" << name << "}";
- else {
- h_preamble << "\\usepackage[" << opts << "]{"
- << name << "}";
- options.clear();
- }
- }
-
- // We need to do something with the options...
- if (!options.empty())
- cerr << "Ignoring options '" << join(options, ",")
- << "' of package " << name << '.' << endl;
-
- // remove the whitespace
- p.skip_spaces();
-}
-
-
-void handle_if(Parser & p, bool in_lyx_preamble)
-{
- while (p.good()) {
- Token t = p.get_token();
- if (t.cat() == catEscape &&
- is_known(t.cs(), known_if_commands))
- handle_if(p, in_lyx_preamble);
- else {
- if (!in_lyx_preamble)
- h_preamble << t.asInput();
- if (t.cat() == catEscape && t.cs() == "fi")
- return;
- }
- }
-}
-
-
-void end_preamble(ostream & os, TextClass const & /*textclass*/)
-{
- // translate from babel to LyX names
- h_language = babel2lyx(h_language);
-
- // set the quote language
- // LyX only knows the following quotes languages:
- // english, swedish, german, polish, french and danish
- // (quotes for "japanese" and "chinese-traditional" are missing because
- // they wouldn't be useful: http://www.lyx.org/trac/ticket/6383)
- // conversion list taken from
- // http://en.wikipedia.org/wiki/Quotation_mark,_non-English_usage
- // (quotes for kazakh and interlingua are unknown)
- // danish
- if (h_language == "danish")
- h_quotes_language = "danish";
- // french
- else if (is_known(h_language, known_french_quotes_languages))
- h_quotes_language = "french";
- // german
- else if (is_known(h_language, known_german_quotes_languages))
- h_quotes_language = "german";
- // polish
- else if (is_known(h_language, known_polish_quotes_languages))
- h_quotes_language = "polish";
- // swedish
- else if (is_known(h_language, known_swedish_quotes_languages))
- h_quotes_language = "swedish";
- //english
- else if (is_known(h_language, known_english_quotes_languages))
- h_quotes_language = "english";
-
- // output the LyX file settings
- os << "#LyX file created by tex2lyx " << PACKAGE_VERSION << "\n"
- << "\\lyxformat " << LYX_FORMAT << '\n'
- << "\\begin_document\n"
- << "\\begin_header\n"
- << "\\textclass " << h_textclass << "\n";
- if (!h_preamble.str().empty())
- os << "\\begin_preamble\n" << h_preamble.str() << "\n\\end_preamble\n";
- if (!h_options.empty())
- os << "\\options " << h_options << "\n";
- os << "\\use_default_options " << h_use_default_options << "\n"
- << modules_placeholder
- << "\\language " << h_language << "\n"
- << "\\language_package " << h_language_package << "\n"
- << "\\inputencoding " << h_inputencoding << "\n"
- << "\\fontencoding " << h_fontencoding << "\n"
- << "\\font_roman " << h_font_roman << "\n"
- << "\\font_sans " << h_font_sans << "\n"
- << "\\font_typewriter " << h_font_typewriter << "\n"
- << "\\font_default_family " << h_font_default_family << "\n"
- << "\\font_sc " << h_font_sc << "\n"
- << "\\font_osf " << h_font_osf << "\n"
- << "\\font_sf_scale " << h_font_sf_scale << "\n"
- << "\\font_tt_scale " << h_font_tt_scale << "\n"
- << "\\graphics " << h_graphics << "\n";
- if (!h_float_placement.empty())
- os << "\\float_placement " << h_float_placement << "\n";
- os << "\\paperfontsize " << h_paperfontsize << "\n"
- << "\\spacing " << h_spacing << "\n"
- << "\\use_hyperref " << h_use_hyperref << '\n';
- if (h_use_hyperref == "1") {
- if (!h_pdf_title.empty())
- os << "\\pdf_title \"" << h_pdf_title << "\"\n";
- if (!h_pdf_author.empty())
- os << "\\pdf_author \"" << h_pdf_author << "\"\n";
- if (!h_pdf_subject.empty())
- os << "\\pdf_subject \"" << h_pdf_subject << "\"\n";
- if (!h_pdf_keywords.empty())
- os << "\\pdf_keywords \"" << h_pdf_keywords << "\"\n";
- os << "\\pdf_bookmarks " << h_pdf_bookmarks << "\n"
- "\\pdf_bookmarksnumbered " << h_pdf_bookmarksnumbered << "\n"
- "\\pdf_bookmarksopen " << h_pdf_bookmarksopen << "\n"
- "\\pdf_bookmarksopenlevel " << h_pdf_bookmarksopenlevel << "\n"
- "\\pdf_breaklinks " << h_pdf_breaklinks << "\n"
- "\\pdf_pdfborder " << h_pdf_pdfborder << "\n"
- "\\pdf_colorlinks " << h_pdf_colorlinks << "\n"
- "\\pdf_backref " << h_pdf_backref << "\n"
- "\\pdf_pdfusetitle " << h_pdf_pdfusetitle << '\n';
- if (!h_pdf_pagemode.empty())
- os << "\\pdf_pagemode " << h_pdf_pagemode << '\n';
- if (!h_pdf_quoted_options.empty())
- os << "\\pdf_quoted_options \"" << h_pdf_quoted_options << "\"\n";
- }
- os << "\\papersize " << h_papersize << "\n"
- << "\\use_geometry " << h_use_geometry << "\n"
- << "\\use_amsmath " << h_use_amsmath << "\n"
- << "\\use_esint " << h_use_esint << "\n"
- << "\\use_mhchem " << h_use_mhchem << "\n"
- << "\\use_mathdots " << h_use_mathdots << "\n"
- << "\\cite_engine " << h_cite_engine << "\n"
- << "\\use_bibtopic " << h_use_bibtopic << "\n"
- << "\\paperorientation " << h_paperorientation << '\n'
- << "\\suppress_date " << h_suppress_date << '\n'
- << "\\use_refstyle " << h_use_refstyle << '\n';
- if (!h_fontcolor.empty())
- os << "\\fontcolor " << h_fontcolor << '\n';
- if (!h_notefontcolor.empty())
- os << "\\notefontcolor " << h_notefontcolor << '\n';
- if (!h_backgroundcolor.empty())
- os << "\\backgroundcolor " << h_backgroundcolor << '\n';
- if (!h_boxbgcolor.empty())
- os << "\\boxbgcolor " << h_boxbgcolor << '\n';
- os << h_margins
- << "\\secnumdepth " << h_secnumdepth << "\n"
- << "\\tocdepth " << h_tocdepth << "\n"
- << "\\paragraph_separation " << h_paragraph_separation << "\n";
- if (h_paragraph_separation == "skip")
- os << "\\defskip " << h_defskip << "\n";
- else
- os << "\\paragraph_indentation " << h_paragraph_indentation << "\n";
- os << "\\quotes_language " << h_quotes_language << "\n"
- << "\\papercolumns " << h_papercolumns << "\n"
- << "\\papersides " << h_papersides << "\n"
- << "\\paperpagestyle " << h_paperpagestyle << "\n";
- if (!h_listings_params.empty())
- os << "\\listings_params " << h_listings_params << "\n";
- os << "\\tracking_changes " << h_tracking_changes << "\n"
- << "\\output_changes " << h_output_changes << "\n"
- << "\\html_math_output " << h_html_math_output << "\n"
- << "\\html_css_as_file " << h_html_css_as_file << "\n"
- << "\\html_be_strict " << h_html_be_strict << "\n"
- << "\\end_header\n\n"
- << "\\begin_body\n";
- // clear preamble for subdocuments
- h_preamble.str("");
-}
-
-} // anonymous namespace
-
-
-void parse_preamble(Parser & p, ostream & os,
- string const & forceclass, TeX2LyXDocClass & tc)
-{
- // initialize fixed types
- special_columns['D'] = 3;
- bool is_full_document = false;
- bool is_lyx_file = false;
- bool in_lyx_preamble = false;
-
- // determine whether this is a full document or a fragment for inclusion
- while (p.good()) {
- Token const & t = p.get_token();
-
- if (t.cat() == catEscape && t.cs() == "documentclass") {
- is_full_document = true;
- break;
- }
- }
- p.reset();
-
- while (is_full_document && p.good()) {
- Token const & t = p.get_token();
-
-#ifdef FILEDEBUG
- cerr << "t: " << t << "\n";
-#endif
-
- //
- // cat codes
- //
- if (!in_lyx_preamble &&
- (t.cat() == catLetter ||
- t.cat() == catSuper ||
- t.cat() == catSub ||
- t.cat() == catOther ||
- t.cat() == catMath ||
- t.cat() == catActive ||
- t.cat() == catBegin ||
- t.cat() == catEnd ||
- t.cat() == catAlign ||
- t.cat() == catParameter))
- h_preamble << t.cs();
-
- else if (!in_lyx_preamble &&
- (t.cat() == catSpace || t.cat() == catNewline))
- h_preamble << t.asInput();
-
- else if (t.cat() == catComment) {
- static regex const islyxfile("%% LyX .* created this file");
- static regex const usercommands("User specified LaTeX commands");
-
- string const comment = t.asInput();
-
- // magically switch encoding default if it looks like XeLaTeX
- static string const magicXeLaTeX =
- "% This document must be compiled with XeLaTeX ";
- if (comment.size() > magicXeLaTeX.size()
- && comment.substr(0, magicXeLaTeX.size()) == magicXeLaTeX
- && h_inputencoding == "auto") {
- cerr << "XeLaTeX comment found, switching to UTF8\n";
- h_inputencoding = "utf8";
- }
- smatch sub;
- if (regex_search(comment, sub, islyxfile)) {
- is_lyx_file = true;
- in_lyx_preamble = true;
- } else if (is_lyx_file
- && regex_search(comment, sub, usercommands))
- in_lyx_preamble = false;
- else if (!in_lyx_preamble)
- h_preamble << t.asInput();
- }
-
- else if (t.cs() == "pagestyle")
- h_paperpagestyle = p.verbatim_item();
-
- else if (t.cs() == "date") {
- string argument = p.getArg('{', '}');
- if (argument.empty())
- h_suppress_date = "true";
- else
- h_preamble << t.asInput() << '{' << argument << '}';
- }
-
- else if (t.cs() == "color") {
- string argument = p.getArg('{', '}');
- // check the case that a standard color is used
- if (is_known(argument, known_basic_colors))
- h_fontcolor = color2code(argument);
- // check the case that LyX's document_fontcolor is defined
- // but not used for \color
- if (argument != "document_fontcolor"
- && !is_known(argument, known_basic_colors)) {
- h_preamble << t.asInput() << '{' << argument << '}';
- // the color might already be set because \definecolor
- // is parsed before this
- h_fontcolor = "";
- }
- }
-
- else if (t.cs() == "pagecolor") {
- string argument = p.getArg('{', '}');
- // check the case that a standard color is used
- if (is_known(argument, known_basic_colors))
- h_backgroundcolor = color2code(argument);
- // check the case that LyX's page_backgroundcolor is defined
- // but not used for \pagecolor
- if (argument != "page_backgroundcolor"
- && !is_known(argument, known_basic_colors)) {
- h_preamble << t.asInput() << '{' << argument << '}';
- // the color might already be set because \definecolor
- // is parsed before this
- h_backgroundcolor = "";
- }
- }
-
- else if (t.cs() == "makeatletter") {
- // LyX takes care of this
- p.setCatCode('@', catLetter);
- }
-
- else if (t.cs() == "makeatother") {
- // LyX takes care of this
- p.setCatCode('@', catOther);
- }
-
- else if (t.cs() == "newcommand" || t.cs() == "newcommandx"
- || t.cs() == "renewcommand" || t.cs() == "renewcommandx"
- || t.cs() == "providecommand" || t.cs() == "providecommandx"
- || t.cs() == "DeclareRobustCommand"
- || t.cs() == "DeclareRobustCommandx"
- || t.cs() == "ProvideTextCommandDefault"
- || t.cs() == "DeclareMathAccent") {
- bool star = false;
- if (p.next_token().character() == '*') {
- p.get_token();
- star = true;
- }
- string const name = p.verbatim_item();
- string const opt1 = p.getFullOpt();
- string const opt2 = p.getFullOpt();
- string const body = p.verbatim_item();
- // font settings
- if (name == "\\rmdefault")
- if (is_known(body, known_roman_fonts))
- h_font_roman = body;
- if (name == "\\sfdefault")
- if (is_known(body, known_sans_fonts))
- h_font_sans = body;
- if (name == "\\ttdefault")
- if (is_known(body, known_typewriter_fonts))
- h_font_typewriter = body;
- if (name == "\\familydefault") {
- string family = body;
- // remove leading "\"
- h_font_default_family = family.erase(0,1);
- }
-
- // Add the command to the known commands
- add_known_command(name, opt1, !opt2.empty(), from_utf8(body));
-
- // only non-lyxspecific stuff
- if (!in_lyx_preamble) {
- ostringstream ss;
- ss << '\\' << t.cs();
- if (star)
- ss << '*';
- ss << '{' << name << '}' << opt1 << opt2
- << '{' << body << "}";
- h_preamble << ss.str();
-/*
- ostream & out = in_preamble ? h_preamble : os;
- out << "\\" << t.cs() << "{" << name << "}"
- << opts << "{" << body << "}";
-*/
- }
- }
-
- else if (t.cs() == "documentclass") {
- vector<string>::iterator it;
- vector<string> opts = split_options(p.getArg('[', ']'));
- handle_opt(opts, known_fontsizes, h_paperfontsize);
- delete_opt(opts, known_fontsizes);
- // delete "pt" at the end
- string::size_type i = h_paperfontsize.find("pt");
- if (i != string::npos)
- h_paperfontsize.erase(i);
- // The documentclass options are always parsed before the options
- // of the babel call so that a language cannot overwrite the babel
- // options.
- handle_opt(opts, known_languages, h_language);
- delete_opt(opts, known_languages);
-
- // paper orientation
- if ((it = find(opts.begin(), opts.end(), "landscape")) != opts.end()) {
- h_paperorientation = "landscape";
- opts.erase(it);
- }
- // paper sides
- if ((it = find(opts.begin(), opts.end(), "oneside"))
- != opts.end()) {
- h_papersides = "1";
- opts.erase(it);
- }
- if ((it = find(opts.begin(), opts.end(), "twoside"))
- != opts.end()) {
- h_papersides = "2";
- opts.erase(it);
- }
- // paper columns
- if ((it = find(opts.begin(), opts.end(), "onecolumn"))
- != opts.end()) {
- h_papercolumns = "1";
- opts.erase(it);
- }
- if ((it = find(opts.begin(), opts.end(), "twocolumn"))
- != opts.end()) {
- h_papercolumns = "2";
- opts.erase(it);
- }
- // paper sizes
- // some size options are know to any document classes, other sizes
- // are handled by the \geometry command of the geometry package
- handle_opt(opts, known_class_paper_sizes, h_papersize);
- delete_opt(opts, known_class_paper_sizes);
- // the remaining options
- h_options = join(opts, ",");
- // FIXME This does not work for classes that have a
- // different name in LyX than in LaTeX
- h_textclass = p.getArg('{', '}');
- }
-
- else if (t.cs() == "usepackage") {
- string const options = p.getArg('[', ']');
- string const name = p.getArg('{', '}');
- vector<string> vecnames;
- split(name, vecnames, ',');
- vector<string>::const_iterator it = vecnames.begin();
- vector<string>::const_iterator end = vecnames.end();
- for (; it != end; ++it)
- handle_package(p, trim(*it), options,
- in_lyx_preamble);
- }
-
- else if (t.cs() == "inputencoding") {
- string const encoding = p.getArg('{','}');
- h_inputencoding = encoding;
- p.setEncoding(encoding);
- }
-
- else if (t.cs() == "newenvironment") {
- string const name = p.getArg('{', '}');
- string const opt1 = p.getFullOpt();
- string const opt2 = p.getFullOpt();
- string const beg = p.verbatim_item();
- string const end = p.verbatim_item();
- if (!in_lyx_preamble) {
- h_preamble << "\\newenvironment{" << name
- << '}' << opt1 << opt2 << '{'
- << beg << "}{" << end << '}';
- }
- add_known_environment(name, opt1, !opt2.empty(),
- from_utf8(beg), from_utf8(end));
-
- }
-
- else if (t.cs() == "def") {
- string name = p.get_token().cs();
- while (p.next_token().cat() != catBegin)
- name += p.get_token().cs();
- if (!in_lyx_preamble)
- h_preamble << "\\def\\" << name << '{'
- << p.verbatim_item() << "}";
- }
-
- else if (t.cs() == "newcolumntype") {
- string const name = p.getArg('{', '}');
- trim(name);
- int nargs = 0;
- string opts = p.getOpt();
- if (!opts.empty()) {
- istringstream is(string(opts, 1));
- is >> nargs;
- }
- special_columns[name[0]] = nargs;
- h_preamble << "\\newcolumntype{" << name << "}";
- if (nargs)
- h_preamble << "[" << nargs << "]";
- h_preamble << "{" << p.verbatim_item() << "}";
- }
-
- else if (t.cs() == "setcounter") {
- string const name = p.getArg('{', '}');
- string const content = p.getArg('{', '}');
- if (name == "secnumdepth")
- h_secnumdepth = content;
- else if (name == "tocdepth")
- h_tocdepth = content;
- else
- h_preamble << "\\setcounter{" << name << "}{" << content << "}";
- }
-
- else if (t.cs() == "setlength") {
- string const name = p.verbatim_item();
- string const content = p.verbatim_item();
- // the paragraphs are only not indented when \parindent is set to zero
- if (name == "\\parindent" && content != "") {
- if (content[0] == '0')
- h_paragraph_separation = "skip";
- else
- h_paragraph_indentation = translate_len(content);
- } else if (name == "\\parskip") {
- if (content == "\\smallskipamount")
- h_defskip = "smallskip";
- else if (content == "\\medskipamount")
- h_defskip = "medskip";
- else if (content == "\\bigskipamount")
- h_defskip = "bigskip";
- else
- h_defskip = content;
- } else
- h_preamble << "\\setlength{" << name << "}{" << content << "}";
- }
-
- else if (t.cs() == "onehalfspacing")
- h_spacing = "onehalf";
-
- else if (t.cs() == "doublespacing")
- h_spacing = "double";
-
- else if (t.cs() == "setstretch")
- h_spacing = "other " + p.verbatim_item();
-
- else if (t.cs() == "begin") {
- string const name = p.getArg('{', '}');
- if (name == "document")
- break;
- h_preamble << "\\begin{" << name << "}";
- }
-
- else if (t.cs() == "geometry") {
- h_use_geometry = "true";
- vector<string> opts = split_options(p.getArg('{', '}'));
- vector<string>::iterator it;
- // paper orientation
- if ((it = find(opts.begin(), opts.end(), "landscape")) != opts.end()) {
- h_paperorientation = "landscape";
- opts.erase(it);
- }
- // paper size
- handle_opt(opts, known_paper_sizes, h_papersize);
- delete_opt(opts, known_paper_sizes);
- // page margins
- char const * const * margin = known_paper_margins;
- int k = -1;
- for (; *margin; ++margin) {
- k += 1;
- // search for the "=" in e.g. "lmargin=2cm" to get the value
- for(size_t i = 0; i != opts.size(); i++) {
- if (opts.at(i).find(*margin) != string::npos) {
- string::size_type pos = opts.at(i).find("=");
- string value = opts.at(i).substr(pos + 1);
- string name = known_coded_paper_margins[k];
- h_margins += "\\" + name + " " + value + "\n";
- }
- }
- }
- }
-
- else if (t.cs() == "definecolor") {
- string const color = p.getArg('{', '}');
- string const space = p.getArg('{', '}');
- string const value = p.getArg('{', '}');
- if (color == "document_fontcolor" && space == "rgb") {
- RGBColor c(RGBColorFromLaTeX(value));
- h_fontcolor = X11hexname(c);
- } else if (color == "note_fontcolor" && space == "rgb") {
- RGBColor c(RGBColorFromLaTeX(value));
- h_notefontcolor = X11hexname(c);
- } else if (color == "page_backgroundcolor" && space == "rgb") {
- RGBColor c(RGBColorFromLaTeX(value));
- h_backgroundcolor = X11hexname(c);
- } else if (color == "shadecolor" && space == "rgb") {
- RGBColor c(RGBColorFromLaTeX(value));
- h_boxbgcolor = X11hexname(c);
- } else {
- h_preamble << "\\definecolor{" << color
- << "}{" << space << "}{" << value
- << '}';
- }
- }
-
- else if (t.cs() == "jurabibsetup") {
- // FIXME p.getArg('{', '}') is most probably wrong (it
- // does not handle nested braces).
- // Use p.verbatim_item() instead.
- vector<string> jurabibsetup =
- split_options(p.getArg('{', '}'));
- // add jurabibsetup to the jurabib package options
- add_package("jurabib", jurabibsetup);
- if (!jurabibsetup.empty()) {
- h_preamble << "\\jurabibsetup{"
- << join(jurabibsetup, ",") << '}';
- }
- }
-
- else if (t.cs() == "hypersetup") {
- vector<string> hypersetup =
- split_options(p.verbatim_item());
- // add hypersetup to the hyperref package options
- handle_hyperref(hypersetup);
- if (!hypersetup.empty()) {
- h_preamble << "\\hypersetup{"
- << join(hypersetup, ",") << '}';
- }
- }
-
- else if (is_known(t.cs(), known_if_3arg_commands)) {
- // prevent misparsing of \usepackage if it is used
- // as an argument (see e.g. our own output of
- // \@ifundefined above)
- string const arg1 = p.verbatim_item();
- string const arg2 = p.verbatim_item();
- string const arg3 = p.verbatim_item();
- // test case \@ifundefined{date}{}{\date{}}
- if (arg1 == "date" && arg2.empty() && arg3 == "\\date{}") {
- h_suppress_date = "true";
- // test for case
- //\@ifundefined{showcaptionsetup}{}{%
- // \PassOptionsToPackage{caption=false}{subfig}}
- // that LyX uses for subfloats
- } else if (arg1 == "showcaptionsetup" && arg2.empty()
- && arg3 == "%\n \\PassOptionsToPackage{caption=false}{subfig}") {
- ; // do nothing
- } else if (!in_lyx_preamble) {
- h_preamble << t.asInput()
- << '{' << arg1 << '}'
- << '{' << arg2 << '}'
- << '{' << arg3 << '}';
- }
- }
-
- else if (is_known(t.cs(), known_if_commands)) {
- // must not parse anything in conditional code, since
- // LyX would output the parsed contents unconditionally
- if (!in_lyx_preamble)
- h_preamble << t.asInput();
- handle_if(p, in_lyx_preamble);
- }
-
- else if (!t.cs().empty() && !in_lyx_preamble)
- h_preamble << '\\' << t.cs();
- }
-
- // remove the whitespace
- p.skip_spaces();
-
- // Force textclass if the user wanted it
- if (!forceclass.empty())
- h_textclass = forceclass;
- if (noweb_mode && !prefixIs(h_textclass, "literate-"))
- h_textclass.insert(0, "literate-");
- tc.setName(h_textclass);
- if (!tc.load()) {
- cerr << "Error: Could not read layout file for textclass \"" << h_textclass << "\"." << endl;
- exit(EXIT_FAILURE);
- }
- if (h_papersides.empty()) {
- ostringstream ss;
- ss << tc.sides();
- h_papersides = ss.str();
- }
- end_preamble(os, tc);
-}
-
-
-/// translates a babel language name to a LyX language name
-string babel2lyx(string const & language)
-{
- char const * const * where = is_known(language, known_languages);
- if (where)
- return known_coded_languages[where - known_languages];
- return language;
-}
-
-
-/// translates a color name to a LyX color code
-string color2code(string const & name)
-{
- char const * const * where = is_known(name, known_basic_colors);
- if (where)
- return known_basic_color_codes[where - known_basic_colors];
- return name;
-}
-
-// }])
-
-
-} // namespace lyx
#include "tex2lyx.h"
+#include "Preamble.h"
+
#include "support/lassert.h"
#include "support/convert.h"
#include "support/lstrings.h"
public:
RowInfo() : topline(false), bottomline(false), type(LT_NORMAL),
caption(false), newpage(false) {}
+ /// Does this row have any special setting?
+ bool special() const
+ {
+ return topline || bottomline || !top_space.empty() ||
+ !bottom_space.empty() || !interline_space.empty() ||
+ type != LT_NORMAL || caption || newpage;
+ }
/// horizontal line above
bool topline;
/// horizontal line below
bool bottomline;
+ /// Extra space between the top line and this row
+ string top_space;
+ /// Extra space between this row and the bottom line
+ string bottom_space;
+ /// Extra space between the bottom line and the next top line
+ string interline_space;
/// These are for longtabulars only
/// row type (head, foot, firsthead etc.)
LTRowType type;
};
+class ltType {
+public:
+ // constructor
+ ltType() : topDL(false), bottomDL(false), empty(false) {}
+ // we have this header type (is set in the getLT... functions)
+ bool set;
+ // double borders on top
+ bool topDL;
+ // double borders on bottom
+ bool bottomDL;
+ // used for FirstHeader & LastFooter and if this is true
+ // all the rows marked as FirstHeader or LastFooter are
+ // ignored in the output and it is set to be empty!
+ bool empty;
+};
+
+
/// translate a horizontal alignment (as stored in ColInfo and CellInfo) to LyX
inline char const * verbose_align(char c)
{
{
LASSERT(t.cat() == catEscape, return false);
- if (t.cs() == "hline")
- hlines += "\\hline";
+ if (t.cs() == "hline" || t.cs() == "toprule" || t.cs() == "midrule" ||
+ t.cs() == "bottomrule")
+ hlines += '\\' + t.cs();
else if (t.cs() == "cline")
hlines += "\\cline{" + p.verbatim_item() + '}';
+ else if (t.cs() == "cmidrule") {
+ // We cannot handle the \cmidrule(l){3-4} form
+ p.pushPosition();
+ p.skip_spaces(true);
+ bool const hasParentheses(p.getFullArg('(', ')').first);
+ p.popPosition();
+ if (hasParentheses)
+ return false;
+ hlines += "\\cmidrule{" + p.verbatim_item() + '}';
+ }
+
+ else if (t.cs() == "addlinespace") {
+ p.pushPosition();
+ p.skip_spaces(true);
+ bool const hasArgument(p.getFullArg('{', '}').first);
+ p.popPosition();
+ if (hasArgument)
+ hlines += "\\addlinespace{" + p.verbatim_item() + '}';
+ else
+ hlines += "\\addlinespace";
+ }
+
else if (is_long_tabular && t.cs() == "newpage")
hlines += "\\newpage";
}
continue;
}
-
}
// We need a HLINE separator if we either have no hline
pos = IN_COLUMNS;
break;
case IN_HLINES_END:
- // Oops, there is still cell content after hline
- // stuff. This does not work in LaTeX, so we ignore
- // the hlines.
- cerr << "Ignoring '" << hlines << "' in a cell"
- << endl;
+ // Oops, there is still cell content or unsupported
+ // booktabs commands after hline stuff. The latter are
+ // moved to the cell, and the first does not work in
+ // LaTeX, so we ignore the hlines.
os << comments;
- hlines.erase();
comments.erase();
+ if (support::contains(hlines, "\\hline") ||
+ support::contains(hlines, "\\cline") ||
+ support::contains(hlines, "\\newpage"))
+ cerr << "Ignoring '" << hlines
+ << "' in a cell" << endl;
+ else
+ os << hlines;
+ hlines.erase();
pos = IN_COLUMNS;
break;
case IN_COLUMNS:
} // anonymous namespace
-void handle_tabular(Parser & p, ostream & os, bool is_long_tabular,
- Context & context)
+void handle_tabular(Parser & p, ostream & os, string const & name,
+ string const & tabularwidth, Context & context)
{
+ bool const is_long_tabular(name == "longtable");
+ bool booktabs = false;
string tabularvalignment("middle");
string posopts = p.getOpt();
if (!posopts.empty()) {
vector< vector<CellInfo> > cellinfo(lines.size());
vector<RowInfo> rowinfo(lines.size());
+ ltType endfirsthead;
+ ltType endhead;
+ ltType endfoot;
+ ltType endlastfoot;
// split into rows
//cerr << "// split into rows\n";
- for (size_t row = 0; row < rowinfo.size(); ++row) {
+ for (size_t row = 0; row < rowinfo.size();) {
// init row
cellinfo[row].resize(colinfo.size());
+ bool deletelastrow = false;
// split row
vector<string> dummy;
while (p1.good()) {
Token t = p1.get_token();
//cerr << "read token: " << t << "\n";
- if (t.cs() == "hline") {
+ if (t.cs() == "hline" || t.cs() == "toprule" ||
+ t.cs() == "midrule" ||
+ t.cs() == "bottomrule") {
+ if (t.cs() != "hline")
+ booktabs = true;
if (i == 0) {
if (rowinfo[row].topline) {
if (row > 0) // extra bottomline above
handle_hline_below(rowinfo[row - 1], cellinfo[row - 1]);
else
- cerr << "dropping extra hline\n";
+ cerr << "dropping extra "
+ << t.cs() << '\n';
//cerr << "below row: " << row-1 << endl;
} else {
handle_hline_above(rowinfo[row], cellinfo[row]);
//cerr << "below row: " << row << endl;
handle_hline_below(rowinfo[row], cellinfo[row]);
}
- } else if (t.cs() == "cline") {
+ } else if (t.cs() == "cline" || t.cs() == "cmidrule") {
+ if (t.cs() == "cmidrule")
+ booktabs = true;
string arg = p1.verbatim_item();
- //cerr << "read cline arg: '" << arg << "'\n";
- vector<string> t;
- split(arg, t, '-');
- t.resize(2);
- size_t from = convert<unsigned int>(t[0]);
+ //cerr << "read " << t.cs() << " arg: '" << arg << "'\n";
+ vector<string> cols;
+ split(arg, cols, '-');
+ cols.resize(2);
+ size_t from = convert<unsigned int>(cols[0]);
if (from == 0)
cerr << "Could not parse "
- "cline start column."
+ << t.cs() << " start column."
<< endl;
else
// 1 based index -> 0 based
--from;
if (from >= colinfo.size()) {
- cerr << "cline starts at non "
- "existing column "
+ cerr << t.cs() << " starts at "
+ "non existing column "
<< (from + 1) << endl;
from = colinfo.size() - 1;
}
- size_t to = convert<unsigned int>(t[1]);
+ size_t to = convert<unsigned int>(cols[1]);
if (to == 0)
cerr << "Could not parse "
- "cline end column."
+ << t.cs() << " end column."
<< endl;
else
// 1 based index -> 0 based
--to;
if (to >= colinfo.size()) {
- cerr << "cline ends at non "
- "existing column "
+ cerr << t.cs() << " ends at "
+ "non existing column "
<< (to + 1) << endl;
to = colinfo.size() - 1;
}
cellinfo[row][col].bottomline = true;
}
}
+ } else if (t.cs() == "addlinespace") {
+ booktabs = true;
+ string const opt = p.next_token().cat() == catBegin ?
+ p.verbatim_item() : string();
+ if (i == 0) {
+ if (opt.empty())
+ rowinfo[row].top_space = "default";
+ else
+ rowinfo[row].top_space = translate_len(opt);
+ } else if (rowinfo[row].bottomline) {
+ if (opt.empty())
+ rowinfo[row].bottom_space = "default";
+ else
+ rowinfo[row].bottom_space = translate_len(opt);
+ } else {
+ if (opt.empty())
+ rowinfo[row].interline_space = "default";
+ else
+ rowinfo[row].interline_space = translate_len(opt);
+ }
} else if (t.cs() == "endhead") {
- if (i > 0)
+ if (i == 0)
+ endhead.empty = true;
+ else
rowinfo[row].type = LT_HEAD;
for (int r = row - 1; r >= 0; --r) {
if (rowinfo[r].type != LT_NORMAL)
break;
rowinfo[r].type = LT_HEAD;
+ endhead.empty = false;
}
+ endhead.set = true;
} else if (t.cs() == "endfirsthead") {
- if (i > 0)
+ if (i == 0)
+ endfirsthead.empty = true;
+ else
rowinfo[row].type = LT_FIRSTHEAD;
for (int r = row - 1; r >= 0; --r) {
if (rowinfo[r].type != LT_NORMAL)
break;
rowinfo[r].type = LT_FIRSTHEAD;
+ endfirsthead.empty = false;
}
+ endfirsthead.set = true;
} else if (t.cs() == "endfoot") {
- if (i > 0)
+ if (i == 0)
+ endfoot.empty = true;
+ else
rowinfo[row].type = LT_FOOT;
for (int r = row - 1; r >= 0; --r) {
if (rowinfo[r].type != LT_NORMAL)
break;
rowinfo[r].type = LT_FOOT;
+ endfoot.empty = false;
}
+ endfoot.set = true;
} else if (t.cs() == "endlastfoot") {
- if (i > 0)
+ if (i == 0)
+ endlastfoot.empty = true;
+ else
rowinfo[row].type = LT_LASTFOOT;
for (int r = row - 1; r >= 0; --r) {
if (rowinfo[r].type != LT_NORMAL)
break;
rowinfo[r].type = LT_LASTFOOT;
+ endlastfoot.empty = false;
}
+ endlastfoot.set = true;
} else if (t.cs() == "newpage") {
if (i == 0) {
if (row > 0)
}
}
+ // LyX ends headers and footers always with \tabularnewline.
+ // This causes one additional row in the output.
+ // If the last row of a header/footer is empty, we can work
+ // around that by removing it.
+ if (row > 1) {
+ RowInfo test = rowinfo[row-1];
+ test.type = LT_NORMAL;
+ if (lines[row-1].empty() && !test.special()) {
+ switch (rowinfo[row-1].type) {
+ case LT_FIRSTHEAD:
+ if (rowinfo[row].type != LT_FIRSTHEAD &&
+ rowinfo[row-2].type == LT_FIRSTHEAD)
+ deletelastrow = true;
+ break;
+ case LT_HEAD:
+ if (rowinfo[row].type != LT_HEAD &&
+ rowinfo[row-2].type == LT_HEAD)
+ deletelastrow = true;
+ break;
+ case LT_FOOT:
+ if (rowinfo[row].type != LT_FOOT &&
+ rowinfo[row-2].type == LT_FOOT)
+ deletelastrow = true;
+ break;
+ case LT_LASTFOOT:
+ if (rowinfo[row].type != LT_LASTFOOT &&
+ rowinfo[row-2].type == LT_LASTFOOT)
+ deletelastrow = true;
+ break;
+ case LT_NORMAL:
+ break;
+ }
+ }
+ }
+
+ if (deletelastrow) {
+ lines.erase(lines.begin() + (row - 1));
+ rowinfo.erase(rowinfo.begin() + (row - 1));
+ cellinfo.erase(cellinfo.begin() + (row - 1));
+ continue;
+ }
+
// split into cells
vector<string> cells;
split(lines[row], cells, TAB);
cellinfo[row][col].align = 'c';
}
- } else if (col == 0 && is_long_tabular &&
+ } else if (col == 0 && colinfo.size() > 1 &&
+ is_long_tabular &&
p.next_token().cs() == "caption") {
// longtable caption support in LyX is a hack:
// Captions require a row of their own with
// one multicolumn cell. The contents of that
// cell must contain exactly one caption inset
// and nothing else.
- rowinfo[row].caption = true;
- for (size_t c = 1; c < cells.size(); ++c) {
- if (!cells[c].empty()) {
- cerr << "Moving cell content '"
- << cells[c]
- << "' into the caption cell. "
- "This will probably not work."
- << endl;
- cells[0] += cells[c];
+ // LyX outputs all caption rows as first head,
+ // so we must not set the caption flag for
+ // captions not in the first head.
+ // Fortunately, the caption flag is only needed
+ // for tables with more than one column.
+ bool usecaption = (rowinfo[row].type == LT_NORMAL ||
+ rowinfo[row].type == LT_FIRSTHEAD);
+ for (size_t r = 0; r < row && usecaption; ++r)
+ if (rowinfo[row].type != LT_NORMAL &&
+ rowinfo[row].type != LT_FIRSTHEAD)
+ usecaption = false;
+ if (usecaption) {
+ rowinfo[row].caption = true;
+ for (size_t c = 1; c < cells.size(); ++c) {
+ if (!cells[c].empty()) {
+ cerr << "Moving cell content '"
+ << cells[c]
+ << "' into the caption cell. "
+ "This will probably not work."
+ << endl;
+ cells[0] += cells[c];
+ }
}
+ cells.resize(1);
+ cellinfo[row][col].align = colinfo[col].align;
+ cellinfo[row][col].multi = CELL_BEGIN_OF_MULTICOLUMN;
+ } else {
+ cellinfo[row][col].leftlines = colinfo[col].leftlines;
+ cellinfo[row][col].rightlines = colinfo[col].rightlines;
+ cellinfo[row][col].align = colinfo[col].align;
}
- cells.resize(1);
- cellinfo[row][col].align = colinfo[col].align;
- cellinfo[row][col].multi = CELL_BEGIN_OF_MULTICOLUMN;
ostringstream os;
parse_text_in_inset(p, os, FLAG_CELL, false, context);
cellinfo[row][col].content += os.str();
- // add dummy multicolumn cells
- for (size_t c = 1; c < colinfo.size(); ++c)
- cellinfo[row][c].multi = CELL_PART_OF_MULTICOLUMN;
-
+ if (usecaption) {
+ // add dummy multicolumn cells
+ for (size_t c = 1; c < colinfo.size(); ++c)
+ cellinfo[row][c].multi = CELL_PART_OF_MULTICOLUMN;
+ }
} else {
cellinfo[row][col].leftlines = colinfo[col].leftlines;
cellinfo[row][col].rightlines = colinfo[col].rightlines;
cellinfo[row - 1][col].bottomline = true;
rowinfo.pop_back();
}
+
+ ++row;
}
// Now we have the table structure and content in rowinfo, colinfo
}
}
+ if (booktabs)
+ preamble.registerAutomaticallyLoadedPackage("booktabs");
+ if (is_long_tabular)
+ preamble.registerAutomaticallyLoadedPackage("longtable");
+
//cerr << "// output what we have\n";
// output what we have
os << "\n<lyxtabular version=\"3\" rows=\"" << rowinfo.size()
<< "\" columns=\"" << colinfo.size() << "\">\n";
os << "<features"
<< write_attribute("rotate", false)
+ << write_attribute("booktabs", booktabs)
<< write_attribute("islongtable", is_long_tabular);
- if (!is_long_tabular)
- os << write_attribute("tabularvalignment", tabularvalignment);
+ if (is_long_tabular) {
+ os << write_attribute("firstHeadTopDL", endfirsthead.topDL)
+ << write_attribute("firstHeadBottomDL", endfirsthead.bottomDL)
+ << write_attribute("firstHeadEmpty", endfirsthead.empty)
+ << write_attribute("headTopDL", endhead.topDL)
+ << write_attribute("headBottomDL", endhead.bottomDL)
+ << write_attribute("footTopDL", endfoot.topDL)
+ << write_attribute("footBottomDL", endfoot.bottomDL)
+ << write_attribute("lastFootTopDL", endlastfoot.topDL)
+ << write_attribute("lastFootBottomDL", endlastfoot.bottomDL)
+ << write_attribute("lastFootEmpty", endlastfoot.empty);
+ } else
+ os << write_attribute("tabularvalignment", tabularvalignment)
+ << write_attribute("tabularwidth", tabularwidth);
os << ">\n";
//cerr << "// after header\n";
for (size_t row = 0; row < rowinfo.size(); ++row) {
os << "<row"
+ << write_attribute("topspace", rowinfo[row].top_space)
+ << write_attribute("bottomspace", rowinfo[row].bottom_space)
+ << write_attribute("interlinespace", rowinfo[row].interline_space)
<< write_attribute("endhead",
rowinfo[row].type == LT_HEAD)
<< write_attribute("endfirsthead",
\begin{picture}(8,6)
\put(0,0){\makebox(0,0)[tr]{AAA}}
\put(8,0){\makebox(0,0){BBB}}
+\put(0,8){\framebox(0,0){x}}
\put(1,0){\line(1,0){6}}
\end{picture}
\section{Input files\index{Input files}}
We can input files too, like this \input{DummyDocument}, or with the include
-variant \include{DummyDocument} % unfortunately, including the doc twice
-% generates a multiply defined label
+variant \include{DummyDocument} % unfortunately, including the doc twice generates a multiply defined label
+
+We can also import chess diagrams:
+
+\loadgame{../../../lib/examples/iecc05}\showboard
+
+Spreadsheets:
+
+\def\inputGnumericTable{}\input{../../../lib/examples/longsheet.gnumeric}
+
+and PDF pages:
+
+\includepdf[pages=-,angle=22,origin=Bl,width=5cm,height=40mm,keepaspectratio]{../../../lib/examples/beamer-icsi-logo}
If you prefer verbatim input, you can choose
between~\verbatiminput{foo} or~\verbatiminput*{foo}.
Lots of lines& like this.
\end{longtable}
+From bug 7412 another example with more captions (can currently not produced in LyX):
+\begin{longtable}{|l|l|}
+\caption{A long table}
+\endfirsthead
+\caption{A long table -- continued}
+\endhead
+\multicolumn{2}{r}{{Continued on next page}}
+\tabularnewline
+\endfoot
+\endlastfoot
+\hline
+\multicolumn{1}{|c|}{Something} & \multicolumn{1}{c|}{Description}\tabularnewline
+\hline Lots of lines& like this.\\
+\hline Lots of lines& like this.\\
+\hline Lots of lines& like this.\\
+\hline Lots of lines& like this.\\
+\hline Lots of lines& like this.\\
+\hline Lots of lines& like this.\\
+\hline Lots of lines& like this.\\
+\hline Lots of lines& like this.\\
+\hline Lots of lines& like this.\\
+\hline Lots of lines& like this.\\
+\hline Lots of lines& like this.\\
+\hline Lots of lines& like this.\\
+\hline Lots of lines& like this.\\
+\hline Lots of lines& like this.\\
+\hline Lots of lines& like this.\\
+\hline Lots of lines& like this.\\
+\hline Lots of lines& like this.\\
+\hline Lots of lines& like this.\\
+\hline Lots of lines& like this.\\
+\hline Lots of lines& like this.\\
+\hline Lots of lines& like this.\\
+\hline Lots of lines& like this.\\
+\hline Lots of lines& like this.\\
+\hline Lots of lines& like this.\\
+\hline Lots of lines& like this.\\
+\hline Lots of lines& like this.\\
+\hline Lots of lines& like this.\\
+\hline Lots of lines& like this.\\
+\hline Lots of lines& like this.\\
+\hline Lots of lines& like this.\\
+\hline Lots of lines& like this.\\
+\hline Lots of lines& like this.\\
+\hline Lots of lines& like this.\\
+\hline Lots of lines& like this.\\
+\hline Lots of lines& like this.\\
+\hline Lots of lines& like this.\\
+\hline Lots of lines& like this.\\
+\hline Lots of lines& like this.\\
+\hline Lots of lines& like this.\\
+\hline Lots of lines& like this.\\
+\hline Lots of lines& like this.\\
+\hline
+\end{longtable}
+
+A table*:
+
+\begin{tabular*} % some comment
+{0.8\columnwidth}[b]{lr}
+two\\
+lonely&lines
+\end{tabular*}
+
+A booktabs table:
+
+\begin{table}[h]
+\caption{\label{tab:Special-booktabs-table}Special booktabs-table}
+
+
+\centering{}%
+\begin{tabular}{cccc}
+\toprule
+System & Chip\,1 & \multicolumn{2}{c}{Chip\,2}\tabularnewline
+\cmidrule(r){2-2}\cmidrule(l){3-4}\morecmidrules \cmidrule{2-4}Detector
+thickness in \textmu{}m & 300 & 300 & 700\tabularnewline
+\midrule
+Edge angle in \textdegree{} & 3.55 & 2.71 & 7.99\tabularnewline
+\addlinespace
+Spatial resolution in \textmu{}m & 4.26 & 10.17 & 10.56\tabularnewline
+\addlinespace
+MTF at $f_{\mathrm{max}}$ & 0.53 & 0.37 & 0.39\tabularnewline
+\midrule
+\morecmidrules \cmidrule{3-4}LSF-spatial resolution & & & \tabularnewline
+in \textmu{}m & 129.7 & 52.75 & 50.78\tabularnewline
+in \% of pixel size & 76.3 & 95.9 & 92.3\tabularnewline
+\bottomrule
+\end{tabular}
+\end{table}
+
+
\section{Macros}
LyX supports several kinds of macros:
\newcommand{\noun}[1]{\textsc{#1}}
%% Because html converters don't know tabularnewline
\providecommand{\tabularnewline}{\\}
+\newcommand{\lyxadded}[3]{#3}
+\newcommand{\lyxdeleted}[3]{}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Textclass specific LaTeX commands.
\newenvironment{lyxlist}[1]
An environment
\end{quote}
+We also support change tracking:
+\lyxadded{Hans Wurst}{Sun Nov 6 10:39:39 2011}{Added text}
+some parts remain
+\lyxdeleted{Hans Wurst}{Sun Nov 6 10:39:55 2011}{This was the original text}
+some parts remain
+
\section*{A starred section for floats}
\begin{figure}
\begin{lyxlist}{00.00.0000}
\item [label~1] first item
\item [label~2] second item
+\item [{$\left[\textrm{ }\right]^{x}$}] Label with space, math and ] in it
\end{lyxlist}
and bibliography:
\begin{thebibliography}{9}
course show up in the LyX window. Check Document->Settings->LaTeX Preamble to see the result.
.SS "What tex2lyx Can't Handle --- But it's \s-1OK\s0"
.IP "\(bu" 4
-tabular* tables
-.IP "\(bu" 4
some spacing commands (\f(CW\ehspace\fR, \f(CW\epagebreak\fR and \f(CW\elinebreak\fR)
.IP "\(bu" 4
\f(CW\ecentering\fR, \f(CW\eraggedleft\fR, \f(CW\eraggedright\fR
#include "LayoutFile.h"
#include "LayoutModuleList.h"
#include "ModuleList.h"
+#include "Preamble.h"
#include "TextClass.h"
#include "support/convert.h"
bool noweb_mode = false;
bool pdflatex = false;
+bool xetex = false;
bool roundtrip = false;
string const arg = p.getArg('{', '}');
if (arg == "translate")
arguments.push_back(required);
+ else if (arg == "group")
+ arguments.push_back(req_group);
else if (arg == "item")
arguments.push_back(item);
+ else if (arg == "displaymath")
+ arguments.push_back(displaymath);
else
arguments.push_back(verbatim);
} else {
- p.getArg('[', ']');
- arguments.push_back(optional);
+ string const arg = p.getArg('[', ']');
+ if (arg == "group")
+ arguments.push_back(opt_group);
+ else
+ arguments.push_back(optional);
}
}
commands[command] = arguments;
* You must ensure that \p parentFilePath is properly set before calling
* this function!
*/
-void tex2lyx(idocstream & is, ostream & os, string encoding)
+bool tex2lyx(idocstream & is, ostream & os, string encoding)
{
// Set a sensible default encoding.
// This is used until an encoding command is found.
// since latin1 does not cause an iconv error if the actual encoding
// is different (bug 7509).
if (encoding.empty()) {
- if (h_inputencoding == "auto")
+ if (preamble.inputencoding() == "auto")
encoding = "latin1";
else
- encoding = h_inputencoding;
+ encoding = preamble.inputencoding();
}
Parser p(is);
p.setEncoding(encoding);
//p.dump();
- ostringstream ps;
- parse_preamble(p, ps, documentclass, textclass);
+ preamble.parse(p, documentclass, textclass);
active_environments.push_back("document");
Context context(true, textclass);
active_environments.pop_back();
// We know the used modules only after parsing the full text
- ostringstream ms;
if (!used_modules.empty()) {
- ms << "\\begin_modules\n";
LayoutModuleList::const_iterator const end = used_modules.end();
LayoutModuleList::const_iterator it = used_modules.begin();
for (; it != end; it++)
- ms << *it << '\n';
- ms << "\\end_modules\n";
+ preamble.addModule(*it);
+ }
+ if (!preamble.writeLyXHeader(os, !active_environments.empty())) {
+ cerr << "Could write LyX file header." << endl;
+ return false;
}
- os << subst(ps.str(), modules_placeholder, ms.str());
ss.seekg(0);
os << ss.str();
parsertest << p.get_token().asInput();
// <origfile> and parsertest.tex should now have identical content
#endif
+ return true;
}
}
string const oldParentFilePath = parentFilePath;
parentFilePath = onlyPath(infilename.absFileName());
- tex2lyx(is, os, encoding);
+ bool retval = tex2lyx(is, os, encoding);
parentFilePath = oldParentFilePath;
- return true;
+ return retval;
}
} // anonymous namespace
void setName(std::string const & name) { name_ = name; }
};
-/// in preamble.cpp
-void parse_preamble(Parser & p, std::ostream & os,
- std::string const & forceclass, TeX2LyXDocClass & tc);
/// Translate babel language name to LyX language name
extern std::string babel2lyx(std::string const & language);
-/// translate color name to LyX color code
-extern std::string color2code(std::string const & name);
-
-/// used packages with options
-extern std::map<std::string, std::vector<std::string> > used_packages;
-extern const char * const modules_placeholder;
-extern std::string h_inputencoding;
-extern std::string h_paragraph_separation;
+/// Translate basic color name or RGB color in LaTeX syntax to LyX color code
+extern std::string rgbcolor2code(std::string const & name);
/// in text.cpp
std::string translate_len(std::string const &);
/// in table.cpp
-void handle_tabular(Parser & p, std::ostream & os, bool is_long_tabular,
- Context & context);
+void handle_tabular(Parser & p, std::ostream & os, std::string const & name,
+ std::string const & width, Context & context);
/// in tex2lyx.cpp
char const * delim);
bool is_math_env(std::string const & name);
+bool is_display_math_env(std::string const & name);
char const * const * is_known(std::string const &, char const * const *);
/*!
enum ArgumentType {
required,
+ req_group,
verbatim,
item,
- optional
+ optional,
+ opt_group,
+ displaymath,
};
class FullCommand {
extern bool noweb_mode;
/// Did we recognize any pdflatex-only construct?
extern bool pdflatex;
+/// Did we recognize any xetex-only construct?
+extern bool xetex;
/// LyX format that is created by tex2lyx
int const LYX_FORMAT = 413;
#include "Context.h"
#include "Encoding.h"
#include "FloatList.h"
+#include "LaTeXPackages.h"
#include "Layout.h"
#include "Length.h"
+#include "Preamble.h"
#include "support/lassert.h"
#include "support/convert.h"
#include "support/FileName.h"
#include "support/filetools.h"
#include "support/lstrings.h"
+#include "support/lyxtime.h"
#include <algorithm>
#include <iostream>
char const * const known_font_families[] = { "rmfamily", "sffamily",
"ttfamily", 0};
-/// the same as known_old_font_families and known_font_families with .lyx names
+/// LaTeX names for font family changing commands
+char const * const known_text_font_families[] = { "textrm", "textsf",
+"texttt", 0};
+
+/// The same as known_old_font_families, known_font_families and
+/// known_text_font_families with .lyx names
char const * const known_coded_font_families[] = { "roman", "sans",
"typewriter", 0};
/// LaTeX names for font series
char const * const known_font_series[] = { "bfseries", "mdseries", 0};
-/// the same as known_old_font_series and known_font_series with .lyx names
+/// LaTeX names for font series changing commands
+char const * const known_text_font_series[] = { "textbf", "textmd", 0};
+
+/// The same as known_old_font_series, known_font_series and
+/// known_text_font_series with .lyx names
char const * const known_coded_font_series[] = { "bold", "medium", 0};
/// LaTeX 2.09 names for font shapes
char const * const known_font_shapes[] = { "itshape", "slshape", "scshape",
"upshape", 0};
-/// the same as known_old_font_shapes and known_font_shapes with .lyx names
+/// LaTeX names for font shape changing commands
+char const * const known_text_font_shapes[] = { "textit", "textsl", "textsc",
+"textup", 0};
+
+/// The same as known_old_font_shapes, known_font_shapes and
+/// known_text_font_shapes with .lyx names
char const * const known_coded_font_shapes[] = { "italic", "slanted",
"smallcaps", "up", 0};
+/// Known special characters which need skip_spaces_braces() afterwards
+char const * const known_special_chars[] = {"ldots", "lyxarrow",
+"textcompwordmark", "slash", 0};
+
+/// the same as known_special_chars with .lyx names
+char const * const known_coded_special_chars[] = {"ldots{}", "menuseparator",
+"textcompwordmark{}", "slash{}", 0};
+
/*!
* Graphics file extensions known by the dvips driver of the graphics package.
* These extensions are used to complete the filename of an included
for (size_t i = 0; i < no_arguments; ++i) {
switch (template_arguments[i]) {
case required:
+ case req_group:
// This argument contains regular LaTeX
handle_ert(os, ert + '{', context);
eat_whitespace(p, os, context, false);
- parse_text(p, os, FLAG_ITEM, outer, context);
+ if (template_arguments[i] == required)
+ parse_text(p, os, FLAG_ITEM, outer, context);
+ else
+ parse_text_snippet(p, os, FLAG_ITEM, outer, context);
ert = "}";
break;
case item:
else
ert += p.verbatim_item();
break;
+ case displaymath:
case verbatim:
// This argument may contain special characters
ert += '{' + p.verbatim_item() + '}';
break;
case optional:
+ case opt_group:
// true because we must not eat whitespace
// if an optional arg follows we must not strip the
// brackets from this one
latex_width = p.verbatim_item();
// if e.g. only \ovalbox{content} was used, set the width to 1\columnwidth
// as this is LyX's standard for such cases (except for makebox)
- // \framebox is special and handled below
+ // \framebox is more special and handled below
if (latex_width.empty() && inner_type != "makebox"
&& outer_type != "framebox")
latex_width = "1\\columnwidth";
(outer_type == "minipage" && inner_type == "shaded") ||
(outer_type == "parbox" && inner_type == "shaded")) {
os << "Shaded\n";
+ preamble.registerAutomaticallyLoadedPackage("color");
} else if (outer_type == "doublebox")
os << "Doublebox\n";
else if (outer_type.empty())
void parse_environment(Parser & p, ostream & os, bool outer,
- string & last_env, Context & parent_context)
+ string & last_env, bool & title_layout_found,
+ Context & parent_context)
{
Layout const * newlayout;
InsetLayout const * newinsetlayout = 0;
parse_math(p, os, FLAG_END, MATH_MODE);
os << "\\end{" << name << "}";
end_inset(os);
+ if (is_display_math_env(name)) {
+ // Prevent the conversion of a line break to a space
+ // (bug 7668). This does not change the output, but
+ // looks ugly in LyX.
+ eat_whitespace(p, os, parent_context, false);
+ }
}
- else if (name == "tabular" || name == "longtable") {
+ else if (unstarred_name == "tabular" || name == "longtable") {
eat_whitespace(p, os, parent_context, false);
+ string width = "0pt";
+ if (name == "tabular*") {
+ width = lyx::translate_len(p.getArg('{', '}'));
+ eat_whitespace(p, os, parent_context, false);
+ }
parent_context.check_layout(os);
begin_inset(os, "Tabular ");
- handle_tabular(p, os, name == "longtable", parent_context);
+ handle_tabular(p, os, name, width, parent_context);
end_inset(os);
p.skip_spaces();
}
float_type = "";
if (!opt.empty())
os << "placement " << opt << '\n';
+ if (contains(opt, "H"))
+ preamble.registerAutomaticallyLoadedPackage("float");
+ else {
+ Floating const & fl = parent_context.textclass.floats()
+ .getType(unstarred_name);
+ if (!fl.floattype().empty() && fl.usesFloatPkg())
+ preamble.registerAutomaticallyLoadedPackage("float");
+ }
+
os << "wide " << convert<string>(is_starred)
<< "\nsideways false"
<< "\nstatus open\n\n";
parse_text_in_inset(p, os, FLAG_END, outer, parent_context);
end_inset(os);
p.skip_spaces();
+ if (!preamble.notefontcolor().empty())
+ preamble.registerAutomaticallyLoadedPackage("color");
}
else if (name == "framed" || name == "shaded") {
else if (name == "lstlisting") {
eat_whitespace(p, os, parent_context, false);
// FIXME handle listings with parameters
+ // If this is added, don't forgot to handle the
+ // automatic color package loading
if (p.hasOpt())
parse_unknown_environment(p, name, os, FLAG_END,
outer, parent_context);
parent_context.add_extra_stuff("\\align center\n");
else if (name == "singlespace")
parent_context.add_extra_stuff("\\paragraph_spacing single\n");
- else if (name == "onehalfspace")
+ else if (name == "onehalfspace") {
parent_context.add_extra_stuff("\\paragraph_spacing onehalf\n");
- else if (name == "doublespace")
+ preamble.registerAutomaticallyLoadedPackage("setspace");
+ } else if (name == "doublespace") {
parent_context.add_extra_stuff("\\paragraph_spacing double\n");
- else if (name == "spacing")
+ preamble.registerAutomaticallyLoadedPackage("setspace");
+ } else if (name == "spacing") {
parent_context.add_extra_stuff("\\paragraph_spacing other " + p.verbatim_item() + "\n");
+ preamble.registerAutomaticallyLoadedPackage("setspace");
+ }
parse_text(p, os, FLAG_END, outer, parent_context);
// Just in case the environment is empty
parent_context.extra_stuff.erase();
context.check_end_deeper(os);
parent_context.new_paragraph(os);
p.skip_spaces();
+ if (!title_layout_found)
+ title_layout_found = newlayout->intitle;
+ set<string> const & req = newlayout->requires();
+ for (set<string>::const_iterator it = req.begin(); it != req.end(); it++)
+ preamble.registerAutomaticallyLoadedPackage(*it);
}
// The single '=' is meant here.
{
Layout const * newlayout = 0;
InsetLayout const * newinsetlayout = 0;
+ char const * const * where = 0;
// Store the latest bibliographystyle and nocite{*} option
// (needed for bibtex inset)
string btprint;
string bibliographystyle;
- bool const use_natbib = used_packages.find("natbib") != used_packages.end();
- bool const use_jurabib = used_packages.find("jurabib") != used_packages.end();
+ bool const use_natbib = preamble.isPackageUsed("natbib");
+ bool const use_jurabib = preamble.isPackageUsed("jurabib");
string last_env;
+ bool title_layout_found = false;
while (p.good()) {
Token const & t = p.get_token();
context.check_layout(os);
begin_inset(os, "Formula ");
Token const & n = p.get_token();
- if (n.cat() == catMath && outer) {
+ bool const display(n.cat() == catMath && outer);
+ if (display) {
// TeX's $$...$$ syntax for displayed math
os << "\\[";
parse_math(p, os, FLAG_SIMPLE, MATH_MODE);
os << '$';
}
end_inset(os);
+ if (display) {
+ // Prevent the conversion of a line break to a
+ // space (bug 7668). This does not change the
+ // output, but looks ugly in LyX.
+ eat_whitespace(p, os, context, false);
+ }
}
else if (t.cat() == catSuper || t.cat() == catSub)
os << t.cs();
}
- else if (t.cat() == catBegin &&
- p.next_token().cat() == catEnd) {
+ else if (t.cat() == catBegin) {
+ Token const next = p.next_token();
+ Token const end = p.next_next_token();
+ if (next.cat() == catEnd) {
// {}
Token const prev = p.prev_token();
p.get_token();
; // ignore it in {}`` or -{}-
else
handle_ert(os, "{}", context);
-
- }
-
- else if (t.cat() == catBegin) {
+ } else if (next.cat() == catEscape &&
+ is_known(next.cs(), known_quotes) &&
+ end.cat() == catEnd) {
+ // Something like {\textquoteright} (e.g.
+ // from writer2latex). LyX writes
+ // \textquoteright{}, so we may skip the
+ // braces here for better readability.
+ parse_text_snippet(p, os, FLAG_BRACE_LAST,
+ outer, context);
+ } else {
context.check_layout(os);
// special handling of font attribute changes
Token const prev = p.prev_token();
- Token const next = p.next_token();
TeXFont const oldFont = context.font;
if (next.character() == '[' ||
next.character() == ']' ||
parse_text_snippet(p, os, FLAG_BRACE_LAST,
outer, context);
handle_ert(os, "}", context);
+ }
}
}
parse_math(p, os, FLAG_EQUATION, MATH_MODE);
os << "\\]";
end_inset(os);
+ // Prevent the conversion of a line break to a space
+ // (bug 7668). This does not change the output, but
+ // looks ugly in LyX.
+ eat_whitespace(p, os, context, false);
}
else if (t.cs() == "begin")
- parse_environment(p, os, outer, last_env, context);
+ parse_environment(p, os, outer, last_env,
+ title_layout_found, context);
else if (t.cs() == "end") {
if (flags & FLAG_END) {
// FIXME: This swallows comments, but we cannot use
// eat_whitespace() since we must not output
// anything before the item.
- s = p.getArg('[', ']');
+ p.skip_spaces(true);
+ s = p.verbatimOption();
} else
p.skip_spaces(false);
context.set_item();
else if (t.cs() == "bibitem") {
context.set_item();
context.check_layout(os);
- string label = convert_command_inset_arg(p.getArg('[', ']'));
+ eat_whitespace(p, os, context, false);
+ string label = convert_command_inset_arg(p.verbatimOption());
string key = convert_command_inset_arg(p.verbatim_item());
if (contains(label, '\\') || contains(key, '\\')) {
// LyX can't handle LaTeX commands in labels or keys
}
}
- else if (is_macro(p))
- parse_macro(p, os, context);
+ else if (is_macro(p)) {
+ // catch the case of \def\inputGnumericTable
+ bool macro = true;
+ if (t.cs() == "def") {
+ Token second = p.next_token();
+ if (second.cs() == "inputGnumericTable") {
+ p.pushPosition();
+ p.get_token();
+ skip_braces(p);
+ Token third = p.get_token();
+ p.popPosition();
+ if (third.cs() == "input") {
+ p.get_token();
+ skip_braces(p);
+ p.get_token();
+ string name = normalize_filename(p.verbatim_item());
+ string const path = getMasterFilePath();
+ // We want to preserve relative / absolute filenames,
+ // therefore path is only used for testing
+ if (!makeAbsPath(name, path).exists()) {
+ // The file extension is probably missing.
+ // Now try to find it out.
+ char const * const Gnumeric_formats[] = {"gnumeric"
+ "ods", "xls", 0};
+ string const Gnumeric_name =
+ find_file(name, path, Gnumeric_formats);
+ if (!Gnumeric_name.empty())
+ name = Gnumeric_name;
+ }
+ if (makeAbsPath(name, path).exists())
+ fix_relative_filename(name);
+ else
+ cerr << "Warning: Could not find file '"
+ << name << "'." << endl;
+ context.check_layout(os);
+ begin_inset(os, "External\n\ttemplate ");
+ os << "GnumericSpreadsheet\n\tfilename "
+ << name << "\n";
+ end_inset(os);
+ context.check_layout(os);
+ macro = false;
+ }
+ }
+ }
+ if (macro)
+ parse_macro(p, os, context);
+ }
else if (t.cs() == "noindent") {
p.skip_spaces();
eat_whitespace(p, os, context, true);
}
+ // Must catch empty dates before findLayout is called below
+ else if (t.cs() == "date") {
+ string const date = p.verbatim_item();
+ if (date.empty())
+ preamble.suppressDate(true);
+ else {
+ preamble.suppressDate(false);
+ if (context.new_layout_allowed &&
+ (newlayout = findLayout(context.textclass,
+ t.cs(), true))) {
+ // write the layout
+ output_command_layout(os, p, outer,
+ context, newlayout);
+ p.skip_spaces();
+ if (!title_layout_found)
+ title_layout_found = newlayout->intitle;
+ set<string> const & req = newlayout->requires();
+ for (set<string>::const_iterator it = req.begin();
+ it != req.end(); it++)
+ preamble.registerAutomaticallyLoadedPackage(*it);
+ } else
+ handle_ert(os, "\\date{" + date + '}',
+ context);
+ }
+ }
+
// Starred section headings
// Must attempt to parse "Section*" before "Section".
else if ((p.next_token().asInput() == "*") &&
p.get_token();
output_command_layout(os, p, outer, context, newlayout);
p.skip_spaces();
+ if (!title_layout_found)
+ title_layout_found = newlayout->intitle;
+ set<string> const & req = newlayout->requires();
+ for (set<string>::const_iterator it = req.begin(); it != req.end(); it++)
+ preamble.registerAutomaticallyLoadedPackage(*it);
}
// Section headings and the like
// write the layout
output_command_layout(os, p, outer, context, newlayout);
p.skip_spaces();
+ if (!title_layout_found)
+ title_layout_found = newlayout->intitle;
+ set<string> const & req = newlayout->requires();
+ for (set<string>::const_iterator it = req.begin(); it != req.end(); it++)
+ preamble.registerAutomaticallyLoadedPackage(*it);
}
else if (t.cs() == "caption") {
}
else if (t.cs() == "makeindex" || t.cs() == "maketitle") {
- // FIXME: Somehow prevent title layouts if
- // "maketitle" was not found
- // swallow this
- skip_spaces_braces(p);
+ if (title_layout_found) {
+ // swallow this
+ skip_spaces_braces(p);
+ } else
+ handle_ert(os, t.asInput(), context);
}
else if (t.cs() == "tableofcontents") {
handle_ert(os, "\\listof{" + name + "}", context);
}
- else if (t.cs() == "textrm")
- parse_text_attributes(p, os, FLAG_ITEM, outer,
- context, "\\family",
- context.font.family, "roman");
-
- else if (t.cs() == "textsf")
- parse_text_attributes(p, os, FLAG_ITEM, outer,
- context, "\\family",
- context.font.family, "sans");
-
- else if (t.cs() == "texttt")
- parse_text_attributes(p, os, FLAG_ITEM, outer,
- context, "\\family",
- context.font.family, "typewriter");
-
- else if (t.cs() == "textmd")
- parse_text_attributes(p, os, FLAG_ITEM, outer,
- context, "\\series",
- context.font.series, "medium");
-
- else if (t.cs() == "textbf")
- parse_text_attributes(p, os, FLAG_ITEM, outer,
- context, "\\series",
- context.font.series, "bold");
-
- else if (t.cs() == "textup")
- parse_text_attributes(p, os, FLAG_ITEM, outer,
- context, "\\shape",
- context.font.shape, "up");
-
- else if (t.cs() == "textit")
+ else if ((where = is_known(t.cs(), known_text_font_families)))
parse_text_attributes(p, os, FLAG_ITEM, outer,
- context, "\\shape",
- context.font.shape, "italic");
+ context, "\\family", context.font.family,
+ known_coded_font_families[where - known_text_font_families]);
- else if (t.cs() == "textsl")
+ else if ((where = is_known(t.cs(), known_text_font_series)))
parse_text_attributes(p, os, FLAG_ITEM, outer,
- context, "\\shape",
- context.font.shape, "slanted");
+ context, "\\series", context.font.series,
+ known_coded_font_series[where - known_text_font_series]);
- else if (t.cs() == "textsc")
+ else if ((where = is_known(t.cs(), known_text_font_shapes)))
parse_text_attributes(p, os, FLAG_ITEM, outer,
- context, "\\shape",
- context.font.shape, "smallcaps");
+ context, "\\shape", context.font.shape,
+ known_coded_font_shapes[where - known_text_font_shapes]);
else if (t.cs() == "textnormal" || t.cs() == "normalfont") {
context.check_layout(os);
parse_text_snippet(p, os, FLAG_ITEM, outer, context);
context.check_layout(os);
os << "\n\\color inherit\n";
+ preamble.registerAutomaticallyLoadedPackage("color");
} else
// for custom defined colors
handle_ert(os, t.asInput() + "{" + color + "}", context);
parse_text_snippet(p, os, FLAG_ITEM, outer, context);
context.check_layout(os);
os << "\n\\bar default\n";
+ preamble.registerAutomaticallyLoadedPackage("ulem");
}
else if (t.cs() == "sout") {
parse_text_snippet(p, os, FLAG_ITEM, outer, context);
context.check_layout(os);
os << "\n\\strikeout default\n";
+ preamble.registerAutomaticallyLoadedPackage("ulem");
}
else if (t.cs() == "uuline" || t.cs() == "uwave" ||
parse_text_snippet(p, os, FLAG_ITEM, outer, context);
context.check_layout(os);
os << "\n\\" << t.cs() << " default\n";
+ if (t.cs() == "uuline" || t.cs() == "uwave")
+ preamble.registerAutomaticallyLoadedPackage("ulem");
+ }
+
+ else if (t.cs() == "lyxadded" || t.cs() == "lyxdeleted") {
+ context.check_layout(os);
+ string name = p.getArg('{', '}');
+ string localtime = p.getArg('{', '}');
+ preamble.registerAuthor(name);
+ Author const & author = preamble.getAuthor(name);
+ // from_ctime() will fail if LyX decides to output the
+ // time in the text language. It might also use a wrong
+ // time zone (if the original LyX document was exported
+ // with a different time zone).
+ time_t ptime = from_ctime(localtime);
+ if (ptime == static_cast<time_t>(-1)) {
+ cerr << "Warning: Could not parse time `" << localtime
+ << "´ for change tracking, using current time instead.\n";
+ ptime = current_time();
+ }
+ if (t.cs() == "lyxadded")
+ os << "\n\\change_inserted ";
+ else
+ os << "\n\\change_deleted ";
+ os << author.bufferId() << ' ' << ptime << '\n';
+ parse_text_snippet(p, os, FLAG_ITEM, outer, context);
+ bool dvipost = LaTeXPackages::isAvailable("dvipost");
+ bool xcolorulem = LaTeXPackages::isAvailable("ulem") &&
+ LaTeXPackages::isAvailable("xcolor");
+ // No need to test for luatex, since luatex comes in
+ // two flavours (dvi and pdf), like latex, and those
+ // are detected by pdflatex.
+ if (pdflatex || xetex) {
+ if (xcolorulem) {
+ preamble.registerAutomaticallyLoadedPackage("ulem");
+ preamble.registerAutomaticallyLoadedPackage("xcolor");
+ preamble.registerAutomaticallyLoadedPackage("pdfcolmk");
+ }
+ } else {
+ if (dvipost) {
+ preamble.registerAutomaticallyLoadedPackage("dvipost");
+ } else if (xcolorulem) {
+ preamble.registerAutomaticallyLoadedPackage("ulem");
+ preamble.registerAutomaticallyLoadedPackage("xcolor");
+ }
+ }
}
else if (t.cs() == "phantom" || t.cs() == "hphantom" ||
// about the empty paragraph.
context.new_paragraph(os);
}
- if (h_paragraph_separation == "indent") {
+ if (preamble.indentParagraphs()) {
// we need to unindent, lest the line be too long
context.add_par_extra_stuff("\\noindent\n");
}
is_known(p.next_token().cs(), known_phrases))) {
// LyX sometimes puts a \protect in front, so we have to ignore it
// FIXME: This needs to be changed when bug 4752 is fixed.
- char const * const * where = is_known(
+ where = is_known(
t.cs() == "protect" ? p.get_token().cs() : t.cs(),
known_phrases);
context.check_layout(os);
skip_spaces_braces(p);
}
- else if (is_known(t.cs(), known_ref_commands)) {
+ else if ((where = is_known(t.cs(), known_ref_commands))) {
string const opt = p.getOpt();
if (opt.empty()) {
context.check_layout(os);
- char const * const * where = is_known(t.cs(),
- known_ref_commands);
begin_command_inset(os, "ref",
known_coded_ref_commands[where - known_ref_commands]);
os << "reference \""
p.get_token();
}
char argumentOrder = '\0';
- vector<string> const & options = used_packages["jurabib"];
+ vector<string> const options =
+ preamble.getPackageOptions("jurabib");
if (find(options.begin(), options.end(),
"natbiborder") != options.end())
argumentOrder = 'n';
<< convert_command_inset_arg(p.verbatim_item())
<< "\"\n";
end_inset(os);
+ preamble.registerAutomaticallyLoadedPackage("nomencl");
}
else if (t.cs() == "label") {
os << "type \"idx\"\n";
end_inset(os);
skip_spaces_braces(p);
+ preamble.registerAutomaticallyLoadedPackage("makeidx");
+ if (preamble.use_indices() == "true")
+ preamble.registerAutomaticallyLoadedPackage("splitidx");
}
else if (t.cs() == "printnomenclature") {
os << "width \"" << width << '\"';
end_inset(os);
skip_spaces_braces(p);
+ preamble.registerAutomaticallyLoadedPackage("nomencl");
}
else if ((t.cs() == "textsuperscript" || t.cs() == "textsubscript")) {
os << t.cs().substr(4) << '\n';
parse_text_in_inset(p, os, FLAG_ITEM, false, context);
end_inset(os);
+ if (t.cs() == "textsubscript")
+ preamble.registerAutomaticallyLoadedPackage("subscript");
}
- else if (is_known(t.cs(), known_quotes)) {
- char const * const * where = is_known(t.cs(), known_quotes);
+ else if ((where = is_known(t.cs(), known_quotes))) {
context.check_layout(os);
begin_inset(os, "Quotes ");
os << known_coded_quotes[where - known_quotes];
skip_braces(p);
}
- else if (is_known(t.cs(), known_sizes) &&
+ else if ((where = is_known(t.cs(), known_sizes)) &&
context.new_layout_allowed) {
- char const * const * where = is_known(t.cs(), known_sizes);
context.check_layout(os);
TeXFont const oldFont = context.font;
context.font.size = known_coded_sizes[where - known_sizes];
eat_whitespace(p, os, context, false);
}
- else if (is_known(t.cs(), known_font_families) &&
+ else if ((where = is_known(t.cs(), known_font_families)) &&
context.new_layout_allowed) {
- char const * const * where =
- is_known(t.cs(), known_font_families);
context.check_layout(os);
TeXFont const oldFont = context.font;
context.font.family =
eat_whitespace(p, os, context, false);
}
- else if (is_known(t.cs(), known_font_series) &&
+ else if ((where = is_known(t.cs(), known_font_series)) &&
context.new_layout_allowed) {
- char const * const * where =
- is_known(t.cs(), known_font_series);
context.check_layout(os);
TeXFont const oldFont = context.font;
context.font.series =
eat_whitespace(p, os, context, false);
}
- else if (is_known(t.cs(), known_font_shapes) &&
+ else if ((where = is_known(t.cs(), known_font_shapes)) &&
context.new_layout_allowed) {
- char const * const * where =
- is_known(t.cs(), known_font_shapes);
context.check_layout(os);
TeXFont const oldFont = context.font;
context.font.shape =
output_font_change(os, oldFont, context.font);
eat_whitespace(p, os, context, false);
}
- else if (is_known(t.cs(), known_old_font_families) &&
+ else if ((where = is_known(t.cs(), known_old_font_families)) &&
context.new_layout_allowed) {
- char const * const * where =
- is_known(t.cs(), known_old_font_families);
context.check_layout(os);
TeXFont const oldFont = context.font;
context.font.init();
eat_whitespace(p, os, context, false);
}
- else if (is_known(t.cs(), known_old_font_series) &&
+ else if ((where = is_known(t.cs(), known_old_font_series)) &&
context.new_layout_allowed) {
- char const * const * where =
- is_known(t.cs(), known_old_font_series);
context.check_layout(os);
TeXFont const oldFont = context.font;
context.font.init();
eat_whitespace(p, os, context, false);
}
- else if (is_known(t.cs(), known_old_font_shapes) &&
+ else if ((where = is_known(t.cs(), known_old_font_shapes)) &&
context.new_layout_allowed) {
- char const * const * where =
- is_known(t.cs(), known_old_font_shapes);
context.check_layout(os);
TeXFont const oldFont = context.font;
context.font.init();
p.setEncoding(enc);
}
- else if (t.cs() == "ldots") {
+ else if ((where = is_known(t.cs(), known_special_chars))) {
context.check_layout(os);
- os << "\\SpecialChar \\ldots{}\n";
- skip_spaces_braces(p);
- }
-
- else if (t.cs() == "lyxarrow") {
- context.check_layout(os);
- os << "\\SpecialChar \\menuseparator\n";
- skip_spaces_braces(p);
- }
-
- else if (t.cs() == "textcompwordmark") {
- context.check_layout(os);
- os << "\\SpecialChar \\textcompwordmark{}\n";
- skip_spaces_braces(p);
- }
-
- else if (t.cs() == "slash") {
- context.check_layout(os);
- os << "\\SpecialChar \\slash{}\n";
+ os << "\\SpecialChar \\"
+ << known_coded_special_chars[where - known_special_chars]
+ << '\n';
skip_spaces_braces(p);
}
parse_outer_box(p, os, FLAG_ITEM, outer, context, t.cs(), "");
else if (t.cs() == "framebox") {
- string special = p.getFullOpt();
- special += p.getOpt();
- parse_outer_box(p, os, FLAG_ITEM, outer, context, t.cs(), special);
+ if (p.next_token().character() == '(') {
+ //the syntax is: \framebox(x,y)[position]{content}
+ string arg = t.asInput();
+ arg += p.getFullParentheseArg();
+ arg += p.getFullOpt();
+ eat_whitespace(p, os, context, false);
+ handle_ert(os, arg + '{', context);
+ eat_whitespace(p, os, context, false);
+ parse_text(p, os, FLAG_ITEM, outer, context);
+ handle_ert(os, "}", context);
+ } else {
+ string special = p.getFullOpt();
+ special += p.getOpt();
+ parse_outer_box(p, os, FLAG_ITEM, outer,
+ context, t.cs(), special);
+ }
}
//\makebox() is part of the picture environment and different from \makebox{}
//\makebox{} will be parsed by parse_box
else if (t.cs() == "makebox") {
- string arg = t.asInput();
if (p.next_token().character() == '(') {
//the syntax is: \makebox(x,y)[position]{content}
+ string arg = t.asInput();
arg += p.getFullParentheseArg();
arg += p.getFullOpt();
eat_whitespace(p, os, context, false);
skip_spaces_braces(p);
}
- else if (is_known(t.cs(), known_spaces)) {
- char const * const * where = is_known(t.cs(), known_spaces);
+ else if ((where = is_known(t.cs(), known_spaces))) {
context.check_layout(os);
begin_inset(os, "space ");
os << '\\' << known_coded_spaces[where - known_spaces]
t.cs() == "DeclareRobustCommandx" ||
t.cs() == "newcommand" ||
t.cs() == "newcommandx" ||
- t.cs() == "providecommand" ||
+ t.cs() == "providecommand" ||
t.cs() == "providecommandx" ||
t.cs() == "renewcommand" ||
t.cs() == "renewcommandx") {
end_inset(os);
}
+ else if (t.cs() == "loadgame") {
+ p.skip_spaces();
+ string name = normalize_filename(p.verbatim_item());
+ string const path = getMasterFilePath();
+ // We want to preserve relative / absolute filenames,
+ // therefore path is only used for testing
+ if (!makeAbsPath(name, path).exists()) {
+ // The file extension is probably missing.
+ // Now try to find it out.
+ char const * const lyxskak_format[] = {"fen", 0};
+ string const lyxskak_name =
+ find_file(name, path, lyxskak_format);
+ if (!lyxskak_name.empty())
+ name = lyxskak_name;
+ }
+ if (makeAbsPath(name, path).exists())
+ fix_relative_filename(name);
+ else
+ cerr << "Warning: Could not find file '"
+ << name << "'." << endl;
+ context.check_layout(os);
+ begin_inset(os, "External\n\ttemplate ");
+ os << "ChessDiagram\n\tfilename "
+ << name << "\n";
+ end_inset(os);
+ context.check_layout(os);
+ // after a \loadgame follows a \showboard
+ if (p.get_token().asInput() == "showboard")
+ p.get_token();
+ }
+
else {
// try to see whether the string is in unicodesymbols
// Only use text mode commands, since we are in text mode here,
* TEX2LYX IMPROVEMENTS
+- Chess diagram and Spreadsheet external templates are imported
+
+- tabular* environments are imported
+
* USER INTERFACE
* TEX2LYX
+- tex2lyx roundtips pollutes preamble with color code (bug 7845).
+
+- tex2lyx support for \date{} (bug 7844).
+
+- Latex import whitespace (bug 7668).
+
+- asme2e issues (bug 6449).
+
+- tex2lyx: problem with macros nested in \foreignlanguage (bug 5187).
+
+- tex2lyx booktabs support (bug 4553).
+
+- tex2lyx change tracking support (bug 4213).
+
+- tex2lyx problems with character style switches (bug 3036).
+
* USER INTERFACE