我用 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
。但是這樣我們就必須在整個運行過程中佔用一個檔案句柄。透過以一個區塊的方式讀取文件,我們可以盡快釋放文件句柄。