2009-05-11 15 views
2

In verschiedenen IDEs führt die Eingabe von Open-Curly zu einem übereinstimmenden Klammerpaar. In der Regel werden die geschweiften Klammern in einer kontextabhängigen Weise eingefügt. In einem Zeichenfolgenliteral wird keine neue Zwischenzeile zwischen den geschweiften Klammern eingefügt. Außerhalb eines String-Literals gibt es eine neue Zeile, und die Dinge werden sofort eingerückt.Intelligente elektrische Klammer in cc-modes (C#, Java usw.)

Während ich weiter am Cursor tippe, wird der gesamte neue Code korrekt eingerückt. In Emacs, standardmäßig in meinem cc-Modus (csharp-mode, java-mode, usw.), führt ein open-locked den Befehl self-insert aus, der nur die offene Klammer ohne Einrückung einfügt. Die eng-lockige läuft c-electric-brace, die nur die enge lockig, nicht den vollen Umfang einzieht. Das Ergebnis ist, während ich in den geschweiften Bereich eingeben, die Einrückung ist falsch, und ich muss den geschweiften Bereich manuell neu einrücken, wenn es geschlossen wird.

Gibt es einen einfachen Weg, um Emacs dazu zu bringen, sich wie die populären IDEs zu verhalten, die ich benutzt habe? Ich habe ein paar Emacs Lisp geschrieben, aber es ist nicht sehr allgemein und ich möchte wissen, ob ich etwas verpasse.

Ich weiß über die Skelett-Paar-Insert-Maybe-Funktion. Es fügt passende Paare von was auch immer: Klammern, Parens, Zitate, spitze Klammern, eckige Klammern. Diese Funktion führt jedoch keine kontextsensitive Einrückung durch und gibt mir keine leere Zeilenschaltung. Gibt es eine Möglichkeit, um es zu Einzug oder ... gibt es eine andere Funktion, die ich an Open-lockig binden sollte, um zu bekommen, was ich will?

PS: meine Emacs Lisp sieht wie folgt aus:

; The default binding for "open curly" was skeleton-pair-insert-maybe. It 
; inserts a pair of braces and then does not insert a newline, and does not 
; indent. I want the braces to get newlines and appropriate indenting. I 
; think there is a way to get this to happen appropriately just within emacs, 
; but I could not figure out how to do it. So I wrote this alternative. The 
; key thing is to determine if the point is within a string. In cc-mode, this 
; is at least sometimes done by looking at the font face. Then, if not in a 
; literal string, do the appropriate magic. This seems to work. 
(defun cheeso-insert-open-brace() 
    "if point is not within a quoted string literal, insert an open brace, two newlines, and a close brace; indent everything and leave point on the empty line. If point is within a string literal, just insert a pair or braces, and leave point between them." 
    (interactive) 
    (if 
     ; are we inside a string? 
     (c-got-face-at (point) c-literal-faces) 
     ; if so, then just insert a pair of braces and put the point between them 
     (progn 
     (self-insert-command 1) 
     (insert "}") 
     (backward-char) 
     ) 
    ; not inside a literal string. 
    ; therefore, insert paired braces with an intervening newline, and indent everything appropriately. 
    (progn 
     (self-insert-command 1) 
     (c-indent-command) 
     (newline) 
     (insert "}") 
     (c-indent-command) 
     (previous-line) 
     (newline-and-indent) 
     ; point ends up on an empty line, within the braces, properly indented 
    ) 
    ) 
) 

Antwort

1

This .emacs Auszug (ich es noch einige Zeit auf EmacsWiki vor gefunden haben müssen) werden tun, was Sie brauchen:

;; Enter indents the new line 
(defun my-make-CR-do-indent() 
    (define-key c-mode-base-map "\C-m" 'c-context-line-break)) 
(add-hook 'c-initialization-hook 'my-make-CR-do-indent) 

Works wie folgt:

int main(void) 
{ 
    { 
    { 
     { 

Nirgendwo musste ich Leerzeichen oder Tab drücken, um es einzugeben.

2

Ich akzeptierte die Antwort von Kastauyra, aber ging immer noch mit meiner eigenen benutzerdefinierten elisp zu tun, was ich wollte, die eine passende Reihe von geschweiften Klammern als geeignet eingefügt wurde. Der ursprüngliche elisp-Code, den ich gepostet habe, ist für einige Randfälle fehlgeschlagen. Dies ist der aktualisierte elisp-Code, den ich jetzt verwende.

(defun cheeso-looking-back-at-regexp (regexp) 
    "calls backward-sexp and then checks for the regexp. Returns t if it is found, else nil" 
    (interactive "s") 
    (save-excursion 
    (backward-sexp) 
    (looking-at regexp) 
    ) 
) 

(defun cheeso-looking-back-at-equals-or-array-init() 
    "returns t if an equals or [] is immediate preceding. else nil." 
    (interactive) 
    (cheeso-looking-back-at-regexp "\\(\\w+\\b *=\\|[[]]+\\)") 
) 


(defun cheeso-prior-sexp-same-statement-same-line() 
    "returns t if the prior sexp is on the same line. else nil" 
    (interactive) 
    (save-excursion 
    (let ((curline (line-number-at-pos)) 
      (curpoint (point)) 
      (aftline (progn 
         (backward-sexp) 
         (line-number-at-pos)))) 
     (= curline aftline) 
    ) 
    ) 
) 



(defun cheeso-insert-open-brace() 
    "if point is not within a quoted string literal, insert an open brace, two newlines, and a close brace; indent everything and leave point on the empty line. If point is within a string literal, just insert a pair or braces, and leave point between them." 
    (interactive) 
    (cond 

    ;; are we inside a string literan? 
    ((c-got-face-at (point) c-literal-faces) 

    ;; if so, then just insert a pair of braces and put the point between them 
    (self-insert-command 1) 
    (insert "}") 
    (backward-char) 
    ) 

    ;; was the last non-space an equals sign? or square brackets? Then it's an initializer. 
    ((cheeso-looking-back-at-equals-or-array-init) 
     (self-insert-command 1) 
     ;; all on the same line 
     (insert " };") 
     (backward-char 3) 
     ) 

    ;; else, it's a new scope. 
    ;; therefore, insert paired braces with an intervening newline, and indent everything appropriately. 
    (t 
    (if (cheeso-prior-sexp-same-statement-same-line) 
     (newline-and-indent)) 
     (self-insert-command 1) 
     (c-indent-line-or-region) 
     (end-of-line) 
     (newline) 
     (insert "}") 
     ;;(c-indent-command) ;; not sure of the difference here 
     (c-indent-line-or-region) 
     (previous-line) 
     (end-of-line) 
     (newline-and-indent) 
     ; point ends up on an empty line, within the braces, properly indented 
    ) 
    ) 
) 

In meiner c-mode-Hook-Funktion, band ich die Open-lockig '{' Cheeso-Insert-open-Klammer, etwa so:

 (local-set-key (kbd "{") 'cheeso-insert-open-brace) 

Das Ergebnis ist, wenn ich so etwas wie dieses:

for(;;) 

und geben Sie dann in einem offenen lockig, bekomme ich diese:

for(;;) 
{ 
    _cursor_ 
} 

Wenn ich einen Initialisierer wie diese:

byte[] x = 

und ich Schlüssel in einer offenen lockig, bekomme ich diese:

byte[] x = { _cursor_ }; 
+0

Dank dafür. Nur eine Randnotiz, wenn Sie nicht möchten, dass die bsd-like Einrückungsstil, sondern stattdessen die erste geschweifte Klammer auf die gleiche, löschen Sie einfach (if (cheeso-vorherige-sexp-same-Anweisung-same-line) (newline-and-indent)) aus der Funktion cheeso-insert-open-brace. – sluukkonen

+0

Ich muss sagen, das sieht nach einer Menge Codes aus, um so eine kleine Geste zu erreichen; Ich frage mich, ob es eine elegantere Lösung dafür gibt. – polyglot

+0

stimme ich zu; Ich war enttäuscht von der Menge an Code, den ich schreiben musste, um das zu tun, was ich wollte. Aber bisher hat niemand einen einfacheren Weg vorgeschlagen, um das zu erreichen. – Cheeso