]> git.lyx.org Git - features.git/commitdiff
handle natbib and jurabib packages and citation commands
authorGeorg Baum <Georg.Baum@post.rwth-aachen.de>
Tue, 10 Aug 2004 09:40:53 +0000 (09:40 +0000)
committerGeorg Baum <Georg.Baum@post.rwth-aachen.de>
Tue, 10 Aug 2004 09:40:53 +0000 (09:40 +0000)
git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@8882 a592a061-630c-0410-9148-cb99ea01b6c8

src/tex2lyx/ChangeLog
src/tex2lyx/preamble.C
src/tex2lyx/tex2lyx.h
src/tex2lyx/text.C

index 9520dad905833bdffcec490b68ce3b579568fedb..8ac816b51528768c3f4f49dbff41420238a7a741 100644 (file)
@@ -1,3 +1,18 @@
+2004-08-10  Georg Baum  <Georg.Baum@post.rwth-aachen.de>
+
+       * preamble.C (split_options): new, split package options into vector
+       * preamble.C (add_package): new, add a package with options to
+       used_packages
+       * preamble.C, tex2lyx.h (used_packages): new map of used packages
+       and options
+       * preamble.C (handle_package): handle natbib and jurabib package
+       * preamble.C (handle_package): output a message for unhandled options
+       * preamble.C (parse_preamble): handle \jurabibsetup
+       * text.C (known_natbib_commands): new list of known natbib ccommands
+       * text.C (known_jurabib_commands): new list of known jurabib ccommands
+       * text.C (getCiteArguments): new, parse cite command arguments
+       * text.C (parse_text): handle natbib and jurabib citation commands
+
 2004-07-29  Georg Baum  <Georg.Baum@post.rwth-aachen.de>
 
        * preamble.C (end_preamble): change file format from 228 to 235
index d4f80b9b1a95d29b67c09c42c11b46c3664089cb..cd61b2f5838270477308f0f44cffaeb4e1580c33 100644 (file)
@@ -39,6 +39,8 @@ using lyx::support::LibFileSearch;
 // 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",
@@ -103,8 +105,68 @@ void handle_opt(vector<string> & opts, char const * const * what, string & targe
 }
 
 
-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";
@@ -121,21 +183,42 @@ void handle_package(string const & name, string const & options)
                ; // 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;
 }
 
 
@@ -362,6 +445,17 @@ LyXTextClass const parse_preamble(Parser & p, ostream & os, string const & force
                        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();
        }
index f93bc0398ef2ecbc467cefb39b80075f0c609be5..650d9fcc75c9097c946e2fc271167bc0f124c4a1 100644 (file)
@@ -26,6 +26,9 @@ class Context;
 /// in preamble.C
 LyXTextClass const parse_preamble(Parser & p, std::ostream & os, std::string const & forceclass);
 
+/// used packages with options
+extern std::map<std::string, std::vector<std::string> > used_packages;
+
 
 /// in text.C
 void parse_text(Parser & p, std::ostream & os, unsigned flags, bool outer,
index 37b553bdbcc3167a37cf1c9572df766c85e2a8f1..4c369e48380d1d0f92d597c0d19fb5c2410ed966 100644 (file)
@@ -22,6 +22,8 @@
 #include "support/tostr.h"
 #include "support/filetools.h"
 
+#include <boost/tuple/tuple.hpp>
+
 #include <iostream>
 #include <map>
 #include <sstream>
@@ -82,6 +84,29 @@ namespace {
 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};
@@ -821,6 +846,35 @@ void parse_text_attributes(Parser & p, ostream & os, unsigned flags, bool outer,
        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
 
 
@@ -830,6 +884,8 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
        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();
 
@@ -1402,7 +1458,98 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        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();