Klammern automatisch formatieren

9

Ich versuche, eine Funktion zu erstellen, die geschweifte Klammern gemäß der Allman-Formatierung (zum Codieren in C) platziert / ausrichtet / einrückt.

Im Allgemeinen bin ich ein Fan der Smartparens-Benutzeroberfläche, die Benutzern zum Anpassen von Funktionen zur Verfügung steht. Ich habe eine Reihe anderer Funktionen über die Smartparens-Oberfläche geschrieben, daher würde ich es vorziehen, an dieser Stelle keine Pakete zu wechseln. Trotzdem bin ich offen für paketunabhängige Implementierungen (z. B. könnte defadvicedies hier relevant sein?).

Weiter zum Problem. Was ist das Endziel? Nehmen wir an, wir codieren und erreichen den unten dargestellten Status. Das Pipe-Symbol steht für den Cursor. Ich habe den Funktionskopf und die öffnende Klammer {eingegeben, und Smartparens hat die schließende Klammer automatisch hinzugefügt }. An dieser Stelle möchte ich, dass das Drücken RET...

int main {|}

... führt zu Folgendem:

int main
{
    |
}

Ich konnte die Funktion schreiben, die zu diesem Verhalten führt, aber sie funktioniert nur für die erste Einrückungsstufe (z. B. für unsere Hauptfunktion im obigen Beispiel). Ich kann es nicht für nachfolgende Einrückungsstufen zum Laufen bringen (siehe GIF):

Geben Sie hier die Bildbeschreibung ein

Der entsprechende Code ist unten. Die Funktion ist nicht schön, aber ich denke, sie sollte funktionieren ... Die allerletzte Zeile ist die Schnittstelle zu Smartparens.

Irgendwelche Vorschläge?


(defun my-create-newline-and-enter-sexp (&rest _ignored)
  "Open a new brace or bracket expression, with relevant newlines and indent. "
  (interactive)
  (progn
    (backward-char 2) (newline) (forward-char) (newline)     
    (indent-according-to-mode)                               
    (previous-line 2) (indent-according-to-mode)         
    (next-line) (next-line) (indent-according-to-mode)))      

(sp-local-pair 'c-mode "{" nil :post-handlers '((my-create-newline-and-enter-sexp "RET")))
Eismann
quelle

Antworten:

11

Emacs-24.4 electric-pair-modemacht einen Teil dessen, was Sie bereits wollen (dieser Modus ist autopair.el sehr ähnlich, nicht sicher, wie er mit Smartparens verglichen wird). Und c-toggle-auto-newlinemacht den anderen Teil.

Aber leider arbeiten sie nicht richtig zusammen. Bitte, M-x report-emacs-bugdamit wir das beheben können.

Stattdessen c-toggle-auto-newlinekönnen Sie auch electric-layout-modemit einer Einstellung wie verwenden (setq electric-layout-rules '((?\{ . around) (?\} . around))).

Stefan
quelle
1
gemeldet! Es wäre in der Tat schön, wenn die beiden zusammenarbeiten könnten.
Iceman
7

Gelöst. Die Abfolge der Cursorbewegungen aus meiner ersten Version (im ursprünglichen Beitrag) war funky.

Als Referenz für zukünftige Leser sollte der folgende Code funktionieren. Es benötigt das Smartparens-Paket (das Sie von git-hub erhalten können). Ich verwende Emacs 24.4. Es funktioniert mit aktiviertem oder deaktiviertem Elektroeinrückungsmodus.

(defun my-create-newline-and-allman-format (&rest _ignored)
"Allman-style formatting for C."
  (interactive)
  (progn
    (newline-and-indent)
    (previous-line) (previous-line) (search-forward "{") (backward-char) (newline-and-indent)
    (next-line) (indent-according-to-mode)))

Und irgendwo nach dem Laden des Smartparens-Pakets müssen Sie Folgendes in Ihre Init-Datei aufnehmen:

(sp-local-pair '(c-mode) "{" nil :post-handlers '((my-create-newline-and-allman-format "RET")))
Eismann
quelle
2
Anstatt Dinge wie previous-linemit search-forwardzu verwenden, um herauszufinden, wo Sie sich befanden, ist es viel besser, sich an Ihre Position in einer Variablen zu erinnern und sie dann einfach zu verwenden goto-char.
Stefan
Das ist wahrscheinlich die robustere Route. Gibt es Funktionen / Variablen / usw., die Ihrer Meinung nach in diesem Zusammenhang hilfreich sein könnten? Ich kann nur daran denken save-excursion, bin mir aber sicher, dass es andere gibt, die ich nicht kenne.
Iceman
0

Hier ist der Code, den ich verwende, um Ihnen weitere Ideen zur Änderung Ihres Codes zu geben:

(defun ins-c++-curly ()
  "Insert {}.
Threat is as function body when from endline before )"
  (interactive)
  (cond ((eq major-mode 'term-mode)
         (term-send-raw-string "{}")
         (term-send-raw-string "^B"))
        ((looking-back "\\()\\|try\\|else\\|const\\|:\\)$")
         (insert " {\n\n}")
         (indent-according-to-mode)
         (forward-line -1)
         (indent-according-to-mode))
        ((region-active-p)
         (let ((beg (region-beginning))
               (end (region-end)))
           (deactivate-mark)
           (goto-char beg)
           (insert "{")
           (goto-char (1+ end))
           (insert "}")))
        (t
         (insert "{}")
         (indent-according-to-mode)
         (backward-char))))

Ich bevorzuge den Stil der hängenden Zahnspange, da er Platz spart.

abo-abo
quelle