GNU EMACS для технических писателей
184 subscribers
8 photos
13 files
65 links
Настройка, использование, хаки
Download Telegram
Про мизинец, который в английском "pinki".

На клавиатурах для LISP-машин клавиша [Ctrl] размещалась там, где сейчас [Alt]. А там, где сейчас [Ctrl], находилась клавиша [Meta]. Поэтому сочетания для Emacs были там весьма удобны: зажимаешь большим пальцем [Ctrl], потом нужную клавишу. Сейчас [Ctrl] приходится нажимать мизинцем, и это породило целый мем среди пользователей редактора: "pinki problem".

Есть разные способы решения этой проблемы, но основных два:
- повесить Ctrl на CapsLock и нажимать его ребром ладони;
- на уровне системы поменять поведение Ctrl и Alt, превратив их по сути в Meta и Ctrl.

Мне оба способа не нравятся, и я пользуюсь обычными сочетаниями. Мизинец не болит.

Если у вас болит — посмотрите пакет ergoemacs-mode.
В канале Любители AsciiDoc спросили, как быстро перемещаться между разделами в больших AsciiDoc-файлах в Sublime Text.
У пользователей Emacs несколько вариантов:

1. occur с регулярным выражением "^=* " (обратите внимание на пробел после =).
2. isearch. Классика.
3. minimap. Помните такой? Он всё ещё жив, но у меня работает как-то глючно, поэтому не пользуюсь.
4. breadcrumb-mode. У него есть команда breadcrumb-jump, которая как occur, только по заголовкам. Правда, есть большой вопрос: "А что она считает заголовком?" Я её потестировал на исходном коде книги, и увидел дублирование некоторых пунктов в результатах поиска.
Хочу понять, кто меня читает. Поэтому сегодня посмотрим, какая ОС у вас основная:
Anonymous Poll
23%
Windows
53%
Linux
18%
macOS
5%
Что-то из BSD (FreeBSD, OpenBSD, NetBSD...)
С аудиторией разобрались. 20% сидящих на Windows это много. Надеюсь, у вас там WSL2 и всё хорошо.

Вернёмся к Emacs. Он не существует как сферический конь в вакууме сам по себе, а работает с теми переменными, которые заданы на уровне окружения. Например, переменная HOME. В *nix-системах это путь к домашнему каталогу. В Windows по умолчанию такой переменной нет, и Emacs вынужден подставить туда хоть что-то. По умолчанию — путь к каталогу с профилем. Ну, вот этот вот, типа C:\Users\mdunaevsky\AppData\Roaming. Не очень красивое название, правда? Мне больше нравится D:\dunaevsky. Впрочем, вы можете создать эту переменную сами в настройках ОС.

Когда вы переходите в какой-нибудь каталог и открываете файл, Emacs по-прежнему знает про переменные окружения. Самая важная из них — PATH. Она хранит список каталогов, в которых нужно выполнять поиск при запуске команд. В Windows эта переменная тоже есть. Поэтому, когда вы смотрите статус Flycheck, то видите там те пути к своим линтерам, которые Emacs смог найти в каталогах, указанных в PATH.

Если путь к каталогу с исполняемым файлом линтера не входит в PATH, Emacs (точнее, Flycheck), не сможет использовать его. Разумеется, другие команды тоже не будут работать. Вы вызываете projectile-build-command:

make dirhtml


Emacs пишет:

sphinx-build not found


Это потому, что Sphinx установлен в виртуальном окружении, про которое Emacs ничего не знает.

Виртуальное окружение, как правило, активируется с помощью этой команды:

source .venv/bin/activate


Эта команда добавляет в PATH нужные пути, и делает много какой другой работы. Когда вы активируете окружение, то получаете настроенные переменные окружения. Это работает не только с Python. Например, утилита Bundler из мира Ruby делает то же самое: заполняет переменные окружения нужными значениями.

Вы вызываете команду:

bundle exec asciidoctor-pdf ...


Bundler заполняет переменные окружения нужными значениями, а уже потом запускает asciidoctor-pdf. Вот только использовать его совместно с Flycheck в этом случае не получится, я проверял. Нужно что-то другое.

THE BAD

Установите asciidoctor в системное окружение с помощью команды:

gem install asciidoctor


Возможно, это даже не сломает вашу систему. А может быть сломает. Разработчики Debian запретили установку и обновление системных пакетов Python с помощью PIP. Думаю, скоро настанет и очередь Ruby.

THE UGLY

Используйте пакет asciidoctor, входящий в состав дистрибутива. Скорее всего, там будет какое-нибудь старьё, но этот способ даёт хоть какой-то контроль над происходящим.

THE GOOD

Установите в систему утилиту direnv. А вот как её использовать, и при чём тут Emacs — тема отдельного поста.

#direnv #ruby #python
direnv

Классический порядок работы с виртуальными окружениями такой:

1. Перейти в каталог проекта.
2. Создать виртуальное окружение:

python3 -m venv .venv/


3. Активировать созданное окружение:

source .venv/bin/activate


4. Установить зависимости:

pip3 install -r REQUIREMENTS


5. Работать работу.
6. Деактивировать окружение:

deactivate


Шаги 1, 2 и 4 нужно выполнить только один раз. А вот шаги 3, 5 и 6 приходится делать каждый раз. То есть это явное поле для автоматизации.

Утилита direnv работает так:

1. Вы переходите в каталог.
2. direnv ищет в каталоге файл .envrc.
3. Если этот файл существует и разрешён к использованию, direnv выполняет указанные в нём команды, которые в 99% случаев просто присваивают переменным окружения нужные значения.
4. Вы работаете работу.
5. Как только вы покидаете каталог, direnv возвращает состояние переменных окружения к значениям, которые у них были до перехода в каталог.

Если у вас под рукой есть проект на Python, попробуйте это сделать:

1. Создайте в каталоге проекта файл .evnrc:

source .venv/bin/activate


2. Перейдите в каталог проекта. direnv напишет, что использование файла .envrc не разрешено.
3. Разрешите использование файла .envrc:

direnv allow


Вы увидите, что direnv тут же выполнит команды, указанные в .envrc. В данном случае — просто активирует виртуальное окружение. Список изменённых переменных окружения будет выведен в терминал.
Как только вы покинете каталог, direnv снова выведет сообщение, на этот раз уведомление о возвращении переменных в исходное состояние. Всё, больше никаких workon и source .venv/bin/activate.

При чём тут Emacs? А для него есть несколько пакетов, которые либо интегрируются с direnv, либо делают то же самое, что и он: читают .envrc и получают из него нужные значения переменных окружения.
Я насчитал три пакета, которые делают это:

1. direnv
2. envrc
3. buffer-env

Я не могу сказать, какой из них лучше, а какой хуже, но скажу по секрету, что мне больше других нравится envrc:

;; 📦 ENVRC
;; https://github.com/purcell/envrc
;; Загрузка переменных окружения из `.envrc'.
(unless (package-installed-p 'envrc)
(package-vc-install '(envrc
:url "https://github.com/purcell/envrc.git"
:branch "0.12")))
(use-package envrc
:hook (after-init . envrc-global-mode))
YaSnippet

В Emacs есть такая штука — аббревиатуры (abbrevs). Вы вводите текст, а он автоматически заменяется на другой. Например, вы можете настроить замену строки TF на Terraform (пример из реальной жизни, пользовался на одном из проектов). Однако, аббревиатуры не подходят, когда вам нужно сделать оформление и вёрстку. Например, как в ReStructured Text сделать аббревиатуру для такого?

.. _link:

Title
=====


Никак. Тут нужны сниппеты — небольшие фрагменты, которые будут автоматически заменяться на нужную вёрстку. Пакет YaSnippet предоставляет такой механизм, причём с удобствами. Давайте установим его и сделаем несколько сниппетов?

1. Добавьте код, который создаёт каталог snippets и устанавливает пакеты:

;; 📦 YASNIPPET
;; https://elpa.gnu.org/packages/yasnippet.html
;; Библиотека для управления сниппетами. Требуется для расширения функций Eglot.
(use-package yasnippet
:ensure t
:init
(progn
(defvar init-el-yasnippet-snippets-dir (expand-file-name "snippets" user-emacs-directory))
(unless (file-directory-p init-el-yasnippet-snippets-dir)
(make-directory init-el-yasnippet-snippets-dir))
(unless (file-directory-p init-el-autosave-dir)
(make-directory init-el-autosave-dir)))
:config (yas-global-mode 1))


;; 📦 YASNIPPET-SNIPPETS
;; https://github.com/AndreaCrotti/yasnippet-snippets
;; Набор сниппетов для `yasnippet'
(use-package yasnippet-snippets
:ensure t)


Каталог snippets нужен для того, чтобы YaSnippet не падал замертво при запуске.

2. Создайте в каталоге snippets подкаталоги с названиями режимов, для которых будете создавать сниппеты. Я создал такие:

snippets/
├── adoc-mode
└── rst-mode


3. Внутри каталогов создайте файлы со сниппетами. У меня получилось так:

snippets/
├── adoc-mode
│   ├── admonition
│   ├── caution
│   ├── important
│   ├── note
│   ├── source
│   ├── table
│   ├── tip
│   └── warning
└── rst-mode
├── admonition
├── h1
├── h2
├── h3
├── h4
├── image
└── va


3. Давайте посмотрим самый простой сниппет, adoc-mode/note:

# -*- mode: snippet -*-
# name: note
# key: note
# --
[NOTE]
====
$1
====
$0


Работает он так:

1. Введите строку note.
2. Нажмите [TAB].
3. Строка note заменится фрагментом кода:

[NOTE]
====

====


4. Введите текст. Курсор будет автоматически перемещён в позицию между ==== (в коде сниппета это $1).
5. Нажмите [TAB] ещё раз, и курсор переместится за пределы сниппета, то есть вернётся к нормальному режиму работы.

Давайте посмотрим пример посложнее. Количество разделителей под заголовками в ReStructured Text должно быть таким же, как количество символов в самом заголовке. Вот этот код — некорректен:

Заголовок первого уровня
#####


Вот этот правильный:

Заголовок первого уровня
########################


Давайте ещё и ссылку тут же будем вводить:

.. _link:

Текст
#####


Итоговый сниппет для заголовков первого уровня будет выглядеть так (snippets/rst-mode/h1):

# -*- mode: snippet -*-
# name: Header level 1
# key: h1
# --

.. _${1:href}:

${2:Title}
${2:$(make-string (string-width yas-text) ?\#)}

$0
Добрый день, дорогие читатели!

Рад поделиться новостью о выходе на Boosty версии книги v24.11.
Список изменений:

1. В раздел про Emacs Lisp добавлено немного про циклы. Может быть полезно, если вы предпочитаете не использовать use-package для управления конфигурацией.
2. Добавлено частичное описание настроек Flycheck и Flymake.
3. Обновлён раздел про управление пакетами.
4. Исправлены уровни заголовков. Навигация по PDF должна стать удобнее.
5. Исправлено описание настроек для direnv.
6. Исправлены описания основных терминов.
7. Исправлены несколько опечаток.
8. Добавлена глава про установку и настройку тем.
9. Добавлено описание базовых настроек adoc-mode.
10. Добавлена глава про работу Emacs с окружением: direnv, envrc и buffer-env.
11. Добавлена инструкция по переключению буферов с помощью Ctrl+Tab и Ctrl+Shift+Tab.
12. Добавлено описание работы с YASnippet.
13. Добавлено описание пакета css-mode.
14. Добавлена заготовка главы про Sphinx. Это экспериментальная глава: она может вырасти во что-то большее или быть удалённой вовсе.
15. Добавлено описание пакета Delight.
16. Добавлено частичное описание настроек пакета Dired.
17. Добавлена глава про работу с файлами PO.
18. Добавлена глава про Swiper.

В отдельном посте доступна версия Monokai. Отличие только в теме оформления. Что касается темы оформления, то это продукт, идентичный натуральному, т. е. PDF, собранному с "белой" темой.
Дорогие подписчики, представляю вашему вниманию сайт GNU Emacs по-русски!
Он сейчас в стадии разработки, а это значит, что:
- сертификат пока не настроен как следует;
- маловато контента;
- не настроена тема оформления (взял стандартную тему проекта Antora, пока без кастомизации).
Материалы про Emacs будут доступны сначала в книге, а спустя какое-то время будут появляться и на сайте.
Я вам не скажу за все modeline, но мне очень нравится nano-modeline. Код:

;; 📦 NANO-MODELINE
;; https://elpa.gnu.org/packages/nano-modeline.html
;; Статусная строка маленькая вообще жестб
(use-package nano-modeline
:ensure t
:custom
(nano-modeline-position 'nano-modeline-footer "Показывать внизу")
:hook
(messages-buffer-mode . nano-modeline-message-mode)
(org-agenda-mode . nano-modeline-org-agenda-mode)
(org-capture-mode . nano-modeline-org-capture-mode)
(org-mode . nano-modeline-org-mode)
(prog-mode . nano-modeline-prog-mode)
(term-mode . nano-modeline-term-mode)
(text-mode . nano-modeline-text-mode))
Как это выглядит: режим, имя файла, ветка, наличие изменений, строка, колонка. Ничего лишнего.
По мотивам комментария в канале «Технические писатели» я решил написать очередную статью на Хабр в духе "Вы неправильно настраиваете Emacs: что бывает, если вы пытаетесь сделать из него "нормальный" редактор".

Но пока статья в работе, поделюсь небольшим открытием по поводу функции mark-word. По умолчанию она привязан к сочетанию [M-@], т. е. на самом деле к [Alt+Shift+2] (двойка из верхнего ряда). Повторное нажатие этого сочетания расширяет выделенную область, захватывая всё новые и новые слова.

Долгое время я думал, что эта функция работает только в одном направлении — от текущей позиции курсора к концу текста. Однако, сегодня я узнал, что это не совсем так. Если выделить хотя бы одно слово и нажать [M-f], будет выделено ещё одно слово, будто вы нажали [M-@], а вот если нажать [M-b] — будет выделено слово перед курсором, то есть выделение можно расширять в обратном направлении. Разумеется, [C-f] и [C-b] тоже работают, но добавляют к выделению не слова, а отдельные символы.
Репозиторий с минимальными настройками и очень подробным описанием `init.el`
Anonymous Poll
14%
Не нужен
75%
Хочу
11%
Да, сейчас дам ссылку 😊
Сайт с документацией по Emacs на русском языке перемещён с https://emacs.dunaevsky-ms.ru/ на адрес https://dunaevsky-ms.ru/emacs/
А ещё вчера на Boosty вышла новая версия книги: переписан раздел про базовые операции с текстом. Ввод специальных символов тоже переехал из "Альбедо" в "Нигредо", как раз в операции правки.

Ещё не говорил об этом, поэтому просто запомните сочетания для вставки TAB и перехода на новую строку там, где это обычно делать нельзя (например, в минибуфере):

1. [C-q <tab>]
2. [C-q C-j]
У Emacs есть неприятная особенность при работе со ссылками.

1. Вы запустили Emacs и открыли ссылку.
2. Emacs запустил браузер и передал ссылку ему.
3. Браузер открыл ссылку, показал страницу.
4. Вы работаете дальше: пишете текст, смотрите задачи в трекере, читаете Habr, OpenNet или LOR, и так далее.
5. По какой-то причине вы решили завершить работу Emacs.
6. Браузер тоже завершил работу, хотя вы об этом не просили.

Поэтому лучше запускать браузер до того, как открывать какие-либо ссылки в Emacs. Тогда точно закрываться не будет.
Какие из указанных терминов не используется в Emacs?
Anonymous Quiz
13%
symbol
3%
word
6%
char
9%
paragraph
13%
sentence
6%
page
44%
footnote
6%
line
Поговорим о частях текста в Emacs.

symbol и char на русский переводятся как "символ", но первое слово имеет значение "слово, имеющее строго определённое значение". Переменная — symbol, название класса — symbol и так далее.

Слово char уже ближе к тому, что мы обычно подразумеваем под этим: буква, цифра, дефис, тире, пробел и так далее. Т. е. неделимая часть текста.

Word — последовательность символов. Слова отделяются друг от друга разделителями — пробелами, точками, запятыми, подчёркиваниями. Для Emacs UserAccess — одно слово, а User-Access — два. User Access — тоже два. Use apt-get — три. Дефис играет роль разделителя.

Sentence это "предложение", то есть часть текста, в конце которой стоит точка, восклицательный или вопросительный знак. А как же переход на новую строку? А никак. В ReStructured Text, AsciiDoc и некоторых диалектах Markdown это всё — одно предложение. Вот вам пример в ReStructured Text:

Мой дядя самых честных правил,
Когда не в шутку занемог,
Он уважать себя заставил
И лучше выдумать не мог.


При сборке получится такое:

Мой дядя самых честных правил, Когда не в шутку занемог, Он уважать себя заставил И лучше выдумать не мог.


Paragraph — это абзац. Surprise, motherfucker! Абзацы отделяются друг от друга пустыми строками. Это значит, что вот это — один абзац, хотя тут 3 предложения:

Мое любимое и главное подразделение людей в то время, о котором я пишу, было на людей comme il faut и на comme il ne faut pas.
Второй род подразделялся еще на людей собственно не comme il faut и простой народ.
Людей comme il faut я уважал и считал достойными иметь со мной равные отношения; вторых — притворялся, что презираю, но, в сущности, ненавидел их, питая к ним какое-то оскорбленное чувство личности; третьи для меня не существовали — я их презирал совершенно.


Page — это страница. Тут ничего нового. Вы вряд ли их используете в повседневной работе с Emacs, но наверняка встречали. В тексте они выглядят как последовательность ^L. Нужны они для постраничного просмотра текста. Не приходилось использовать, и в целом не вижу смысла в этой штуке, но она до сих пор поддерживается.

Line — это просто строка. Они бывают видимые и логические. Логическая строка — это последовательность символов между символами начала и конца строки. Видимая строка — это часть логической строки, отображаемая в одну линию. Вы наверняка используете режим visual-line-mode. Это значит, что если строка не влезает в экран, то та часть, что не влезла, просто переносится на новую строку.

А вот никаких footnote в Emacs нет. В Sphinx их можно добавить с помощью плагина, а в AsciiDoc они входят в спецификацию.