我正在基于上下文日志条目。每次选定的(修补的)宏被调用时,它应该提供其内容以及有意义的日志条目。
“有意义的”日志条目定义:
每个自定义日志条目提供以下上下文:
- 节计数器值
- 章节标题
- 页码
- 文件名/路径
- 电话号码
这就是我要的:
<macro content> (<section counter value>:<section title>:<page number>:<file>:<line number>)
问题
我猜我有两个问题:
\thetitle
当其中一个选定的宏属于分段命令本身时进行处理。- 在使用宏的情况下,将扩展宏的完整值作为字符串放入日志中
\myproduct
。
我如何实现“有意义的”日志条目
\thetitle
获取部分计数器titlesec
\@currentlabelname
获取章节标题titlesec
提供\def\@currentlabelname
nameref(我仅使用直类测试了这一点,即没有底线标题的类)\thepage
获取页面乳胶\the\inputlineno
获取行号LaTeX(使用时指的是当前文件中的 lineno\input
)max_print_line=10000
扩展texmf.cnf
日志输出中每行的最大字符数(与这个问题无关,但对于可能还想实现自定义日志的人来说相关)
希望我上面所说的事实是正确的。
问题 2(几乎可以工作,排版良好)
有时我的章节标题包含宏。这可能会导致扩展问题。此外,有时章节标题包含我正在跟踪的宏,这使得\thetitle
在日志条目中使用它会变得很棘手,\section{About \myproduct{monkey shampoo}}
例如应该产生例如MacGyver.monkey shampoo (2:About MacGyver.monkey shampoo:[1]:test.tex:11)
。
\documentclass{article}
\usepackage{fontspec}% use xelatex
\usepackage{titlesec}% adds \thetitle and \@currentlabelname
\usepackage{currfile}% adds \currfilepath
% Define a couple commands to track
\newcommand\myapp[1]{\textit{#1}}
\newcommand\myproduct[1]{MacGyver.\textit{#1}}% Purposefully made this one contain more text that what is saved in #1
% The following is normally put into separate file as to modularize the application of patches
% Define a context macro as described
\makeatletter
\def\contextinfo{\thetitle:\@currentlabelname:[\thepage]:\currfilepath:\the\inputlineno}
\makeatother
% Apply Patches
\usepackage{regexpatch}
\xapptocmd{\myapp}{\typeout{ ==> #1 (\contextinfo)}}{}{}
\xapptocmd{\myproduct}{\typeout{ ==> #1 (\contextinfo)}}{}{}% <-- I'd rather show MacGyver.monkey shampoo, but unsure how best to implement
% Note: \typeout is always fully expanded due to \write %http://tex.stackexchange.com/a/60976/13552
\begin{document}
\section{Elephant}
\section{Monkey}
\subsection{Bonabo}
\myapp{listmonkeys}
\myproduct{monkey shampoo}
\end{document}
日志输出
参见上面的问题 2:如何才能让“猴子洗发水“ 是 ”MacGyver.猴子洗发水“或者更简单:MacGyver.\textit{猴子洗发水}
==> listmonkeys (2.1:Bonabo:[1]:test.tex:34)
==> monkey shampoo (2.1:Bonabo:[1]:test.tex:35)
问题 1(不工作,不排版)
参见上面的问题 1:如何处理在中\thetitle
定义的?titlesec
\gdef\thetitle{\csname the#1\endcsname}%
\documentclass{article}
\usepackage{fontspec}% use xelatex
\usepackage{titlesec}% adds \thetitle and \@currentlabelname
\usepackage{currfile}% adds \currfilepath
% Define a couple commands to track
\newcommand\myapp[1]{\textit{#1}}
\newcommand\myproduct[1]{MacGyver.\textit{#1}}% Purposefully made this one contain more text that what is saved in #1
% The following is normally put into separate file as to modularize the application of patches
% Define a context macro as described
\makeatletter
\def\contextinfo{\thetitle:\@currentlabelname:[\thepage]:\currfilepath:\the\inputlineno}
\makeatother
% Apply Patches
\usepackage{regexpatch}
\xapptocmd{\myapp}{\typeout{ ==> #1 (\contextinfo)}}{}{}
\xapptocmd{\myproduct}{\typeout{ ==> #1 (\contextinfo)}}{}{}% <-- I'd rather show MacGyver.monkey shampoo, but unsure how best to implement
% Note: \typeout is always fully expanded due to \write %http://tex.stackexchange.com/a/60976/13552
\begin{document}
\section{Elephant \myapp{watcher}}% probably \thetitle has not been set yet, causing error
\section{Monkey \myproduct{monkey shampoo}}
\subsection{Bonabo}
\end{document}
日志输出
! TeX capacity exceeded, sorry [input stack size=5000].
答案1
您必须处理的一个大问题是内容的可扩展性,因为您正在向终端写入内容。为了解决这个问题,我定义了两个版本的\myapp
和\myproduct
函数。常规\myapp
和\myproduct
被声明为健壮的,而\@myapp
和\@myproduct
是可扩展的和简化的版本(例如,删除与字体相关的设置\textit
,如)。
我也避免了titlesec
并构建我自己的\thenumber
(包含章节编号)和\thetitle
(包含使用\@myapp
和/或的简化版本的章节标题\@myproduct
)。
\documentclass{article}
\usepackage{currfile}% adds \currfilepath
% Define a couple commands to track
\DeclareRobustCommand{\myapp}[1]{\textit{#1}}
\DeclareRobustCommand{\myproduct}[1]{MacGyver.\textit{#1}}
\makeatletter
\newcommand{\@myapp}[1]{#1}
\newcommand{\@myproduct}[1]{MacGyver.#1}
\makeatother
% The following is normally put into separate file as to modularize the application of patches
% Define a context macro as described
\def\contextinfo{\thenumber:\thetitle:[\thepage]:\currfilepath:\the\inputlineno}
% Apply Patches
\usepackage{regexpatch}
\xapptocmd{\myapp}{\typeout{ ==> #1 (\contextinfo)}}{}{}
\xapptocmd{\myproduct}{\typeout{ ==> #1 (\contextinfo)}}{}{}% <-- I'd rather show MacGyver.monkey shampoo, but unsure how best to implement
% Note: \typeout is always fully expanded due to \write %http://tex.stackexchange.com/a/60976/13552
%\usepackage{xparse}% Loaded by regexpatch
\let\oldsection\section
\makeatletter
\RenewDocumentCommand{\section}{s o m}{%
\begingroup
% Extract the counter representation
\stepcounter{section}%
\xdef\thenumber{\thesection}%
\addtocounter{section}{-1}%
% Temporarily change \myapp and \myproduct to be expandable and ordinary
\let\myapp\@myapp
\let\myproduct\@myproduct
% Extract the title with possible \myapp and \myproduct (now ordinary/expandable)
\protected@xdef\thetitle{#3}%
\endgroup
% Regular section
\IfBooleanTF{#1}
{\oldsection*{#3}}
{\IfValueTF{#2}
{\oldsection[#2]{#3}}
{\oldsection{#3}}}
}
\makeatother
\begin{document}
\section{Elephant \myapp{watcher}}% probably \thetitle has not been set yet, causing error
\section{About \myproduct{monkey shampoo}}
\subsection{Bonabo}
\end{document}
输出.log
==> watcher (1:Elephant watcher:[1]:test.tex:48)
==> monkey shampoo (2:About MacGyver.monkey shampoo:[1]:test.tex:49)
答案2
这是你想要的吗?
\documentclass{article}
\usepackage{fontspec}% use xelatex
\usepackage{titlesec}% adds \thetitle and \@currentlabelname
\usepackage{nameref}
\usepackage{regexpatch}
\usepackage{currfile}% adds \currfilepath
% Define a couple commands to track
\newcommand\myapp[1]{\textit{#1}}
\newcommand\myproduct[1]{MacGyver.\textit{#1}}% Purposefully made this one contain more text that what is saved in #1
% The following is normally put into separate file as to modularize the application of patches
% Define a context macro as described
\makeatletter
\def\contextinfo{\thetitle\space:\@currentlabelname:[\thepage]:\currfilepath:\the\inputlineno}
\DeclareRobustCommand{\WriteToLog}[1]{%
\gdef\@currentlabelname{#1}\immediate\write-1{ ==> #1 (\contextinfo)}
}
\AtBeginDocument{%
\xapptocmd{\myapp}{\WriteToLog{#1}}{}{}
\xapptocmd{\myproduct}{\WriteToLog{#1}}{}{}
}
\makeatother
\begin{document}
\section{Elephant \myapp{watcher}}\label{foo}% probably \thetitle has not been set yet, causing error
\section{Monkey \myproduct{monkey shampoo}}
\subsection{Bonabo}
\end{document}
答案3
“宏追踪器”解决方案 更新 2016-07-12
基于 Werner 的代码,我想出了一个很好的日志解决方案。
在生成干净日志输出的过程中:
##############################################################################
Document Diagnostics
##############################################################################
Main File: logs.tex
Page Count: 2
xparsemacro
##############################################################################
--BEGIN-----------------------------------------------------------------------
==> pre-section example (::logs.tex:[1]:144)
==> post-section example (1:Section:logs.tex:[1]:147)
==> post-section example (1.1:Subsection:logs.tex:[1]:150)
==> post-section example (1.1.1:Subsubsection:logs.tex:[1]:153)
==> post-section example (1.1.1.1:Paragraph:logs.tex:[1]:156)
==> in-section call (2:\xparsemacro {in-section call}:logs.tex:[1]:159)
--END-------------------------------------------------------------------------
该代码最适合用作标签的简单、单一输入宏,这些宏可能分散在您的文本中。此外,将环境变量max_print_line
设置为高于 79 的数字后,日志看起来会更好。例如,export max_print_line=1000
在我的/usr/local/texlive/2016/texmf-dist/web2c/texmf.cnf
文件中,我注释掉了
770 %error_line = 79 771 %half_error_line = 50 772 %max_print_line = 79
并将它们添加到/usr/local/texlive/2016/texmf.cnf
11 error_line = 254 12 half_error_line = 238 13 max_print_line = 1000
如何使用
- 使用以下方式定义单输入(
#1
)宏xparse's
\NewDocumentCommand
(请注意,\newcommand
当使用包含类似以下格式化宏时,可能会导致递归调用\texttt
) \doforeach{}
将宏添加到不带斜线的跟踪宏列表中
实验代码
\listfiles
\documentclass{article}
\usepackage{regexpatch}
\usepackage{xparse}
\usepackage{etoolbox} % define \do
\usepackage{atveryend} % define \AtEndAfterFileList
\usepackage{currfile} % define \currfilepath
% --------------------------------------------------------------------------------------------------
% My Macros (Variable Placeholders)
%
\newcommand\latexmacro[1]{#1}
\newcommand\latexmacrott[1]{\texttt{latex}.#1}
\DeclareRobustCommand{\latexrobusttt}[1]{\texttt{latexrobust}.#1}
\NewDocumentCommand{\xparsemacro}{m}{#1}
\NewDocumentCommand{\xparsemacrott}{m}{\texttt{xparse}.#1}
% --------------------------------------------------------------------------------------------------
% Log Delimiters
%
\catcode`#=12 % Define out log output delimiter lines using # as catcode 12 instead of 6
\newcommand{\macloglineL}{##############################################################################}
\newcommand{\macloglineB}{--BEGIN-----------------------------------------------------------------------}
\newcommand{\macloglineE}{--END-------------------------------------------------------------------------}
\catcode`#=6
% --------------------------------------------------------------------------------------------------
% Initialize Variables and Define Context-specific log entry
%
\def\currnum{}% initialize (for when section not yet typeset)
\def\currtitle{}% initialize (for when section not yet typeset)
\def\contextinfo{\currnum:\currtitle:\currfilepath:[\thepage]:\the\inputlineno}
% --------------------------------------------------------------------------------------------------
% Create loop macro that supports macros as items
%
\makeatletter
\newcommand\doforeach[2]{\renewcommand\do[1]{#2}\docsvlist{#1}}% Needs etoolbox http://tex.stackexchange.com/questions/318875/how-can-i-loop-through-macros-with-foreach-and-pass-them-to-xapptocmd
% -----------------------------------------------------------------------------------------------
% Make Document Diagnostics Header
%
\def\docdiagnosticsheader{%
\typeout{%
\macloglineL
^^J%
\space\space Document Diagnostics
^^J%
\macloglineL%
^^J%
Main File: \jobname.tex
^^J%
Page Count: \thepage
}
}%
\AtEndAfterFileList{\docdiagnosticsheader}
% Patch loop (syntax: \doforeach{macro,macro,macro}{what to do for each item})
% Patches tag macros
%
\doforeach{latexmacro,latexmacrott,latexrebusttt,xparsemacro,xparsemacrott}{% macro names wmacout slashes
\expandafter\ifx\csname #1-tracker\endcsname\relax
% does not exist, so create it
\expandafter\def\csname #1-tracker\endcsname{^^J^^J #1 ^^J\macloglineL^^J\macloglineB}
\else
% exists, do nothing
\fi
\expandafter\xapptocmd\csname#1\endcsname{\expandafter\protected@xdef\csname #1-tracker\endcsname{\unexpanded\expandafter\expandafter\expandafter{\csname #1-tracker\endcsname}^^J==> \unexpanded{##1} (\contextinfo)}}{\typeout{MACMessage: Successfully patched #1}}{\typeout{MACWarning: Failed to patch #1}}% 2 \expandafter needed, yet 3 are here because one is just to prep the \csname token.
\AtEndAfterFileList{\expandafter\typeout{\csname #1-tracker\endcsname^^J\macloglineE}}% Uncomment to enable tracking in log output
}%
\makeatother
% --------------------------------------------------------------------------------------------------
% The following temporarily redefine sectioning commands to extract titleno and title as \currnum and \currtitle, respectively for \contextinfo
%
\let\oldsection\section% Redefine section to grab number + title when tracking macros
\makeatletter
\RenewDocumentCommand{\section}{s o m}{%
\begingroup
\stepcounter{section}% Extract the counter representation
\xdef\currnum{\thesection}%
\addtocounter{section}{-1}%
\protected@xdef\currtitle{#3}% Extract the title wmac possible tracked macros
\endgroup
\IfBooleanTF{#1}% Regular section
{\oldsection*{#3}}
{\IfValueTF{#2}
{\oldsection[#2]{#3}}
{\oldsection{#3}}}
}
\makeatother
\let\oldsubsection\subsection% Redefine section to grab number + title when tracking macros
\makeatletter
\RenewDocumentCommand{\subsection}{s o m}{%
\begingroup
\stepcounter{subsection}% Extract the counter representation
\xdef\currnum{\thesubsection}%
\addtocounter{subsection}{-1}% Restore for normal subsection
\protected@xdef\currtitle{#3}% Extract the title wmac possible tracked macros
\endgroup
\IfBooleanTF{#1}% Regular section
{\oldsubsection*{#3}}
{\IfValueTF{#2}
{\oldsubsection[#2]{#3}}
{\oldsubsection{#3}}}
}
\makeatother
\makeatletter
\RenewDocumentCommand{\subsubsection}{s o m}{%
\begingroup
\stepcounter{subsubsection}% Extract the counter representation
\xdef\currnum{\thesubsubsection}%
\addtocounter{subsubsection}{-1}% Restore for normal subsection
\protected@xdef\currtitle{#3}% Extract the title wmac possible tracked macros
\endgroup
\IfBooleanTF{#1}% Regular section
{\oldsubsubsection*{#3}}
{\IfValueTF{#2}
{\oldsubsubsection[#2]{#3}}
{\oldsubsubsection{#3}}}
}
\makeatother
\let\oldparagraph\paragraph% Redefine section to grab number + title when tracking macros
\makeatletter
\RenewDocumentCommand{\paragraph}{s o m}{%
\begingroup
\stepcounter{paragraph}% Extract the counter representation
\xdef\currnum{\theparagraph}%
\addtocounter{paragraph}{-1}% Restore for normal subsection
\protected@xdef\currtitle{#3}% Extract the title wmac possible tracked macros
\endgroup
\IfBooleanTF{#1}% Regular section
{\oldparagraph*{#3}}
{\IfValueTF{#2}
{\oldparagraph[#2]{#3}}
{\oldparagraph{#3}}}
}
\makeatother
\begin{document}
\latexmacro{pre-section example}
\xparsemacro{pre-section example}
\section{Section}
\latexmacro{post-section example}
\xparsemacro{post-section example}
\subsection{Subsection}
\latexmacro{post-section example}
\xparsemacro{post-section example}
\subsubsection{Subsubsection}
\latexmacro{post-section example}
\xparsemacro{post-section example}
\paragraph{Paragraph}
\latexmacro{post-section example}
\xparsemacro{post-section example}
%\section{\latexmacrott{in-section call}}
%\section{\latexrebusttt{in-section call}}
\section{\xparsemacro{in-section call}}
\section{\xparsemacrott{in-section call}}
%\subsection{\latexmacro{in-subsection call}\xparsemacro{in-subsection call}}
%\subsubsection{\latexmacro{in-subsubsection call}\xparsemacro{in-subsubsection call}}
%\paragraph{\latexmacro{in-paragraph call}\xparsemacro{in-paragraph call}}
\end{document}