Ich führe ein persönliches Tagebuch mit LaTeX. Ich möchte eine Umgebung erstellen, die das Datum jedes Eintrags automatisch festhält, ohne dass ich es selbst manuell eingeben muss. Dies ist der bisherige Code
\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}
So wie es ist, newday
ist die Umgebung nur eine kompliziertere Version des viel einfacheren
\NewDocumentEnvironment{ newday }{ o }{
\textbf{#1}
\marginnote{ \datedayname,~\today } \\
}{
\vspace{0.5cm}
}
Das Problem, das ich lösen möchte, ist folgendes: Angenommen, ich gebe ein „ newday
Heute“ ein, also den 25. Februar 2019. Wie verhindere ich, dass der Code das Datum dieser Eingabe ändert, wenn der Tag endet?
Ich begann mit dem Codieren der ersten Option in dem Glauben, dass ich damit jedes Datum in einer separaten Datei speichern könnte. Allerdings wurde mir schnell klar, dass die .jrn
Datei bei jeder Kompilierung überschrieben wird und daher nutzlos ist.
Irgendwelche Ideen, wie dieses Problem gelöst werden könnte?
BEARBEITENproblematischer Code
\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}
Antwort1
Immer wenn du eine startest newday
, musst du prüfen, ob in der Hilfsdatei bereits ein Datum gesetzt ist. Wenn ja, kopierst du es einfach in die neue Datei, andernfalls setzt du das aktuelle Datum:
\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}
Indem wir die Datei erst ganz am Ende zum Schreiben öffnen, stellen wir sicher, dass die alte Datei nur überschrieben wird, wenn das verbleibende Dokument bis zum Ende interpretiert wurde. So löschen wir die Datei nicht und verlieren Informationen, wenn die Kompilierung fehlschlägt.
Anstatt die Datei zunächst in einer Sequenz einzulesen, könnten wir bei jedem Aufruf von eine Zeile der Hilfsdatei einlesen newday
. Dann müssten wir allerdings einen Dateihandle für den gesamten Lauf belegen. Durch das Einlesen der Datei in einem Block können wir den Dateihandle möglichst schnell freigeben.