From 2ba584957cf11c80ecaf360bc8f7559c76e79a01 Mon Sep 17 00:00:00 2001 From: Juergen Spitzmueller Date: Fri, 13 Apr 2018 17:46:37 +0200 Subject: [PATCH] Add basic support for cprotect This allows (some) verbatim contents in macros, such as \url's with specific chars (#, % etc.) in section headings or footnotes (#449) or comments in captions (#9313). The mentioned two bugs are fixed by this commit. Note that the implementation is still rather basic and might need extension for other cases. --- lib/chkconfig.ltx | 1 + lib/doc/Customization.lyx | 73 ++++++++++++++++++++++++++++++++++++++ lib/doc/LaTeXConfig.lyx | 28 +++++++++++++++ lib/layouts/stdinsets.inc | 2 ++ src/LaTeXFeatures.cpp | 1 + src/Paragraph.cpp | 13 +++++++ src/Paragraph.h | 3 ++ src/insets/Inset.h | 3 ++ src/insets/InsetLayout.cpp | 9 +++-- src/insets/InsetLayout.h | 4 +++ src/insets/InsetText.cpp | 48 ++++++++++++++++++++++++- src/insets/InsetText.h | 5 +++ src/output_latex.cpp | 2 ++ 13 files changed, 189 insertions(+), 3 deletions(-) diff --git a/lib/chkconfig.ltx b/lib/chkconfig.ltx index e4ba2edce8..a3e3518859 100644 --- a/lib/chkconfig.ltx +++ b/lib/chkconfig.ltx @@ -299,6 +299,7 @@ \TestPackage{chicago} \TestPackage{color} % this one should be there if graphics.sty is there. \TestPackage{covington} +\TestPackage{cprotect} \TestPackage{csquotes} \TestPackage[koi8-r.def]{cyrillic} \TestPackage{dvipost} diff --git a/lib/doc/Customization.lyx b/lib/doc/Customization.lyx index 7b81ff850e..ab1092e8cb 100644 --- a/lib/doc/Customization.lyx +++ b/lib/doc/Customization.lyx @@ -19663,6 +19663,79 @@ protect not \emph default whether the command should itself be protected.) Default is false. +\change_inserted -712698321 1523633958 + +\end_layout + +\begin_layout Description + +\change_inserted -712698321 1523634088 +\begin_inset Flex Code +status collapsed + +\begin_layout Plain Layout + +\change_inserted -712698321 1523633961 +NeedCProtect +\end_layout + +\end_inset + + [ +\begin_inset Flex Code +status collapsed + +\begin_layout Plain Layout + +\change_inserted -712698321 1523633958 + +\emph on +0 +\end_layout + +\end_inset + +, +\begin_inset space \thinspace{} +\end_inset + + +\begin_inset Flex Code +status collapsed + +\begin_layout Plain Layout + +\change_inserted -712698321 1523633958 +1 +\end_layout + +\end_inset + +] This causes macros that contain this inset to be protected with +\begin_inset Flex Code +status collapsed + +\begin_layout Plain Layout + +\change_inserted -712698321 1523634038 + +\backslash +cprotect +\change_unchanged + +\end_layout + +\end_inset + + (cf. + package +\family sans +cprotect +\family default +) if necessary and thus allows (some) verbatim stuff in macros. + Default is false. +\change_unchanged + \end_layout \begin_layout Description diff --git a/lib/doc/LaTeXConfig.lyx b/lib/doc/LaTeXConfig.lyx index 2fbba56ab9..fc71a6c3bc 100644 --- a/lib/doc/LaTeXConfig.lyx +++ b/lib/doc/LaTeXConfig.lyx @@ -7069,6 +7069,34 @@ cancelto . \end_layout +\begin_layout Subsection +cprotect +\end_layout + +\begin_layout Description +Found: +\begin_inset Info +type "package" +arg "cprotect" +\end_inset + + +\end_layout + +\begin_layout Description +CTAN: +\family typewriter +macros/latex/contrib/cprotect/ +\end_layout + +\begin_layout Description +Notes: The package +\family sans +cprotect +\family default + is used to allow (some) verbatim stuff in macros. +\end_layout + \begin_layout Subsection CJKutf8 \end_layout diff --git a/lib/layouts/stdinsets.inc b/lib/layouts/stdinsets.inc index b66b1caee2..31f53c585a 100644 --- a/lib/layouts/stdinsets.inc +++ b/lib/layouts/stdinsets.inc @@ -150,6 +150,7 @@ InsetLayout Note:Comment EndHTMLStyle AddToToc note IsTocCaption true + NeedCProtect true End @@ -552,6 +553,7 @@ InsetLayout "Flex:URL" PassThru true FreeSpacing true ForceLTR true + NeedCProtect true Font Family Typewriter Color urltext diff --git a/src/LaTeXFeatures.cpp b/src/LaTeXFeatures.cpp index 85f3009eed..146fddb217 100644 --- a/src/LaTeXFeatures.cpp +++ b/src/LaTeXFeatures.cpp @@ -908,6 +908,7 @@ char const * simplefeatures[] = { // note that the package order here will be the same in the LaTeX-output "array", "verbatim", + "cprotect", "longtable", "rotating", "latexsym", diff --git a/src/Paragraph.cpp b/src/Paragraph.cpp index 56741ad20f..b7ce543caf 100644 --- a/src/Paragraph.cpp +++ b/src/Paragraph.cpp @@ -1694,6 +1694,8 @@ void Paragraph::write(ostream & os, BufferParams const & bparams, void Paragraph::validate(LaTeXFeatures & features) const { d->validate(features); + if (needsCProtection()) + features.require("cprotect"); } @@ -3376,6 +3378,17 @@ bool Paragraph::isHardHyphenOrApostrophe(pos_type pos) const } +bool Paragraph::needsCProtection() const +{ + pos_type size = d->text_.size(); + for (pos_type i = 0; i < size; ++i) + if (isInset(i)) + return getInset(i)->needsCProtection(); + + return false; +} + + FontSpan const & Paragraph::getSpellRange(pos_type pos) const { return d->speller_state_.getRange(pos); diff --git a/src/Paragraph.h b/src/Paragraph.h index 84fcf759e2..2a308d6efa 100644 --- a/src/Paragraph.h +++ b/src/Paragraph.h @@ -424,6 +424,9 @@ public: /// True if the element at this point is a hard hyphen or a apostrophe /// If it is enclosed by spaces return false bool isHardHyphenOrApostrophe(pos_type pos) const; + /// Return true if this paragraph has verbatim content that needs to be + /// protected by \cprotect + bool needsCProtection() const; /// returns true if at least one line break or line separator has been deleted /// at the beginning of the paragraph (either physically or logically) diff --git a/src/insets/Inset.h b/src/insets/Inset.h index ecd171dc45..f6df439b3b 100644 --- a/src/insets/Inset.h +++ b/src/insets/Inset.h @@ -594,6 +594,9 @@ public: /// reject the changes within the inset virtual void rejectChanges() {} + /// + virtual bool needsCProtection() const { return false; } + /// virtual ColorCode backgroundColor(PainterInfo const &) const; /// diff --git a/src/insets/InsetLayout.cpp b/src/insets/InsetLayout.cpp index 621e784174..ef8e7d3f66 100644 --- a/src/insets/InsetLayout.cpp +++ b/src/insets/InsetLayout.cpp @@ -42,8 +42,8 @@ InsetLayout::InsetLayout() : htmlisblock_(true), multipar_(true), custompars_(true), forceplain_(false), passthru_(false), parbreakisnewline_(false), freespacing_(false), keepempty_(false), forceltr_(false), - forceownlines_(false), needprotect_(false), intoc_(false), - spellcheck_(true), resetsfont_(false), display_(true), + forceownlines_(false), needprotect_(false), needcprotect_(false), + intoc_(false), spellcheck_(true), resetsfont_(false), display_(true), forcelocalfontswitch_(false), add_to_toc_(false), is_toc_caption_(false) { labelfont_.setColor(Color_error); @@ -119,6 +119,7 @@ bool InsetLayout::read(Lexer & lex, TextClass const & tclass) IL_OBSOLETEDBY, IL_KEEPEMPTY, IL_MULTIPAR, + IL_NEEDCPROTECT, IL_NEEDPROTECT, IL_PASSTHRU, IL_PASSTHRU_CHARS, @@ -174,6 +175,7 @@ bool InsetLayout::read(Lexer & lex, TextClass const & tclass) { "leftdelim", IL_LEFTDELIM }, { "lyxtype", IL_LYXTYPE }, { "multipar", IL_MULTIPAR }, + { "needcprotect", IL_NEEDCPROTECT }, { "needprotect", IL_NEEDPROTECT }, { "obsoletedby", IL_OBSOLETEDBY }, { "parbreakisnewline", IL_PARBREAKISNEWLINE }, @@ -322,6 +324,9 @@ bool InsetLayout::read(Lexer & lex, TextClass const & tclass) case IL_NEEDPROTECT: lex >> needprotect_; break; + case IL_NEEDCPROTECT: + lex >> needcprotect_; + break; case IL_CONTENTASLABEL: lex >> contentaslabel_; break; diff --git a/src/insets/InsetLayout.h b/src/insets/InsetLayout.h index c4a12a4018..b48ea7c290 100644 --- a/src/insets/InsetLayout.h +++ b/src/insets/InsetLayout.h @@ -162,6 +162,8 @@ public: /// bool isNeedProtect() const { return needprotect_; } /// + bool needsCProtect() const { return needcprotect_; } + /// bool isFreeSpacing() const { return freespacing_; } /// bool isKeepEmpty() const { return keepempty_; } @@ -283,6 +285,8 @@ private: bool forceownlines_; /// bool needprotect_; + /// + bool needcprotect_; /// should the contents be written to TOC strings? bool intoc_; /// check spelling of this inset? diff --git a/src/insets/InsetText.cpp b/src/insets/InsetText.cpp index b19b3841ae..4c560f492c 100644 --- a/src/insets/InsetText.cpp +++ b/src/insets/InsetText.cpp @@ -458,7 +458,9 @@ void InsetText::latex(otexstream & os, OutputParams const & runparams) const // FIXME UNICODE // FIXME \protect should only be used for fragile // commands, but we do not provide this information yet. - if (runparams.moving_arg) + if (hasCProtectContent()) + os << "\\cprotect"; + else if (runparams.moving_arg) os << "\\protect"; os << '\\' << from_utf8(il.latexname()); if (!il.latexargs().empty()) @@ -760,6 +762,19 @@ ParagraphList & InsetText::paragraphs() } +bool InsetText::hasCProtectContent() const +{ + ParagraphList const & pars = paragraphs(); + pit_type pend = paragraphs().size(); + for (pit_type pit = 0; pit != pend; ++pit) { + Paragraph const & par = pars[pit]; + if (par.needsCProtection()) + return true; + } + return false; +} + + bool InsetText::insetAllowed(InsetCode code) const { switch (code) { @@ -1070,4 +1085,35 @@ InsetText::XHTMLOptions operator|(InsetText::XHTMLOptions a1, InsetText::XHTMLOp return static_cast((int)a1 | (int)a2); } + +bool InsetText::needsCProtection() const +{ + if (!getLayout().needsCProtect()) + return false; + + // Environments need cprotection regardless the content + if (getLayout().latextype() == InsetLayout::ENVIRONMENT) + return true; + + // Commands need cprotection if they contain specific chars + int const nchars_escape = 9; + static char_type const chars_escape[nchars_escape] = { + '&', '_', '$', '%', '#', '^', '{', '}', '\\'}; + + ParagraphList const & pars = paragraphs(); + pit_type pend = paragraphs().size(); + + for (pit_type pit = 0; pit != pend; ++pit) { + Paragraph const & par = pars[pit]; + if (par.needsCProtection()) + return true; + docstring const pars = par.asString(); + for (int k = 0; k < nchars_escape; k++) { + if (contains(pars, chars_escape[k])) + return true; + } + } + return false; +} + } // namespace lyx diff --git a/src/insets/InsetText.h b/src/insets/InsetText.h index eea88cdd69..537c8bbfb5 100644 --- a/src/insets/InsetText.h +++ b/src/insets/InsetText.h @@ -223,6 +223,9 @@ public: /// bool confirmDeletion() const { return !text().empty(); } + /// + bool needsCProtection() const; + protected: /// void iterateForToc(DocIterator const & cdit, bool output_active, @@ -238,6 +241,8 @@ private: void closeAddToTocForParagraph(pit_type start, pit_type end, TocBackend & backend) const; /// + bool hasCProtectContent() const; + /// bool drawFrame_; /// ColorCode frame_color_; diff --git a/src/output_latex.cpp b/src/output_latex.cpp index c91c06981a..f8da22ca5c 100644 --- a/src/output_latex.cpp +++ b/src/output_latex.cpp @@ -654,6 +654,8 @@ void parStartCommand(Paragraph const & par, otexstream & os, { switch (style.latextype) { case LATEX_COMMAND: + if (par.needsCProtection()) + os << "\\cprotect"; os << '\\' << from_ascii(style.latexname()); // Command arguments -- 2.39.2