autounindent 不能与 hyperref 和 hypcap 一起使用

autounindent 不能与 hyperref 和 hypcap 一起使用

这个问题与我之前由 Jubobs 回答的问题相关这里。我使用 TeX Live 2013 和 TeX Live 2014 预测试编译了下面给出的代码。两者产生相同的结果。

情况1

预期结果autounindent如下。

在此处输入图片描述

案例 2

当我加载时hyperrefautounindent不再按如下方式工作。

在此处输入图片描述

案例 3

最糟糕的情况是,当我同时加载hyperref和时hypcap,出现了以下一些错误。

在此处输入图片描述

平均能量损失

\documentclass[12pt]{article}

%TODO
% - handle tabs

\usepackage{accsupp}
\newcommand*{\noaccsupp}[1]{\BeginAccSupp{ActualText={}}#1\EndAccSupp{}}

\usepackage{xcolor}
\usepackage{listings}

\makeatletter

% -------- ugly details --------

% custom key
\lst@Key{autounindent}f[t]{\lstKV@SetIf{#1}\lst@ifautounindent}

% --- accumulation of tokens ---
\toks@={
    \lst@DefSaveDef{`\ }\lsts@myspace{\processmyspace}
    %\lst@DefSaveDef{`\^^I}\lsts@mytab{\processmytab}
}


% --- egreg's helper function for accumulating tokens ---
\def\add@savedef#1#2{%
  \begingroup\lccode`?=#1\relax
  \lowercase{\endgroup
  \edef\@temp{%
    \noexpand\lst@DefSaveDef{\number#1}%
    \expandafter\noexpand\csname lsts@?\endcsname{\noexpand#2% % I had to swap things around to fix a bug here;
      \expandafter\noexpand\csname lsts@?\endcsname}%          % otherwise, comment highlighting would be broken.
  }}%
  \toks@=\expandafter{\the\expandafter\toks@\@temp}%
}

\count@=33
\loop
    \add@savedef\count@\processchar
  \ifnum\count@<127
  \advance\count@\@ne
\repeat

% --- to keep track of the state ---
\newcount\spacesToGobble
\newcount\spacesGobbledSoFar
\newif\ifafterindent
\newif\ifonBasisLine
\newif\ifPostponeCountToNextLine


\lst@AddToHook{Init}
{%
  \lst@ifautounindent%
    % patch hook macros
    \let\@ddedToInitVarsBOLhook\@@ddedToInitVarsBOLhook%
    \let\@ddedToEOLhook\@@ddedToEOLhook%
    % initialise things
    \global\onBasisLinetrue%
    \global\afterindentfalse%
    \global\spacesToGobble=0%
    \lst@ifincluderangemarker%
      \ifnum9999999=\lst@firstline% (i.e. if firstline option not used)
        \global\PostponeCountToNextLinetrue%
      \fi
    \fi
  \fi
}


\lst@AddToHook{SelectCharTable}
{%
    \lst@ifautounindent%
        \lst@lAddTo\lst@DeveloperSCT{\the\toks@}%
    \fi
}


\lst@AddToHook{InitVarsBOL}{\@ddedToInitVarsBOLhook}
\newcommand\@ddedToInitVarsBOLhook{}
\newcommand\@@ddedToInitVarsBOLhook
{%
  \global\afterindentfalse%
}

\lst@AddToHook{EOL}{\@ddedToEOLhook}
\newcommand\@ddedToEOLhook{}
\newcommand\@@ddedToEOLhook
{%
  \ifonBasisLine%
    \ifPostponeCountToNextLine%
    \else
      \global\onBasisLinefalse%
    \fi
  \fi
  \global\spacesGobbledSoFar=0%
  \global\PostponeCountToNextLinefalse%
}

\lst@AddToHook{DeInit}
{%
  \lst@ifautounindent%
    % undo patches
    \def\@ddedToInitVarsBOLhook{}%
    \def\@ddedToEOLhook{}%
  \fi
}


% --- helper macros ---
\newcommand\processchar
{%
  \global\afterindenttrue%
}

\newcommand\processmyspace
{%
  \ifafterindent%
    \lsts@myspace%
  \else
    \ifonBasisLine%
      \global\advance\spacesToGobble\@ne\relax%
    \else
      \ifnum\spacesGobbledSoFar<\spacesToGobble\relax%
        \global\advance\spacesGobbledSoFar\@ne\relax%
      \else
        \lsts@myspace%
      \fi
    \fi
  \fi
}

\makeatother

% ---------- end of ugly details ----------

\usepackage{filecontents}
\begin{filecontents*}{Program.cs}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Delegate
{
    class Program 
    {
        // start
        sdfgsd fgdsfg  static void Main(string[] args)
        {
            for (int x = 0; x < 10; x++)
                Console.WriteLine(x);
        }
        /* sdflkjhsdf */
        // stop
    }
}
\end{filecontents*}

% --- general style definition ---
\lstdefinestyle{Common}
{   
    language={[Sharp]C},
    numbers=left,
    numbersep=1em,
    numberstyle=\tiny\noaccsupp,
    frame=single,
    framesep=\fboxsep,
    framerule=\fboxrule,
    rulecolor=\color{red},
    xleftmargin=\dimexpr\fboxsep+\fboxrule,
    xrightmargin=\dimexpr\fboxsep+\fboxrule,
    breaklines=true,
    breakindent=0pt,
    tabsize=2,
    columns=flexible,
    %includerangemarker=false,
    rangeprefix=//\ ,
}

\lstdefinestyle{A}
{
    style=Common,
    backgroundcolor=\color{yellow!10},
    basicstyle=\scriptsize\ttfamily,
    keywordstyle=\color{blue}\bf,
    identifierstyle=\color{black},
    stringstyle=\color{red},
    commentstyle=\color{green},
}

%\usepackage[colorlinks,bookmarksnumbered,bookmarksopen]{hyperref} % makes  autounindent no longer work
%\usepackage[all]{hypcap}% causes errors.

\begin{document}


\section*{Using \texttt{linerange} with \texttt{autounindent}}
\lstinputlisting[style=A,linerange=start-stop,autounindent]{Program.cs}


\end{document}

问题

如何解决这些问题?

答案1

问题不在于软件包顺序。修补的代码listings使用令牌寄存器\toks@(临时暂存寄存器)作为永久令牌寄存器。因此,令牌寄存器也被其他软件包(如或)\toks@使用,并且它们随后会留下垃圾。然后,这些垃圾被“自动取消缩进”功能内部调用,从而导致不必要的意外效果(如错误消息)。hyperrefhypcaplstlisting

\toks@是一个临时的临时令牌寄存器,任何包或命令都可以使用它。如果在使用前清除该寄存器,也无济于事,因为前言中的令牌寄存器的设置将因“自动取消缩进”功能而丢失。

以下修复\toks@由新分配的令牌寄存器替换:

\documentclass[12pt]{article}

%TODO
% - handle tabs

\usepackage{accsupp}
\newcommand*{\noaccsupp}[1]{\BeginAccSupp{ActualText={}}#1\EndAccSupp{}}

\usepackage{xcolor}
\usepackage{listings}

\makeatletter

% -------- ugly details --------

\newtoks\mylsttoks

% custom key
\lst@Key{autounindent}f[t]{\lstKV@SetIf{#1}\lst@ifautounindent}

% --- accumulation of tokens ---
\mylsttoks={
    \lst@DefSaveDef{`\ }\lsts@myspace{\processmyspace}
    %\lst@DefSaveDef{`\^^I}\lsts@mytab{\processmytab}
}

% --- egreg's helper function for accumulating tokens ---
\def\add@savedef#1#2{%
  \begingroup\lccode`?=#1\relax
  \lowercase{\endgroup
  \edef\@temp{%
    \noexpand\lst@DefSaveDef{\number#1}%
    \expandafter\noexpand\csname lsts@?\endcsname{\noexpand#2%
      % I had to swap things around to fix a bug here;
      \expandafter\noexpand\csname lsts@?\endcsname}%
      % otherwise, comment highlighting would be broken.
  }}%
  \mylsttoks=\expandafter{\the\expandafter\mylsttoks\@temp}%
}

\count@=33
\loop
    \add@savedef\count@\processchar
  \ifnum\count@<127
  \advance\count@\@ne
\repeat

% --- to keep track of the state ---
\newcount\spacesToGobble
\newcount\spacesGobbledSoFar
\newif\ifafterindent
\newif\ifonBasisLine
\newif\ifPostponeCountToNextLine


\lst@AddToHook{Init}
{%
  \lst@ifautounindent%
    % patch hook macros
    \let\@ddedToInitVarsBOLhook\@@ddedToInitVarsBOLhook%
    \let\@ddedToEOLhook\@@ddedToEOLhook%
    % initialise things
    \global\onBasisLinetrue%
    \global\afterindentfalse%
    \global\spacesToGobble=0%
    \lst@ifincluderangemarker%
      \ifnum9999999=\lst@firstline% (i.e. if firstline option not used)
        \global\PostponeCountToNextLinetrue%
      \fi
    \fi
  \fi
}


\lst@AddToHook{SelectCharTable}
{%
    \lst@ifautounindent%
        \lst@lAddTo\lst@DeveloperSCT{\the\mylsttoks}%
    \fi
}


\lst@AddToHook{InitVarsBOL}{\@ddedToInitVarsBOLhook}
\newcommand\@ddedToInitVarsBOLhook{}
\newcommand\@@ddedToInitVarsBOLhook
{%
  \global\afterindentfalse%
}

\lst@AddToHook{EOL}{\@ddedToEOLhook}
\newcommand\@ddedToEOLhook{}
\newcommand\@@ddedToEOLhook
{%
  \ifonBasisLine%
    \ifPostponeCountToNextLine%
    \else
      \global\onBasisLinefalse%
    \fi
  \fi
  \global\spacesGobbledSoFar=0%
  \global\PostponeCountToNextLinefalse%
}

\lst@AddToHook{DeInit}
{%
  \lst@ifautounindent%
    % undo patches
    \def\@ddedToInitVarsBOLhook{}%
    \def\@ddedToEOLhook{}%
  \fi
}


% --- helper macros ---
\newcommand\processchar
{%
  \global\afterindenttrue%
}

\newcommand\processmyspace
{%
  \ifafterindent%
    \lsts@myspace%
  \else
    \ifonBasisLine%
      \global\advance\spacesToGobble\@ne\relax%
    \else
      \ifnum\spacesGobbledSoFar<\spacesToGobble\relax%
        \global\advance\spacesGobbledSoFar\@ne\relax%
      \else
        \lsts@myspace%
      \fi
    \fi
  \fi
}

\makeatother

% ---------- end of ugly details ----------

\usepackage{filecontents}
\begin{filecontents*}{Program.cs}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Delegate
{
    class Program 
    {
        // start
        sdfgsd fgdsfg  static void Main(string[] args)
        {
            for (int x = 0; x < 10; x++)
                Console.WriteLine(x);
        }
        /* sdflkjhsdf */
        // stop
    }
}
\end{filecontents*}

% --- general style definition ---
\lstdefinestyle{Common}
{   
    language={[Sharp]C},
    numbers=left,
    numbersep=1em,
    numberstyle=\tiny\noaccsupp,
    frame=single,
    framesep=\fboxsep,
    framerule=\fboxrule,
    rulecolor=\color{red},
    xleftmargin=\dimexpr\fboxsep+\fboxrule,
    xrightmargin=\dimexpr\fboxsep+\fboxrule,
    breaklines=true,
    breakindent=0pt,
    tabsize=2,
    columns=flexible,
    %includerangemarker=false,
    rangeprefix=//\ ,
}

\lstdefinestyle{A}
{
    style=Common,
    backgroundcolor=\color{yellow!10},
    basicstyle=\scriptsize\ttfamily,
    keywordstyle=\color{blue}\bf,
    identifierstyle=\color{black},
    stringstyle=\color{red},
    commentstyle=\color{green},
}

\usepackage[colorlinks,bookmarksnumbered,bookmarksopen]{hyperref}
\usepackage[all]{hypcap}

\begin{document}
  \section*{Using \texttt{linerange} with \texttt{autounindent}}
  \lstinputlisting[style=A,linerange=start-stop,autounindent]{Program.cs}
\end{document}

结果

答案2

更改顺序:如果你的文档以

\documentclass[12pt]{article}
\usepackage[colorlinks,bookmarksnumbered,bookmarksopen]{hyperref}
\usepackage[all]{hypcap}

并将其余部分保持原样,您应该会得到预期的结果。

相关内容