ЛаТеХ
7 коммент.
Предисловие
Автор этих строк - человек очень ленивый, но любопытный и обожающий ковырять свой Дебиан на предмет того, как бы сбросить побольше рутины на компьютер. Так появилась LaTeX-реализация организационной системы Getting Things Done, которая выполнена полностью на латехе, вместе с адресной книгой и календарём.Календарь на LaTeX реализован с помощью пакета расширений calendar [скачать ZIP-файл]. Проблема в том, что месяцы в календаре нужно обновлять самому, а вот это как раз и забывается чаще всего. Поэтому хочется, чтобы дни, месяцы и годы в календарике LaTeX обновлялись автомагически латехом и без вмешательства ленивого и забывчивого автора этих строк.
Нужно сказать, что LaTeX является Turing complete language, то есть на нем можно писать любые программы. Например, можно написать интерпретатор Бейсика, симулятор машины Тьюринга, Mandelbrot with LaTeX и другие программы. То есть на латехе можно писать что угодно. Не всегда это просто (особенно в случае с календарём), но можно.Пост поделён на две части: сначала немного о возможностях пакета Calendar, а потом про то, как обновление названий месяцев сделать автоматически из LaTeX.
Возможности пакета Calendar в LaTeX
О возможностях пакета Calendar уже говорилось, но тем не менее. Последнюю версию пакета расширений calendar, который можно загрузить отсюда. Файлы примеров этого поста доступны здесь, батарейки в комплекте (пакет calendar там уже есть).После распаковки всех файлов в преамбуле документа подключаем пакеты:
%%% Turning on the Monthly calendar and Event listдля календаря на месяц и списка событий, и:
\usepackage{monthly,evntlist,lscape} \parindent=0pt
%%% Turning on the Yearly calendarдля календаря на год соответсвенно.
\usepackage{yearly}
Создание событий для календаря
Пакет calendar не просто создаёт календарь, но и позволяет отображать в нём события. Все события хранятся в одном текстовом файле myEvents.cld из которого они дёргаются календарём. Файл событий выглядит так:%%%%%%% My Personal CalendarСначала указываем год в отдельном файле Essentials/Calenda/year2010.cld в котором пишем:
range Essentials/Calendar/year2010 %% What year do we want?
%% ONE-TIME EVENTS
january 28 2010 {Описать GTD} [Описать GTD для блога]
%%%%% RECURRING EVENTS
every Sunday {Еженед. обзор} [Еженед. обзор]
%% Span the whole year hereПовторяющиеся события будут определены только в интервале из этого файла.
January 1 2010 to December 31 2010 {The year 2010}
Список событий из календаря
Часто нужно просто видеть события, приуроченные к календарным датам (особенно если их не так много). Для этого мы пользуемся окружением eventlist, которое предоставляет пакет calendar. Настройки того, как выглядит список событий, хранятся в файле evntlist.sty который можно приукрасить разными значками и иконками.Чтобы распечатать события между нужными датами, вы просто ставите две даты, между которыми хотите показывать события (хранятся в файле events.cld):
\begin{eventlist} {} {Essentials/Calendar/myEvents}и собираете LaTeXом документ, получая список календарных событий на это время:
january 24 2010 to january 30 2010
\end{eventlist}
Иконки сделаны пакетами шрифтов marvosym и wasysym.
Календарь на месяц с отображением событий
Пакет calendar может больше - можно создать календарь на месяц и показывать там события. Код такой:\begin{monthly}Все события в календаре на указанный месяц (январь 2010 в данном случае) берутся из того же файла events.cld, который мы использовали для генерации списка календарных дней на неделю.
{firstday=1} %% begins with Monday
{Essentials/Calendar/myEvents}
jan 2010
\end{monthly}
Компилируем документ и вот он, календарь на месяц, обновлённый и со вставленными событиями:
Календарь работает с кириллицей, во всяком случае кодировка KOI8-R у него возражений не вызывает.
Календарь на год
Места для отображения событий в календаре на год особенно не много, но возможность сгенерировать годовой календарь, не\begin{yearly}После сборки документа годовой календарик будет выглядеть так:
{title= \begin{center} \textbf{\Large The Year 2013}\end{center} \normalsize,firstday=1}
{}
2013
\end{yearly}
Можно посылать в печать.
Вызов скриптов из LaTeX
С календарём всё сравнительно понятно, и теперь настало время его автоматизировать: хочется, чтобы названия месяцев и дней подставлялись автоматически. Это не такая простая задача, как может показаться. Дело в том, что стандартные команды типа \the\year с пакетом calendar работать не будут, как не получится и подставлять значения из файлов через команду \input.Поэтому мы пойдём другим путём, как завещал нам Ильич, и напишем скрипт на питоне, генерирующий полный текст латеховского файла с использованием безграничных возможностей команды date. Собственно, идея в том, чтобы написать простенький скрипт на Питоне и вызывать его каждый раз латехом для обновления файлов календаря.
Скрипт на Питоне для генерации файлов календаря
Скрипт просто склеивает строки для латеха, дёргая команду date и вставляя даты куда нужно. В примере ниже показана часть генерации файла календаря на месяц.Весь латеховский файл представляет собой склеенные строки в переменной out. Вставка символа r в строках
out +=r'\begin{landscape}'+'\n'
указывает Питону не интерпретировать \b а печатать как есть. Вызов команды date делается через os.popen(cmd)
, хотя теперь так уже не модно (но тем не менее работает), а модно через subprocess.check_output
(но у меня так не получилось).От полученной строки из команды date отдельно откусывается символ новой строки через
.rstrip('\n')
и далее сшивается с другими стоками. Результат записывается в файл tmpCalendarMonth.tex, который в свою очередь вставляется в ЛаТеХ через \input{Calendar/tmpCalendarMonth} и обрабатывается при сборке. Скрипт на питоне ниже: #! /usr/bin/python import string, os import commands kmvStartDir = '.' kmvDestDir = kmvStartDir+'/Calendar/' #destination directory for graphs ###### Getting dates and months as text using DATE command in Linux #### cmd='date --date="today" +%Y' stdout_handle = os.popen(cmd) kmv_year = stdout_handle.read() kmv_year = kmv_year.rstrip('\n') stdout_handle.close() cmd='date --date="today" +%B' stdout_handle = os.popen(cmd) kmv_month = stdout_handle.read() kmv_month = kmv_month.rstrip('\n') stdout_handle.close() cmd='date --date="today" +%e' stdout_handle = os.popen(cmd) kmv_day = stdout_handle.read() kmv_day = kmv_day.rstrip('\n') stdout_handle.close() #################################### #### Month Calendar regeneration ### #################################### kmvCalName = kmvDestDir+'tmpCalendarMonth' out = '' out +=r'\begin{landscape}'+'\n' out +=r'\begin{monthly}' out +='\n {firstday=1} \n' out +='{Calendar/myEvents} \n' out +=kmv_month+' '+kmv_year+'\n' out +='\end{monthly}\n' out +='\end{landscape}\n' ### Output to the Calendar's file ###### kmvCalName+='.tex' fout=open(kmvCalName,'w') fout.write(out) fout.close() ####################################
calendar_regenerate.py
и все остальные файлы можно взять отсюда. Скрипт написан для того, чтобы быть максимально понятным, а не красивым или эффективным.Вызов скрипта на Питоне из LaTeX
Вызывать скрипты из латеха можно несколькими способами:Здесь я приведу второй вариант, как наиболее простой. Для этого мы помещаем питоний скрипт
calendar_regenerate.py
в тот же каталог, где лежит файл 4myGTD.tex, из которого скрипт будет вызываться. В преамбуле документа пишем:%%% Python script for calendar regeneration \immediate\write18{./calendar_regenerate.py}
Чтобы всё это заработало, нужно вызывать LaTeX с параметром
-shell-escape
который позволяет выполнение внешних скриптов.Кто такой \write18 и почему так называется?!
Команда \write это низкоуровневая инструкция TeX, которая используется для того, чтобы производить запись в файловые "потоки". ТеХ ссылается на каждый открытый файл не по имени, а по номеру. Поток 18 является особым и зарезервирован для того, чтобы попросить операционную систему что-то выполнить - например, внешний скрипт.
Внимание! Как совершенно справедливо отмечается многими, подобный трюк в сочетании с параметром –shell-escape
небезопасен и представляет собой потенциальную дыру в безопасности. Так
можно написать вредоносный документ с командой типа \write18{rm -rf ~} в
Unix. По этому поводу есть статья (PDF) об этой и других опасных командах в LaTeX.
Команда \immediate приказывает ЛаТеХ выполнить скрипт немедленно,
не дожидаясь окончания генерации всего документа. В данном случае это
оправдано, так как мы хотим, чтобы в документ вставился уже обновлённый
календарь.