突出显示列表中的行范围:部分解决方案,但存在扩展问题

突出显示列表中的行范围:部分解决方案,但存在扩展问题

为了寻求更好的解决方案如何使用时更改特定线条的外观\lstincludelisting,我偶然发现了linebackground=,我在 Martin Scharrer 的回答中使用列表创建斑马效果

基本思想是有一个宏

% \btLstHL<overlay spec>{range list}
\newcommand<>{\btLstHL}[1]{%
  \only#2{\btIfInRange{\value{lstnumber}}{#1}{\color{blue!30}}{}}%
}%

\color{blue!30}如果当前行适合范围,则扩展为 a ,\empty否则扩展为 (?)。然后将其与linebackground

\begin{lstlisting}[language=C, gobble=6,linebackgroundcolor={%
    \btLstHL{4}%
    \btLstHL<1>{1-2,5-6}%
    \btLstHL<2>{7}%
  }]
    /**
    * Prints Hello World.
    **/
    #include <stdio.h>

    int main(void) {
       printf("Hello World!");  
       return 0;
    }
\end{lstlisting}

然而,这并没有按预期工作,因为所有未选定的行现在都得到了白色背景:

截屏

罪魁祸首,我猜,正在实施中lstlinebackground,以及在其处理过程中如何btLstHL扩展:

    \lst@Key{linebackgroundcolor}{}{%
        \def\lst@linebgrdcolor{#1}%
    }
    \newcommand{\lst@linebgrd}{%
        \ifx\lst@linebgrdcolor\empty\else  % PROBLEM: for \btLstHL does not expand to \empty ???
        \rlap{%
            \lst@basicstyle
            \color{-.}% By default use the opposite (`-`) of the current color (`.`) as background
            \lst@linebgrdcolor{%
            \kern-\dimexpr\lst@linebgrdsep\relax%
            \lst@linebgrdcmd{\lst@linebgrdwidth}{\lst@linebgrdheight}{\lst@linebgrddepth}%
            }%
        }%
        \fi
    }

显然,\btLstHL扩展为“无”,但\empty对于未选定的行则不然,这会导致\lst@linebgrd背景突出显示,但使用其默认颜色,与当前文本颜色(黑色)相反。

这时我迷失了 :-(

那么,如果该线不在给定范围内,\btLstHL它就扩展为如何定义?\empty

完成 MWE:

\documentclass{beamer}

% beamer class setup
\usecolortheme{rose}
\setbeamertemplate{navigation symbols}{}

% we use UTF8
\usepackage[utf8]{inputenc}
% font setup
\usepackage[T1]{fontenc}
\usepackage[scaled=0.85]{beramono}
\usepackage{xcolor,listings, pgffor}

\makeatletter

  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %
  % \btIfInRange{number}{range list}{TRUE}{FALSE}
  %
  % Test if int number <number> is element of a (comma separated) list of ranges
  % (such as: {1,3-5,7,10-12,14}) and processes <TRUE> or <FALSE> respectively

  \newcount\bt@rangea
  \newcount\bt@rangeb

  \newcommand\btIfInRange[2]{%
      \global\let\bt@inrange\@secondoftwo%
      \edef\bt@rangelist{#2}%
      \foreach \range in \bt@rangelist {%
          \afterassignment\bt@getrangeb%
          \bt@rangea=0\range\relax%
          \pgfmathtruncatemacro\result{ ( #1 >= \bt@rangea) && (#1 <= \bt@rangeb) }%
          \ifnum\result=1\relax%
              \breakforeach%
              \global\let\bt@inrange\@firstoftwo%
          \fi%
      }%
      \bt@inrange%
  }
  \newcommand\bt@getrangeb{%
      \@ifnextchar\relax%
          {\bt@rangeb=\bt@rangea}%
          {\@getrangeb}%
  }
  \def\@getrangeb-#1\relax{%
      \ifx\relax#1\relax%
          \bt@rangeb=100000%   \maxdimen is too large for pgfmath
      \else%
          \bt@rangeb=#1\relax%
      \fi%
  }

  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %
  % \btLstHL<overlay spec>{range list}
  %
  \newcommand<>{\btLstHL}[1]{%
    \only#2{\btIfInRange{\value{lstnumber}}{#1}{\color{blue!30}}{}}%
  }%


  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %
  % \btInputEmph<overlay spec>[listing options]{range list}{file name}
  %
  \newcommand<>{\btLstInputEmph}[3][\empty]{%                                                    
    \only#4{%
      \lstset{linebackgroundcolor=\btLstHL{#2}}%
      \lstinputlisting{#3}%
   }% \only
  }


  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  %% lstlinebgrd.sty
  %% see: https://tex.stackexchange.com/questions/18969/creating-a-zebra-effect-using-listings/18989#18989
  %%
  %% This small package is not yet published/not commonly available.
  %%
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

    % Patch line number key to call line background macro
    \lst@Key{numbers}{none}{%
        \def\lst@PlaceNumber{\lst@linebgrd}%
        \lstKV@SwitchCases{#1}%
        {none&\\%
         left&\def\lst@PlaceNumber{\llap{\normalfont
                    \lst@numberstyle{\thelstnumber}\kern\lst@numbersep}\lst@linebgrd}\\%
         right&\def\lst@PlaceNumber{\rlap{\normalfont
                    \kern\linewidth \kern\lst@numbersep
                    \lst@numberstyle{\thelstnumber}}\lst@linebgrd}%
        }{\PackageError{Listings}{Numbers #1 unknown}\@ehc}}

    % New keys
    \lst@Key{linebackgroundcolor}{}{%
        \def\lst@linebgrdcolor{#1}%
    }
    \lst@Key{linebackgroundsep}{0pt}{%
        \def\lst@linebgrdsep{#1}%
    }
    \lst@Key{linebackgroundwidth}{\linewidth}{%
        \def\lst@linebgrdwidth{#1}%
    }
    \lst@Key{linebackgroundheight}{\ht\strutbox}{%
        \def\lst@linebgrdheight{#1}%
    }
    \lst@Key{linebackgrounddepth}{\dp\strutbox}{%
        \def\lst@linebgrddepth{#1}%
    }
    \lst@Key{linebackgroundcmd}{\color@block}{%
        \def\lst@linebgrdcmd{#1}%
    }

    % Line Background macro
    \newcommand{\lst@linebgrd}{%
        \ifx\lst@linebgrdcolor\empty\else
        \rlap{%
            \lst@basicstyle
            \color{-.}% By default use the opposite (`-`) of the current color (`.`) as background
            \lst@linebgrdcolor{%
            \kern-\dimexpr\lst@linebgrdsep\relax%
            \lst@linebgrdcmd{\lst@linebgrdwidth}{\lst@linebgrdheight}{\lst@linebgrddepth}%
            }%
        }%
        \fi
    }

\makeatother

\begin{document}

\begin{frame}[fragile]{Problem}
  \begin{alertblock}{A cool app; unfortunately it has a white background}
    \begin{lstlisting}[language=C, gobble=6,linebackgroundcolor={%
        \btLstHL{4}%
        \btLstHL<1>{1-2,5-6}%
        \btLstHL<2>{7}%
      }]
        /**
        * Prints Hello World.
        **/
        #include <stdio.h>

        int main(void) {
           printf("Hello World!");  
           return 0;
        }
    \end{lstlisting}
  \end{alertblock}
\end{frame}

\end{document}

答案1

在更好地理解了它的\ifx实际作用之后(感谢 whlt3!)我得出结论,我无法\btLstHL以第一级扩展的方式定义它\empty

我的当前解决方法是走另一条路线并重新定义\lst@linebgrdcmd\btLstHL以便它成为未选定行的无操作:

  % \btLstHL<overlay spec>{range list}
  \newcommand<>{\btLstHL}[1]{%
    \only#2{\btIfInRange{\value{lstnumber}}{#1}%
      {\color{blue!30}}%
      {\def\lst@linebgrdcmd####1####2####3{}}% define as no-op
    }%
  }%

笔记:要不使用 beamer 来使用它,只需<>\newcommand\only#2命令(包括其花括号)中删除 即可。

这样我确实得到了预期的结果。但是,这个解决方案有点“老套”。我仍然愿意接受更好的方法。

相关内容