使用日历代替目录

使用日历代替目录

情况

我打算在类似“实验室手册”的乳胶文档中做一些笔记(比较这些模板12)。该议定书将跨越很长的时间,并且条目可能从几个项目到几个方面不等。

为了更好地记录我什么时候做了什么,我想有一个日历(例如或者显示章节标题(可能还有页码)。这些应该链接到各个部分(就像图片那样)这里)。

显然,可以使用 hyperref 并简单地手动执行。然而,以自动生成的方式生成目录是更可取的。

问题

我如何创建看起来像日历的目录?

(或:像目录一样的日历)

(可能不是最小的)工作示例

看起来不是特别好看,创建起来也不是很快捷(即使我使用了自定义命令来输入):

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Monthly Calendar
% LaTeX Template
%
% This template has been downloaded from:
% http://www.latextemplates.com
%
% Original calendar style author:
% Evan Sultanik (http://www.sultanik.com/LaTeX_calendar_style)
%
% Important note:
% This template requires the calendar.sty file to be in the same directory as the
% .tex file. The calendar.sty file provides the necessary structure to create the
% calendar.
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%   Modified in order to represent the MWE for tex.stackexchange question:
%   https://tex.stackexchange.com/q/356889/74942
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%----------------------------------------------------------------------------------------
%   PACKAGES AND OTHER DOCUMENT CONFIGURATIONS
%----------------------------------------------------------------------------------------

\documentclass[a4paper]{article}
%
\usepackage{filecontents}
\begin{filecontents}{calendar.sty}
\NeedsTeXFormat{LaTeX2e}

\def\CalendarVersion{3.1}
\def\CalendarVersionDate{2009/04/24}

\ProvidesClass{calendar}[\CalendarVersionDate
LaTeX2e class file `calendar' v\CalendarVersion]

\typeout{'calendar' style \CalendarVersion \CalendarVersionDate.}
\typeout{Created by Evan Sultanik}
\typeout{****** Bugs/comments/suggestions/technicalities to Evan Sultanik -- [email protected] ******}

\RequirePackage{tabularx}

\def\@CALtrue{1}
\newcount\@currentdaynum
\newcounter{calendardate}
\newcount\StartingDayNumber

\def\dayheader#1#2{
    \noindent
    \begin{minipage}[t]{0.87\hsize}
        \noindent
        \raggedright
        \textit{#1}
    \end{minipage}
    \begin{minipage}[t]{0.1\hsize}
        \noindent
        \raggedleft
        \textit{#2}
    \end{minipage}
}
\def\activities#1{
    \parbox{\hsize}{\vspace*{5pt}\raggedright\scriptsize #1}\smallskip
}

\let\@colbreak=&

\def\printdayname#1{\hfil\textsc{#1}\hfil}

\newcommand{\dayname}[1]{
    \ifnum#1=1 Sunday\else
    \ifnum#1=2 Monday\else
    \ifnum#1=3 Tuesday\else
    \ifnum#1=4 Wednesday\else
    \ifnum#1=5 Thursday\else
    \ifnum#1=6 Friday\else
    \ifnum#1=7 Saturday\else
    \PackageError{calendar}{Unrecognized day number: #1!}
    \fi\fi\fi\fi\fi\fi\fi
}

\StartingDayNumber=1
\newenvironment{calendar}[1]{
    \newdimen\@calendarwidth
    \@calendarwidth=#1
    \begingroup
    \def\@calendarmode{\@CALtrue}
    \def\day##1##2{
        \if\@calendarmode\@CALtrue\else\PackageWarning{calendar}{The '\day' macro is expected to be used in the 'calendar' environment!}\fi
        \ifnum\@currentdaynum>7\global\@currentdaynum=1\fi
        \global\advance\@currentdaynum by 1
        \dayheader{##1}{\thecalendardate}\def\daysep{\vskip1pt\hrule\vskip1pt}
        \activities{##2}
        \addtocounter{calendardate}{1}
        \ifnum\@currentdaynum>7\@arraycr\hline\else&\fi
    }
    \def\finishCalendar{
        \ifnum\@currentdaynum=6 &\\\hline\else
        \ifnum\@currentdaynum=5 &&\\\hline\else
        \ifnum\@currentdaynum=4 &&&\\\hline\else
        \ifnum\@currentdaynum=3 &&&&\\\hline\else
        \ifnum\@currentdaynum=2 &&&&&\\\hline\else
        \ifnum\@currentdaynum=1 &&&&&&\\\hline
        \fi\fi\fi\fi\fi\fi
    }
    \def\BlankDay{
        \if\@calendarmode\@CALtrue\else\PackageWarning{calendar}{The '\calendarday' macro is expected to be used in the 'calendar' environment!}\fi
        \ifnum\@currentdaynum>7\global\@currentdaynum=1\fi
        \global\advance\@currentdaynum by 1
        \addtocounter{calendardate}{1}
        \ifnum\@currentdaynum>7\@arraycr\hline\else&\fi
    }

    \setcounter{calendardate}{1}
    \newcount\@currday
    \@currday=\StartingDayNumber
    \newcount\@numdays
    \@numdays=7
    \let\@cbreak=&
    \tabularx{\@calendarwidth}{|X|X|X|X|X|X|X|} \hline
    \ifnum\@currday>\@numdays\@currday=1\fi\printdayname{\dayname{\@currday}} \global\advance\@currday by 1 &
    \ifnum\@currday>\@numdays\@currday=1\fi\printdayname{\dayname{\@currday}} \global\advance\@currday by 1 &
    \ifnum\@currday>\@numdays\@currday=1\fi\printdayname{\dayname{\@currday}} \global\advance\@currday by 1 &
    \ifnum\@currday>\@numdays\@currday=1\fi\printdayname{\dayname{\@currday}} \global\advance\@currday by 1 &
    \ifnum\@currday>\@numdays\@currday=1\fi\printdayname{\dayname{\@currday}} \global\advance\@currday by 1 &
    \ifnum\@currday>\@numdays\@currday=1\fi\printdayname{\dayname{\@currday}} \global\advance\@currday by 1 &
    \ifnum\@currday>\@numdays\@currday=1\fi\printdayname{\dayname{\@currday}} \global\advance\@currday by 1 \\ \hline \hline
    \@currentdaynum=1
    \let\@firstline=\@CALtrue
}{
    \endtabularx
    \endgroup
}
\end{filecontents}
%
\usepackage{calendar} % Use the calendar.sty style
\usepackage[colorlinks=false,linkcolor=black,bookmarks=false]{hyperref}
\usepackage[margin=0.5in]{geometry}



\begin{document}

\pagestyle{empty} % Removes the page number from the bottom of the page

\noindent

\StartingDayNumber=1 % Calendar starting day, default of 1 means Sunday, 2 for Monday, etc

%----------------------------------------------------------------------------------------
%   MONTH AND YEAR SECTION
%----------------------------------------------------------------------------------------
\setcounter{section}{-1}
\section{Table of Contents}
\begin{center}
\textsc{\LARGE january}\\ % Month
\textsc{\large 2017} % Year
\end{center}

%----------------------------------------------------------------------------------------

\begin{calendar}{\hsize}

%----------------------------------------------------------------------------------------
%   BLANK DAYS BEFORE THE BEGINNING OF THE CALENDAR
%----------------------------------------------------------------------------------------

% This part is very finicky. It defines the number of blank days at the beginning of the calendar before the first of the month starts. If you need this to be more than 4 (i.e. the first starts on a Friday or Saturday in a 31 day month), then you have two options: 
% 1) You can uncomment another one or two \BlankDay's below which will make a new week (6 total) which makes the calendar too big for one page, remedy this by decreasing the size of each day by replacing 2.5cm below with a smaller number. 
% 2) Make the spill-over days start at the top left of the calendar (i.e. the calendar starts with 31 then a few days blank then 1, 2, 3, etc). The second option can be configured by uncommenting the below:

%\setcounter{calendardate}{31} % Begin the count with 31 so the top left day is 31; this can be changed to 29 or 30 as required
%\day{}{\vspace{2.5cm}} % 31 - add another line identical to this if starting at 30 or earlier

% You will need to comment out the 31 in the NUMBERED DAYS AND CALENDAR CONTENT section below for this as well as commenting out one of the \BlankDay's below. Play around with it and you will get it.

%\BlankDay
%\BlankDay
%\BlankDay
%\BlankDay
%\BlankDay
%\BlankDay

%----------------------------------------------------------------------------------------
%   NUMBERED DAYS AND CALENDAR CONTENT
%----------------------------------------------------------------------------------------

% These are the numbered days in the template - if there are less than 31 days simply comment out the bottom lines.

% \vspace{2.5cm} is only there to provide an even look to the calendar where each day is 2.5cm tall, it can be changed or removed to automatically adjust to the day in the week with the most content

\setcounter{calendardate}{1} % Start the date counter at 1

\day{}{
            \hyperref[01012017]{\nameref{01012017}} \hfill \pageref{01012017} \\
            \hyperref[01012017_h]{\nameref{01012017_h}} \hfill \pageref{01012017_h} \\
            \hyperref[01012017_s]{\nameref{01012017_s}} \hfill \pageref{01012017_s}
            } % 1 - Example of content
\day{}{
    \hyperref[02012017]{\nameref{02012017}} \hfill \pageref{02012017} \\
    \hyperref[02012017_a]{\nameref{02012017_a}} \hfill \pageref{02012017_a} \\
    \hyperref[02012017_b]{\nameref{02012017_b}} \hfill \pageref{02012017_b}
} % 2 
\day{}{\vspace{2.5cm}} % 3
\day{}{\vspace{2.5cm}} % 4
\day{}{\vspace{2.5cm}} % 5
\day{}{\vspace{2.5cm}} % 6
\day{}{\vspace{2.5cm}} % 7
\day{}{\vspace{2.5cm}} % 8
\day{}{
    \hyperref[09012017]{\nameref{09012017}} \hfill \pageref{09012017} \\
} % 9
\day{}{\vspace{2.5cm}} % 10
\day{}{\vspace{2.5cm}} % 11
\day{}{\vspace{2.5cm}} % 12
\day{}{\vspace{2.5cm}} % 13
\day{}{\vspace{2.5cm}} % 14
\day{}{\vspace{2.5cm}} % 15
\day{}{\vspace{2.5cm}} % 16
\day{}{\vspace{2.5cm}} % 17
\day{}{\vspace{2.5cm}} % 18
\day{}{\vspace{2.5cm}} % 19
\day{}{\vspace{2.5cm}} % 20 
\day{}{\vspace{2.5cm}} % 21
\day{}{\vspace{2.5cm}} % 22
\day{}{\vspace{2.5cm}} % 23
\day{}{\vspace{2.5cm}} % 24
\day{}{\vspace{2.5cm}} % 25
\day{}{\vspace{2.5cm}} % 26
\day{}{\vspace{2.5cm}} % 27
\day{}{\vspace{2.5cm}} % 28
\day{}{\vspace{2.5cm}} % 29 
\day{}{\vspace{2.5cm}} % 30 
\day{}{\vspace{2.5cm}} % 31

% Un-comment the \BlankDay below if the bottom line of the calendar is missing
%\BlankDay

% Un-comment to start counting again after 31
%\setcounter{calendardate}{1}
%\day{}{\vspace{2.5cm}} % 1
%\day{}{\vspace{2.5cm}} % 2
%\day{}{\vspace{2.5cm}} % 3

%----------------------------------------------------------------------------------------

\finishCalendar
\end{calendar}

\newpage
\section{day1 - 01.01.2017}\label{01012017}
\begin{itemize}
    \item did some setup things
    \item $\dots$
\end{itemize}

\subsection{hardware}\label{01012017_h}
My tedious written composition of annoying hardware setup.
\newpage
~
\newpage
\subsection{software}\label{01012017_s}
The fun part: software!


\newpage
\section{day2 - 02.01.2017}\label{02012017}
\section{first test project}\label{02012017_a}
some text
\newpage
\section{video shoot}\label{02012017_b}
notes on my video log recording
\newpage
~
\newpage
\section{something important}\label{09012017}

\end{document}

(我不想删除太多信息,这样就不会有人误以为这不是来自latextemplates.com。此外,我不知道实际上最低要求是什么)

生成: 在此处输入图片描述



编辑2:

第一个外包问题: 将‘\today’烘焙到源文件(或自定义辅助文件)中

编辑1:

我仍在调查此问题,因此...... 有用的信息,例如有关 ToC 的生成、该项目所需的更深层次的 TeX(编程)或任何其他信息,也将非常感激!

答案1

我认为这也许能实现你想要的。

结果

在发送我的代码之前,请注意以下事项要求需要满足:

  • 编译器必须是LuaLaTeX。
  • 下载MD5工具并将其放在源文件夹中。这是为了为章节/子章节创建有效的标签。
  • 放入mycode.lua源文件夹。

mycode.lua

-- for debugging
-- https://github.com/kikito/inspect.lua
-- inspect = require("inspect")

-- https://github.com/kikito/md5.lua/blob/master/md5.lua
md5 = require("md5")

function strip(str)
    return string.gsub(str, "^%s*(.-)%s*$", "%1")
end

function split_strip(inputstr, sep)
    if sep == nil then
        sep = "%s"
    end
    local t={}
    for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
        local stripped = strip(str)
        table.insert(t, stripped)
    end
    return t
end

function parse_time(time_str)
    local tab = split_strip(time_str, "%-")
    assert(#tab == 2, "invalid section format")

    local day_str = string.gsub(tab[1], "day%s+", "")
    local day_ind = tonumber(day_str)
    assert(day_ind ~= nil, "invalid day index")

    -- day/month/year format
    local tab_mdy = split_strip(tab[2], "%.")
    assert(#tab_mdy == 3, "invalid date format")
    local month = tab_mdy[2]
    local day = tab_mdy[1]
    local year = tab_mdy[3]
    
    local tp = os.time{year=year, month=month, day=day, hour=0, sec=1}
    local date = os.date("*t", tp)
    return {
        day_ind=day_ind,
        date=date
    }
end

function label_section(storage, section_str)
    return md5.sumhexa(section_str)
end

function label_subsection(storage, subsection_str)
    local offset = storage["offset"]
    local subsec_size = 0
    if storage["subsection"][offset] ~= nil then
        subsec_size = #storage["subsection"][offset]
    end
    local full_str = storage["section"][offset][1] .. subsection_str .. tostring(subsec_size)
    return md5.sumhexa(full_str)
end

-- no integrity check for section headings
-- avoid duplicated dates
-- must have day 1
function register_section(storage, date_str)
    local parse_res = parse_time(date_str)
    local offset = parse_res["day_ind"]
    if offset == 1 then
        storage["num_blanks"] = parse_res["date"]["wday"] - 1
    end
    storage["offset"] = offset
    local label = label_section(storage, date_str)
    local t_in = {date_str, label}
    storage["section"][offset] = t_in
    storage["subsection"][offset] = {}
    return t_in
end

function register_subsection(storage, subsection_str)
    local offset = storage["offset"]
    local label = label_subsection(storage, subsection_str)
    local t_in = {subsection_str, label}
    table.insert(storage["subsection"][offset], t_in)
    return t_in
end

function new_storage()
    local t = {}
    t["section"] = {}
    t["subsection"] = {}
    t["num_days"] = 31
    t["empty_fill"] = [[\vspace{2.5cm}]]
    return t
end

function create_toc(storage)
    local t = {}
    table.insert(t, [[\begin{calendar}{\hsize}]])

    local j = storage["num_blanks"]
    for i=1,j do
        table.insert(t, [[\BlankDay]])
    end
    table.insert(t, [[\setcounter{calendardate}{1}]])

    j = storage["num_days"]
    for i=1,j do
        local tt = {}
        if storage["section"][i] ~= nil then
            local sec_label = storage["section"][i][2]
            table.insert(tt, string.format([[\hyperref[%s]{\nameref{%s} \hfill \pageref{%s}}\newline]], 
                sec_label, sec_label, sec_label))
            if storage["subsection"][i] ~= nil then
                local subsec = storage["subsection"][i]
                for _, val in pairs(subsec) do
                    local subsec_label = val[2]
                    table.insert(tt, string.format([[\hyperref[%s]{\nameref{%s} \hfill \pageref{%s}}\newline]], 
                        subsec_label, subsec_label, subsec_label))
                end
            end
        end

        local str = ""
        if #tt == 0 then
            str = storage["empty_fill"]
        else
            str = table.concat(tt, "\n")
        end
        local day_str = string.format([[\day{}{%s}]], str)
        table.insert(t, day_str)
    end

    table.insert(t, [[\finishCalendar]])
    table.insert(t, [[\end{calendar}]])

    return table.concat(t, "\n")
end

主文件

\documentclass[a4paper]{article}
\usepackage{calendar} % Use the calendar.sty style
\usepackage[colorlinks=false,linkcolor=black,bookmarks=false]{hyperref}
\usepackage[margin=0.5in]{geometry}
\usepackage{luacode}

\begin{document}

\pagestyle{empty} % Removes the page number from the bottom of the page

\noindent

\setcounter{section}{-1}
\section{Table of Contents}
\begin{center}
\textsc{\LARGE january}\\ % Month
\textsc{\large 2020} % Year
\end{center}

\directlua{
    require("mycode")
    % declare new global storage
    storage = new_storage()
}

\let\oldsection\section
\let\oldsubsection\subsection

\renewcommand{\section}[1]{
    \directlua{
        cur_sec = register_section(storage, "\luaescapestring{#1}")
    }
    \oldsection{#1}\label{\directlua{tex.print(cur_sec[2])}}
}

\renewcommand{\subsection}[1]{
    \directlua{
        cur_subsec = register_subsection(storage, "\luaescapestring{#1}")
    }
    \oldsubsection{#1}\label{\directlua{tex.print(cur_subsec[2])}}
}

% update calendar source file
\AtEndDocument{
    \directlua{
        local out = create_toc(storage)
        local file = io.open("\jobname.calendar", "w")
        file:write(out)
        file:close()
    }
}

% read the calendar from file
\InputIfFileExists{\jobname.calendar}


\newpage
\section{day 1 - 01.01.2020}
\begin{itemize}
    \item did some setup things
    \item $\dots$
\end{itemize}

\subsection{hardware}
My tedious written composition of annoying hardware setup.
\newpage
~
\newpage
\subsection{software}
The fun part: software!


\newpage
\section{day 2 - 02.01.2020}
\section{day 5 - 05.01.2020}
some text
\newpage

\section{day 10 - 10.01.2020}
\subsection{notes on my video log recording}
\newpage
% test identical section heading
\subsection{notes on my video log recording}

\newpage
~
\newpage
\section{day 20 - 20.01.2020}

\end{document}

更多细节

核心处理完全在 Lua 中完成。我覆盖了默认\section\subsection命令来实现自动标记。使用 Lua 的日期函数可以自动计算 的数量\BlankDay。每次编译结束时,生成的日历源将存储在 中\jobname.calendar并在下次运行中使用。

示例生成的日历源

\begin{calendar}{\hsize}
\BlankDay
\BlankDay
\BlankDay
\setcounter{calendardate}{1}
\day{}{\hyperref[457625da265eeceb803943ba0808c2aa]{\nameref{457625da265eeceb803943ba0808c2aa} \hfill \pageref{457625da265eeceb803943ba0808c2aa}}\newline
\hyperref[de221fb236d079c07b5af80cf9ecef34]{\nameref{de221fb236d079c07b5af80cf9ecef34} \hfill \pageref{de221fb236d079c07b5af80cf9ecef34}}\newline
\hyperref[17592e2d9eafe348603ebdcc29dcb4ad]{\nameref{17592e2d9eafe348603ebdcc29dcb4ad} \hfill \pageref{17592e2d9eafe348603ebdcc29dcb4ad}}\newline}
\day{}{\hyperref[96f35bbca7ba14a54c2730705f376746]{\nameref{96f35bbca7ba14a54c2730705f376746} \hfill \pageref{96f35bbca7ba14a54c2730705f376746}}\newline}
\day{}{\vspace{2.5cm}}
\day{}{\vspace{2.5cm}}
\day{}{\hyperref[69cc2168ce348de7a0d82d6f597cd274]{\nameref{69cc2168ce348de7a0d82d6f597cd274} \hfill \pageref{69cc2168ce348de7a0d82d6f597cd274}}\newline}
\day{}{\vspace{2.5cm}}
\day{}{\vspace{2.5cm}}
\day{}{\vspace{2.5cm}}
\day{}{\vspace{2.5cm}}
\day{}{\hyperref[a402e6830c5d12dbda9ca2fb80398cd4]{\nameref{a402e6830c5d12dbda9ca2fb80398cd4} \hfill \pageref{a402e6830c5d12dbda9ca2fb80398cd4}}\newline
\hyperref[831be6085cb90cfa125282e6b78ac8d5]{\nameref{831be6085cb90cfa125282e6b78ac8d5} \hfill \pageref{831be6085cb90cfa125282e6b78ac8d5}}\newline
\hyperref[2df3994fff21c52f583af09d414f5d2e]{\nameref{2df3994fff21c52f583af09d414f5d2e} \hfill \pageref{2df3994fff21c52f583af09d414f5d2e}}\newline}
\day{}{\vspace{2.5cm}}
\day{}{\vspace{2.5cm}}
\day{}{\vspace{2.5cm}}
\day{}{\vspace{2.5cm}}
\day{}{\vspace{2.5cm}}
\day{}{\vspace{2.5cm}}
\day{}{\vspace{2.5cm}}
\day{}{\vspace{2.5cm}}
\day{}{\vspace{2.5cm}}
\day{}{\hyperref[4c03bdd9c0e81f64cf961a4c48199e97]{\nameref{4c03bdd9c0e81f64cf961a4c48199e97} \hfill \pageref{4c03bdd9c0e81f64cf961a4c48199e97}}\newline}
\day{}{\vspace{2.5cm}}
\day{}{\vspace{2.5cm}}
\day{}{\vspace{2.5cm}}
\day{}{\vspace{2.5cm}}
\day{}{\vspace{2.5cm}}
\day{}{\vspace{2.5cm}}
\day{}{\vspace{2.5cm}}
\day{}{\vspace{2.5cm}}
\day{}{\vspace{2.5cm}}
\day{}{\vspace{2.5cm}}
\day{}{\vspace{2.5cm}}
\finishCalendar
\end{calendar}

其他提醒

  1. 章节标题必须严格遵循特定格式。否则,解析机制将不起作用。尽管章节标题中有天数和日期,但只使用第 1 天的日期。因此,后续标题中的日期在某种程度上是多余的!
  2. 默认日期格式为 dd/mm/yyyy。

相关内容