X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2FBiblioInfo.cpp;h=638579a752abe5f9b99e2a020d98d28cdbb34eb3;hb=124e0fc2be2446f7182cba0e5b54961dc1cfab91;hp=80cafeb3595bf1a60b005084f43bf5c2bf295ac2;hpb=bebc18405430a87718d7b398235bf2483d2994f2;p=lyx.git diff --git a/src/BiblioInfo.cpp b/src/BiblioInfo.cpp index 80cafeb359..638579a752 100644 --- a/src/BiblioInfo.cpp +++ b/src/BiblioInfo.cpp @@ -5,7 +5,7 @@ * * \author Angus Leeming * \author Herbert Voß - * \author Richard Heck + * \author Richard Kimberly Heck * \author Julien Rioux * \author Jürgen Spitzmüller * @@ -15,28 +15,27 @@ #include #include "BiblioInfo.h" + #include "Buffer.h" #include "BufferParams.h" -#include "buffer_funcs.h" #include "Citation.h" #include "Encoding.h" -#include "InsetIterator.h" #include "Language.h" -#include "output_xhtml.h" -#include "Paragraph.h" #include "TextClass.h" #include "TocBackend.h" +#include "xml.h" #include "support/convert.h" #include "support/debug.h" #include "support/docstream.h" +#include "support/FileName.h" #include "support/gettext.h" #include "support/lassert.h" #include "support/lstrings.h" -#include "support/regex.h" #include "support/textutils.h" #include +#include #include using namespace std; @@ -223,7 +222,7 @@ name_parts nameParts(docstring const & iname) } -docstring constructName(docstring const & name, string const scheme) +docstring constructName(docstring const & name, string const & scheme) { // re-constructs a name from name parts according // to a given scheme @@ -313,7 +312,7 @@ vector const getAuthors(docstring const & author) } -bool multipleAuthors(docstring const author) +bool multipleAuthors(docstring const & author) { return getAuthors(author).size() > 1; } @@ -384,8 +383,8 @@ docstring convertLaTeXCommands(docstring const & str) // {\v a} to \v{a} (see #9340). // FIXME: This is a sort of mini-tex2lyx. // Use the real tex2lyx instead! - static lyx::regex const tma_reg("^\\{\\\\[bcCdfGhHkrtuUv]\\s\\w\\}"); - if (lyx::regex_search(to_utf8(val), tma_reg)) { + static regex const tma_reg("^\\{\\\\[bcCdfGhHkrtuUv]\\s\\w\\}"); + if (regex_search(to_utf8(val), tma_reg)) { val = val.substr(1); val.replace(2, 1, from_ascii("{")); continue; @@ -412,8 +411,8 @@ docstring convertLaTeXCommands(docstring const & str) // look for that and change it, if necessary. // FIXME: This is a sort of mini-tex2lyx. // Use the real tex2lyx instead! - static lyx::regex const reg("^\\\\\\W\\w"); - if (lyx::regex_search(to_utf8(val), reg)) { + static regex const reg("^\\\\\\W\\w"); + if (regex_search(to_utf8(val), reg)) { val.insert(3, from_ascii("}")); val.insert(2, from_ascii("{")); } @@ -488,8 +487,8 @@ docstring processRichtext(docstring const & str, bool richtext) ////////////////////////////////////////////////////////////////////// BibTeXInfo::BibTeXInfo(docstring const & key, docstring const & type) - : is_bibtex_(true), bib_key_(key), entry_type_(type), info_(), - modifier_(0) + : is_bibtex_(true), bib_key_(key), num_bib_key_(0), entry_type_(type), + info_(), format_(), modifier_(0) {} @@ -651,6 +650,75 @@ docstring const BibTeXInfo::getYear() const } +void BibTeXInfo::getLocators(docstring & doi, docstring & url, docstring & file) const +{ + if (is_bibtex_) { + // get "doi" entry from citation record + doi = operator[]("doi"); + if (!doi.empty() && !prefixIs(doi,from_ascii("http"))) + doi = "https://doi.org/" + doi; + // get "url" entry from citation record + url = operator[]("url"); + // get "file" entry from citation record + file = operator[]("file"); + + // Jabref case, field has a format: + // Description:Location:Filetype;Description:Location:Filetype... + // We will grab only first pdf + if (!file.empty()) { + docstring ret, filedest, tmp; + ret = split(file, tmp, ':'); + tmp = split(ret, filedest, ':'); + //TODO howto deal with relative directories? + FileName f(to_utf8(filedest)); + if (f.exists()) + file = "file:///" + filedest; + } + + // kbibtex case, format: + // file1.pdf;file2.pdf + // We will grab only first pdf + docstring kfile; + if (file.empty()) + kfile = operator[]("localfile"); + if (!kfile.empty()) { + docstring filedest, tmp; + tmp = split(kfile, filedest, ';'); + //TODO howto deal with relative directories? + FileName f(to_utf8(filedest)); + if (f.exists()) + file = "file:///" + filedest; + } + + if (!url.empty()) + return; + + // try biblatex specific fields, see its manual + // 3.13.7 "Electronic Publishing Informationl" + docstring eprinttype = operator[]("eprinttype"); + docstring eprint = operator[]("eprint"); + if (eprint.empty()) + return; + + if (eprinttype == "arxiv") + url = "https://arxiv.org/abs/" + eprint; + if (eprinttype == "jstor") + url = "https://www.jstor.org/stable/" + eprint; + if (eprinttype == "pubmed") + url = "http://www.ncbi.nlm.nih.gov/pubmed/" + eprint; + if (eprinttype == "hdl") + url = "https://hdl.handle.net/" + eprint; + if (eprinttype == "googlebooks") + url = "http://books.google.com/books?id=" + eprint; + + return; + } + + // Here can be handled the bibliography environment. All one could do + // here is let LyX scan the entry for URL or HRef insets. +} + + namespace { docstring parseOptions(docstring const & format, string & optkey, @@ -776,7 +844,7 @@ I can tell, but it still feels like a hack. Fixing this would require quite a bit of work, however. */ docstring BibTeXInfo::expandFormat(docstring const & format, - BibTeXInfoList const xrefs, int & counter, Buffer const & buf, + BibTeXInfoList const & xrefs, int & counter, Buffer const & buf, CiteItem const & ci, bool next, bool second) const { // incorrect use of macros could put us in an infinite loop @@ -926,13 +994,28 @@ docstring BibTeXInfo::expandFormat(docstring const & format, } -docstring const & BibTeXInfo::getInfo(BibTeXInfoList const xrefs, - Buffer const & buf, CiteItem const & ci) const +docstring const & BibTeXInfo::getInfo(BibTeXInfoList const & xrefs, + Buffer const & buf, CiteItem const & ci, docstring const & format_in) const { bool const richtext = ci.richtext; - if (!richtext && !info_.empty()) + CiteEngineType const engine_type = buf.params().citeEngineType(); + DocumentClass const & dc = buf.params().documentClass(); + docstring const & format = format_in.empty()? + from_utf8(dc.getCiteFormat(engine_type, to_utf8(entry_type_))) + : format_in; + + if (format != format_) { + // clear caches since format changed + info_.clear(); + info_richtext_.clear(); + format_ = format; + } + + if (!richtext && !info_.empty()) { + info_ = convertLaTeXCommands(processRichtext(info_, false)); return info_; + } if (richtext && !info_richtext_.empty()) return info_richtext_; @@ -942,10 +1025,6 @@ docstring const & BibTeXInfo::getInfo(BibTeXInfoList const xrefs, return info_; } - CiteEngineType const engine_type = buf.params().citeEngineType(); - DocumentClass const & dc = buf.params().documentClass(); - docstring const & format = - from_utf8(dc.getCiteFormat(engine_type, to_utf8(entry_type_))); int counter = 0; info_ = expandFormat(format, xrefs, counter, buf, ci, false, false); @@ -965,7 +1044,7 @@ docstring const & BibTeXInfo::getInfo(BibTeXInfoList const xrefs, } -docstring const BibTeXInfo::getLabel(BibTeXInfoList const xrefs, +docstring const BibTeXInfo::getLabel(BibTeXInfoList const & xrefs, Buffer const & buf, docstring const & format, CiteItem const & ci, bool next, bool second) const { @@ -1000,7 +1079,7 @@ docstring const & BibTeXInfo::operator[](string const & field) const docstring BibTeXInfo::getValueForKey(string const & oldkey, Buffer const & buf, - CiteItem const & ci, BibTeXInfoList const xrefs, size_t maxsize) const + CiteItem const & ci, BibTeXInfoList const & xrefs, size_t maxsize) const { // anything less is pointless LASSERT(maxsize >= 16, maxsize = 16); @@ -1013,11 +1092,10 @@ docstring BibTeXInfo::getValueForKey(string const & oldkey, Buffer const & buf, docstring ret = operator[](key); if (ret.empty() && !xrefs.empty()) { - vector::const_iterator it = xrefs.begin(); - vector::const_iterator en = xrefs.end(); - for (; it != en; ++it) { - if (*it && !(**it)[key].empty()) { - ret = (**it)[key]; + // xr is a (reference to a) BibTeXInfo const * + for (auto const & xr : xrefs) { + if (xr && !(*xr)[key].empty()) { + ret = (*xr)[key]; break; } } @@ -1129,16 +1207,38 @@ docstring BibTeXInfo::getValueForKey(string const & oldkey, Buffer const & buf, ret = ci.textBefore; else if (key == "textafter") ret = ci.textAfter; - else if (key == "curpretext") - ret = ci.getPretexts()[bib_key_]; - else if (key == "curposttext") - ret = ci.getPosttexts()[bib_key_]; - else if (key == "year") + else if (key == "curpretext") { + vector> pres = ci.getPretexts(); + vector>::iterator it = pres.begin(); + int numkey = 1; + for (; it != pres.end() ; ++it) { + if ((*it).first == bib_key_ && numkey == num_bib_key_) { + ret = (*it).second; + pres.erase(it); + break; + } + if ((*it).first == bib_key_) + ++numkey; + } + } else if (key == "curposttext") { + vector> posts = ci.getPosttexts(); + vector>::iterator it = posts.begin(); + int numkey = 1; + for (; it != posts.end() ; ++it) { + if ((*it).first == bib_key_ && numkey == num_bib_key_) { + ret = (*it).second; + posts.erase(it); + break; + } + if ((*it).first == bib_key_) + ++numkey; + } + } else if (key == "year") ret = getYear(); } if (cleanit) - ret = html::cleanAttr(ret); + ret = xml::cleanAttr(ret); // make sure it is not too big support::truncateWithEllipsis(ret, maxsize); @@ -1155,13 +1255,9 @@ docstring BibTeXInfo::getValueForKey(string const & oldkey, Buffer const & buf, namespace { // A functor for use with sort, leading to case insensitive sorting -class compareNoCase: public binary_function -{ -public: - bool operator()(docstring const & s1, docstring const & s2) const { - return compare_no_case(s1, s2) < 0; - } -}; +bool compareNoCase(const docstring & a, const docstring & b) { + return compare_no_case(a, b) < 0; +} } // namespace @@ -1188,10 +1284,7 @@ vector const BiblioInfo::getXRefs(BibTeXInfo const & data, bool const // XData field can consist of a comma-separated list of keys vector const xdatakeys = getVectorFromString(data["xdata"]); if (!xdatakeys.empty()) { - vector::const_iterator xit = xdatakeys.begin(); - vector::const_iterator xen = xdatakeys.end(); - for (; xit != xen; ++xit) { - docstring const xdatakey = *xit; + for (auto const & xdatakey : xdatakeys) { result.push_back(xdatakey); BiblioInfo::const_iterator it = find(xdatakey); if (it != end()) { @@ -1209,10 +1302,9 @@ vector const BiblioInfo::getXRefs(BibTeXInfo const & data, bool const vector const BiblioInfo::getKeys() const { vector bibkeys; - BiblioInfo::const_iterator it = begin(); - for (; it != end(); ++it) - bibkeys.push_back(it->first); - sort(bibkeys.begin(), bibkeys.end(), compareNoCase()); + for (auto const & bi : *this) + bibkeys.push_back(bi.first); + sort(bibkeys.begin(), bibkeys.end(), &compareNoCase); return bibkeys; } @@ -1220,10 +1312,8 @@ vector const BiblioInfo::getKeys() const vector const BiblioInfo::getFields() const { vector bibfields; - set::const_iterator it = field_names_.begin(); - set::const_iterator end = field_names_.end(); - for (; it != end; ++it) - bibfields.push_back(*it); + for (auto const & fn : field_names_) + bibfields.push_back(fn); sort(bibfields.begin(), bibfields.end()); return bibfields; } @@ -1232,10 +1322,8 @@ vector const BiblioInfo::getFields() const vector const BiblioInfo::getEntries() const { vector bibentries; - set::const_iterator it = entry_types_.begin(); - set::const_iterator end = entry_types_.end(); - for (; it != end; ++it) - bibentries.push_back(*it); + for (auto const & et : entry_types_) + bibentries.push_back(et); sort(bibentries.begin(), bibentries.end()); return bibentries; } @@ -1260,6 +1348,15 @@ docstring const BiblioInfo::getCiteNumber(docstring const & key) const return data.citeNumber(); } +void BiblioInfo::getLocators(docstring const & key, docstring & doi, docstring & url, docstring & file) const +{ + BiblioInfo::const_iterator it = find(key); + if (it == end()) + return; + BibTeXInfo const & data = it->second; + data.getLocators(doi,url,file); +} + docstring const BiblioInfo::getYear(docstring const & key, bool use_modifier) const { @@ -1301,20 +1398,19 @@ docstring const BiblioInfo::getYear(docstring const & key, Buffer const & buf, b docstring const BiblioInfo::getInfo(docstring const & key, - Buffer const & buf, CiteItem const & ci) const + Buffer const & buf, CiteItem const & ci, docstring const & format) const { BiblioInfo::const_iterator it = find(key); if (it == end()) - return docstring(_("Bibliography entry not found!")); + return _("Bibliography entry not found!"); BibTeXInfo const & data = it->second; BibTeXInfoList xrefptrs; - vector const xrefs = getXRefs(data); for (docstring const & xref : getXRefs(data)) { BiblioInfo::const_iterator const xrefit = find(xref); if (xrefit != end()) xrefptrs.push_back(&(xrefit->second)); } - return data.getInfo(xrefptrs, buf, ci); + return data.getInfo(xrefptrs, buf, ci, format); } @@ -1326,9 +1422,15 @@ docstring const BiblioInfo::getLabel(vector keys, LASSERT(max_size >= 16, max_size = 16); // we can't display more than 10 of these, anyway + // but since we truncate in the middle, + // we need to split into two halfs. bool const too_many_keys = keys.size() > 10; - if (too_many_keys) - keys.resize(10); + vector lkeys; + if (too_many_keys) { + lkeys.insert(lkeys.end(), keys.end() - 5, keys.end()); + keys.resize(5); + keys.insert(keys.end(), lkeys.begin(), lkeys.end()); + } CiteEngineType const engine_type = buf.params().citeEngineType(); DocumentClass const & dc = buf.params().documentClass(); @@ -1336,7 +1438,14 @@ docstring const BiblioInfo::getLabel(vector keys, docstring ret = format; vector::const_iterator key = keys.begin(); vector::const_iterator ken = keys.end(); + vector handled_keys; for (int i = 0; key != ken; ++key, ++i) { + handled_keys.push_back(*key); + int n = 0; + for (auto const & k : handled_keys) { + if (k == *key) + ++n; + } BiblioInfo::const_iterator it = find(*key); BibTeXInfo empty_data; empty_data.key(*key); @@ -1350,12 +1459,12 @@ docstring const BiblioInfo::getLabel(vector keys, xrefptrs.push_back(&(xrefit->second)); } } + data.numKey(n); ret = data.getLabel(xrefptrs, buf, ret, ci, key + 1 != ken, i == 1); } - if (too_many_keys) - ret.push_back(0x2026);//HORIZONTAL ELLIPSIS - support::truncateWithEllipsis(ret, max_size); + support::truncateWithEllipsis(ret, max_size, true); + return ret; } @@ -1424,13 +1533,11 @@ void BiblioInfo::collectCitedEntries(Buffer const & buf) // FIXME We may want to collect these differently, in the first case, // so that we might have them in order of appearance. set citekeys; - shared_ptr toc = buf.tocBackend().toc("citation"); - Toc::const_iterator it = toc->begin(); - Toc::const_iterator const en = toc->end(); - for (; it != en; ++it) { - if (it->str().empty()) + Toc const & toc = *buf.tocBackend().toc("citation"); + for (auto const & t : toc) { + if (t.str().empty()) continue; - vector const keys = getVectorFromString(it->str()); + vector const keys = getVectorFromString(t.str()); citekeys.insert(keys.begin(), keys.end()); } if (citekeys.empty()) @@ -1440,10 +1547,8 @@ void BiblioInfo::collectCitedEntries(Buffer const & buf) // We will now convert it to a list of the BibTeXInfo objects used in // this document... vector bi; - set::const_iterator cit = citekeys.begin(); - set::const_iterator const cen = citekeys.end(); - for (; cit != cen; ++cit) { - BiblioInfo::const_iterator const bt = find(*cit); + for (auto const & ck : citekeys) { + BiblioInfo::const_iterator const bt = find(ck); if (bt == end() || !bt->second.isBibTeX()) continue; bi.push_back(&(bt->second)); @@ -1452,10 +1557,9 @@ void BiblioInfo::collectCitedEntries(Buffer const & buf) sort(bi.begin(), bi.end(), lSorter); // Now we can write the sorted keys - vector::const_iterator bit = bi.begin(); - vector::const_iterator ben = bi.end(); - for (; bit != ben; ++bit) - cited_entries_.push_back((*bit)->key()); + // b is a BibTeXInfo const * + for (auto const & b : bi) + cited_entries_.push_back(b->key()); } @@ -1472,10 +1576,9 @@ void BiblioInfo::makeCitationLabels(Buffer const & buf) // modifiers, like "1984a" map::iterator last = bimap_.end(); - vector::const_iterator it = cited_entries_.begin(); - vector::const_iterator const en = cited_entries_.end(); - for (; it != en; ++it) { - map::iterator const biit = bimap_.find(*it); + // add letters to years + for (auto const & ce : cited_entries_) { + map::iterator const biit = bimap_.find(ce); // this shouldn't happen, but... if (biit == bimap_.end()) // ...fail gracefully, anyway. @@ -1510,9 +1613,8 @@ void BiblioInfo::makeCitationLabels(Buffer const & buf) } } // Set the labels - it = cited_entries_.begin(); - for (; it != en; ++it) { - map::iterator const biit = bimap_.find(*it); + for (auto const & ce : cited_entries_) { + map::iterator const biit = bimap_.find(ce); // this shouldn't happen, but... if (biit == bimap_.end()) // ...fail gracefully, anyway. @@ -1524,7 +1626,7 @@ void BiblioInfo::makeCitationLabels(Buffer const & buf) docstring const auth = entry.getAuthorOrEditorList(&buf, false); // we do it this way so as to access the xref, if necessary // note that this also gives us the modifier - docstring const year = getYear(*it, buf, true); + docstring const year = getYear(ce, buf, true); if (!auth.empty() && !year.empty()) entry.label(auth + ' ' + year); else @@ -1577,4 +1679,79 @@ string citationStyleToString(const CitationStyle & cs, bool const latex) return cmd; } + +docstring authorsToDocBookAuthorGroup(docstring const & authorsString, XMLStream & xs, Buffer const & buf) +{ + // This function closely mimics getAuthorList, but produces DocBook instead of text. + // It has been greatly simplified, as the complete list of authors is always produced. No separators are required, + // as the output has a database-like shape. + // constructName has also been merged within, as it becomes really simple and leads to no copy-paste. + + if (authorsString.empty()) { + return docstring(); + } + + // Split the input list of authors into individual authors. + vector const authors = getAuthors(authorsString); + + // Retrieve the "et al." variation. + string const etal = buf.params().documentClass().getCiteMacro(buf.params().citeEngineType(), "_etal"); + + // Output the list of authors. + xs << xml::StartTag("authorgroup"); + xs << xml::CR(); + + auto it = authors.cbegin(); + auto en = authors.cend(); + for (size_t i = 0; it != en; ++it, ++i) { + xs << xml::StartTag("author"); + xs << xml::CR(); + xs << xml::StartTag("personname"); + xs << xml::CR(); + docstring name = *it; + + // All authors go in a . If more structure is known, use it; otherwise (just "et al."), print it as such. + if (name == "others") { + xs << buf.B_(etal); + } else { + name_parts parts = nameParts(name); + if (! parts.prefix.empty()) { + xs << xml::StartTag("honorific"); + xs << parts.prefix; + xs << xml::EndTag("honorific"); + xs << xml::CR(); + } + if (! parts.prename.empty()) { + xs << xml::StartTag("firstname"); + xs << parts.prename; + xs << xml::EndTag("firstname"); + xs << xml::CR(); + } + if (! parts.surname.empty()) { + xs << xml::StartTag("surname"); + xs << parts.surname; + xs << xml::EndTag("surname"); + xs << xml::CR(); + } + if (! parts.suffix.empty()) { + xs << xml::StartTag("othername", "role=\"suffix\""); + xs << parts.suffix; + xs << xml::EndTag("othername"); + xs << xml::CR(); + } + } + + xs << xml::EndTag("personname"); + xs << xml::CR(); + xs << xml::EndTag("author"); + xs << xml::CR(); + + // Could add an affiliation after , but not stored in BibTeX. + } + xs << xml::EndTag("authorgroup"); + xs << xml::CR(); + + return docstring(); +} + } // namespace lyx