\NeedsTeXFormat{LaTeX2e}[1994/06/01] \ProvidesPackage{highlightlatex}[2021/03/14] % Repository: https://github.com/vkuhlmann/highlight-latex % Copyright (c) 2021 Vincent Kuhlmann % % Permission is hereby granted, free of charge, to any person % obtaining a copy of this software and associated documentation % files (the "Software"), to deal in the Software without % restriction, including without limitation the rights to use, % copy, modify, merge, publish, distribute, sublicense, and/or sell % copies of the Software, and to permit persons to whom the % Software is furnished to do so, subject to the following % conditions: % % The above copyright notice and this permission notice shall be % included in all copies or substantial portions of the Software. % % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, % EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES % OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND % NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT % HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, % WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING % FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR % OTHER DEALINGS IN THE SOFTWARE. \RequirePackage{listings} \RequirePackage{xcolor} \RequirePackage{xkeyval} \RequirePackage{etoolbox} % Snippet source: % https://tex.stackexchange.com/questions/406015/defining-macro-gsetlength-as-global-setlength-reliable \gdef\gsetlength#1#2{% \begingroup \setlength\skip@{#2}% \global#1=\skip@ \endgroup } \def\@highlight@frame{none} \newlength{\hll@offset@fixskip} \setlength{\hll@offset@fixskip}{0pt} \newif\ifhllStyleAnywhere \newcommand\defaultgobble{0} \newif\ifhllDebugFrame %\hllDebugFrametrue \newlength\hllBeforeSkip \setlength\hllBeforeSkip{2pt} \newlength\hllAfterSkip \setlength\hllAfterSkip{0pt} \DeclareOptionX{frame}{ \setframe{#1} } \DeclareOptionX{noframe}{ \setframe{none} } \def\setframe#1{% \def\frameval{#1}% \ifx\relax#1\relax \def\frameval{lines}% \fi \def\linesvalue{lines}% % \xdef\@highlight@frame{\frameval}% % \ifx\frameval\linesvalue \gsetlength{\hll@offset@fixskip}{6pt}% \else \gsetlength{\hll@offset@fixskip}{0pt}% \fi } \DeclareOptionX{styleanywhere}{ \hllStyleAnywheretrue } \DeclareOptionX*{\PackageWarning{highlight-latex}{`\CurrentOption' ignored}} \ExecuteOptionsX{frame=lines} \ProcessOptionsX\relax \colorlet{curlyBrackets}{red!50!blue} \colorlet{squareBrackets}{blue!50!white} \colorlet{codeBackground}{gray!10!white} \colorlet{comment}{green!40!black} \colorlet{accDefault}{blue!90!black} \definecolor{accStructure}{RGB}{0,149,255} \colorlet{accentB}{green!60!black} \catcode`\{=11 \let\myopenbrace={ \catcode`\{=1 \catcode`\}=11 \let\myclosebrace=} \catcode`\}=2 \lstdefinelanguage{ColoredLaTeX} [LaTeX]{TeX}{ backgroundcolor=\color{codeBackground}, keywordstyle=\bfseries\color{accDefault}, basicstyle=\footnotesize\ttfamily, commentstyle=\color{comment}, numbers=none, tabsize=2, mathescape=false, alsoletter={$@_!|?$}, % classoffset=0, keywordstyle=\color{accDefault}, texcsstyle=*\color{accDefault}, moretexcs={subsection,thesubsection,thesection,theoremstyle}, deletetexcs={begin,end}, % classoffset=1, keywordstyle=\color{accStructure}, texcsstyle=*\color{accStructure}, moretexcs={begin,end}, % classoffset=2, escapeinside=~~, % classoffset=0, %literate={textA}{textB}{3}% %https://tex.stackexchange.com/questions/172945/coloring-in-listing literate={\{}{{\textcolor{curlyBrackets}{\myopenbrace}}}{1} {\}}{{\textcolor{curlyBrackets}{\myclosebrace}}}{1} {[}{{\textcolor{squareBrackets}{[}}}{1} {]}{{\textcolor{squareBrackets}{]}}}{1}% % {(}{{\textcolor{delimiterColor}{(}}}{1} % {)}{{\textcolor{delimiterColor}{)}}}{1}% %texcsstyle=\color{blue} } \lstset{language=ColoredLaTeX} \newcommand{\hllDelimDollar}[1][\color{green!40!black}]{% \lstset{ classoffset=2, moredelim=**[s][#1]{$}{$}, classoffset=0 }% } \newcommand{\hllDelimParen}[1][\color{green!40!black}]{% \lstset{ classoffset=2, moredelim=**[s][#1]{\(}{\)}, classoffset=0 }% } \def\hll@assignlabel#1#2{% \expandafter\gdef\csname hll@labeltoclassoffset@#1\endcsname{#2}% } \hll@assignlabel{default}{0} \hll@assignlabel{structure}{1} % ========================= % block & inline markup % ========================= \newcommand{\hllPrepareBlock}{% \lstset{framesep=0.1cm,framerule=0.6pt}% \def\setHighlightFrame##1{% \lstset{frame=##1}% }% \expandafter\setHighlightFrame\expandafter{\@highlight@frame}% \lstset{belowskip=0pt,aboveskip=0pt,belowcaptionskip=0pt,gobble=\defaultgobble}% \setlength\parskip{0pt}% \setlength\parindent{0pt}% } \lstnewenvironment{highlightblock}[1][] {% \vspace{\hllBeforeSkip}% \begingroup \hllPrepareBlock\lstset{#1}% }{% \nointerlineskip \endgroup \vspace{\hllAfterSkip}% } \lstnewenvironment{hllblock}[1][] {% \vspace{\hllBeforeSkip}% \begingroup \hllPrepareBlock\lstset{#1}% }{% \endgroup \vspace{\hllAfterSkip}% } \def\hll{\lstinline} % ================ % block saving % ================ \newenvironment{saveblock}[1]{% \expandafter\ifx\csname @codebox@#1\endcsname\relax \expandafter\newbox\csname @codebox@#1\endcsname\relax \fi % % The trick from latex/base/latex.ltx \edef\@bracehack{% \endgroup \expandafter\setbox\csname @codebox@#1\endcsname\vbox{% \begingroup\aftergroup}% \def\noexpand\@currenvir{\@currenvir}% \def\noexpand\@currenvline{\on@line}}% \@bracehack \begingroup\vspace{\hll@offset@fixskip} \ignorespaces% }{% \endgroup } \newcommand\useblock[1]{% \ifhllDebugFrame \par {% \setlength{\fboxsep}{0pt}% \fcolorbox{orange}{red}{\expandafter\usebox\csname @codebox@#1\endcsname}% }% \par \else \par\expandafter\usebox\csname @codebox@#1\endcsname\par \fi } \newcommand\consumeblock[1]{% \ifhllDebugFrame \par {% \setlength{\fboxsep}{0pt}% \setlength{\fboxrule}{1pt}% \fcolorbox{orange}{red}{\leavevmode\expandafter\box\csname @codebox@#1\endcsname\relax}% } \par \expandafter\let\csname @codebox@#1\endcsname\relax \else \par\leavevmode\expandafter\box\csname @codebox@#1\endcsname\relax\par \expandafter\let\csname @codebox@#1\endcsname\relax \fi } % =================== % updatehighlight % =================== \def\hll@update@label{} \newcounter{hll@update@state} \newcounter{hll@update@nextclassoffset} \setcounter{hll@update@nextclassoffset}{5} \newcounter{hll@update@classoffset} \def\hll@update@fixclassoffset{% \ifnum\value{hll@update@state}<1\relax \setcounter{hll@update@classoffset}{\thehll@update@nextclassoffset}% \stepcounter{hll@update@nextclassoffset}% \setcounter{hll@update@state}{1}% \fi } \newcommand{\updatehighlight}[1]{% \setcounter{hll@update@state}{-1}% \gdef\hll@update@label{}% \setkeys{updatehighlight}{#1}% % \lstset{classoffset=0}% } %%% KEY: label %%% ---------- \define@key{updatehighlight}{label}{% \hll@update@setlabel{#1}% } \define@key{updatehighlight}{name}{% \hll@update@setlabel{#1}% } \def\hll@update@setlabel#1{ \gdef\hll@update@label{#1}% \expandafter\def\expandafter\@capturedlabel\expandafter{\csname hll@labeltoclassoffset@#1\endcsname}% \expandafter\unless\expandafter\ifx\@capturedlabel\relax\relax % Label exists \edef\@val{\@capturedlabel}% \setcounter{hll@update@classoffset}{\@val}% \setcounter{hll@update@state}{1}% \else % Allocate new label \edef\@val{\thehll@update@nextclassoffset}% \setcounter{hll@update@classoffset}{\@val}% \stepcounter{hll@update@nextclassoffset}% \setcounter{hll@update@state}{1}% % \expandafter\xdef\@capturedlabel{\@val}% \fi } %%% KEY: classoffset %%% ---------------- \define@key{updatehighlight}{classoffset}{% \setcounter{hll@update@classoffset}{#1}% \setcounter{hll@update@state}{1}% } %%% KEY: commands %%% ------------- \define@key{updatehighlight}{macros}{% \hll@update@macros{#1}% } \define@key{updatehighlight}{commands}{% \hll@update@macros{#1}% } \def\hll@update@macros#1{% \hll@update@fixclassoffset \def\@inv##1{\forcsvlist{\hll@update@addmacro{##1}}{#1}}% \expandafter\@inv\expandafter{\the\c@hll@update@classoffset} % \setcounter{hll@update@state}{2}% } \def\hll@update@addmacro#1#2{% \if\noexpand#2\relax \edef\keywordpure{\expandafter\@gobble\string#2}% \def\callwithpure##1{\hll@update@addmacro@i{#1}{##1}}% \expandafter\callwithpure\expandafter{\keywordpure}% \else \hll@update@addmacro@i{#1}{#2}% \fi } \def\hll@update@addmacro@i#1#2{% \lstset{ classoffset=0,deletetexcs={#2}, classoffset=1,deletetexcs={#2}, classoffset=#1,moretexcs={#2}, classoffset=0 }% } %%% KEY: add %%% -------- \define@key{updatehighlight}{add}{% \hll@update@add{#1}% } \def\hll@update@add#1{% \hll@update@fixclassoffset \def\@inv##1{\forcsvlist{\hll@update@additem{##1}}{#1}}% \expandafter\@inv\expandafter{\the\c@hll@update@classoffset} % \setcounter{hll@update@state}{2}% } \def\hll@update@additem#1#2{% \if\noexpand#2\relax \edef\keywordpure{\expandafter\@gobble\string#2}% \def\callwithpure##1{\hll@update@addmacro@i{#1}{##1}}% \expandafter\callwithpure\expandafter{\keywordpure}% \else \hll@update@addkeyword{#1}{#2}% \fi } %%% KEY: remove %%% ----------- \define@key{updatehighlight}{remove}{% \hll@update@remove{#1}% } \def\hll@update@remove#1{% \hll@update@fixclassoffset \def\@inv##1{\forcsvlist{\hll@update@removeitem{##1}}{#1}}% \expandafter\@inv\expandafter{\the\c@hll@update@classoffset} % \setcounter{hll@update@state}{2}% } \def\hll@update@removeitem#1#2{% \if\noexpand#2\relax \edef\keywordpure{\expandafter\@gobble\string#2}% \def\callwithpure##1{\hll@update@removemacro{#1}{##1}}% \expandafter\callwithpure\expandafter{\keywordpure}% \else \hll@update@removekeyword{#1}{#2}% \fi } \def\hll@update@removemacro#1#2{% \lstset{ classoffset={#1}, deletetexcs={#2} }% } \def\hll@update@removekeyword#1#2{% \lstset{ classoffset={#1}, deletekeywords={#2} }% } %%% KEY: keywords %%% ------------- \define@key{updatehighlight}{keywords}{% \hll@update@keywords{#1}% } \def\hll@update@keywords#1{% \hll@update@fixclassoffset \def\@inv##1{\forcsvlist{\hll@update@addkeyword{##1}}{#1}}% \expandafter\@inv\expandafter{\the\c@hll@update@classoffset}% % \setcounter{hll@update@state}{2}% } \def\hll@update@addkeyword#1#2{% \lstset{ classoffset=0,deletekeywords={#2}, classoffset=1,deletekeywords={#2}, classoffset=#1,otherkeywords={#2},morekeywords={#2}, classoffset=0 }% } %%% KEY: style %%% ---------- \define@key{updatehighlight}{style}{% \hll@update@fixclassoffset \unless\ifhllStyleAnywhere \ifnum\value{hll@update@state}>1\relax \setcounter{hll@update@state}{0}% \hll@update@fixclassoffset \fi \fi % \expandafter\hll@update@setstyle\expandafter{\the\c@hll@update@classoffset}{#1}% } \def\hll@update@setstyle#1#2{% \lstset{% classoffset=#1, keywordstyle={#2}, texcsstyle={*#2}, }% } %%% KEY: color %%% ---------- \define@key{updatehighlight}{color}{% \hll@update@fixclassoffset \unless\ifhllStyleAnywhere \ifnum\value{hll@update@state}>1\relax \setcounter{hll@update@state}{0}% \hll@update@fixclassoffset \fi \fi % \expandafter\hll@update@setcolor\expandafter{\the\c@hll@update@classoffset}{#1}% } \def\hll@update@setcolor#1#2{% \lstset{% classoffset=#1, keywordstyle={\color{#2}}, texcsstyle={*\color{#2}}, }% } %%% KEY: clear %%% ---------- \define@key{updatehighlight}{clear}[]{% \hll@update@fixclassoffset \expandafter\hll@update@clear\expandafter{\the\c@hll@update@classoffset}% } \def\hll@update@clear#1{% \lstset{ classoffset=#1, texcs={}, keywords={}, classoffset=0 }% }