Automatisches erneutes Einrücken von Elisp-Code, wenn Code vor einem eingerückten Block hinzugefügt oder entfernt wird

18

Angenommen, ich habe einen Elisp-Code wie:

(+ 2 3▮(+ 3
          4))

Gibt es eine Möglichkeit, das Geschlecht nach dem Cursor automatisch neu einzurücken, wenn ich Symbole hinzufüge oder entferne?

Nach dem Drücken von SPC 4 SPCwürde ich also automatisch Folgendes erhalten:

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

Ich kann dieses Handbuch ausführen, mark-sexpindem ich gefolgt von anrufe indent-region. Gibt es dafür bessere Möglichkeiten?

Maciej Goszczycki
quelle
Ich glaube nicht, dass es irgendwelche bequemen Standard-Tastenkombinationen gibt, aber Sie könnten leicht selbst welche erstellen.
Shosti
Ich weiß, aber ich frage mich, ob es dafür bessere Möglichkeiten gibt . Zum Beispiel, wie electric-indent-modeist viel besser als die Zuordnung <return>zunewline-and-indent
Maciej Goszczycki

Antworten:

14

Anstelle von mark-sexp+ indent-regionkönnen Sie auch drücken C-M-q. Dies wird anrufen indent-pp-sexp. Nicht automatisch, aber ein bisschen besser, als zwei Befehle aufrufen zu müssen.

Oder paredit-modedrücken Sie, wenn Sie verwenden M-q. Dadurch wird die gesamte Funktionsdefinition, in der Sie sich befinden, erneut berücksichtigt.

Dmitry
quelle
1
(add-hook 'post-self-insert-hook 'indent-pp-sexp)funktioniert überraschend gut.
Maciej Goszczycki
Sieht gut aus. Das mag in einigen Modi teuer sein, aber es ist trotzdem ein guter Ansatz.
Dmitry
Für Smartparens-Benutzer können Sie die aktuelle Definition mit erneut einblenden M-x sp-indent-defun. Ich binde das an C-M-q.
Radon Rosborough
15

Modus für aggressive Einrückung

Da einige Leute danach fragten, habe ich diese Antwort in ein Paket umgewandelt .

Wenn Sie Melpa konfiguriert haben, können Sie es mit installieren

M-x package-install RET aggressive-indent

In der Readme-Datei finden Sie alle Optionen. Die einfachste Methode zum Aktivieren ist jedoch:

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

Die alte Antwort

Im Folgenden wird die automatische Einrückung nur für Elisp-Puffer ausgeführt. Es hat den Vorteil, dass es auch funktioniert, wenn Sie etwas löschen oder ruckeln (anstatt nur zu tippen). Es ist auch einfach, andere Modi hinzuzufügen.

Diese Funktion rückt jeden S-Ausdruck ein, in dem sich der Punkt gerade befindet. Sie können es an einen Schlüssel binden, wenn Sie möchten, aber sehen Sie zuerst weiter unten.

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

Dieser Haken bewirkt, dass diese Funktion ausgeführt wird, nachdem Sie etwas eingegeben haben, jedoch nur in Elisp-Puffern. Dies sollte alles immer eingerückt halten.

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

Versuch es! Es funktioniert bemerkenswert gut.

Wenn Sie dem Vorschlag von @ holocronweaver in den Kommentaren folgen, können Sie für c-ähnliche Sprachen Folgendes verwenden:

(define-key c++-mode-map ";"
  (lambda () (interactive)
    (insert ";")
    (endless/indent-defun)))
Malabarba
quelle
Wäre hervorragend, wenn diese Nachrichten automatisch zum Schweigen gebracht und Sprachen, die mit Semikolons enden, besser gehandhabt würden.
Holocronweaver
@holocronweaver sicher, das kann ich probieren. In welchem ​​Hauptmodus werden Nachrichten eingerückt? Und was ist das Problem mit Semikolons?
Malabarba
Alle Modi, die ich in Emacs Trunk ausprobiert habe, haben Einrückungsnachrichten erzeugt, einschließlich Elisp. Da Semikolons eine Zeile in mehreren Sprachen beenden, springt die folgende Zeile so, als ob sie Teil der aktuellen Zeile wäre, bis Sie das Semikolon eingeben.
Holocronweaver
@holocronweaver Die Nachrichten wurden stummgeschaltet. Vielen Dank für den Hinweis.
Malabarba
Danke für die Lösung! Eine Lösung für das Semikolonproblem besteht darin, in C-Modus-Sprachen nur einzurücken, wenn ein Semikolon eingegeben wird.
Holocronweaver
3

Ich kenne keine bereits vorhandene Lösung, aber Sie können diese verwenden post-self-insert-hook, um dies selbst zu erreichen:

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

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

Ich würde mir allerdings Sorgen um mögliche Leistungsprobleme machen.

Shosti
quelle
1

Sie können den el-fly-indent-Modus ausprobieren , der sich besser aggressive-indent-modeverhält als bei Elisp.

Jiahao
quelle