Дата — это просто!

об автоматизации

В это сложно поверить, но компьютер может подчиняться пользователю, а не наоборот.

Тим Маринин

Было у меня вчера, к ночи ближе, просветление.

Я до вчерашнего дня в файлах для этого сайта дату вручную выставлял. Это несложно, в общем-то, но неудобно, и чем дальше, тем больше напрягает, как камешек в ботинке.

Исходники страниц для Hugo — файлы Markdown, а служебная информация, вроде той же даты публикации, добавляется в начало файла «нашлёпкой» TOML (можно YAML или даже JSON, по вкусу), в терминах Hugo это называется «Front Matter». Например, начало файла с вот этой вот записью выглядит так:

+++
title = "Дата — это просто!"
subtitle = "об автоматизации"
date = 2020-06-05T11:39:46+03:00
tags = ["linux", "hugo", "чему не учат в школе"]
categories = ["IT"]
+++
> В это сложно поверить, но компьютер может[...]

Дата, как видите, строкой в формате ISO 8601. И набирать вот эту строку каждый раз руками очень лень. Надо сделать, чтобы текущая дата (нужна-то, как правило, именно текущая) вставлялась сама. Но как?

Просто брать дату коммита из Git (раз уж всё равно всё это в Git сохраняется) — не вариант: тогда дата будет обновляться при каждом исправлении опечаток или форматирования1.

Встроенный в Hugo механизм решения этой проблемы — шаблоны для создаваемых файлов. Можно сделать, чтобы по команде

$ hugo new /posts/2020/date.md

создавался файл сразу с заполненной во Front Matter текущей датой (и другими полями, если хочется). Этот вариант в целом годится для коротких заметок, но пост, даже не очень длинный, может писаться долго2, и хочется, чтобы в нём стояла дата (и время), когда он был закончен, а не когда он был задуман и файл создан.

Я уже стал было поглядывать в сторону плагина для Vim, который, в числе прочего, умеет вставлять дату в нужном формате. Беда в том, что мне неудобно писать посты в Vim3, а в ReText, которым я пользуюсь для написания этого вот поста, плагины не предусмотрены.

Вчера меня, наконец, осенило:

А что, собственно, мешает вставлять текущую дату средствами системы?!

У меня ж тут вроде бы Linux, в котором вроде бы возможно всё — и ещё немножко. Так неужто нельзя организовать вставку текущей даты в формате ISO 8601 в любое место по желанию? А ведь можно же!

Как и в любом приличном системном интерфейсе, в KDE, которым пользуюсь я, есть возможности назначить выполнение любой команды на сочетание клавиш. Например, на Ctrl-Alt-D. Надо только понять, как должна выглядеть команда, которая вставит текущую дату. И куда вставит-то, кстати?

Найти сходу команду, которая вставляла бы произвольный текст в позицию курсора в любое окно, я не смог. Зато есть утилита xsel для работы с буфером обмена, можно вставить текущую дату туда. Надо попробовать:

date -Is | tr -d "\n" | xsel -b -i

Работает!4 Текущая дата в нужном формате появляется в буфере, потом можно нажать ‘Ctrl-V’ (или ‘Shift-Ins’, кому что удобно) — и дата вставится куда пожелаешь. Но на это уходит два сочетания клавиш, и буфер обмена при этом перезаписывается — неаккуратненько как-то это всё. Хочется, чтобы в одно нажатие и без манипуляций с буфером…

Гугл подсказал, что есть утилита xdotool, которая умеет печатать за пользователя. Интересно, она заработает по сочетанию клавиш? Заведём-ка что-нибудь вроде

xdotool type "test"

на сочетание Ctrl-Shift-T и попробуем в текстовом редакторе… Упс! В редакторе открылось окно «сохранить как». Что за чертовщина?!

Оказывается, xdotool-то печатает, но клавиатура-то при этом ввод даёт тоже, а у меня же в этот момент нажаты Ctrl и Shift! Поэтому редактор (а это в тесте был Kate) не получил Ctrl-Shift-T (его перехватила система), но получил Ctrl-Shift-E (на которое никакого действия не предусмотрено), а потом Ctrl-Shift-S («сохранить как»), и повторное Ctrl-Shift-T уже игнорировал.

Так не пойдёт! Благо, для xdotool есть опция --clearmodifiers, которая «отпускает» перед началом печати все нажатые клавиши (включая CapsLock, например), а после окончания печати восстанавливает состояние в исходное. Пробуем…

Уже лучше. Правда, зачем-то xdotool «отпустил» ещё и T, поэтому первая буква пропала, а потом «нажал обратно» Ctrl и Shift (и редактор вёл себя очень странно, пока я не догадался нажать это сочетание снова). Но это всё уже не проблема: буква D, которая у меня будет входить в сочетание для даты, в дате не встречается, а «отпустить» клавиши, «нажатые обратно», можно заставить сам xdotool:

xdotool type --clearmodifiers $(date -Is | tr -d "\n") && xdotool keyup ctrl alt d

Нажимаем Ctrl-Alt-D

Вот и славно! Работает где угодно, хоть в консоли, хоть в ReText, хоть в том же Vim…

Конечно, на то, чтобы разобраться (особенно с xdotool) ушло время5. Конечно, кто-то назовёт это «ненужным красноглазием». Но мой компьютер теперь делает то, что я хочу, и так, как я хочу. Для чего, собственно, компьютер-то и нужен по-хорошему…

Мне думается, таким вещам надо обязательно в школе учить.


  1. Это можно использовать (и использую) для показа даты обновления. Например, вот этот пост написан в июле прошлого года, а месяц назад я чуть скорректировал ошибки, возникшие при импорте из Known, поэтому в заголовке июль 2019 (из Front Matter), а в нижней части, над тэгами — май 2020 (дата последнего коммита этого файла в Git). ↩︎

  2. Что-то пишется урывками в свободное время, что-то обдумывается подолгу. Можно было бы писать в отдельном файле, а перед публикацией вставлять в новосозданный, но к чему эти лишние телодвижения… ↩︎

  3. Это тема для отдельного поста. Я с удовольствием пользуюсь Vim для правки конфигов, написания скриптов на bash и кода на Go, но мне жутко неудобно писать в нём связный текст на человеческом языке — changelog ещё могу, а вот readme уже тяжко. ↩︎

  4. date -Is даёт дату в нужном формате, tr -d "\n" убирает из полученной строки символ конца строки (условный «Enter», который date зачем-то добавляет в конец), а xsel -b -i записывает полученную строку в системный буфер обмена. ↩︎

  5. Как всегда. ↩︎

Комментарии — это вебменшены.