#include "InsetCitation.h"
+#include "BiblioInfo.h"
#include "Buffer.h"
#include "buffer_funcs.h"
#include "BufferParams.h"
#include "BufferView.h"
#include "DispatchResult.h"
+#include "FuncCode.h"
#include "FuncRequest.h"
#include "LaTeXFeatures.h"
#include "output_xhtml.h"
InsetCitation::InsetCitation(Buffer * buf, InsetCommandParams const & p)
- : InsetCommand(buf, p, "citation")
+ : InsetCommand(buf, p)
{}
}
+void InsetCitation::doDispatch(Cursor & cur, FuncRequest & cmd)
+{
+ if (cmd.action() == LFUN_INSET_MODIFY)
+ cache.recalculate = true;
+ InsetCommand::doDispatch(cur, cmd);
+}
+
+
docstring InsetCitation::toolTip(BufferView const & bv, int, int) const
{
Buffer const & buf = bv.buffer();
vector<docstring>::const_iterator en = keys.end();
docstring tip;
for (; it != en; ++it) {
- docstring const key_info = bi.getInfo(*it);
+ docstring const key_info = bi.getInfo(*it, buffer());
if (key_info.empty())
continue;
if (!tip.empty())
namespace {
-
+
// FIXME See the header for the issue.
-string defaultCiteCommand(CiteEngine engine)
+string defaultCiteCommand(CiteEngine engine, CiteEngineType engine_type)
{
string str;
switch (engine) {
case ENGINE_BASIC:
str = "cite";
break;
- case ENGINE_NATBIB_AUTHORYEAR:
- str = "citet";
- break;
- case ENGINE_NATBIB_NUMERICAL:
- str = "citep";
+ case ENGINE_NATBIB:
+ if (engine_type == ENGINE_TYPE_AUTHORYEAR)
+ str = "citet";
+ else
+ str = "citep";
break;
case ENGINE_JURABIB:
str = "cite";
return str;
}
-
-string asValidLatexCommand(string const & input, CiteEngine const engine)
+
+string asValidLatexCommand(string const & input, CiteEngine const engine,
+ CiteEngineType const engine_type)
{
- string const default_str = defaultCiteCommand(engine);
+ string const default_str = defaultCiteCommand(engine, engine_type);
if (!InsetCitation::isCompatibleCommand(input))
return default_str;
output = default_str;
break;
- case ENGINE_NATBIB_AUTHORYEAR:
- case ENGINE_NATBIB_NUMERICAL:
+ case ENGINE_NATBIB:
if (input == "cite" || input == "citefield"
|| input == "citetitle" || input == "cite*")
output = default_str;
}
-inline docstring wrapCitation(docstring const & key,
+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>";
+ return "<a href='#" + key + "'>" +
+ html::htmlize(content, XHTMLStream::ESCAPE_ALL) + "</a>";
}
} // anonymous namespace
// CITE: author/<before field>
CiteEngine const engine = buffer().params().citeEngine();
+ CiteEngineType const engine_type = buffer().params().citeEngineType();
// We don't currently use the full or forceUCase fields.
- string cite_type = asValidLatexCommand(getCmdName(), engine);
+ string cite_type = asValidLatexCommand(getCmdName(), engine, engine_type);
if (cite_type[0] == 'C')
// If we were going to use them, this would mean ForceUCase
cite_type = string(1, 'c') + cite_type.substr(1);
else
label += wrapCitation(*it, author, for_xhtml) + sep_str;
}
- }
+ }
// nocite
else if (cite_type == "nocite") {
label += *it + sep_str;
- }
+ }
// (authors1 (<before> year); ... ;
// authors_last (<before> year, <after>)
else if (cite_type == "citet") {
switch (engine) {
- case ENGINE_NATBIB_AUTHORYEAR:
- label += author + op_str + before_str +
- wrapCitation(*it, year, for_xhtml) + cp + sep_str;
- break;
- case ENGINE_NATBIB_NUMERICAL:
- label += author + op_str + before_str +
- wrapCitation(*it, citenum, for_xhtml) + cp + sep_str;
+ case ENGINE_NATBIB:
+ if (engine_type == ENGINE_TYPE_AUTHORYEAR)
+ label += author + op_str + before_str +
+ wrapCitation(*it, year, for_xhtml) + cp + sep_str;
+ else
+ label += author + op_str + before_str +
+ wrapCitation(*it, citenum, for_xhtml) + cp + sep_str;
break;
case ENGINE_JURABIB:
label += before_str + author + op_str +
case ENGINE_BASIC:
break;
}
- }
- // author, year; author, year; ...
+ }
+ // author, year; author, year; ...
else if (cite_type == "citep" ||
cite_type == "citealp") {
- if (engine == ENGINE_NATBIB_NUMERICAL) {
+ if (engine_type == ENGINE_TYPE_NUMERICAL) {
label += wrapCitation(*it, citenum, for_xhtml) + sep_str;
} else {
label += wrapCitation(*it, author + ", " + year, for_xhtml) + sep_str;
}
- }
+ }
// (authors1 <before> year;
// authors_last <before> year, <after>)
else if (cite_type == "citealt") {
switch (engine) {
- case ENGINE_NATBIB_AUTHORYEAR:
- label += author + ' ' + before_str +
- wrapCitation(*it, year, for_xhtml) + sep_str;
- break;
- case ENGINE_NATBIB_NUMERICAL:
- label += author + ' ' + before_str + '#' +
- wrapCitation(*it, citenum, for_xhtml) + sep_str;
+ case ENGINE_NATBIB:
+ if (engine_type == ENGINE_TYPE_AUTHORYEAR)
+ label += author + ' ' + before_str +
+ wrapCitation(*it, year, for_xhtml) + sep_str;
+ else
+ label += author + ' ' + before_str + '#' +
+ wrapCitation(*it, citenum, for_xhtml) + sep_str;
break;
case ENGINE_JURABIB:
- label += before_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 += wrapCitation(*it, author, for_xhtml) + sep_str;
label.insert(label.size() - 1, after_str);
} else {
bool const add =
- !(engine == ENGINE_NATBIB_NUMERICAL &&
+ !(engine == ENGINE_NATBIB &&
+ engine_type == ENGINE_TYPE_NUMERICAL &&
(cite_type == "citeauthor" ||
cite_type == "citeyear"));
if (add)
label = before_str + label;
}
- if (cite_type == "citep" || cite_type == "citeyearpar" ||
+ if (cite_type == "citep" || cite_type == "citeyearpar" ||
(cite_type == "cite" && engine == ENGINE_BASIC) )
label = op + label + cp;
docstring keys = getParam("key");
docstring label;
- if (contains(keys, ',')) {
- // Final comma allows while loop to cover all keys
- keys = ltrim(split(keys, label, ',')) + ',';
- while (contains(keys, ',')) {
- docstring key;
- keys = ltrim(split(keys, key, ','));
- label += ", " + wrapCitation(key, key, for_xhtml);
- }
- } else {
- label = wrapCitation(keys, keys, for_xhtml);
- }
+ docstring key;
+ do {
+ // if there is no comma, then everything goes into key
+ // and keys will be empty.
+ keys = trim(split(keys, key, ','));
+ key = trim(key);
+ if (!label.empty())
+ label += ", ";
+ label += wrapCitation(key, key, for_xhtml);
+ } while (!keys.empty());
docstring const & after = getParam("after");
if (!after.empty())
}
-void InsetCitation::updateLabels(ParIterator const &, bool)
+void InsetCitation::updateBuffer(ParIterator const &, UpdateType)
{
- CiteEngine const engine = buffer().params().citeEngine();
- if (cache.params == params() && cache.engine == engine)
+ if (!cache.recalculate && buffer().citeLabelsValid())
return;
- // The label has changed, so we have to re-create it.
+ // The label may have changed, so we have to re-create it.
docstring const glabel = generateLabel();
unsigned int const maxLabelChars = 45;
docstring label = glabel;
if (label.size() > maxLabelChars) {
- label.erase(maxLabelChars-3);
+ label.erase(maxLabelChars - 3);
label += "...";
}
- cache.engine = engine;
- cache.params = params();
+ cache.recalculate = false;
cache.generated_label = glabel;
cache.screen_label = label;
}
-void InsetCitation::addToToc(DocIterator const & cpit)
+void InsetCitation::addToToc(DocIterator const & cpit) const
{
+ // NOTE
+ // XHTML output uses the TOC to collect the citations
+ // from the document. So if this gets changed, then we
+ // will need to change how the citations are collected.
+ docstring const tocitem = getParam("key");
Toc & toc = buffer().tocBackend().toc("citation");
- toc.push_back(TocItem(cpit, 0, getParam("key")));
+ toc.push_back(TocItem(cpit, 0, tocitem));
}
return docstring();
// have to output this raw, because generateLabel() will include tags
- xs << XHTMLStream::NextRaw() << generateLabel(true);
+ xs << XHTMLStream::ESCAPE_NONE << generateLabel(true);
return docstring();
}
-void InsetCitation::tocString(odocstream & os) const
+void InsetCitation::toString(odocstream & os) const
{
plaintext(os, OutputParams(0));
}
+void InsetCitation::forToc(docstring & os, size_t) const
+{
+ os += screenLabel();
+}
+
+
// Have to overwrite the default InsetCommand method in order to check that
// the \cite command is valid. Eg, the user has natbib enabled, inputs some
// citations and then changes his mind, turning natbib support off. The output
// should revert to \cite[]{}
-int InsetCitation::latex(odocstream & os, OutputParams const & runparams) const
+void InsetCitation::latex(otexstream & os, OutputParams const & runparams) const
{
CiteEngine cite_engine = buffer().params().citeEngine();
+ CiteEngineType cite_engine_type = buffer().params().citeEngineType();
+ BiblioInfo const & bi = buffer().masterBibInfo();
// FIXME UNICODE
docstring const cite_str = from_utf8(
- asValidLatexCommand(getCmdName(), cite_engine));
+ asValidLatexCommand(getCmdName(), cite_engine, cite_engine_type));
if (runparams.inulemcmd)
os << "\\mbox{";
else if (!after.empty())
os << '[' << after << ']';
- os << '{' << cleanupWhitespace(getParam("key")) << '}';
+ if (!bi.isBibtex(getParam("key")))
+ // escape chars with bibitems
+ os << '{' << escape(cleanupWhitespace(getParam("key"))) << '}';
+ else
+ os << '{' << cleanupWhitespace(getParam("key")) << '}';
if (runparams.inulemcmd)
os << "}";
-
- return 0;
}
switch (features.bufferParams().citeEngine()) {
case ENGINE_BASIC:
break;
- case ENGINE_NATBIB_AUTHORYEAR:
- case ENGINE_NATBIB_NUMERICAL:
+ case ENGINE_NATBIB:
features.require("natbib");
break;
case ENGINE_JURABIB:
}
-docstring InsetCitation::contextMenu(BufferView const &, int, int) const
+string InsetCitation::contextMenuName() const
{
- return from_ascii("context-citation");
+ return "context-citation";
}