commit 2ba584957cf11c80ecaf360bc8f7559c76e79a01
Author: Juergen Spitzmueller <[email protected]>
Date: Fri Apr 13 17:46:37 2018 +0200
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 e4ba2ed..a3e3518 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 7b81ff8..ab1092e 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 2fbba56..fc71a6c 100644
--- a/lib/doc/LaTeXConfig.lyx
+++ b/lib/doc/LaTeXConfig.lyx
@@ -7070,6 +7070,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 b66b1ca..31f53c5 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 85f3009..146fddb 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 56741ad..b7ce543 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 84fcf75..2a308d6 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 ecd171d..f6df439 100644
--- a/src/insets/Inset.h
+++ b/src/insets/Inset.h
@@ -595,6 +595,9 @@ public:
virtual void rejectChanges() {}
///
+ virtual bool needsCProtection() const { return false; }
+
+ ///
virtual ColorCode backgroundColor(PainterInfo const &) const;
///
virtual ColorCode labelColor() const;
diff --git a/src/insets/InsetLayout.cpp b/src/insets/InsetLayout.cpp
index 621e784..ef8e7d3 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 c4a12a4..b48ea7c 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 b19b384..4c560f4 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<InsetText::XHTMLOptions>((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 eea88cd..537c8bb 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 c91c069..f8da22c 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