//////////////////////////////////////////////////////////////////////
BibTeXInfo::BibTeXInfo(docstring const & key, docstring const & type)
- : is_bibtex_(true), bib_key_(key), entry_type_(type), info_()
+ : is_bibtex_(true), bib_key_(key), entry_type_(type), info_(),
+ modifier_(0)
{}
}
-docstring const BiblioInfo::getYear(docstring const & key) const
+docstring const BiblioInfo::getCiteNumber(docstring const & key) const
+{
+ BiblioInfo::const_iterator it = find(key);
+ if (it == end())
+ return docstring();
+ BibTeXInfo const & data = it->second;
+ return data.citeNumber();
+}
+
+
+docstring const BiblioInfo::getYear(docstring const & key, bool use_modifier) const
{
BiblioInfo::const_iterator it = find(key);
if (it == end())
return docstring();
BibTeXInfo const & data = it->second;
docstring year = data.getYear();
- if (!year.empty())
- return year;
- // let's try the crossref
- docstring const xref = data.getXRef();
- if (xref.empty())
- return _("No year"); // no luck
- BiblioInfo::const_iterator const xrefit = find(xref);
- if (xrefit == end())
- return _("No year"); // no luck again
- BibTeXInfo const & xref_data = xrefit->second;
- return xref_data.getYear();
- return data.getYear();
+ if (year.empty()) {
+ // let's try the crossref
+ docstring const xref = data.getXRef();
+ if (xref.empty())
+ return _("No year"); // no luck
+ BiblioInfo::const_iterator const xrefit = find(xref);
+ if (xrefit == end())
+ return _("No year"); // no luck again
+ BibTeXInfo const & xref_data = xrefit->second;
+ year = xref_data.getYear();
+ }
+ if (use_modifier && data.modifier() != 0)
+ year += data.modifier();
+ return year;
}
// used in xhtml to sort a list of BibTeXInfo objects
bool lSorter(BibTeXInfo const * lhs, BibTeXInfo const * rhs)
{
- return lhs->getAbbreviatedAuthor() < rhs->getAbbreviatedAuthor();
+ docstring const lauth = lhs->getAbbreviatedAuthor();
+ docstring const rauth = rhs->getAbbreviatedAuthor();
+ docstring const lyear = lhs->getYear();
+ docstring const ryear = rhs->getYear();
+ docstring const ltitl = lhs->operator[]("title");
+ docstring const rtitl = rhs->operator[]("title");
+ return (lauth < rauth)
+ || (lauth == rauth && lyear < ryear)
+ || (lauth == rauth && lyear == ryear && ltitl < rtitl);
}
}
void BiblioInfo::makeCitationLabels(Buffer const & buf)
{
collectCitedEntries(buf);
- // FIXME It'd be nice to do author-year as well as numerical
- // and maybe even some other sorts of labels.
+ CiteEngine const engine = buf.params().citeEngine();
+ bool const numbers =
+ (engine == ENGINE_BASIC || engine == ENGINE_NATBIB_NUMERICAL);
+
+ int keynumber = 0;
+ char modifier = 0;
+ // used to remember the last one we saw
+ // we'll be comparing entries to see if we need to add
+ // modifiers, like "1984a"
+ map<docstring, BibTeXInfo>::iterator last;
+
vector<docstring>::const_iterator it = cited_entries_.begin();
vector<docstring>::const_iterator const en = cited_entries_.end();
- int keynumber = 0;
for (; it != en; ++it) {
map<docstring, BibTeXInfo>::iterator const biit = bimap_.find(*it);
// this shouldn't happen, but...
if (biit == bimap_.end())
+ // ...fail gracefully, anyway.
continue;
BibTeXInfo & entry = biit->second;
- docstring const key = convert<docstring>(++keynumber);
- entry.setCiteKey(key);
+ if (numbers) {
+ docstring const num = convert<docstring>(++keynumber);
+ entry.setCiteNumber(num);
+ } else {
+ if (it != cited_entries_.begin()
+ && entry.getAbbreviatedAuthor() == last->second.getAbbreviatedAuthor()
+ // we access the year via getYear() so as to get it from the xref,
+ // if we need to do so
+ && getYear(entry.key()) == getYear(last->second.key())) {
+ if (modifier == 0) {
+ // so the last one should have been 'a'
+ last->second.setModifier('a');
+ modifier = 'b';
+ } else if (modifier == 'z')
+ modifier = 'A';
+ else
+ modifier++;
+ } else {
+ modifier = 0;
+ }
+ entry.setModifier(modifier);
+ // remember the last one
+ last = biit;
+ }
}
}
docstring const & label() const { return label_; }
///
docstring const & key() const { return bib_key_; }
+ /// numerical key for citing this entry. currently used only
+ /// by XHTML output routines.
+ docstring citeNumber() const { return cite_number_; }
///
- docstring citeKey() const { return cite_key_; }
+ void setCiteNumber(docstring const & num) { cite_number_ = num; }
+ /// a,b,c, etc, for author-year. currently used only by XHTML
+ /// output routines.
+ char modifier() const { return modifier_; }
///
- void setCiteKey(docstring const & k) { cite_key_ = k; }
+ void setModifier(char c) { modifier_ = c; }
///
docstring entryType() const { return entry_type_; }
///
docstring entry_type_;
/// a cache for getInfo()
mutable docstring info_;
- /// key to use when citing this entry
- /// currently used only by XHTML output routines
- docstring cite_key_;
+ ///
+ docstring cite_number_;
+ ///
+ char modifier_;
/// our map: <field, value>
std::map <docstring, docstring> bimap_;
};
std::vector<docstring> const getEntries() const;
/// \return the short form of an authorlist
docstring const getAbbreviatedAuthor(docstring const & key) const;
- /// \return the year from the bibtex data record
+ /// \return the year from the bibtex data record for \param key
+ /// if \param use_modifier is true, then we will also append any
+ /// modifier for this entry (e.g., 1998b).
/// Note that this will get the year from the crossref if it's
- /// not present in the record itself
- docstring const getYear(docstring const & key) const;
+ /// not present in the record itself.
+ docstring const getYear(docstring const & key,
+ bool use_modifier = false) const;
+ ///
+ docstring const getCiteNumber(docstring const & key) const;
/// \return formatted BibTeX data associated with a given key.
/// Empty if no info exists.
/// Note that this will retrieve data from the crossref as needed.
void collectCitedEntries(Buffer const & buf);
/// A list of BibTeX keys cited in the current document, sorted by
/// the last name of the author.
- std::vector<docstring> const & citedEntries() const { return cited_entries_; }
+ /// Make sure you have called collectCitedEntries() before you try to
+ /// use this. You should probably call it just before you use this.
+ std::vector<docstring> const & citedEntries() const
+ { return cited_entries_; }
///
void makeCitationLabels(Buffer const & buf);
///
}
+// FIXME
+// docstring InsetBibtex::entriesAsXHTML(vector<docstring> const & entries)
+// And then here just: entriesAsXHTML(buffer().masterBibInfo().citedEntries())
docstring InsetBibtex::xhtml(XHTMLStream & xs, OutputParams const &) const
{
BiblioInfo const & bibinfo = buffer().masterBibInfo();
vector<docstring> const & cites = bibinfo.citedEntries();
+ CiteEngine const engine = buffer().params().citeEngine();
+ bool const numbers =
+ (engine == ENGINE_BASIC || engine == ENGINE_NATBIB_NUMERICAL);
+
xs << StartTag("h2", "class='bibtex'")
<< _("References")
<< EndTag("h2")
// The same name/id problem we have elsewhere.
string const attr = "id='" + to_utf8(entry.key()) + "'";
xs << CompTag("a", attr);
- docstring citekey = entry.citeKey();
+ docstring citekey;
+ if (numbers)
+ citekey = entry.citeNumber();
+ else {
+ docstring const auth = entry.getAbbreviatedAuthor();
+ // we do it this way so as to access the xref, if necessary
+ // note that this also gives us the modifier
+ docstring const year = bibinfo.getYear(*vit, true);
+ if (!auth.empty() && !year.empty())
+ citekey = auth + ' ' + year;
+ }
if (citekey.empty()) {
citekey = entry.label();
if (citekey.empty())
<< bibinfo.getInfo(entry.key())
<< EndTag("span")
<< EndTag("div");
+ xs.cr();
}
xs << EndTag("div");
return docstring();
return output;
}
+
+inline docstring wrapCitation(docstring const & key,
+ docstring const & content, bool for_xhtml)
+{
+ if (!for_xhtml)
+ return content;
+ // we have to do the escaping here, because we will ultimately
+ // write this as a raw string, so as not to escape the tags.
+ return "<a href='#" + key + "'>" + html::htmlize(content) + "</a>";
+}
+
} // anonymous namespace
-docstring InsetCitation::generateLabel() const
+docstring InsetCitation::generateLabel(bool for_xhtml) const
{
docstring label;
- label = complexLabel();
+ label = complexLabel(for_xhtml);
// Fallback to fail-safe
if (label.empty())
- label = basicLabel();
+ label = basicLabel(for_xhtml);
return label;
}
-docstring InsetCitation::complexLabel() const
+docstring InsetCitation::complexLabel(bool for_xhtml) const
{
Buffer const & buf = buffer();
// Only start the process off after the buffer is loaded from file.
for (; it != end; ++it) {
// get the bibdata corresponding to the key
docstring const author = biblist.getAbbreviatedAuthor(*it);
- docstring const year = biblist.getYear(*it);
+ docstring const year = biblist.getYear(*it, for_xhtml);
+ docstring const citenum = for_xhtml ? biblist.getCiteNumber(*it) : *it;
- // Something isn't right. Fail safely.
if (author.empty() || year.empty())
+ // We can't construct a "complex" label without that info.
+ // So fail safely.
return docstring();
// authors1/<before>; ... ;
// authors_last, <after>
if (cite_type == "cite") {
if (engine == ENGINE_BASIC) {
- label += *it + sep_str;
+ label += wrapCitation(*it, citenum, for_xhtml) + sep_str;
} else if (engine == ENGINE_JURABIB) {
if (it == keys.begin())
- label += author + before_str + sep_str;
+ label += wrapCitation(*it, author, for_xhtml) + before_str + sep_str;
else
- label += author + sep_str;
+ label += wrapCitation(*it, author, for_xhtml) + sep_str;
}
-
+ }
// nocite
- } else if (cite_type == "nocite") {
+ else if (cite_type == "nocite") {
label += *it + sep_str;
-
+ }
// (authors1 (<before> year); ... ;
// authors_last (<before> year, <after>)
- } else if (cite_type == "citet") {
+ else if (cite_type == "citet") {
switch (engine) {
case ENGINE_NATBIB_AUTHORYEAR:
label += author + op_str + before_str +
- year + cp + sep_str;
+ wrapCitation(*it, year, for_xhtml) + cp + sep_str;
break;
case ENGINE_NATBIB_NUMERICAL:
- label += author + op_str + before_str + '#' + *it + cp + sep_str;
+ label += author + op_str + before_str +
+ wrapCitation(*it, citenum, for_xhtml) + cp + sep_str;
break;
case ENGINE_JURABIB:
label += before_str + author + op_str +
- year + cp + sep_str;
+ wrapCitation(*it, year, for_xhtml) + cp + sep_str;
break;
case ENGINE_BASIC:
break;
}
-
- // author, year; author, year; ...
- } else if (cite_type == "citep" ||
+ }
+ // author, year; author, year; ...
+ else if (cite_type == "citep" ||
cite_type == "citealp") {
if (engine == ENGINE_NATBIB_NUMERICAL) {
- label += *it + sep_str;
+ label += wrapCitation(*it, citenum, for_xhtml) + sep_str;
} else {
- label += author + ", " + year + sep_str;
+ label += wrapCitation(*it, author + ", " + year, for_xhtml) + sep_str;
}
+ }
// (authors1 <before> year;
// authors_last <before> year, <after>)
- } else if (cite_type == "citealt") {
+ else if (cite_type == "citealt") {
switch (engine) {
case ENGINE_NATBIB_AUTHORYEAR:
label += author + ' ' + before_str +
- year + sep_str;
+ wrapCitation(*it, year, for_xhtml) + sep_str;
break;
case ENGINE_NATBIB_NUMERICAL:
- label += author + ' ' + before_str + '#' + *it + sep_str;
+ label += author + ' ' + before_str + '#' +
+ wrapCitation(*it, citenum, for_xhtml) + sep_str;
break;
case ENGINE_JURABIB:
- label += before_str + author + ' ' +
- year + sep_str;
+ label += before_str +
+ wrapCitation(*it, author + ' ' + year, for_xhtml) + sep_str;
break;
case ENGINE_BASIC:
break;
}
+
+ }
// author; author; ...
- } else if (cite_type == "citeauthor") {
- label += author + sep_str;
-
+ else if (cite_type == "citeauthor") {
+ label += wrapCitation(*it, author, for_xhtml) + sep_str;
+ }
// year; year; ...
- } else if (cite_type == "citeyear" ||
+ else if (cite_type == "citeyear" ||
cite_type == "citeyearpar") {
- label += year + sep_str;
+ label += wrapCitation(*it, year, for_xhtml) + sep_str;
}
}
label = rtrim(rtrim(label), sep);
}
-docstring InsetCitation::basicLabel() const
+docstring InsetCitation::basicLabel(bool for_xhtml) const
{
docstring keys = getParam("key");
docstring label;
while (contains(keys, ',')) {
docstring key;
keys = ltrim(split(keys, key, ','));
- label += ", " + key;
+ label += ", " + wrapCitation(key, key, for_xhtml);
}
} else {
- label = keys;
+ label = wrapCitation(keys, keys, for_xhtml);
}
docstring const & after = getParam("after");
if (cmd == "nocite")
return docstring();
- BiblioInfo const & bi = buffer().masterBibInfo();
- docstring const & key_list = getParam("key");
- if (key_list.empty())
- return docstring();
+ // have to output this raw, because generateLabel() will include tags
+ xs << XHTMLStream::NextRaw() << generateLabel(true);
- // FIXME We should do a better job outputing different things for the
- // different citation styles. For now, we use square brackets for every
- // case.
- xs << "[";
- docstring const & before = getParam("before");
- if (!before.empty())
- xs << before << " ";
-
- vector<docstring> const keys = getVectorFromString(key_list);
- vector<docstring>::const_iterator it = keys.begin();
- vector<docstring>::const_iterator const en = keys.end();
- bool first = true;
- for (; it != en; ++it) {
- BiblioInfo::const_iterator const bt = bi.find(*it);
- if (bt == bi.end())
- continue;
- BibTeXInfo const & bibinfo = bt->second;
- if (!first) {
- xs << ", ";
- first = false;
- }
- docstring citekey = bibinfo.citeKey();
- if (citekey.empty()) {
- citekey = bibinfo.label();
- if (citekey.empty())
- citekey = *it;
- }
- string const attr = "href='#" + to_utf8(*it) + "'";
- xs << StartTag("a", attr) << citekey << EndTag("a");
- }
-
- docstring const & after = getParam("after");
- if (!after.empty())
- xs << ", " << after;
- xs << "]";
return docstring();
}
private:
///
Inset * clone() const { return new InsetCitation(*this); }
- /// This function does the donkey work of creating the pretty label
- docstring generateLabel() const;
- ///
- docstring complexLabel() const;
- ///
- docstring basicLabel() const;
+ /// tries to make a pretty label and makes a basic one if not
+ docstring generateLabel(bool for_xhtml = false) const;
+ /// makes a pretty label
+ docstring complexLabel(bool for_xhtml = false) const;
+ /// makes a very basic label, in case we can't make a pretty one
+ docstring basicLabel(bool for_xhtml = false) const;
/// we'll eventually want to be able to get info on this from the
/// various CiteEngines
static ParamInfo param_info_;