Automatyczne ponowne wcięcie kodu elisp podczas dodawania lub usuwania kodu przed wciętym blokiem

18

Powiedz, że mam kod elisp, taki jak:

(+ 2 3▮(+ 3
          4))

Czy istnieje sposób automatycznego ponownego wcięcia seksu za kursorem, gdy dodam lub usunę symbole?

Po naciśnięciu SPC 4 SPCautomatycznie uzyskałbym:

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

Mogę wykonać tę instrukcję, dzwoniąc, mark-sexpa następnie indent-region. Czy są na to lepsze sposoby?

Maciej Goszczycki
źródło
Nie sądzę, że istnieją jakieś wygodne domyślne skróty klawiszowe, ale możesz je łatwo stworzyć samodzielnie.
shosti
Wiem, ale zastanawiam się, czy są na to lepsze sposoby. Na przykład, o electric-indent-modeile lepiej niż mapowanie <return>donewline-and-indent
Maciej Goszczycki

Odpowiedzi:

14

Zamiast mark-sexp+ indent-regionmożesz nacisnąć C-M-q. To zadzwoni indent-pp-sexp. Nie automatyczny, ale nieco lepszy niż konieczność wywoływania dwóch poleceń.

Lub jeśli używasz paredit-mode, naciśnij M-q. To ponownie oprze się na całej definicji funkcji, w której się znajdujesz.

Dmitry
źródło
1
(add-hook 'post-self-insert-hook 'indent-pp-sexp)działa zaskakująco dobrze.
Maciej Goszczycki
Wygląda dobrze. W niektórych trybach może to być kosztowne, ale mimo to jest to przyjemne podejście.
Dmitry
W przypadku użytkowników Smartparens możesz ponownie włączyć bieżący defun M-x sp-indent-defun. Wiążę to z C-M-q.
Radon Rosborough
15

Tryb agresywnego wcięcia

Ponieważ niektórzy o to prosili, zamieniłem tę odpowiedź w pakiet .

Jeśli masz skonfigurowaną Melpę, możesz ją zainstalować za pomocą

M-x package-install RET aggressive-indent

Zobacz plik Readme dla wszystkich opcji, ale najprostszym sposobem na jego włączenie jest:

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

Stara odpowiedź

Następujące automatyczne wcięcie dotyczy tylko buforów elisp. Ma tę zaletę, że działa również podczas wymazywania lub szarpania (zamiast pisania). Łatwo jest również dodać do innych trybów.

Ta funkcja wcina dowolne wyrażenie s, w którym znajduje się obecnie punkt. Możesz powiązać go z kluczem, jeśli chcesz, ale najpierw zobacz poniżej.

(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))))))

Ten haczyk sprawi, że ta funkcja będzie uruchamiana po wpisaniu czegokolwiek, ale tylko w buforach elisp. To powinno sprawić, że wszystko będzie zawsze wcięte.

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

Spróbuj! Działa wyjątkowo dobrze.

Ponadto, postępując zgodnie z sugestią @ holocronweaver w komentarzach, możesz użyć czegoś takiego jak dla języków podobnych do c:

(define-key c++-mode-map ";"
  (lambda () (interactive)
    (insert ";")
    (endless/indent-defun)))
Malabarba
źródło
Byłoby doskonale, gdyby to uciszyło automatyczne wcięcia i lepiej obsługiwało języki kończące się średnikami.
holocronweaver
@holocronweaver na pewno mogę tego spróbować. Który tryb główny ma wiadomości z wcięciami? Na czym polega problem ze średnikami?
Malabarba
Wszystkie tryby, które wypróbowałem na pniu Emacsa, generowały wcięcia, w tym elisp. Ponieważ średniki kończą wiersz w wielu językach, dopóki nie wpiszesz średnika, następna linia przeskakuje tak, jakby była częścią bieżącego wiersza.
holocronweaver
@holocronweaver Wyciszono wiadomości. Dzięki za zwrócenie na to uwagi.
Malabarba
Dzięki za poprawkę! Jednym z rozwiązań problemu średnika jest wcięcie tylko w językach trybu c, gdy jest wpisany średnik.
holocronweaver
3

Nie znam wcześniejszego rozwiązania, ale możesz post-self-insert-hookto zrobić samodzielnie:

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

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

Martwiłbym się jednak potencjalnymi problemami z wydajnością.

shosti
źródło
1

Możesz wypróbować tryb wcięcia el-fly , który jest bardziej aggressive-indent-modegrzeczny niż w przypadku Elisp.

Jiahao
źródło