]> git.lyx.org Git - features.git/commitdiff
tex2lyx: support biblatex
authorJuergen Spitzmueller <spitz@lyx.org>
Sun, 4 Mar 2018 15:46:31 +0000 (16:46 +0100)
committerJuergen Spitzmueller <spitz@lyx.org>
Sun, 4 Mar 2018 15:46:31 +0000 (16:46 +0100)
(qualified citation lists and multibib not yet supported)

src/tex2lyx/Preamble.cpp
src/tex2lyx/Preamble.h
src/tex2lyx/TODO.txt
src/tex2lyx/tex2lyx.cpp
src/tex2lyx/tex2lyx.h
src/tex2lyx/text.cpp

index 39796323ed7b5289452d37ebc0d4e1a0e3efded5..48c0033a62a2d20165435a2cf4db5556df2b3209 100644 (file)
@@ -1046,10 +1046,45 @@ void Preamble::handle_package(Parser &p, string const & name,
                        h_biblio_options = join(options, ",");
        }
 
+       else if (name == "biblatex") {
+               h_biblio_style = "plainnat";
+               h_cite_engine = "biblatex";
+               h_cite_engine_type = "authoryear";
+               string opt;
+               vector<string>::iterator it =
+                       find(options.begin(), options.end(), "natbib");
+               if (it != options.end()) {
+                       options.erase(it);
+                       h_cite_engine = "biblatex-natbib";
+               } else {
+                       opt = process_keyval_opt(options, "natbib");
+                       if (opt == "true")
+                               h_cite_engine = "biblatex-natbib";
+               }
+               opt = process_keyval_opt(options, "style");
+               if (!opt.empty()) {
+                       h_biblatex_citestyle = opt;
+                       h_biblatex_bibstyle = opt;
+               } else {
+                       opt = process_keyval_opt(options, "citestyle");
+                       if (!opt.empty())
+                               h_biblatex_citestyle = opt;
+                       opt = process_keyval_opt(options, "bibstyle");
+                       if (!opt.empty())
+                               h_biblatex_bibstyle = opt;
+               }
+               if (!options.empty()) {
+                       h_biblio_options = join(options, ",");
+                       options.clear();
+               }
+       }
+
        else if (name == "jurabib") {
                h_biblio_style = "jurabib";
                h_cite_engine = "jurabib";
                h_cite_engine_type = "authoryear";
+               if (!options.empty())
+                       h_biblio_options = join(options, ",");
        }
 
        else if (name == "bibtopic")
@@ -1270,8 +1305,14 @@ bool Preamble::writeLyXHeader(ostream & os, bool subdoc, string const & outfiled
        os << "\\cite_engine " << h_cite_engine << '\n'
           << "\\cite_engine_type " << h_cite_engine_type << '\n'
           << "\\biblio_style " << h_biblio_style << "\n"
-          << "\\use_bibtopic " << h_use_bibtopic << "\n"
-          << "\\use_indices " << h_use_indices << "\n"
+          << "\\use_bibtopic " << h_use_bibtopic << "\n";
+       if (!h_biblio_options.empty())
+               os << "\\biblio_options " << h_biblio_options << "\n";
+       if (!h_biblatex_bibstyle.empty())
+               os << "\\biblatex_bibstyle " << h_biblatex_bibstyle << "\n";
+       if (!h_biblatex_citestyle.empty())
+               os << "\\biblatex_citestyle " << h_biblatex_citestyle << "\n";
+       os << "\\use_indices " << h_use_indices << "\n"
           << "\\paperorientation " << h_paperorientation << '\n'
           << "\\suppress_date " << h_suppress_date << '\n'
           << "\\justification " << h_justification << '\n'
@@ -1566,6 +1607,14 @@ void Preamble::parse(Parser & p, string const & forceclass,
                        p.skip_spaces();
                }
 
+               else if (t.cs() == "addbibresource")
+                       biblatex_bibliographies.push_back(removeExtension(p.getArg('{', '}')));
+
+               else if (t.cs() == "bibliography") {
+                       vector<string> bibs = getVectorFromString(p.getArg('{', '}'));
+                       biblatex_bibliographies.insert(biblatex_bibliographies.end(), bibs.begin(), bibs.end());
+               }
+
                else if (t.cs() == "RS@ifundefined") {
                        string const name = p.verbatim_item();
                        string const body1 = p.verbatim_item();
index 288dd87bf681405e78c9c787d5d845dbca3c3346..389bf5e48a6c9fe64a2f00a1493ca7f5514b466c 100644 (file)
@@ -104,6 +104,8 @@ public:
        static const char * const polyglossia_languages[];
        /// the same as polyglossia_languages with .lyx names
        static const char * const coded_polyglossia_languages[];
+       ///
+       std::vector<std::string> biblatex_bibliographies;
 
 private:
        ///
@@ -132,6 +134,9 @@ private:
        std::ostringstream h_preamble;
        std::string h_backgroundcolor;
        std::string h_biblio_style;
+       std::string h_biblio_options;
+       std::string h_biblatex_bibstyle;
+       std::string h_biblatex_citestyle;
        std::string h_bibtex_command;
        std::string h_boxbgcolor;
        std::string h_cite_engine;
index c448a45569ea19b85d51c3f1cf9dda08627ed53f..f5744e7f934fa2668aaa7a78cf22f7bb3684ee0a 100644 (file)
@@ -102,34 +102,6 @@ Format LaTeX feature                        LyX feature
        - cjkangle (angle brackets)           \begin_inset Quotes k..
 526
        Plural and capitalized refstyles      InsetRef
-528    Biblatex
-       \usepackage{biblatex}                 \cite_engine biblatex
-       ...[...natbib=true...]...             \cite_engine biblatex-natbib
-       ...[...style=<val>...]...             \biblatex_bibstyle <val>
-                                             \biblatex_citestyle <val>
-       ...[...bibstyle=<val>...]...          \biblatex_bibstyle <val>
-       ...[...citestyle=<val>...]...         \biblatex_citestyle <val>
-       ...[...<any other opt>...]...         \biblio_options <any other opt>
-       \printbibliography[<opts>]            \begin_inset CommandInset bibtex
-                                              biblatexopts "<opts>"
-       \addbibresource{file.bib}            \begin_inset CommandInset bibtex
-         [multiple possible!]                 bibfiles "...,file,..."         [NB: strip ext!]
-       \bibliography{file1,file2,...}      \begin_inset CommandInset bibtex
-                                              bibfiles "...,file1,file2,..."
-                                           \begin_inset CommandInset citation
-       \Cite                                LatexCmd Cite
-       \cite*                               LatexCmd citeyear
-       \citeyear                            LatexCmd citebyear
-       \{T,t}extcite                        LatexCmd {C,c}itet
-       \{P,p}arencite                       LatexCmd {C,c}itep
-       \parencite*                          LatexCmd citeyearpar
-       \{S,s}martcite                       LatexCmd {F,f}ootcite
-       \{F,f}ootcite                        LatexCmd {F,f}ootcite
-       \{A,a}utocite                        LatexCmd {A,a}utocite
-       \citecite[*]                         LatexCmd citecite[*]
-       \fullcite                            LatexCmd fullcite
-       \footfullcite                        LatexCmd footfullcite
-       \supercite                           LatexCmd supercite
 531    Biblatex "qualified citation lists"
        \cites(pre)(post)[pre1][post1]{key1}[pre2][post2]{key2}...
                                            \begin_inset CommandInset citation
index 1db7d0ddd834dbfd55399e7bb737cfb6ffd01cfa..26f1f666d3094618cfea318c2021f1c2df0b6f6a 100644 (file)
@@ -874,6 +874,8 @@ bool tex2lyx(idocstream & is, ostream & os, string const & encoding,
        context.font.language = preamble.defaultLanguage();
        // parse the main text
        parse_text(p, ss, FLAG_END, true, context);
+       // check if we need a commented bibtex inset (biblatex)
+       check_comment_bib(ss, context);
        if (Context::empty)
                // Empty document body. LyX needs at least one paragraph.
                context.check_layout(ss);
index a1bd9b42b8947a57af6d92ca650b20efb38f06ac..4c12099bdeb5e89d16e7ca459d6ccca777275763 100644 (file)
@@ -49,6 +49,7 @@ std::string translate_len(std::string const &);
 
 void parse_text(Parser & p, std::ostream & os, unsigned flags, bool outer,
                Context & context);
+void check_comment_bib(std::ostream & os, Context & context);
 
 /*!
  * Parses a subdocument, usually useful in insets (whence the name).
index 71eb6a52f06044457946310cb58f395931d34142..8b8dc6180fe966b337a00294e73b0133f77ed602 100644 (file)
@@ -184,6 +184,18 @@ char const * const known_jurabib_commands[] = { "cite", "citet", "citep",
 // "footciteauthor", "footciteyear", "footciteyearpar",
 "citefield", "citetitle", 0 };
 
+/*!
+ * biblatex commands.
+ * Known starred forms: \cite*, \citeauthor*, \Citeauthor*, \parencite*, \citetitle*.
+ */
+char const * const known_biblatex_commands[] = { "cite", "Cite", "textcite", "Textcite",
+"parencite", "Parencite", "citeauthor", "Citeauthor", "citeyear", "smartcite", "Smartcite",
+ "footcite", "Footcite", "autocite", "Autocite", "citetitle", "fullcite", "footfullcite",
+"supercite", 0 };
+
+// Whether we need to insert a bibtex inset in a comment
+bool need_commentbib = false;
+
 /// LaTeX names for quotes
 char const * const known_quotes[] = { "dq", "guillemotleft", "flqq", "og",
 "guillemotright", "frqq", "fg", "glq", "glqq", "textquoteleft", "grq", "grqq",
@@ -2482,6 +2494,11 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
        string bibliographystyle;
        bool const use_natbib = isProvided("natbib");
        bool const use_jurabib = isProvided("jurabib");
+       bool const use_biblatex = isProvided("biblatex")
+                       && preamble.citeEngine() != "biblatex-natbib";
+       bool const use_biblatex_natbib = isProvided("biblatex-natbib")
+                       || (isProvided("biblatex") && preamble.citeEngine() == "biblatex-natbib");
+       need_commentbib = use_biblatex || use_biblatex_natbib;
        string last_env;
 
        // it is impossible to determine the correct encoding for non-CJK Japanese.
@@ -3819,6 +3836,157 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                                preamble.citeEngine("natbib");
                }
 
+               else if (use_biblatex
+                        && is_known(t.cs(), known_biblatex_commands)
+                        && ((t.cs() == "cite"
+                            || t.cs() == "citeauthor"
+                            || t.cs() == "Citeauthor"
+                            || t.cs() == "parencite"
+                            || t.cs() == "citetitle")
+                        || p.next_token().asInput() != "*")) {
+                       context.check_layout(os);
+                       string command = t.cs();
+                       if (p.next_token().asInput() == "*") {
+                               command += '*';
+                               p.get_token();
+                       }
+
+                       // text before the citation
+                       string before;
+                       // text after the citation
+                       string after;
+                       get_cite_arguments(p, true, before, after);
+
+                       // These use natbib cmd names in LyX
+                       // for inter-citeengine compativility
+                       if (command == "citeyear")
+                               command = "citebyear";
+                       else if (command == "cite*")
+                               command = "citeyear";
+                       else if (command == "textcite")
+                               command = "citet";
+                       else if (command == "Textcite")
+                               command = "Citet";
+                       else if (command == "parencite")
+                               command = "citep";
+                       else if (command == "Parencite")
+                               command = "Citep";
+                       else if (command == "parencite*")
+                               command = "citeyearpar";
+                       else if (command == "smartcite")
+                               command = "footcite";
+                       else if (command == "Smartcite")
+                               command = "Footcite";
+
+                       if (before.empty() && after == "[]")
+                               // avoid \cite[]{a}
+                               after.erase();
+                       else if (before == "[]" && after == "[]") {
+                               // avoid \cite[][]{a}
+                               before.erase();
+                               after.erase();
+                       }
+                       // remove the brackets around after and before
+                       if (!after.empty()) {
+                               after.erase(0, 1);
+                               after.erase(after.length() - 1, 1);
+                               after = convert_command_inset_arg(after);
+                       }
+                       if (!before.empty()) {
+                               before.erase(0, 1);
+                               before.erase(before.length() - 1, 1);
+                               before = convert_command_inset_arg(before);
+                       }
+                       begin_command_inset(os, "citation", command);
+                       os << "after " << '"' << after << '"' << "\n";
+                       os << "before " << '"' << before << '"' << "\n";
+                       os << "key \""
+                          << convert_command_inset_arg(p.verbatim_item())
+                          << "\"\n"
+                          << "literal \"true\"\n";
+                       end_inset(os);
+                       // Need to set the cite engine if biblatex is loaded by
+                       // the document class directly
+                       if (preamble.citeEngine() == "basic")
+                               preamble.citeEngine("biblatex");
+               }
+
+               else if (use_biblatex_natbib
+                        && (is_known(t.cs(), known_biblatex_commands)
+                            || is_known(t.cs(), known_natbib_commands))
+                        && ((t.cs() == "cite" || t.cs() == "citet" || t.cs() == "Citet"
+                             || t.cs() == "citep" || t.cs() == "Citep" || t.cs() == "citealt"
+                             || t.cs() == "Citealt" || t.cs() == "citealp" || t.cs() == "Citealp"
+                             || t.cs() == "citeauthor" || t.cs() == "Citeauthor"
+                             || t.cs() == "parencite" || t.cs() == "citetitle")
+                           || p.next_token().asInput() != "*")) {
+                       context.check_layout(os);
+                       string command = t.cs();
+                       if (p.next_token().asInput() == "*") {
+                               command += '*';
+                               p.get_token();
+                       }
+
+                       // text before the citation
+                       string before;
+                       // text after the citation
+                       string after;
+                       get_cite_arguments(p, true, before, after);
+
+                       // These use natbib cmd names in LyX
+                       // for inter-citeengine compativility
+                       if (command == "citeyear")
+                               command = "citebyear";
+                       else if (command == "cite*")
+                               command = "citeyear";
+                       else if (command == "textcite")
+                               command = "citet";
+                       else if (command == "Textcite")
+                               command = "Citet";
+                       else if (command == "parencite")
+                               command = "citep";
+                       else if (command == "Parencite")
+                               command = "Citep";
+                       else if (command == "parencite*")
+                               command = "citeyearpar";
+                       else if (command == "smartcite")
+                               command = "footcite";
+                       else if (command == "Smartcite")
+                               command = "Footcite";
+
+                       if (before.empty() && after == "[]")
+                               // avoid \cite[]{a}
+                               after.erase();
+                       else if (before == "[]" && after == "[]") {
+                               // avoid \cite[][]{a}
+                               before.erase();
+                               after.erase();
+                       }
+                       // remove the brackets around after and before
+                       if (!after.empty()) {
+                               after.erase(0, 1);
+                               after.erase(after.length() - 1, 1);
+                               after = convert_command_inset_arg(after);
+                       }
+                       if (!before.empty()) {
+                               before.erase(0, 1);
+                               before.erase(before.length() - 1, 1);
+                               before = convert_command_inset_arg(before);
+                       }
+                       begin_command_inset(os, "citation", command);
+                       os << "after " << '"' << after << '"' << "\n";
+                       os << "before " << '"' << before << '"' << "\n";
+                       os << "key \""
+                          << convert_command_inset_arg(p.verbatim_item())
+                          << "\"\n"
+                          << "literal \"true\"\n";
+                       end_inset(os);
+                       // Need to set the cite engine if biblatex is loaded by
+                       // the document class directly
+                       if (preamble.citeEngine() == "basic")
+                               preamble.citeEngine("biblatex-natbib");
+               }
+
                else if (use_jurabib &&
                         is_known(t.cs(), known_jurabib_commands) &&
                         (t.cs() == "cite" || p.next_token().asInput() != "*")) {
@@ -4463,6 +4631,46 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
                        end_inset(os);
                }
 
+               else if (t.cs() == "printbibliography") {
+                       context.check_layout(os);
+                       string BibOpts;
+                       string bbloptions = p.hasOpt() ? p.getArg('[', ']') : string();
+                       vector<string> opts = getVectorFromString(bbloptions);
+                       vector<string>::iterator it =
+                               find(opts.begin(), opts.end(), "heading=bibintoc");
+                       if (it != opts.end()) {
+                               opts.erase(it);
+                               BibOpts = "bibtotoc";
+                       }
+                       bbloptions = getStringFromVector(opts);
+                       begin_command_inset(os, "bibtex", "bibtex");
+                       if (!btprint.empty()) {
+                               os << "btprint " << '"' << "btPrintAll" << '"' << "\n";
+                               // clear the string because the next BibTeX inset can be without the
+                               // \nocite{*} option
+                               btprint.clear();
+                       }
+                       string bibfiles;
+                       for (auto const & bf : preamble.biblatex_bibliographies) {
+                               if (!bibfiles.empty())
+                                       bibfiles += ",";
+                               bibfiles += normalize_filename(bf);
+                       }
+                       if (!bibfiles.empty())
+                               os << "bibfiles " << '"' << bibfiles << '"' << "\n";
+                       // Do we have addcontentsline?
+                       if (contentslineContent == "\\refname") {
+                               BibOpts = "bibtotoc";
+                               // clear string because next BibTeX inset can be without addcontentsline
+                               contentslineContent.clear();
+                       }
+                       os << "options " << '"' << BibOpts << '"' << "\n";
+                       if (!bbloptions.empty())
+                               os << "biblatexopts " << '"' << bbloptions << '"' << "\n";
+                       end_inset(os);
+                       need_commentbib = false;
+               }
+
                else if (t.cs() == "parbox") {
                        // Test whether this is an outer box of a shaded box
                        p.pushPosition();
@@ -5200,6 +5408,31 @@ string guessLanguage(Parser & p, string const & lang)
        return use->first;
 }
 
+
+void check_comment_bib(ostream & os, Context & context)
+{
+       if (!need_commentbib)
+               return;
+       // We have a bibliography database, but no bibliography with biblatex
+       // which is completely valid. Insert a bibtex inset in a note.
+       context.check_layout(os);
+       begin_inset(os, "Note Note\n");
+       os << "status open\n";
+       os << "\\begin_layout Plain Layout\n";
+       begin_command_inset(os, "bibtex", "bibtex");
+       string bibfiles;
+       for (auto const & bf : preamble.biblatex_bibliographies) {
+               if (!bibfiles.empty())
+                       bibfiles += ",";
+               bibfiles += normalize_filename(bf);
+       }
+       if (!bibfiles.empty())
+               os << "bibfiles " << '"' << bibfiles << '"' << "\n";
+       end_inset(os);// Bibtex
+       os << "\\end_layout\n";
+       end_inset(os);// Note
+}
+
 // }])