Герой обзора - утилита espanso, позволяющая на лету заменять текстовые фрагменты.
Опять прога на Rust. И опять впечатление "ух ты!", как от ruff и uv.
DRY! Не повторяйся при наборе текста!
У людей, которые целый день пишут тесты: кодеры, тестеры, админы, тех-писатели, тех-поддержка, наставники, кураторы и прочие - у всех, кто работает с клавиатурой весь день, часто возникает коллекция повторяющихся фрагментов, заготовок.
Зачем мне самому коллекция заготовок
Я ревьювер в ЯндексПрактикуме с 2020 года, комментирую коды студентов уже пять лет. 95%-90%-80% комментариев повторяются десятки-сотни-тысячи раз.
Расскажу, какие мне попадались организации такой коллекции, расставлю им "за" ➕ и "против" ➖ (имхо оценки). Надеюсь, в комментариях поделятся другими.
Примитивный файл с текстовыми фрагментами
➕ Придумал новый фрагмент, добавил в конец файла - все, можно пользоваться.
➖ Поиск фрагмента примитивный - по его словам средствами редактора.
➖ Вставка фрагмента низкотехнологичная - копипастой.
Личный опыт
Поразительно живучий формат. Мне не удалось от него избавиться - в нем застревают редко применяемые, но явно полезные фрагменты.
Дополнительные возможности утилит другого назначения
Punto предоставляет сервис "замены текста на текст".
AutoHotKey способен замороченным способом реализовывать замены.
➕ Годится для крохотной коллекции.
➖ Не масштабируется по размерам и числу фрагментов.
Личный опыт
Пунто-заменяльщик был моей первой попыткой. После мновенного разрастания коллекции до нескольких десятков замен стало понятно "это не годится". Но рудименты остались - десяток замен все еще выполняются Пунтой.
AHK настолько мало приспособлен для поставленной задачи, что попытки заглохли за пару дней.
Obsidian и подобные
➕ Богатый сервис: поиски, визуализации связей, плагины - красота!
➖ Вставка фрагмента - копипастой.
➖ Высокий порог входа.
Личный опыт
Обсидиан произвел сильное впечатление. Коллеги его применяют. Но мне он не годится, так как мой DRY включает, в том числе, и частые подстановки коротких фраз и даже отдельных слов – ходить в соседнюю прогу "за словами" это уже никакая не "личная продуктивность".
espanso
Специализированная утилита, работающая по юникс-принципу "решай одну задачу, но решай ее максимально хорошо".
➕ Вставка фрагмента автоматическая: демон следит за нажатиями клавиш, распознает фрагменты-триггеры и на лету заменяет их на новые фрагменты.
➕ Начать пользоваться “не просто, а очень просто!”
➕ Легко указать место каретки (курсора) после вставки.
➕ Есть подстановки содержимого буфера обмена.
➖ Триггеры нужно придумывать и потом вспоминать/искать.
➖ Триггеры могут срабатывать неуместно, нужна аккуратность при их создании.
Быстрый старт
Скачать и установить утилиту для своей ОС Win/Linux/Mac.
Открыть YAML-файл с триггерами
в Вин%AppData%\espanso\match\base.ymlв Линhome/$USER/.config/espanso/match/base.yml
в Мак/Users/$USER/Library/Application Support/espanso/match/base.ymlУдалить примеры от автора.
Заполнить своими триггерами.
Сохранить. Все! Можно пользоваться.
Замены будут доступны в любом месте, где возможен ввод текста: в редакторе, в браузере, в терминале, в окне выбора файла и т.п.
Два способа применения:
Либо набрать триггер-фрагмент – тут же выполнится подстановка.
Либо вызвать диалог для поиска по триггерам и заменам

Найдено пять вариантов в котором:
Набрать текст 1️⃣. Произойдет его фаззи-поиск в триггерах и заменяемых текстах.
Выбрать из найденных вариантов 2️⃣
– либо кликом,
– либо стрелками+ВВОД,
– либо через ускорители 4️⃣ для первых восьми вариантов.
Лучше запомнить триггер 3️⃣ примененно�� замены. Ведь если через две минуты нужна такая же замена, то применение этого триггера первым способом даст большую экономию.
Вызов диалога происходит
– либо по сочетанию клавиш (в Вин этоAlt+пробел, настраивается),
– либо по специальному триггеру (можно настроить).
Пример.
Если заполнить файл base.yml такmatches: - trigger: Дд replace: Добрый день! - trigger: ддфио replace: | Добрый день! С уважением Имя Фамилия - trigger: ч-т-о replace: "c:\\users\\me\\Downloads\\что-то-особое\\"
то будут доступны три замены:
Ддбудет подменяться наДобрый день!.
Пригодится для общения в чатах и письмах.ддфиобудет подменяться наДобрый день!С уважениемИмя Фамилия
Пригодится для начала письма.ч-т-обудет подменяться наc:\users\me\Downloads\что-то-особое\.
Пригодится для ввода спец-папки при сохранении из браузера.
Вкусности
Через
$|$можно указать место для каретки внутри вставленного фрагмента.Если описать триггер так
- trigger: "н"replace: "новость"word: true
то замена произойдет только, еслинокажется полным словом.
Значит все буквы кроме тех, которые являются однобуквенными словами
а,в,и,к,о,с,у,я,
можно применять как триггеры. Максимальная экономия!
Свойствоleft_word: trueмягче - оно проверяет, что фрагмент не находится в начале слова.Если описать триггер так
- trigger: "нвст"replace: "новость"propagate_case: true
то замена будет учитывать регистр при вводе:
нвстзаменится нановость,
Нвстзаменится наНовость,
НВСТзаменится наНОВОСТЬ.Через
{{clipboard}}можно добавить к тексту содержимое буфера обмена.
Для этого нужно к описанию триггера еще добавить новый атрибутvars.
Пример- trigger: "змнб"replace: "Замените {{clipboard}} на {{clipboard}}."vars: [{"name": "clipboard", "type": "clipboard"}]Можно вставлять результаты от работы консольных команд или от вызова Питона.
Можно вставить текст одного триггера в другой.
Это может пригодится, если вставляемый большой и/или нестабильный.Можно указать регулярку для триггера.
Автор эспансы рекомендует делать это осторожно и только если нет других способов.Если в подставляемый текст нужно добавить несколько значений, известных только в момент вставки, то это можно сделать через показ формы-диалога.
Например, после ввода триггера может появится такая форма
Если в нее вписать два текстовых поля 1️⃣ и 2️⃣, выбрать вариант в выпадающем списке 3️⃣ и еще вариант в развернутом списке 4️⃣, то после ВВОД триггер заменится на
Добрый день, Андрей!Обратите внимание на неудачный текст.Если появятся вопросы, можетенаписать мне в Пачку @me_pch,либо наставнику @name2 в Пачке.
Для оформления такого триггера нужно больше разметки- trigger: "реакция1"form: |Добрый день, [[name]]!Обратите внимание на [[fragment]].Если появятся вопросы, можетенаписать мне [[to_me]],либо наставнику [[pch_tags]] в Пачке.form_fields:to_me:type: choicevalues:- "в Пачку @me_pch"- "в Телегу @me_tlg"- "на почту me@me.ru"pch_tags:type: listvalues:- "@name1"- "@name2"- "@name3"
Да, разметки много.
Но! Если такой триггер-диалог уже создан, то развивать его легко - достаточно только менять текст послеform: |и элементы в спискахvalues:.Форма может быть минимальной - содержать лишь список вариантов. Так, например, удобно подставлять один из своих мейлов/телефонов/сайтов/...
Можно "подхватывать" через систему плагинов готов��е наборы с hub.espanso.org.
Например, текущие дата/время, эмодзи-символы или эмодзи-фразы, куски TEX-формул и пр.
Проблемы и советы про создание триггеров
Есть противоречия при выборе триггер-фразы:
– Чтобы работала экономия, фраза должна быть как можно короче.
– Чтобы удобно применять триггер, фраза должна состоять из простых символов: в одном регистре, без спец-знаков.
– Но чтобы запомнить фразу, она должна быть содержательной, то есть длинной.
– Но чтобы триггер случайно не срабатывал, выгодно делать фразу сложнее или со спец-знаками.
Поэтому выбор триггеров требует баланса - каждый сам взвешивает риски и выбирает экономию/содержательность и простоту/надежность.
В примерах на сайте самой эспансы все триггеры начинаются с :, то есть ради надежности страдает экономия+простота.
Личный опыт
Создал >1300 триггеров, сейчас в работе ~1000. Помню из них ~400, остальные применяю либо однократно через диалог поиска, либо в диалоге их вспоминаю.
Фразы сложились в почти язык: корни, приставки/суффиксы, глаголы/наречия и прочие связи.
Примеры.
(1) Для ревью нужны комментарии про ошибки - триггеры для них начинаются на приставки
ош- любая ошибка,
лш- логическая ошибка.
(2) Еще приставки:
ли- про что-то лишнее,
ну/до- про нужно добавить,
уд- про удачное место,
не- про неудачное место.
(3) Суффиксбуказывает, что будет вставка из буфера обмена.Мой приоритет – простота применения.
Самый частый способ создания нового триггера - это обрезание текста до почти аббревиатуры. Удача, если получается яркое сокращение.
Примеры:
лиизба= Лишний запрос в базу. Ответ известен заранее.
нупопа= Мало подсказок для отчета о падении подтестов.
ужефан= Лишняя функция. Уже есть штатная фикстура для анонима.
нутаз= Не нужна какая-то случайная запись из базы. Нужна только та, которую редактировали.Очень удобно применять подмены для вставки нерусских терминов/кодов - почти всегда первые буквы на русской раскладке будут уникальной фразой
куй= requests
оы= json
зкш= print()
юащ= .format()
пуещ= get_object()
Замены эспансой позволяют не переключать раскладку.Эспансо-замены отлично сочетаются с маркдауном.
Почти всегда вставляю короткие и многострочные примеры кодов через триггеры, подставляя код из буфера.
