我使用 LaTeX 记个人日记。我想创建一个环境,自动跟踪每条日记的日期,而无需手动输入。这是目前的代码
\documentclass{tufte-book}
\usepackage{datenumber, ifthen, xparse}
\usepackage{lipsum}
\setstartyear{2000}
\newcounter{day}
\setcounter{day}{0}
\newcounter{if_auxnewday_begun}
\setcounter{if_auxnewday_begun}{0}
\ExplSyntaxOn
\iow_new:N \g_journal_stream
\seq_new:N \g_journal_seq
\NewDocumentEnvironment{ newday }{ o }{
\addtocounter{day}{1}
\seq_gput_right:Nx \g_journal_seq {
{ \arabic{day} }
{ \datedayname,~\today }
{ \IfValueTF{ #1 }{ #1 }{} }
}
\file_if_exist_input:n {\c_sys_jobname_str.jrn}
}{
\int_compare:nNnT { \arabic{if_auxnewday_begun} } = { 1 }{
\end{ auxnewday}
\setcounter{if_auxnewday_begun}{0}
}
}
\NewDocumentCommand{ \saveday }{ mmm }{
\int_compare:nNnT { #1 } = { \arabic{day} }{
\begin{ auxnewday }{#2}{#3}
\setcounter{if_auxnewday_begun}{1}
}
}
\NewDocumentEnvironment{ auxnewday } { mm }{
\textbf{ #2 }
\marginnote{ #1} \\
}{
\vspace{0.5cm}
}
\AtEndDocument{
\iow_open:Nn \g_journal_stream { \c_sys_jobname_str.jrn }
\save_days:
\iow_close:N \g_journal_stream
}
\cs_new_protected:Nn \save_days: {
\seq_map_function:NN \g_journal_seq \__save_days:n
}
\cs_new_protected:Nn \__save_days:n {
\iow_now:Nn \g_journal_stream {
\saveday #1
}
}
\ExplSyntaxOff
\begin{document}
\begin{newday}[A day]
\lipsum[1-5]
\end{newday}
\begin{newday}[Another day]
\lipsum[6-9]
\end{newday}
\end{document}
事实上,newday
环境只是更简单的
\NewDocumentEnvironment{ newday }{ o }{
\textbf{#1}
\marginnote{ \datedayname,~\today } \\
}{
\vspace{0.5cm}
}
我想要解决的问题是:假设我输入了newday
今天,即 2019 年 2 月 25 日。如何防止代码在一天结束时更改该条目的日期?
我开始编写第一个选项,认为它可以让我将每个日期保存在单独的文件中,但我很快意识到.jrn
每次编译时该文件都会被覆盖,所以它没用。
关于如何解决这个问题有什么想法吗?
编辑有问题的代码
\documentclass[justified, symmetric]{tufte-book}
\usepackage{ifoddpage, ifthen, xparse}
\usepackage[calc, showdow, english]{datetime2}
\DTMnewdatestyle{mydateformat}{%
\renewcommand{\DTMdisplaydate}[4]{%
\DTMshortweekdayname{##4},\space% short weekday,
\DTMmonthname{##2}\nobreakspace% (full) Month
\number##3,\space% day,
\number##1% year
}%
\renewcommand{\DTMDisplaydate}{\DTMdisplaydate}%
}
\DTMsetdatestyle{mydateformat}
\usepackage{lipsum}
\newcounter{day}
\title{Title}
\author{Author}
\ExplSyntaxOn
% Declare variables
\seq_new:N \g_journal_seq
\seq_new:N \g_journal_out_seq
\iow_new:N \g_journal_stream
\tl_new:N \l_journal_date_tl
% At the beginning of the run, read the lines of the `.jrn` file into a sequence.
% These are the dates. If the file can not be opened, it probably does not exist and we treat it as empty.
\cs_new:Npn \readjournaldates {
\ior_open:NnT \g_journal_stream { \c_sys_jobname_str.jrn } {
\ior_map_inline:Nn \g_journal_stream {
\seq_gput_right:Nn \g_journal_seq { ##1 }
}
\ior_close:N \g_journal_stream
}
}
% The main environment:
\NewDocumentEnvironment{ newday }{ O{} }{
\stepcounter{day}
% If the sequence \g_journal_seq is not empty yet, then we already saved a date
% for the current day. Save this day in `\l_journal_date_tl` and delete it from
% the sequence. Otherwise we have not saved anything yet, so we choose the current date.
\seq_gpop_left:NNF \g_journal_seq \l_journal_date_tl {
\tl_set:Nx \l_journal_date_tl {\today}
}
% Now we have to save the chosen date for the next run. First, only store it in the
% sequence `\g_journal_out_seq`, we only write it to the file at the end to avoid
% overwriting the file if something fails:
\seq_gput_right:NV \g_journal_out_seq \l_journal_date_tl
\textbf{ #1 }
\marginnote{\checkoddpage\ifoddpage \l_journal_date_tl \else\raggedleft \l_journal_date_tl \fi} \\
}{
\vspace{0.5cm}
}
% At the end of the document, iterate over `\g_journal_out_seq` and write every entry into a line.
\AtEndDocument{
\iow_open:Nn \g_journal_stream { \c_sys_jobname_str.jrn }
\seq_map_inline:Nn \g_journal_out_seq {
\iow_now:Nn \g_journal_stream { #1 }
}
\iow_close:N \g_journal_stream
}
\ExplSyntaxOff
\readjournaldates
\begin{document}
\maketitle
\pagenumbering{arabic}
\begin{newday}[A day]
\lipsum[1]
\end{newday}
\begin{newday}[Yet another day]
\lipsum[2]
\end{newday}
\begin{newday}
\lipsum[3]
\end{newday}
\begin{newday}[Ciao]
\lipsum[4]
\end{newday}
\begin{newday}[A day]
\lipsum[1]
\end{newday}
\begin{newday}[Yet another day]
\lipsum[2]
\end{newday}
\begin{newday}
\lipsum[3]
\end{newday}
\begin{newday}[Ciao]
\lipsum[4]
\end{newday}
\begin{newday}[A day]
\lipsum[1]
\end{newday}
\begin{newday}[Yet another day]
\lipsum[2]
\end{newday}
\end{document}
答案1
每当你启动一个 时newday
,你必须检查辅助文件中是否已经设置了日期。如果有,你只需将其复制到新文件中,否则你设置当前日期:
\documentclass{tufte-book}
\usepackage{datenumber, ifthen, xparse}
\usepackage{lipsum}
\setstartyear{2000}
\newcounter{day}
\ExplSyntaxOn
% Declare variables
\seq_new:N \g_journal_seq
\seq_new:N \g_journal_out_seq
\iow_new:N \g_journal_stream
\tl_new:N \l_journal_date_tl
% At the beginning of the run, read the lines of the `.jrn` file into a sequence.
% These are the dates. If the file can not be opened, it probably does not exists
% and we treat it as empty.
\cs_new:Npn \readjournaldates {
\ior_open:NnT \g_journal_stream { \c_sys_jobname_str.jrn } {
\ior_map_inline:Nn \g_journal_stream {
\seq_gput_right:Nn \g_journal_seq { ##1 }
}
\ior_close:N \g_journal_stream
}
}
% The main environment:
\NewDocumentEnvironment{ newday }{ O{} }{
\stepcounter{day}
% If the sequence \g_journal_seq is not empty yet, then we already saved a date
% for the current day. Save this day in `\l_journal_date_tl` and delete it from
% the sequence. Otherwise we have not saved anything yet, so we choose the current
% date.
\seq_gpop_left:NNF \g_journal_seq \l_journal_date_tl {
\tl_set:Nx \l_journal_date_tl {\datedayname,~\today}
}
% Now we have to save the choosen date for the next run. First, only store it in the
% sequence `\g_journal_out_seq`, we only write it to the file at the end to avoid
% overwriting the file if something fails:
\seq_gput_right:NV \g_journal_out_seq \l_journal_date_tl
\textbf{ #1 }
\marginnote{ \l_journal_date_tl } \\
}{
\vspace{0.5cm}
}
% At the end of the document, iterate over `\g_journal_out_seq` and write every entry
% into a line
\AtEndDocument{
\iow_open:Nn \g_journal_stream { \c_sys_jobname_str.jrn }
\seq_map_inline:Nn \g_journal_out_seq {
\iow_now:Nn \g_journal_stream { #1 }
}
\iow_close:N \g_journal_stream
}
\ExplSyntaxOff
\makeatletter
\readjournaldates
\makeatother
\begin{document}
\begin{newday}[A day]
\lipsum[1]
\end{newday}
\begin{newday}[Yet another day]
\lipsum[2]
\end{newday}
\begin{newday}
\lipsum[3]
\end{newday}
\end{document}
通过仅在最后打开文件进行写入,我们确保只有在剩余文档被解释到最后时才会覆盖旧文件,因此如果编译失败,我们不会清除文件并丢失信息。
我们不必先将文件读入序列,而是可以在每次调用时读取一行辅助文件newday
。但这样一来,我们就必须在整个运行过程中占用一个文件句柄。通过在一个块中读取文件,我们可以尽快释放文件句柄。