http://www.lyx.org/trac/ticket/6534
This post on lyx-docs http://marc.info/?l=lyx-docs&m=126595372224033&w=2 pointed me towards various unicode problems in the bibitem inset. Two issues: 1. if the label of a bibitem has a unicode glyph that is unknown to the output encoding, this has to be transformed to proper LaTeX. 2. if the key has a unicode glyph, this needs to be escaped both in the bibitem and the citation macros. Currenty, a unicode glyph (outside the output file's encoding) either in the label or in the key yields a silent iconv error (the document is not output, but the user gets no warning either). The attached patch against branch solves both issues. Objections, comments? Jürgen
Index: src/insets/InsetBibitem.cpp =================================================================== --- src/insets/InsetBibitem.cpp (Revision 33420) +++ src/insets/InsetBibitem.cpp (Arbeitskopie) @@ -20,10 +20,12 @@ #include "BufferView.h" #include "Counters.h" #include "DispatchResult.h" +#include "Encoding.h" #include "FuncRequest.h" #include "InsetIterator.h" #include "InsetList.h" #include "Lexer.h" +#include "OutputParams.h" #include "Paragraph.h" #include "ParagraphList.h" #include "TextClass.h" @@ -31,6 +33,7 @@ #include "frontends/alert.h" #include "support/convert.h" +#include "support/debug.h" #include "support/docstream.h" #include "support/gettext.h" #include "support/lstrings.h" @@ -170,8 +173,48 @@ } +int InsetBibitem::latex(odocstream & os, OutputParams const & runparams) const +{ + docstring cmd = '\\' + from_ascii(defaultCommand()); + docstring uncodable; + if (!getParam("label").empty()) { + cmd += '['; + docstring orig = getParam("label"); + for (size_t n = 0; n < orig.size(); ++n) { + try { + cmd += runparams.encoding->latexChar(orig[n]); + } catch (EncodingException & /* e */) { + LYXERR0("Uncodable character in bibitem!"); + if (runparams.dryrun) { + cmd += "<" + _("LyX Warning: ") + + _("uncodable character") + " '"; + cmd += docstring(1, orig[n]); + cmd += "'>"; + } else + uncodable += orig[n]; + } + } + cmd += ']'; + } + cmd += '{' + escape(getParam("key")) + '}'; + + os << cmd; + + if (!uncodable.empty()) { + // issue a warning about omitted characters + // FIXME: should be passed to the error dialog + frontend::Alert::warning(_("Uncodable characters in bibliography item"), + bformat(_("The following characters in one of the bibliography items are\n" + "not representable in the current encoding and have been omitted:\n%1$s."), + uncodable)); + } + + return 0; +} + + // ale070405 -docstring bibitemWidest(Buffer const & buffer) +docstring bibitemWidest(Buffer const & buffer, OutputParams const & runparams) { int w = 0; @@ -228,8 +271,23 @@ w = wx; } - if (bitem && !bitem->bibLabel().empty()) - return bitem->bibLabel(); + if (bitem && !bitem->bibLabel().empty()) { + docstring lbl = bitem->bibLabel(); + docstring latex_lbl; + for (size_t n = 0; n < lbl.size(); ++n) { + try { + latex_lbl += runparams.encoding->latexChar(lbl[n]); + } catch (EncodingException & /* e */) { + if (runparams.dryrun) { + latex_lbl += "<" + _("LyX Warning: ") + + _("uncodable character") + " '"; + latex_lbl += docstring(1, lbl[n]); + latex_lbl += "'>"; + } + } + } + return latex_lbl; + } return from_ascii("99"); } Index: src/insets/InsetBibitem.h =================================================================== --- src/insets/InsetBibitem.h (Revision 33420) +++ src/insets/InsetBibitem.h (Arbeitskopie) @@ -61,6 +61,8 @@ /// int plaintext(odocstream &, OutputParams const &) const; /// + int latex(odocstream &, OutputParams const &) const; + /// virtual void fillWithBibKeys(BiblioInfo &, InsetIterator const &) const; /// Update the counter of this inset virtual void updateLabels(ParIterator const &); @@ -71,7 +73,7 @@ /// Inset * clone() const { return new InsetBibitem(*this); } - friend docstring bibitemWidest(Buffer const & buffer); + friend docstring bibitemWidest(Buffer const & buffer, OutputParams const &); /// The label that is set by updateLabels docstring autolabel_; /// @@ -80,7 +82,7 @@ /// Return the widest label in the Bibliography. -docstring bibitemWidest(Buffer const &); +docstring bibitemWidest(Buffer const &, OutputParams const &); } // namespace lyx Index: src/insets/InsetCitation.cpp =================================================================== --- src/insets/InsetCitation.cpp (Revision 33420) +++ src/insets/InsetCitation.cpp (Arbeitskopie) @@ -517,6 +517,7 @@ int InsetCitation::latex(odocstream & os, OutputParams const &) const { CiteEngine cite_engine = buffer().params().citeEngine(); + BiblioInfo const & bi = buffer().masterBibInfo(); // FIXME UNICODE docstring const cite_str = from_utf8( asValidLatexCommand(getCmdName(), cite_engine)); @@ -530,7 +531,11 @@ 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")) << '}'; return 0; } Index: src/BiblioInfo.h =================================================================== --- src/BiblioInfo.h (Revision 33420) +++ src/BiblioInfo.h (Arbeitskopie) @@ -53,6 +53,8 @@ /// constructor that sets the entryType BibTeXInfo(docstring const & key, docstring const & type); /// + bool isBibtex() const { return is_bibtex_; } + /// bool hasField(docstring const & field) const; /// return the short form of an authorlist docstring const getAbbreviatedAuthor() const; @@ -126,6 +128,9 @@ /// Empty if no info exists. /// Note that this will retrieve data from the crossref as needed. docstring const getInfo(docstring const & key) const; + /// Is this a reference from a bibtex database + /// or from a bibliography environment? + bool const isBibtex(docstring const & key) const; /** * "Translates" the available Citation Styles into strings for a given key, Index: src/BiblioInfo.cpp =================================================================== --- src/BiblioInfo.cpp (Revision 33420) +++ src/BiblioInfo.cpp (Arbeitskopie) @@ -472,6 +472,16 @@ } +bool const BiblioInfo::isBibtex(docstring const & key) const +{ + BiblioInfo::const_iterator it = find(key); + if (it == end()) + return false; + return it->second.isBibtex(); +} + + + vector<docstring> const BiblioInfo::getCiteStrings( docstring const & key, Buffer const & buf) const { Index: src/output_latex.cpp =================================================================== --- src/output_latex.cpp (Revision 33420) +++ src/output_latex.cpp (Arbeitskopie) @@ -189,7 +189,7 @@ << "}\n"; } else if (style.labeltype == LABEL_BIBLIO) { // ale970405 - os << '{' << bibitemWidest(buf) << "}\n"; + os << '{' << bibitemWidest(buf, runparams) << "}\n"; } else os << from_ascii(style.latexparam()) << '\n'; texrow.newline();