Как определить дополнительные модовые пары для режима электрических пар

13

electric-pair-modeявляется встроенным режимом для автоматической вставки совпадающих пар разделителей (скобки, квадратные скобки и т. д.) в зависимости от текущего основного режима.

Я знаю, что могу определить дополнительные пары (которые будут глобальными ), как это:

(push '(?\' . ?\') electric-pair-pairs)      ; Automatically pair single-quotes
(push '(?\' . ?\') electric-pair-text-pairs) ; ... in comments

У меня вопрос , как я могу определить специфичные для режима пары (например //, ==для org-mode)?

itsjeyd
источник

Ответы:

7

Самый простой способ сделать это путем создания electric-pair-pairsи electric-pair-text-pairsбуфер локального и настраивая их крючками для соответствующих режимов.

Рабочий пример для org-mode:

(defvar org-electric-pairs '((?/ . ?/) (?= . ?=)) "Electric pairs for org-mode.")

(defun org-add-electric-pairs ()
  (setq-local electric-pair-pairs (append electric-pair-pairs org-electric-pairs))
  (setq-local electric-pair-text-pairs electric-pair-pairs))

(add-hook 'org-mode-hook 'org-add-electric-pairs)

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


Дополнительная информация: setq-local

Из раздела « Создание и удаление локальных привязок буфера» руководства Elisp :

Macro: setq-local variable value

Этот макрос создает локальную привязку буфера в текущем буфере VARIABLEи дает ему локальное значение буфера VALUE. Это эквивалентно звонку с make-local-variableпоследующим setq. VARIABLEдолжен быть символом без кавычек.

itsjeyd
источник
7

Правильный путь: заполните отчет об ошибке через соответствующий канал вашего проекта, например, org-submit-bug-reportили report-emacs-bugи обсудите, почему следует изменить класс синтаксиса вашего любимого персонажа.

В качестве альтернативы вы можете изменить правильную синтаксическую таблицу (info "(elisp) Syntax Tables")в своем init.el.

Давайте попробуем Org:

(with-eval-after-load 'org
  (modify-syntax-entry ?/ "(/" org-mode-syntax-table)
  (modify-syntax-entry ?= "(=" org-mode-syntax-table)
  (add-hook 'org-mode-hook 'electric-pair-mode))

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

(defun rasmus/electric-pairs-with-local-pairs (pairs)
  "Start electric pair with buffer-local PAIRS.

  PAIRS is a list of strings and/or cons of strings."
  (require 'elec-pair)
  (let ((ec-lists '(electric-pair-pairs electric-pair-text-pairs)))
    (mapc 'make-local-variable ec-lists)        
    (mapc (lambda (L)
            (mapc (lambda (elm) (add-to-list L elm))
                  (mapcar (lambda (x)
                            (if (consp x)
                                (cons (string-to-char (car x))
                                      (string-to-char (cdr x)))
                              (cons (string-to-char x)
                                    (string-to-char x))))
                          pairs)))
          ec-lists))
  (electric-pair-mode t))

(with-eval-after-load 'org
  (add-hook 'org-mode-hook
            (lambda ()
              (rasmus/electric-pairs-with-local-pairs
               '("/" "=" ("`" . "'"))))))
Расмус
источник
Спасибо за публикацию ответа, который показывает, как изменить таблицу синтаксиса. Из двух предложений в вашем ответе я бы предпочел этот подход. Используя резервные переменные, я нашел другое решение, которое немного короче, чем defunв вашем ответе.
itsjeyd
2

Этот ответ не отвечает на ваш вопрос о том, как настроить electric-pair-mode. Но это может привести вас к желаемым результатам.

wrap-regionПакет , доступный на Melpa может быть ответ на вашу проблему. Вот краткое описание его github:

Wrap Region - это второстепенный режим для Emacs, который оборачивает область пунктуацией. Для «размеченных» режимов разметки, таких как HTML и XML, он переносится тегами.

Вот как я настроил его для работы в выбранных мной режимах. Фрагмент также охватывает вопросы, которые вы подняли в своем вопросе; о org-modeмаркерах свойств шрифта.

(require 'wrap-region)

;; Enable wrap-region in the following major modes
(dolist (hook '(emacs-lisp-mode-hook
                org-mode-hook))
  (add-hook hook 'wrap-region-mode))

(wrap-region-add-wrapper "`" "'") ; select region, hit ` then region -> `region'

(wrap-region-add-wrapper "=" "=" nil 'org-mode) ; select region, hit = then region -> =region= in org-mode
(wrap-region-add-wrapper "*" "*" nil 'org-mode) ; select region, hit * then region -> *region* in org-mode
(wrap-region-add-wrapper "/" "/" nil 'org-mode) ; select region, hit / then region -> /region/ in org-mode
(wrap-region-add-wrapper "_" "_" nil 'org-mode) ; select region, hit _ then region -> _region_ in org-mode
(wrap-region-add-wrapper "+" "+" nil 'org-mode))) ; select region, hit + then region -> +region+ in org-mode

Я хотел бы добавить, что этот пакет действительно хорошо работает с expand-regionпакетом (также доступен на Melpa).

С этими 2 пакетами, когда я буду org-mode, делаю: MY-EXPAND-REGION-BINDING *одним словом выделю жирным шрифтом.

Каушал Моди
источник
Спасибо за Ваш ответ. Я был в курсе wrap-regionпакета; это довольно полезно. В настоящее время я пытаюсь уменьшить количество сторонних пакетов, от которых я зависит, поэтому я не буду использовать это решение, но оно определенно заслуживает упоминания здесь! :)
itjeyd
2

Опираясь на ответ своего Джейд:

(defmacro spw/add-mode-pairs (hook pairs)
  `(add-hook ,hook
             (lambda ()
               (setq-local electric-pair-pairs (append electric-pair-pairs ,pairs))
               (setq-local electric-pair-text-pairs electric-pair-pairs))))

(spw/add-mode-pairs 'emacs-lisp-mode-hook '((?` . ?')))
Шон Уиттон
источник
Я должен был убежать от персонажей, чтобы заставить его работать(?\= . ?\=)
phoxd