ESPN2027 recruiting class rankings: Duke enters top 45 in latest updateThe Jerusalem PostFlights must be open to all or to no one, Iranian adviser says following Iraqi airport suspensionDaily MaverickFreedom from the ANC could be our real emancipationPunchLady apologises for AI-generated Itel power tank explosion imageUN NewsThe Takeaway: UN General Assembly debate Day 3RTP DesportoGP de Portugal antecipado para outubro em 2027, Argentina regressa e Hungria saiInquirerMarcos signs BSKE postponement into lawBollywood HungamaA true MASTERSTROKE: Avengers Endgame: Encore has MORE surprises beyond the leaked scenes; Marvel saves its BIGGEST twist for theatres (SPOILERS ahead)SCMP ChinaXi Jinping marks second Mid-Autumn Festival in US during state visitRadio Times10 Questions with Amol Rajan and Hannah FryBillboardMusic Venue Trust Teams Up With Drowned In Sound to Launch Live Music TitleSouth China Morning PostItaly to ban burkas in schools, with 30% cap on pupils with poor Italian
The Daily Newsstand · Free, Always
Friday, September 25, 2026

Emacs: основные режимы

Translate

В Emacs режимы делятся на основные (major) и дополнительные (minor). Основной режим определяет правила работы с буфером: подсветку синтаксиса, поведение редактора при нажатии клавиш, какие-то дополнительные команды.

Если провести аналогию, то в других редакторах вы задаёте основной режим когда указываете тип файла. Например, в Zed тип файла по умолчанию — Plain Text. Однако, вы можете в любой момент поменять его на один из доступных, и вам тут же станут доступны и подсветка синтаксиса, и его проверка, и другие удобства.

Основной режим в буфере должен быть только одним. Как говорится:

There can be only one.

Существуют пакеты, которые позволяют включать в буферах несколько основных режимов, но я их максимально осуждаю и не рассматриваю.

Наследование

Основные режимы, как правило, создаются на базе одного из четырёх базовых режимов.

  • fundamental-mode — минимальные удобства для ввода и вывода информации. Никакой подсветки синтаксиса и так далее.

  • special-mode — режим для специальных буферов, то есть таких, которые не предназначены для редактирования текстов. Режимы для просмотра изображений и логов, вывода ошибок и сообщений строятся на базе special-mode.

  • text-mode — режим для работы с текстами на естественных языках. На базе text-mode созданы такие режимы, как:

    • rst-mode — для работы с ReStructured Text.

    • markdown-mode — Markdown.

    • adoc-mode — AsciiDoc.

  • prog-mode — режим для буферов с текстами на различных языках программирования. Технически prog-mode — потомок fundamental-mode. На базе prog-mode строятся все остальные режимы для работы с языками программирования, например, эти:

    • python-mode;

    • c-mode;

    • makefile-mode;

    • rust-mode;

    • r-mode.

Впрочем, наследование не является обязательным. В коде многих пакетов вы можете увидеть примерно такое:

;;;###autoload
(define-derived-mode conf-mode nil "Conf[?"
  ;; Код режима
)

Здесь nil — предок, то есть в данном случае режим создаётся с нуля, а не на основе одного из базовых режимов.

Хуки

Итак, мы теперь знаем, что режимы наследуются. Но что нам это даёт? А даёт нам это несколько интересных побочных свойств.

При активации режима-потомка срабатывает и хук активации режима-предка. Рассмотрим на примере.

Наследование режимов в пакете conf-mode.el

Наследование режимов в пакете conf-mode.el

Далее я буду оформлять такие диаграммы как обычные маркированные списки:

  • conf-mode;

    • conf-unix-mode;

      • conf-space-mode;

      • conf-colon-mode;

        • conf-xdefaults-mode;

        • conf-ppd-mode;

      • conf-desktop-mode;

    • conf-windows-mode;

    • conf-javaprop-mode;

    • conf-toml-mode.

Хабр не даёт вставлять SVG, а использовать зашакаленные PNG я не хочу.

Встроенный пакет conf-mode.el предоставляет 10 основных режимов, из них 4 являются прямыми наследниками conf-mode, ещё 3 наследуют от conf-unix-mode, и ещё 2 от conf-colon-mode.

Допустим, мы хотим включать дополнительный режим flymake-mode в буферах с основными режимами conf-toml-mode и conf-unix-mode. В этом случае наивный код будет выглядеть так:

(use-package flymake
  :hook
  (conf-toml-mode . flymake-mode)
  (conf-unix-mode . flymake-mode))

Можно чуть-чуть оптимизировать его:

(use-package flymake
  :hook
  ((conf-toml-mode 
    conf-unix-mode) . flymake-mode))

В обоих случаях мы не решаем 2 важных проблемы:

  1. Если в будущем мы захотим добавить активацию flymake-mode при включении ещё одного из режимов conf-mode.el, нужно будет модифицировать имеющийся код:

    (use-package flymake
      :hook
      (conf-toml-mode
       conf-unix-mode
       conf-ppd-mode) . flymake-mode)
  2. Похожие правки нужно сделать во множестве других мест. Мы же можем активировать в буфере множество дополнительных режимов. И что теперь, делать однотипные правки в десяти местах?

Проблема ещё более усугубляется благодаря TreeSitter. Множество пакетов для языков программирования теперь предоставляют 2 основных режима подсветки синтаксиса:

  • "Классический" режим на базе регулярных выражений.

  • Построение синтаксического древа с помощью TreeSitter.

Оптимизация

Обратимся к пакету python.el. Он предоставляет эти режимы:

  • python-base-mode;

    • python-mode;

    • python-ts-mode.

В зависимости от того, классический режим используется или на базе TreeSitter, настройка дополнительных режимов может выглядеть по-разному:

(use-package flycheck
  :pin gnu
  :ensure t
  :hook
  ((python-mode
    python-ts-mode) . flycheck-mode))

(use-package eglot
  :pin gnu
  :ensure t
  :hook
  ((python-mode
    python-ts-mode) . eglot-ensure))

(use-package indent-bars
  :pin gnu
  :ensure t
  :hook
  ((python-mode
    python-ts-mode) . indent-bars-mode))

Если вы используете python-mode, то хук для python-ts-mode явно не нужен. Соответственно, если вы установили грамматику и настроили TreeSitter, то не нужен хук для python-mode. Код явно не оптимален. Однако, можно упростить его, если повесить обработчик на общего предка:

(use-package flycheck
  :pin gnu
  :ensure t
  :hook
  (python-base-mode . flycheck-mode))

(use-package eglot
  :pin gnu
  :ensure t
  :hook
  (python-base-mode . eglot-ensure))

(use-package indent-bars
  :pin gnu
  :ensure t
  :hook
  (python-base-mode . indent-bars-mode))

Это делает код более отказоустойчивым: какой бы режим для Python мы по факту не использовали, все дополнительные режимы будут активироваться без изменения init.el.

Вернёмся к примеру с conf-mode.el:

(use-package flymake
  :hook
  (conf-colon-mode
   conf-desktop-mode
   conf-javaprop-mode
   conf-ppd-mode
   conf-space-mode
   conf-toml-mode
   conf-unix-mode
   conf-windows-mode
   conf-xdefaults-mode) . flymake-mode)

Этот код можно сократить до такого:

(use-package flymake
  :hook (conf-mode . flymake-mode))

Rust

Множество режимов имеют общего предка, поэтому привязка минорных режимов к его хуку весьма эффективна. Однако, из этого правила есть одно исключение. Пакет rust-mode от авторов языка Rust работает немного не так, как вы думаете.

Он предоставляет режим rust-mode, но является он потомком встроенного режима rust-ts-mode или нет, зависит от настройки rust-mode-treesitter-derive:

(use-package rust-mode
  :pin nongnu
  :ensure t
  :custom
  (rust-mode-treesitter-derive t "Наследование от `rust-ts-mode' ВКЛ.")
  :mode ("\\.rs\\'" . rust-mode))

Таким образом, вы можете использовать rust-mode и с TreeSitter, и без него.

JavaScript

Если мы говорим о встроенном пакете js-mode.el, то там такое наследование:

  • js-base-mode;

    • js-mode;

    • js-ts-mode.

Достаточно повесить обработчик на js-base-mode.

Генеалогия

Как узнать, какой предок у режима?

  1. Напишите в init.el название нужного режима:

    (markdown-mode)
  2. Нажмите [M-.]. Emacs откроет код пакета, предоставляющего режим. В строке с define-derived-mode вы и увидите предка, например:

    ;;;###autoload
    (define-derived-mode markdown-mode text-mode "Markdown"
      "Major mode for editing Markdown files."
      (when buffer-read-only
        ;;; ...
    ))

Кстати, у режимов из markdown-mode.el интересная диаграмма наследования:

  • text-mode;

    • markdown-mode;

      • gfm-mode;

        • gfm-view-mode;

      • markdown-view-mode.

Здесь gfm означает GitHub Flavored Markdown, специальный режим для работы с диалектом Markdown, используемым на GitHub.

View the original on Хабр →

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.