Let your 'variables.tex' - generator do a loop and say for each of the defined commands \foo
etc. \let\foo\relax
etc.
This way it is undefined at the top of each input of the variables.tex
Another way: Use \undef{\foo}
or \csundef{foo}
from etoolbox
package.
variables.tex
\let\foo\relax
\let\foobar\relax
\newcommand{\foo}{Foo}
\newcommand{\foobar}{Foobar}
Driver
\documentclass{memoir}
%% This file is generated automatically, and is full of
%% \newcommand definitions
\begin{document}
\input{variables}
\input{text} % makes heavy use of commands defined in variables.tex
\input{variables}% It will do here too with the same file
\input{text} % makes heavy use of commands defined in variables.tex
\end{document}
text.tex
\foo\ and \foobar\ are nice commands
Update
Another approach without tedious \let\foo\relax
statements:
Use
\begingroup
\input{variables-1}
\input{text}
\endgroup
for each of the relevant cases. In this case, there must not be any occurence of \input{variables}
etc. before!
\input
I think this addresses all the issues...
For the School week thing, I used two conditionals: \ifWeekStarted
, and \ifPrintSW
. The first one is triggered every Monday to signal a week has started. Later on, if we're not in a holiday, and \ifWeekStarted
, the \ifPrintSW
switch is turned on. If this last switch is on, when PGF is drawing the node, it will step the schoolweek
counter and write SW X
. Now it will mark the earliest day of every week that it can. Now we only have to exclude possible holidays, so if the holiday falls on a Monday, it will hold \ifWeekStarted
switch and wait for Tuesday to see if it can enable \ifPrintSW
. We'll get to the holidays later.
Similar to 1, but much easier, we only write a number every week. Here, however, we (may) have a problem. If you want both School Week and Calendar Week to start at 1, then the code is trivial. However, if you want the Calendar Week to start in January 1st, then I don't know if it's possible (with a reasonable amount of effort) without LuaTeX... I implemented a solution that with pdfTeX and XeTeX starts the Calendar Week numbering from 1 with the School Weeks, and with LuaTeX it calls os.date()
to get the week number. Since you said it's OK, then OK :)
I defined a command \addholiday
which takes three arguments: an identifier for the holidays, a comma-separated list of holiday entries, and a style setting (which will be executed by \tikzset
). Each holiday entry is of the form <date conditional>/<holiday name>
. For example, the "Heilige Drei Könige" day is given as equals = 2019-01-06 / Heilige Drei Könige
. All other valid PGF calendar day-selection keys are valid, for example: between = 2018-10-08 and 2018-10-09 / Seven-day weekend!!!
. The code will then loop through the given holidays and print them when appropriate. Additionally, one can use the starred variant, \addholiday*
, to define a "special" day, which is not a holiday per se, so it still counts as a school week, but such special days can have a header printed on them and have a special formatting.
Here's the first page when compiled with LuaTeX:
Note that the weeks are numbered from 37 because the output of date -d 2018-09-10 +%V
(on a Linux machine) says that this is the 37th week of the year. When compiled with pdfTeX or XeTeX it will start from 1.
Notice that due to the Seven-day weekend!!!
the label SW 5.
appears only on Wednesday. Note also that, because for week number 42
I used \addholiday*
, then the week still counts as School Week (SW 6.
), but it gets a "Holiday Label" and gets formatted accordingly.
The first version I created (if someone is interested you can find it in the edit history -- it is too long to post two codes) used low-level definitions and argument handling to define the \addholiday
macro, so it soon became far too awkward to maintain or modify anything (mostly because I was bodging-in features as I was writing the command. Don't recommend that :).
The current version uses expl3
's property lists to store the holidays. This allows me to easily add properties to the holidays, query the existing properties, and use them in the drawing code.
If you call, say, this command:
\addholiday*{HDAY}{%
, between = 2018-10-15 and 2018-10-19 / Special week!
, equals = 2019-01-06 / Heilige Drei Könige
}
{every day/.style={fill=green!30}}
then the property tree created will be like this:
(I am deeply sorry for my attempt using forest
. Code adapted from this answer).
When you do that, the \addholiday
command creates a \l__julia_HDAY_holiday
property list which will contain three properties: special
, style
, and dates
. The special
property will contain a boolean, true
if the starred variant was used, false
otherwise. The style
property will hold the last argument to \addholiday
which will do the formatting of this set of dates. The last property, dates
, will contain the reference to another property list, \l__julia_HDAY_holiday_dates
. This property list will contain as many properties as the number of entries you passed to \addholiday
. Each property will be the name of the holiday, and the corresponding value will be the PGF Calendar test to find the dates.
Now the command \holidaycheck
iterates through the defined holiday lists and calls \__julia_holiday_check:nnn
. This last macro is responsible for checking if the current date is a holiday (with \ifdate
), and executing the provided code if that's the case. With all this structure set up, implementing a verification to print only the first instance of a holiday's name is close to trivial :)
For each holiday (for example Heilige Drei Könige
), we check if a command called \is_Heilige Drei Könige_printed
is defined. If it is not, then we set the boolean \WriteName
to true, write the holiday's name, and define the command \is_Heilige Drei Könige_printed
(the definition is empty). If that command is defined (by the previous step) then we set \WriteName
to false and don't write the name.
Code:
% DIN-A4 doublesided year calendar
% Author: Robert Krause
% License : Creative Commons attribution license
% Submitted to TeXample.net on 13 July 2018
% Modified by julia 2018
\documentclass[a4paper, ngerman, 10pt]{scrartcl}
\usepackage[utf8]{inputenc}
\usepackage[ngerman]{babel}
\usepackage[T1]{fontenc}
\usepackage{tikz,xparse} % Use the calendar.sty style
\usepackage{iftex}
\makeatletter
\ifLuaTeX
\expandafter\@firstofone
\else
\expandafter\@gobble
\fi
{\usepackage{luacode}}
\usepackage{translator} % German Month and Day names
\usepackage{fancyhdr} % header and footer
\usepackage{fix-cm} % Large year in header
\usepackage{xparse}
\usepackage[ headheight = 0.8cm, hmargin=.5cm,
top = 1.7cm, nofoot,bottom=0cm]{geometry}
\usetikzlibrary{calc}
\usetikzlibrary{calendar}
\renewcommand*\familydefault{\sfdefault}
% Names of Holidays are inserted by employing this macro
\def\termin#1#2{%
\node [anchor=north west, text width= 3.4cm] at
($(#1.north west)+(3em, 0em)$) {\tiny{#2}};
}
\ifLuaTeX
\begin{luacode*}
function get_week_number(y,m,d)
return os.date("%V",os.time{year=y,month=m,day=d})
end
\end{luacode*}
\fi
\newcounter{calweek}
\newcounter{schoolweek}
\newcommand\woche[2]{%
\node [anchor=south east, align=right] at
($(#1.south east)+(0em, 0em)$) {\tiny{#2}};}
\newcommand\schulwoche[2]{%
\node [anchor=north east, align=right] at
($(#1.north east)+(0em, 0em)$) {\tiny{SW #2}.};}
\ExplSyntaxOn
\bool_new:N \WriteName
\prop_new:N \l__julia_holiday_list_prop
\bool_new:N \l__julia_special_bool
\cs_new:Npn \exp_args:NNnc { \::N \::n \::c \::: }
\NewDocumentCommand\addholiday
{ s m m m }
{
\IfBooleanTF { #1 }
{ \bool_set_true:N \l__julia_special_bool }
{ \bool_set_false:N \l__julia_special_bool }
\__julia_add_holiday:nnn { #2 } { #3 } { #4 }
}
\cs_new:Npn \__julia_add_holiday:nnn #1 #2 #3
{
\prop_clear_new:c { l__julia_#1_holiday }
\prop_clear_new:c { l__julia_#1_holiday_dates }
\__julia_add_holiday_aux:ccnnn
{ l__julia_#1_holiday } { l__julia_#1_holiday_dates }
{ #1 } { #2 } { #3 }
}
\cs_new:Npn \__julia_add_holiday_aux:NNnnn #1 #2 #3 #4 #5
{
\prop_put:Nnn \l__julia_holiday_list_prop { #3 } { #1 }
\exp_args:NNnV
\prop_put:Nnn #1 { special } \l__julia_special_bool
\prop_put:Nnn #1 { dates } { #2 }
\prop_put:Nnn #1 { style } { #5 }
\clist_map_inline:nn { #4 }
{ \__julia_prop_split_add:Nn #2 { ##1 } }
% \prop_show:N #1
}
\cs_generate_variant:Nn \__julia_add_holiday_aux:NNnnn { ccnnn }
\cs_new:Npn \__julia_prop_split_add:Nn #1 #2
{ \__julia_prop_split_add:Nw #1 #2 \q_stop }
\cs_new:Npn \__julia_prop_split_add:Nw #1 #2 / #3 \q_stop
{
\exp_args:NNff
\prop_put:Nnn #1
{ \tl_trim_spaces:n { #3 } }
{ \tl_trim_spaces:n { #2 } }
}
\cs_new:Npn \holidaycheck #1
{
\cs_gset_eq:NN \HolidayStyle \c_empty_tl
\prop_map_inline:Nn \l__julia_holiday_list_prop
{
\prop_get:NnN ##2 { dates } \HLprop
\prop_get:NnN ##2 { style } \HLstyle
\prop_get:NnN ##2 { special } \HLtype
\prop_map_inline:Nn \HLprop
{
\__julia_holiday_check:nnn
{ #1 } { ####1 } { ####2 }
}
}
}
\cs_new:Npn \__julia_holiday_check:nnn #1 #2 #3
{
% #1 is the code passed to \holidaycheck
% #2 is the holiday name
% #3 is the holiday date
\ifdate { #3 }
{
\cs_set:Npn \name { #2 }
\cs_if_exist:cTF { is_ #2 _printed }
{ \bool_set_false:N \WriteName }
{ \bool_set_true:N \WriteName }
#1
}
{ }
}
\cs_new:Npn \HolidaySetUsed #1
{ \cs_gset_eq:cN { is_ #1 _printed } \c_empty_tl }
\ExplSyntaxOff
%Header
\renewcommand{\headrulewidth}{0.0pt}
\setlength{\headheight}{0.8cm}
\chead{%
\Huge 2018/2019
\Large\textbf{Termine}\hfill
}
\cfoot{}
\newcommand{\kheight}{0.82}
\newcommand{\kwidth}{3.0}
\newcommand{\kshift}{3.4}
\newcommand{\calstartdate}{2018-09-10}
\newif\ifWeekStarted
\WeekStartedfalse
\newif\ifPrintSW
\PrintSWfalse
\newif\ifHasHoliday
\newcommand{\kal}[2]{%
\vspace*{-1cm}
\begin{tikzpicture}[every day/.style={anchor = north}]
\calendar[
dates = #1,
name = cal,
day yshift = 3em,
day code =
{%
\holidaycheck{%
\global\let\HolidayStyle\HLstyle
}%
\expandafter\tikzset\expandafter{\HolidayStyle}%
\node [
name = \pgfcalendarsuggestedname,
every day,
shape = rectangle,
minimum height = \kheight cm,
text width = \kwidth cm,
draw = gray]
{\tikzdaytext\enskip
\pgfcalendarweekdayshortname{\pgfcalendarcurrentweekday}%
};%
\holidaycheck{%
\IfBooleanF{\HLtype}{\global\PrintSWfalse} % A holiday
\IfBooleanTF{\WriteName}
{%
\termin{\pgfcalendarsuggestedname}{\name}{}%
\HolidaySetUsed{\name}%
}%
{}%
}%
\ifPrintSW
\stepcounter{schoolweek}%
\global\WeekStartedfalse
\global\PrintSWfalse
\schulwoche{\pgfcalendarsuggestedname}{\arabic{schoolweek}}%
\fi
\ifdate{Monday}{%
\ifLuaTeX
\setcounter{calweek}{%
\directlua{%
tex.print(
get_week_number(
\pgfcalendarcurrentyear,
\pgfcalendarcurrentmonth,
\pgfcalendarcurrentday
)
)
}%
}%
\else
\stepcounter{calweek}%
\fi
\woche{\pgfcalendarsuggestedname}{\arabic{calweek}}%
}{}%
},
execute before day scope=
{%
\ifdate{day of month=1}
{%
% Shift right
\pgftransformxshift{\kshift cm}
% Print month name
\draw (0,0) node [shape=rectangle, minimum height= \kheight cm,
text width = \kwidth cm, fill = red, text= white, draw = red, text centered]
{\textbf{\pgfcalendarmonthname{\pgfcalendarcurrentmonth}}};
}{}%
\ifdate{Monday}{%
\global\WeekStartedtrue
}{}
\ifdate{workday}
{%
% normal days are white
\tikzset{every day/.style={fill=white}}
% Vacation (Germany, Baden-Wuerrtemberg) gray background
\expandafter\ifdate\expandafter{#2}{%
\tikzset{every day/.style={fill=gray!30}}
}{%
\ifWeekStarted
\global\PrintSWtrue
\fi
}%
}{}%
% Saturdays and half holidays (Christma's and New year's eve)
\ifdate{Saturday}{%
\tikzset{every day/.style={fill=red!10}}%
}{}%
% % Sundays and full holidays
\ifdate{Sunday}{%
\tikzset{every day/.style={fill=red!20}}%
}{}%
},
execute at begin day scope=
{%
% each day is shifted down according to the day of month
\pgftransformyshift{-\kheight*\pgfcalendarcurrentday cm}
}
];
\end{tikzpicture}
}
\addholiday{normal holidays}{%
, between = 2018-10-08 and 2018-10-09 / Seven-day weekend!!!
, equals = 2018-10-03 / Tag der dt. Einheit
, equals = 2019-01-01 / Neujahr
, equals = 2019-01-06 / Heilige Drei Könige
, equals = 2019-04-19 / Karfreitag
, equals = 2019-04-21 / Ostersonntag
, equals = 2019-04-22 / Ostermontag
, equals = 2019-05-01 / Tag der Arbeit
, equals = 2019-05-30 / Christi Himmelfahrt
, equals = 2019-06-09 / Pfingstsonntag
, equals = 2019-06-20 / Pfingstmontag
}
{every day/.style={fill=gray!30}}
\addholiday*{very special week}{%
, between = 2018-10-15 and 2018-10-19 / Special week!
}
{every day/.style={fill=green!30}}
\newcommand{\HolidayList}{%
between=2018-10-03 and 2018-10-05,
between=2018-10-29 and 2018-11-04,
between=2019-02-28 and 2019-02-28,
between=2019-03-01 and 2019-03-08,
between=2019-04-15 and 2019-04-26,
between=2019-06-10 and 2019-06-02,
between=2019-07-29 and 2019-09-01,
}
\begin{document}
\pagestyle{fancy}
\begin{center}
\kal{2018-09-10 to 2019-02-28}{\HolidayList}
\kal{2019-03-01 to 2019-08-30}{\HolidayList}
\pagebreak
% \kal{2019-03-01 to 2019-08-30}{\holidays}
\end{center}
\end{document}
Best Answer
I like to do it like this, using the
datatool
package (like also suggested in the comments) :Then I have all the addresses in a separate
addresses.csv
, like this:The resulting letter is probably not styled like you prefer, of course. But you have the whole world of KOMA options at your disposal, just check the KOMA manual!