From af9305f4ac0617be50dd18535c0b969c7cf99293 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Spitzm=C3=BCller?= Date: Sun, 20 Jul 2008 17:14:10 +0000 Subject: [PATCH] *** sanitize listing's encoding handling *** * src/Encoding.h: - new member hasFixedWidth() * src/output_latex.{cpp,h} (switchEncoding): - add option to force encoding switch * src/insets/InsetListing.cpp (latex): - force encoding switch only in multibyte context, switch the encoding properly, and add some error messages. git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@25730 a592a061-630c-0410-9148-cb99ea01b6c8 --- src/Encoding.h | 2 + src/insets/InsetListings.cpp | 91 ++++++++++++++++++++++++++++++++---- src/output_latex.cpp | 7 +-- src/output_latex.h | 9 ++-- 4 files changed, 93 insertions(+), 16 deletions(-) diff --git a/src/Encoding.h b/src/Encoding.h index 37d4608636..704e3ed611 100644 --- a/src/Encoding.h +++ b/src/Encoding.h @@ -63,6 +63,8 @@ public: std::string const & guiName() const { return guiName_; } /// std::string const & iconvName() const { return iconvName_; } + /// + bool const & hasFixedWidth() const { return fixedwidth_; } /** * Convert \p c to something that LaTeX can understand. * This is either the character itself (if it is representable diff --git a/src/insets/InsetListings.cpp b/src/insets/InsetListings.cpp index a2cb9851a4..93eaf0090c 100644 --- a/src/insets/InsetListings.cpp +++ b/src/insets/InsetListings.cpp @@ -19,12 +19,14 @@ #include "Counters.h" #include "Cursor.h" #include "DispatchResult.h" +#include "Encoding.h" #include "FuncRequest.h" #include "FuncStatus.h" #include "InsetCaption.h" #include "InsetList.h" #include "Language.h" #include "MetricsInfo.h" +#include "output_latex.h" #include "TextClass.h" #include "support/debug.h" @@ -32,6 +34,7 @@ #include "support/gettext.h" #include "support/lstrings.h" +#include "frontends/alert.h" #include "frontends/Application.h" #include @@ -134,9 +137,32 @@ int InsetListings::latex(odocstream & os, OutputParams const & runparams) const // get the paragraphs. We can not output them directly to given odocstream // because we can not yet determine the delimiter character of \lstinline docstring code; + docstring uncodable; ParagraphList::const_iterator par = paragraphs().begin(); ParagraphList::const_iterator end = paragraphs().end(); + bool encoding_switched = false; + Encoding const * const save_enc = runparams.encoding; + + if (!runparams.encoding->hasFixedWidth()) { + // We need to switch to a singlebyte encoding, since the listings + // package cannot deal with multiple-byte-encoded glyphs + Language const * const outer_language = + (runparams.local_font != 0) ? + runparams.local_font->language() + : buffer().params().language; + // We try if there's a singlebyte encoding for the current + // language; if not, fall back to latin1. + Encoding const * const lstenc = + (outer_language->encoding()->hasFixedWidth()) ? + outer_language->encoding() + : encodings.fromLyXName("iso8859-1"); + pair const c = switchEncoding(os, buffer().params(), + runparams, *lstenc, true); + runparams.encoding = lstenc; + encoding_switched = true; + } + while (par != end) { pos_type siz = par->size(); bool captionline = false; @@ -146,7 +172,28 @@ int InsetListings::latex(odocstream & os, OutputParams const & runparams) const // ignore all struck out text and (caption) insets if (par->isDeleted(i) || par->isInset(i)) continue; - code += par->getChar(i); + char_type c = par->getChar(i); + // we can only output characters covered by the current + // encoding! + try { + if (runparams.encoding->latexChar(c) == docstring(1, c)) + code += c; + else if (runparams.dryrun) { + code += "<" + _("LyX Warning: ") + + _("uncodable character") + " '"; + code += docstring(1, c); + code += "'>"; + } else + uncodable += c; + } catch (EncodingException & e) { + if (runparams.dryrun) { + code += "<" + _("LyX Warning: ") + + _("uncodable character") + " '"; + code += docstring(1, c); + code += "'>"; + } else + uncodable += c; + } } ++par; // for the inline case, if there are multiple paragraphs @@ -164,8 +211,19 @@ int InsetListings::latex(odocstream & os, OutputParams const & runparams) const // This code piece contains all possible special character? !!! // Replace ! with a warning message and use ! as delimiter. if (*delimiter == '\0') { - code = subst(code, from_ascii("!"), from_ascii(" WARNING: no lstline delimiter can be used ")); + docstring delim_error = "<" + _("LyX Warning: ") + + _("no more lstline delimiters available") + ">"; + code = subst(code, from_ascii("!"), delim_error); delimiter = lstinline_delimiters; + if (!runparams.dryrun) { + // FIXME: warning should be passed to the error dialog + frontend::Alert::warning(_("Running out of delimiters"), + _("For inline program listings, one character must be reserved\n" + "as a delimiter. One of the listings, however, uses all available\n" + "characters, so none is left for delimiting purposes.\n" + "For the time being, I have replaced '!' by a warning, but you\n" + "must investigate!")); + } } if (param_string.empty()) os << "\\lstinline" << *delimiter; @@ -175,16 +233,13 @@ int InsetListings::latex(odocstream & os, OutputParams const & runparams) const << *delimiter; } else { OutputParams rp = runparams; - // FIXME: the line below would fix bug 4182, - // but real_current_font moved to cursor. - //rp.local_font = &text_.real_current_font; rp.moving_arg = true; docstring const caption = getCaption(rp); runparams.encoding = rp.encoding; if (param_string.empty() && caption.empty()) - os << "\n\\begingroup\n\\inputencoding{latin1}\n\\begin{lstlisting}\n"; + os << "\n\\begin{lstlisting}\n"; else { - os << "\n\\begingroup\n\\inputencoding{latin1}\n\\begin{lstlisting}["; + os << "\n\\begin{lstlisting}["; if (!caption.empty()) { os << "caption={" << caption << '}'; if (!param_string.empty()) @@ -192,9 +247,25 @@ int InsetListings::latex(odocstream & os, OutputParams const & runparams) const } os << from_utf8(param_string) << "]\n"; } - lines += 4; - os << code << "\n\\end{lstlisting}\n\\endgroup\n"; - lines += 3; + lines += 2; + os << code << "\n\\end{lstlisting}\n"; + lines += 2; + } + + if (encoding_switched){ + // Switch back + pair const c = switchEncoding(os, buffer().params(), + runparams, *save_enc, true); + runparams.encoding = save_enc; + } + + if (!uncodable.empty()) { + // issue a warning about omitted characters + // FIXME: should be passed to the error dialog + frontend::Alert::warning(_("Uncodable characters in listings inset"), + bformat(_("The following characters in one of the program listings are\n" + "not representable in the current encoding and have been omitted:\n%1$s."), + uncodable)); } return lines; diff --git a/src/output_latex.cpp b/src/output_latex.cpp index 0391e6d1ee..4ffcda59a8 100644 --- a/src/output_latex.cpp +++ b/src/output_latex.cpp @@ -870,12 +870,13 @@ void latexParagraphs(Buffer const & buf, pair switchEncoding(odocstream & os, BufferParams const & bparams, - OutputParams const & runparams, Encoding const & newEnc) + OutputParams const & runparams, Encoding const & newEnc, + bool force) { Encoding const oldEnc = *runparams.encoding; bool moving_arg = runparams.moving_arg; - if ((bparams.inputenc != "auto" && bparams.inputenc != "default") - || moving_arg) + if (!force && ((bparams.inputenc != "auto" && bparams.inputenc != "default") + || moving_arg)) return make_pair(false, 0); // Do nothing if the encoding is unchanged. diff --git a/src/output_latex.h b/src/output_latex.h index b347f261bd..3f22a159d7 100644 --- a/src/output_latex.h +++ b/src/output_latex.h @@ -44,11 +44,14 @@ void latexParagraphs(Buffer const & buf, OutputParams const &, std::string const & everypar = std::string()); -/// Switch the encoding of \p os from runparams.encoding to \p newEnc if needed. -/// \return (did the encoding change?, number of characters written to \p os) +/** Switch the encoding of \p os from runparams.encoding to \p newEnc if needed. + \p force forces this also within non-default or -auto encodings. + \return (did the encoding change?, number of characters written to \p os) + */ std::pair switchEncoding(odocstream & os, BufferParams const & bparams, - OutputParams const &, Encoding const & newEnc); + OutputParams const &, Encoding const & newEnc, + bool force = false); } // namespace lyx