tex2lyx: support qualified citation lists (biblatex)

This commit is contained in:
Juergen Spitzmueller 2018-03-04 20:12:27 +01:00
parent 1a3dbbf07a
commit 0915e81481
4 changed files with 92 additions and 104 deletions

View File

@ -533,11 +533,11 @@ string Parser::getArg(char left, char right, bool allow_escaping)
} }
string Parser::getFullOpt(bool keepws) string Parser::getFullOpt(bool keepws, char left, char right)
{ {
Arg arg = getFullArg('[', ']'); Arg arg = getFullArg(left, right);
if (arg.first) if (arg.first)
return '[' + arg.second + ']'; return left + arg.second + right;
if (keepws) if (keepws)
unskip_spaces(true); unskip_spaces(true);
return string(); return string();

View File

@ -240,7 +240,8 @@ public:
* Like getOpt(), but distinguishes between a missing argument "" * Like getOpt(), but distinguishes between a missing argument ""
* and an empty argument "[]". * and an empty argument "[]".
*/ */
std::string getFullOpt(bool keepws = false); std::string getFullOpt(bool keepws = false,
char left = '[', char right = ']');
/*! /*!
* \returns getArg('[', ']') including the brackets or the * \returns getArg('[', ']') including the brackets or the
* empty string if there is no such argument. * empty string if there is no such argument.

View File

@ -102,17 +102,6 @@ Format LaTeX feature LyX feature
- cjkangle (angle brackets) \begin_inset Quotes k.. - cjkangle (angle brackets) \begin_inset Quotes k..
526 526
Plural and capitalized refstyles InsetRef Plural and capitalized refstyles InsetRef
531 Biblatex "qualified citation lists"
\cites(pre)(post)[pre1][post1]{key1}[pre2][post2]{key2}...
\begin_inset CommandInset citation
LatexCmd cite
after "post"
before "pre"
key "key1,key2..."
pretextlist "key1 pre1\tab key2 pre2..."
posttextlist "key1 post1\tab key2 post2..."
Same for:
\Cites, \textcites, \Textcites, \parencites, \Parencites, \smartcites, \Smartcites, \autocites, Autocites
533 Multibib support 533 Multibib support
\begin{btUnit}...\end{btUnit} \multibib {none|part|chapter|section|subsection} \begin{btUnit}...\end{btUnit} \multibib {none|part|chapter|section|subsection}
(if a part, chapter, section etc. (if a part, chapter, section etc.

View File

@ -191,7 +191,8 @@ char const * const known_jurabib_commands[] = { "cite", "citet", "citep",
char const * const known_biblatex_commands[] = { "cite", "Cite", "textcite", "Textcite", char const * const known_biblatex_commands[] = { "cite", "Cite", "textcite", "Textcite",
"parencite", "Parencite", "citeauthor", "Citeauthor", "citeyear", "smartcite", "Smartcite", "parencite", "Parencite", "citeauthor", "Citeauthor", "citeyear", "smartcite", "Smartcite",
"footcite", "Footcite", "autocite", "Autocite", "citetitle", "fullcite", "footfullcite", "footcite", "Footcite", "autocite", "Autocite", "citetitle", "fullcite", "footfullcite",
"supercite", 0 }; "supercite", "cites", "Cites", "textcites", "Textcites", "parencites", "Parencites",
"smartcites", "Smartcites", "autocites", "Autocites", 0 };
// Whether we need to insert a bibtex inset in a comment // Whether we need to insert a bibtex inset in a comment
bool need_commentbib = false; bool need_commentbib = false;
@ -2148,17 +2149,17 @@ void parse_text_attributes(Parser & p, ostream & os, unsigned flags, bool outer,
/// get the arguments of a natbib or jurabib citation command /// get the arguments of a natbib or jurabib citation command
void get_cite_arguments(Parser & p, bool natbibOrder, void get_cite_arguments(Parser & p, bool natbibOrder,
string & before, string & after) string & before, string & after, bool const qualified = false)
{ {
// We need to distinguish "" and "[]", so we can't use p.getOpt(). // We need to distinguish "" and "[]", so we can't use p.getOpt().
// text before the citation // text before the citation
before.clear(); before.clear();
// text after the citation // text after the citation
after = p.getFullOpt(); after = qualified ? p.getFullOpt(false, '(', ')') : p.getFullOpt();
if (!after.empty()) { if (!after.empty()) {
before = p.getFullOpt(); before = qualified ? p.getFullOpt(false, '(', ')') : p.getFullOpt();
if (natbibOrder && !before.empty()) if (natbibOrder && !before.empty())
swap(before, after); swap(before, after);
} }
@ -3836,14 +3837,23 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
preamble.citeEngine("natbib"); preamble.citeEngine("natbib");
} }
else if (use_biblatex else if ((use_biblatex
&& is_known(t.cs(), known_biblatex_commands) && is_known(t.cs(), known_biblatex_commands)
&& ((t.cs() == "cite" && ((t.cs() == "cite"
|| t.cs() == "citeauthor" || t.cs() == "citeauthor"
|| t.cs() == "Citeauthor" || t.cs() == "Citeauthor"
|| t.cs() == "parencite" || t.cs() == "parencite"
|| t.cs() == "citetitle") || t.cs() == "citetitle")
|| p.next_token().asInput() != "*")) { || p.next_token().asInput() != "*"))
|| (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); context.check_layout(os);
string command = t.cs(); string command = t.cs();
if (p.next_token().asInput() == "*") { if (p.next_token().asInput() == "*") {
@ -3851,11 +3861,15 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
p.get_token(); p.get_token();
} }
bool const qualified = suffixIs(command, "s");
if (qualified)
command = rtrim(command, "s");
// text before the citation // text before the citation
string before; string before;
// text after the citation // text after the citation
string after; string after;
get_cite_arguments(p, true, before, after); get_cite_arguments(p, true, before, after, qualified);
// These use natbib cmd names in LyX // These use natbib cmd names in LyX
// for inter-citeengine compativility // for inter-citeengine compativility
@ -3878,10 +3892,11 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
else if (command == "Smartcite") else if (command == "Smartcite")
command = "Footcite"; command = "Footcite";
if (before.empty() && after == "[]") string const emptyarg = qualified ? "()" : "[]";
if (before.empty() && after == emptyarg)
// avoid \cite[]{a} // avoid \cite[]{a}
after.erase(); after.erase();
else if (before == "[]" && after == "[]") { else if (before == emptyarg && after == emptyarg) {
// avoid \cite[][]{a} // avoid \cite[][]{a}
before.erase(); before.erase();
after.erase(); after.erase();
@ -3897,94 +3912,77 @@ void parse_text(Parser & p, ostream & os, unsigned flags, bool outer,
before.erase(before.length() - 1, 1); before.erase(before.length() - 1, 1);
before = convert_command_inset_arg(before); before = convert_command_inset_arg(before);
} }
string keys, pretextlist, posttextlist;
if (qualified) {
map<string, string> pres;
map<string, string> posts;
vector<string> lkeys;
// text before the citation
string lbefore;
// text after the citation
string lafter;
string lkey;
while (true) {
get_cite_arguments(p, true, lbefore, lafter);
// remove the brackets around after and before
if (!lafter.empty()) {
lafter.erase(0, 1);
lafter.erase(lafter.length() - 1, 1);
lafter = convert_command_inset_arg(lafter);
}
if (!lbefore.empty()) {
lbefore.erase(0, 1);
lbefore.erase(lbefore.length() - 1, 1);
lbefore = convert_command_inset_arg(lbefore);
}
if (lbefore.empty() && lafter == "[]")
// avoid \cite[]{a}
lafter.erase();
else if (lbefore == "[]" && lafter == "[]") {
// avoid \cite[][]{a}
lbefore.erase();
lafter.erase();
}
lkey = p.getArg('{', '}');
if (lkey.empty())
break;
if (!lbefore.empty())
pres.insert(make_pair(lkey, lbefore));
if (!lafter.empty())
posts.insert(make_pair(lkey, lafter));
lkeys.push_back(lkey);
}
keys = convert_command_inset_arg(getStringFromVector(lkeys));
for (auto const & ptl : pres) {
if (!pretextlist.empty())
pretextlist += '\t';
pretextlist += ptl.first + " " + ptl.second;
}
for (auto const & potl : posts) {
if (!posttextlist.empty())
posttextlist += '\t';
posttextlist += potl.first + " " + potl.second;
}
} else
keys = convert_command_inset_arg(p.verbatim_item());
begin_command_inset(os, "citation", command); begin_command_inset(os, "citation", command);
os << "after " << '"' << after << '"' << "\n"; os << "after " << '"' << after << '"' << "\n";
os << "before " << '"' << before << '"' << "\n"; os << "before " << '"' << before << '"' << "\n";
os << "key \"" os << "key \""
<< convert_command_inset_arg(p.verbatim_item()) << keys
<< "\"\n" << "\"\n";
<< "literal \"true\"\n"; if (!pretextlist.empty())
os << "pretextlist " << '"' << pretextlist << '"' << "\n";
if (!posttextlist.empty())
os << "posttextlist " << '"' << posttextlist << '"' << "\n";
os << "literal \"true\"\n";
end_inset(os); end_inset(os);
// Need to set the cite engine if biblatex is loaded by // Need to set the cite engine if biblatex is loaded by
// the document class directly // the document class directly
if (preamble.citeEngine() == "basic") if (preamble.citeEngine() == "basic")
preamble.citeEngine("biblatex"); use_biblatex_natbib ?
} preamble.citeEngine("biblatex-natbib")
: 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 && else if (use_jurabib &&