我喜欢该包启用彩色文本背景的方式,soul
因为它:
\hl{}
在ed 文本周围不添加填充(\colorbox
除非我们\fboxsep=0cm
在周围的组中设置)- 启用换行(不同于
\colorbox
不可破坏的)
但是,它不支持:
- 透明背景着色
- 嵌套突出显示的文本(如果背景是透明的,则这样做是有意义的)
换句话说,我正在寻找一个神奇的命令,它允许我定义自定义\mhl
突出显示命令,以便:
\documentclass{standalone}
\newcommand{\mhl}[1]{\whichCommandIsThat{black}{.2}{#1}}
\begin{document}
\begin{minipage}{3.4cm}
here is a \mhl{weird \mhl{nested, wrappable} weird} text
\end{minipage}
\end{document}
将产生:
任何想法?
答案1
编辑:请参阅最后更新的完整解决方案。
我确实通过使用包得到了部分答案tcolorbox
,其中可以实现嵌套和透明:
\documentclass{article}
\usepackage{tcolorbox}
\tcbuselibrary{skins,breakable,xparse}
\newcommand{\mhl}[1]{%
\tcbox[tcbox raise base,
left=0mm,right=0mm,top=0mm,bottom=0mm,boxsep=0.5pt,arc=0mm,
boxrule=0pt,opacityfill=0.3,enhanced jigsaw,colback=gray!85!white,
before=\relax,after=\relax]{#1}
}
\begin{document}
I say \mhl{Hello World} !
This box has a no \mhl{defined \mhl{height}} as you can see.
The total \mhl{colored box is \mhl{shrunk to the
\mhl{dimensions} of the \mhl{upper} part}. There} should be no title.
\end{document}
导致:
但它不能跨行拆分。也许可以通过xstring
逐字处理文本来模拟拆分功能……
编辑:
更好的解决方案是使用较新的listofitems
包,该包允许将 的内容拆分\mhl
为单词或内部\mhl
,然后逐个处理它们。为此,将以前的宏\mhl
调用\tcbox
重铸为内部宏\mhl@int
。换行在 \mhl 的第一级有效,但在嵌套的级中无效。
新代码:
\documentclass{article}
\usepackage{tcolorbox}
\usepackage{trimspaces}
\usepackage{listofitems}
\tcbuselibrary{skins,breakable}
%
\makeatletter
\newcommand{\trim}[1]{\trim@spaces@noexp{#1}}
\newlength{\mhl@spacelen}
\settowidth{\mhl@spacelen}{\ }
\def\mhl@space{\kern\mhl@spacelen}
\def\mhl@backspace{\kern-1.1\mhl@spacelen}
%
\newcommand{\mhl@int}[1]{%
\mhl@backspace%
\tcbox[tcbox raise base,
left=0mm,right=0mm,top=0mm,bottom=0mm,boxsep=0pt,arc=0mm,boxrule=0pt,
opacityfill=0.3,enhanced jigsaw,colback=gray!85!white,
before=\relax,after=\relax]{\trim{#1}}
}
%
\newcommand{\mhl}[1]{%
\setsepchar{ }
\ignoreemptyitems
\readlist\phrase{#1}
\foreachitem\mot\in\phrase{\mhl@int{\strut\mot\mhl@space}}
}
%
\makeatother
%
\begin{document}
I say \mhl{Hello World}! This box has a no \mhl{defined \mhl{height}}
as you can see. The total colored \mhl{box is shrunk to
the\mhl{dimensions} of the upper part. \mhl{There} should be
no lower part and no title.}
\end{document}
进一步的改进可能会使用递归调用来mhl
跟踪级别,以摆脱一些额外的空格,并将可破坏性推入嵌套的突出显示的句子中。
编辑:完整解决方案
经过一段时间,我终于得到了这个问题的完整解决方案。它仍然依赖于tcolorbox
为背景着色并使用解析文本listofitems
。由于嵌套tcolorbox
不可破坏,因此程序循环处理句子,逐字突出显示,跟踪级别,并尽可能小心地处理空格。
这是 MWE(抱歉,是法语单词,phrase=sentence,mot=word):
\documentclass{standalone}
\usepackage{listofitems}
\usepackage{xstring}
\usepackage{tcolorbox}
\tcbuselibrary{skins,breakable,xparse}
%
\makeatletter
\newlength{\mhl@spacelen}
\settowidth{\mhl@spacelen}{\space}
\def\mhl@space{\hspace*{\mhl@spacelen}}
\def\mhl@sep{\hspace{\z@}}
\newcounter{nesthl}
\newif\ifmhlstart \mhlstartfalse
\newif\ifmhlend \mhlendfalse
%
\newcommand{\mhl@int}[2]{%
\ifcase#1\def\col{black!10!white}\or\def\col{black!10!white}\or\def\col{black!50!white}\or\def\col{black!85!white}\fi%
\tcbox[tcbox raise base, spartan, left=0mm,right=0mm,top=0mm,bottom=0mm,boxsep=0pt,arc=0mm,
boxrule=0pt,before=\relax,after=\relax, opacityfill=0.35,colback=\col
]{\strut #2}}
\newcommand{\mhl}[1]{%
\setcounter{nesthl}{1}%
\def\beforeskip{}%
\setsepchar{ }\ignoreemptyitems\readlist*\phrase{#1}%
\foreachitem\mot\in\phrase{%
\IfBeginWith{\mot}{+}{\mhlstarttrue}{\mhlstartfalse}%
\IfEndWith{\mot}{+}{\mhlendtrue}{\mhlendfalse}%
\ifmhlstart \StrBehind{\mot}{+}[\nmot]\else\edef\nmot{\mot}\fi%
\ifmhlend\StrBefore{\nmot}{+}[\nnmot]\else\edef\nnmot{\nmot}\fi%
\ifmhlstart\addtocounter{nesthl}{1}\fi%
\ifmhlend \ifnum\thenesthl>1 \def\beforeskip{\mhl@space}\fi
\mhl@int{\thenesthl}{\nnmot}\mhl@sep\addtocounter{nesthl}{-1}%
\else\mhl@int{\thenesthl}{\beforeskip\nnmot\mhl@space}\mhl@sep\def\beforeskip{}\fi%
}
}
\makeatother
\begin{document}
\framebox{
\begin{minipage}{3.7cm}
here is a \mhl{weird nested, +wrappable, +dummy blob+ and nice+} text
\end{minipage}
}
\end{document}
此解决方案的关键思想在于不使用\mhl
会阻止换行的嵌套命令,而是在命令中使用简单的类似 wiki 的标记\mhl
,即+
(*
如果 、 和可能的标点符号未启用,它也可以使用)。以 开头的单词+
(无空格)会初始化一个新级别,以 结尾的单词会+
关闭此级别。 的数量+
必须是偶数,并且它们的相对位置很重要。
最大嵌套深度实际上没有限制,但要使用比这里使用的 3 级更大的深度,就必须修改宏\mhl@int
以扩大可用的阴影数量(第一行)以及opacityfill
盒子的参数。