// special columntypes
extern std::map<char, int> special_columns;
+std::map<string, vector<string> > used_packages;
+
namespace {
const char * const known_languages[] = { "austrian", "babel", "bahasa",
}
-void handle_package(string const & name, string const & options)
+/*!
+ * 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(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(option);
+
+ return options;
+}
+
+
+/*!
+ * 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.C).
+ vector<string>::iterator end =
+ remove(options.begin(), options.end(), "natbiborder");
+ end = remove(options.begin(), end, "jurabiborder");
+ options.erase(end, options.end());
+ }
+}
+
+
+void handle_package(string const & name, string const & opts)
+{
+ vector<string> options = split_options(opts);
+ add_package(name, options);
+
//cerr << "handle_package: '" << name << "'\n";
if (name == "a4wide") {
h_papersize = "a4paper";
; // ignore this
else if (name == "fontenc")
; // ignore this
- else if (name == "inputenc")
- h_inputencoding = options;
- else if (name == "makeidx")
+ else if (name == "inputenc") {
+ h_inputencoding = opts;
+ options.clear();
+ } else if (name == "makeidx")
; // ignore this
else if (name == "verbatim")
; // ignore this
else if (is_known(name, known_languages)) {
h_language = name;
h_quotes_language = name;
- } else {
- if (!options.empty())
- h_preamble << "\\usepackage[" << options << "]{" << name << "}\n";
- else
- h_preamble << "\\usepackage{" << name << "}\n";
+ } 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 (options.empty())
+ h_preamble << "\\usepackage{" << name << "}\n";
+ else {
+ h_preamble << "\\usepackage[" << opts << "]{" << name << "}\n";
+ options.clear();
}
+
+ // We need to do something with the options...
+ if (!options.empty())
+ cerr << "Ignoring options '" << join(options, ",")
+ << "' of package " << name << '.' << endl;
}
h_preamble << "\\begin{" << name << "}";
}
+ else if (t.cs() == "jurabibsetup") {
+ 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().empty())
h_preamble << '\\' << t.cs();
}
#include "support/tostr.h"
#include "support/filetools.h"
+#include <boost/tuple/tuple.hpp>
+
#include <iostream>
#include <map>
#include <sstream>
char const * const known_latex_commands[] = { "ref", "cite", "label", "index",
"printindex", "pageref", "url", "vref", "vpageref", "prettyref", "eqref", 0 };
+/*!
+ * natbib commands.
+ * We can't put these into known_latex_commands because the argument order
+ * is reversed in lyx if there are 2 arguments.
+ * The starred forms are also known.
+ */
+char const * const known_natbib_commands[] = { "cite", "citet", "citep",
+"citealt", "citealp", "citeauthor", "citeyear", "citeyearpar",
+"citefullauthor", "Citet", "Citep", "Citealt", "Citealp", "Citeauthor", 0 };
+
+/*!
+ * jurabib commands.
+ * We can't put these into known_latex_commands because the argument order
+ * is reversed in lyx if there are 2 arguments.
+ * No starred form other than "cite*" known.
+ */
+char const * const known_jurabib_commands[] = { "cite", "citet", "citep",
+"citealt", "citealp", "citeauthor", "citeyear", "citeyearpar", "fullcite",
+// jurabib commands not (yet) supported by LyX:
+// "footcite", "footcitet", "footcitep", "footcitealt", "footcitealp",
+// "footciteauthor", "footciteyear", "footciteyearpar",
+"citefield", "citetitle", "cite*", 0 };
+
/// LaTeX names for quotes
char const * const known_quotes[] = { "glqq", "grqq", "quotedblbase",
"textquotedblleft", "quotesinglbase", "guilsinglleft", "guilsinglright", 0};
os << '\n' << attribute << ' ' << oldvalue << " \n";
}
+
+/// get the arguments of a natbib or jurabib citation command
+std::pair<string, string> getCiteArguments(Parser & p, ostream & os,
+ Context & context, bool natbibOrder)
+{
+ // We need to distinguish "" and "[]", so we can't use p.getOpt().
+
+ // text before the citation
+ string before;
+ // text after the citation
+ string after;
+
+ eat_whitespace(p, os, context, false);
+ if (p.next_token().asInput() == "[") {
+ after = '[' + p.getArg('[', ']') + ']';
+ eat_whitespace(p, os, context, false);
+ if (natbibOrder) {
+ if (p.next_token().asInput() == "[") {
+ before = after;
+ after = '[' + p.getArg('[', ']') + ']';
+ }
+ } else {
+ if (p.next_token().asInput() == "[")
+ before = '[' + p.getArg('[', ']') + ']';
+ }
+ }
+ return std::make_pair(before, after);
+}
+
} // anonymous namespace
LyXLayout_ptr newlayout;
// Store the latest bibliographystyle (needed for bibtex inset)
string bibliographystyle;
+ bool const use_natbib = used_packages.find("natbib") != used_packages.end();
+ bool const use_jurabib = used_packages.find("jurabib") != used_packages.end();
while (p.good()) {
Token const & t = p.get_token();
os << "\n\\" << t.cs() << " default \n";
}
+ else if (use_natbib &&
+ is_known(t.cs(), known_natbib_commands) &&
+ ((t.cs() != "citefullauthor" &&
+ t.cs() != "citeyear" &&
+ t.cs() != "citeyearpar") ||
+ p.next_token().asInput() != "*")) {
+ context.check_layout(os);
+ // tex lyx
+ // \citet[before][after]{a} \citet[after][before]{a}
+ // \citet[before][]{a} \citet[][before]{a}
+ // \citet[after]{a} \citet[after]{a}
+ // \citet{a} \citet{a}
+ string command = '\\' + t.cs();
+ if (p.next_token().asInput() == "*") {
+ command += '*';
+ p.get_token();
+ }
+ if (command == "\\citefullauthor")
+ // alternative name for "\\citeauthor*"
+ command = "\\citeauthor*";
+
+ // text before the citation
+ string before;
+ // text after the citation
+ string after;
+
+ boost::tie(before, after) =
+ getCiteArguments(p, os, context, true);
+ if (command == "\\cite") {
+ // \cite without optional argument means
+ // \citet, \cite with at least one optional
+ // argument means \citep.
+ if (before.empty() && after.empty())
+ command = "\\citet";
+ else
+ command = "\\citep";
+ }
+ if (before.empty() && after == "[]")
+ // avoid \citet[]{a}
+ after.erase();
+ else if (before == "[]" && after == "[]") {
+ // avoid \citet[][]{a}
+ before.erase();
+ after.erase();
+ }
+ begin_inset(os, "LatexCommand ");
+ os << command << after << before
+ << '{' << p.verbatim_item() << "}\n";
+ end_inset(os);
+ }
+
+ else if (use_jurabib &&
+ is_known(t.cs(), known_jurabib_commands)) {
+ context.check_layout(os);
+ string const command = '\\' + t.cs();
+ char argumentOrder = '\0';
+ vector<string> const & options = used_packages["jurabib"];
+ if (std::find(options.begin(), options.end(),
+ "natbiborder") != options.end())
+ argumentOrder = 'n';
+ else if (std::find(options.begin(), options.end(),
+ "jurabiborder") != options.end())
+ argumentOrder = 'j';
+
+ // text before the citation
+ string before;
+ // text after the citation
+ string after;
+
+ boost::tie(before, after) =
+ getCiteArguments(p, os, context,
+ argumentOrder != 'j');
+ string const citation = p.verbatim_item();
+ if (!before.empty() && argumentOrder == '\0') {
+ cerr << "Warning: Assuming argument order "
+ << "of jurabib version 0.6 for\n'"
+ << command << before << after << '{'
+ << citation << "}'.\n"
+ << "Add 'jurabiborder' to the jurabib "
+ << "package options if you used an\n"
+ << "earlier jurabib version." << endl;
+ }
+ begin_inset(os, "LatexCommand ");
+ os << command << after << before
+ << '{' << citation << "}\n";
+ end_inset(os);
+ }
+
else if (is_known(t.cs(), known_latex_commands)) {
+ // This needs to be after the check for natbib and
+ // jurabib commands, because "cite" has different
+ // arguments with natbib and jurabib.
context.check_layout(os);
begin_inset(os, "LatexCommand ");
os << '\\' << t.cs();