Автоматически переопределяет отступ кода elisp при добавлении или удалении кода перед блоком с отступом

18

Скажем, у меня есть код elisp вроде:

(+ 2 3▮(+ 3
          4))

Есть ли способ автоматически сделать отступ в сексе после курсора, когда я добавляю или удаляю символы?

Поэтому после нажатия SPC 4 SPCя бы автоматически получил:

(+ 2 3 4 ▮(+ 3
             4))

Я могу сделать это руководство, позвонив, mark-sexpа затем indent-region. Есть ли лучшие способы сделать это?

Мацей Гошицкий
источник
Я не думаю, что есть какие-то удобные комбинации клавиш по умолчанию, но вы можете легко создать их самостоятельно.
Шости
Я знаю, но мне особенно интересно, есть ли лучшие способы сделать это. Например , как electric-indent-modeэто намного лучше , чем отображение <return>кnewline-and-indent
Мацей Goszczycki

Ответы:

14

Вместо mark-sexp+ indent-regionвы можете нажать C-M-q. Это позвонит indent-pp-sexp. Не автоматически, но немного лучше, чем вызывать две команды.

Или, если вы используете paredit-mode, нажмите M-q. Это переопределяет все определение функции, в котором вы находитесь.

Дмитрий
источник
1
(add-hook 'post-self-insert-hook 'indent-pp-sexp)работает удивительно хорошо.
Мацей Гожчицкий,
Выглядит хорошо. Это может быть дорогостоящим в некоторых режимах, но, тем не менее, это хороший подход.
Дмитрий
Для пользователей Smartparens вы можете переопределить текущий defun с помощью M-x sp-indent-defun. Я связываю это с C-M-q.
Радон Росборо
15

Агрессивный режим отступа

Поскольку некоторые люди просили об этом, я превратил этот ответ в пакет .

Если у вас настроен Melpa, вы можете установить его с

M-x package-install RET aggressive-indent

См. Readme для всех опций, но самый простой способ включить его:

(add-hook 'emacs-lisp-mode-hook #'aggressive-indent-mode)

Старый ответ

Следующее делает авто-отступ только для буферов elisp. Он также имеет преимущество работы, когда вы стираете или дергаете вещи (вместо того, чтобы просто печатать). Это легко добавить и в другие режимы.

Эта функция будет делать отступ для любого s-выражения, внутри которого находится точка. Вы можете привязать его к клавише, если хотите, но сначала смотрите ниже.

(require 'cl-lib)

(defun endless/indent-defun ()
  "Indent current defun.
Do nothing if mark is active (to avoid deactivating it), or if
buffer is not modified (to avoid creating accidental
modifications)."
  (interactive)
  (ignore-errors
    (unless (or (region-active-p)
                buffer-read-only
                (null (buffer-modified-p)))
      (let ((l (save-excursion (beginning-of-defun 1) (point)))
            (r (save-excursion (end-of-defun 1) (point))))
        (cl-letf (((symbol-function 'message) #'ignore))
          (indent-region l r))))))

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

(add-hook
 'emacs-lisp-mode-hook
 (lambda ()
   (add-hook 'post-command-hook
             #'endless/indent-defun nil 'local)))

Попытайся! Это работает замечательно хорошо.

Кроме того, следуя предложению @ holocronweaver в комментариях, вы можете использовать что-то вроде следующего для c-подобных языков:

(define-key c++-mode-map ";"
  (lambda () (interactive)
    (insert ";")
    (endless/indent-defun)))
Malabarba
источник
Было бы замечательно, если бы при этом автоматически подавлялись сообщения с отступом и лучше обрабатывались языки, которые заканчивают строки точкой с запятой.
Holocronweaver
@holocronweaver, конечно, я могу попробовать это. В каком основном режиме есть отступ? А в чем проблема с полуколоннами?
Малабарба
Все режимы, которые я пробовал на транке Emacs, генерировали сообщения с отступами, включая elisp. Поскольку точки с запятой заканчиваются на многих языках, до тех пор, пока вы не введете точку с запятой, следующая строка переходит, как если бы она была частью текущей строки.
Holocronweaver
@holocronweaver Отключил сообщения. Спасибо за указание на это.
Малабарба
Спасибо за исправление! Одним из решений проблемы точки с запятой является использование отступа в языках c-mode только при вводе точки с запятой.
Holocronweaver
3

Я не знаю о ранее существовавшем решении, но вы можете использовать это, post-self-insert-hookчтобы выполнить это самостоятельно:

(defun my-indent-next-sexp ()
  (interactive)
  (mark-sexp)
  (indent-region))

(add-hook 'post-self-insert-hook 'my-indent-next-sexp)

Я бы беспокоился о потенциальных проблемах с производительностью.

shosti
источник