2009-05-11 6 views
2

Dans divers environnements de développement intégrés, la saisie d'une boucle ouverte entraîne l'apparition d'une paire de caractères accolés. Généralement, les accolades sont insérées de manière contextuelle. Dans un littéral de chaîne, il n'y a pas de saut de ligne interposé entre les accolades. En dehors d'un littéral de chaîne, il y a une nouvelle ligne, et les choses sont immédiatement indentées. Comme je continue à taper au curseur, tout nouveau code est correctement indenté. Dans Emacs, cependant, par défaut dans mon mode cc (mode csharp, mode java, etc.), une commande open-curly exécute self-insert-commande qui insère simplement l'accolade ouverte sans retrait. Le bouclé court c-électrique-accolade, qui indent le bouclé proche seulement, pas toute la portée. Le résultat est alors que je saisis dans la portée bouclée, l'indentation est tout faux, et je dois re-indenter manuellement la portée bouclée quand il se ferme.Accolade électrique intelligente dans les modes cc (C#, Java, etc.)

Existe-t-il un moyen facile de faire en sorte qu'Emacs se comporte comme les IDE courants que j'ai utilisés? J'ai écrit quelques Emacs Lisp à faire, mais ce n'est pas très général et je veux savoir si je mets quelque chose en erreur.

Je connais la fonction skeleton-pair-insert-maybe. Il insère des paires appariées de : accolades, parenthèses, guillemets, chevrons et crochets. Mais cette fonction n'effectue pas d'indentation contextuelle et ne me donne pas le retour à la ligne vide. Existe-t-il un moyen de le mettre en retrait ou ... y a-t-il une autre fonction que je devrais lier à ouvrir-bouclée pour obtenir ce que je veux?

PS: mon Emacs Lisp ressemble à ceci:

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

Répondre

1

Ce .emacs extrait (je dois avoir trouvé sur EmacsWiki il y a quelque temps) va faire ce que vous avez besoin:

;; 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 comme ceci:

int main(void) 
{ 
    { 
    { 
     { 

Nulle part j'ai dû appuyer sur l'espace ou la languette pour l'entrer.

2

J'ai accepté la réponse de kastauyra, mais je suis tout de même allé avec mon propre fichier personnalisé pour faire ce que je voulais, qui était d'insérer un ensemble d'accolades, le cas échéant. Le code elisp original que j'ai posté a échoué pour quelques cas de bord. C'est le code elisp mis à jour que j'utilise maintenant.

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

Dans mon c mode fonction de crochet, je lie l'open-curly '{' à cheeso-insert ouvert entretoise, comme ceci:

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

Le résultat est, quand je quelque chose comme ceci:

for(;;) 

puis entrez dans un open-bouclés, je reçois ceci:

for(;;) 
{ 
    _cursor_ 
} 

Si j'ai un initialiseur comme ceci:

byte[] x = 

et je touche dans une frisée ouverte, je reçois ceci:

byte[] x = { _cursor_ }; 
+0

Merci pour cela. Juste un sidenote, si vous ne voulez pas utiliser le style indentation bsd-like, mais au lieu de garder le premier accolade sur la même chose, il suffit de supprimer (si (cheeso-avant-sexp-même-déclaration-même ligne) (newline-and-indent)) à partir de la fonction cheeso-insert-open-brace. – sluukkonen

+0

Je dois dire que cela ressemble à beaucoup de codes pour accomplir un si petit geste; Je me demande s'il existe une solution plus élégante à cela. – polyglot

+0

Je suis d'accord; J'ai été déçu de la quantité de code que j'ai dû écrire pour que je fasse ce que je voulais. Mais, jusqu'à présent, personne n'a suggéré une façon plus simple de le faire. – Cheeso

Questions connexes