cc模式下的智能电动支架(C#,Java等)

时间:2009-05-11 15:24:20

标签: c# java emacs

在各种IDE中,键入开放卷曲会导致匹配的一对大括号字符出现。通常,大括号以某种上下文敏感的方式插入。在字符串文字中,在括号之间没有插入插入的换行符。在字符串文字之外,有一个换行符,并且事物会立即缩进。

{
    _cursor_
}

当我继续键入光标时,所有新代码都正确缩进。

在Emacs中,默认情况下,在我的cc模式(csharp-mode,java-mode等)中,open-curly运行self-insert-command,它只插入没有缩进的open大括号。近距离卷曲运行c-electric-brace,它只收缩近卷曲,而不是整个范围。结果是当我在卷曲范围内键入时,缩进是完全错误的,并且我必须在它关闭时手动重新缩进卷曲范围。

有没有一种简单的方法可以让Emacs像我用过的流行IDE一样?我已经编写了一些Emacs Lisp,但它不是很通用,我想知道我是不是在搞什么。

我知道骨架对插入可能的功能。它插入匹配的无论:括号,parens,引号,尖括号,方括号。但是该函数不执行任何上下文相关的缩进,并且不会给我空白的换行符。有没有办法让它缩进或...是否有另一个函数我应该绑定到开放卷曲来得到我想要的?

PS:我的Emacs Lisp看起来像这样:

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

2 个答案:

答案 0 :(得分:2)

我接受了kastauyra的答案,但仍然使用我自己的自定义elisp来做我想要的,这是适当插入一组匹配的括号。我发布的原始elisp代码失败了几个边缘情况。这是我现在使用的更新的elisp代码。

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

在我的c-mode钩子函数中,我将开放式卷曲'{'绑定到cheeso-insert-open-brace,如下所示:

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

结果是,当我有这样的事情时:

for(;;)

然后键入一个开卷曲,我明白了:

for(;;)
{
   _cursor_
}

如果我有这样的初始化程序:

byte[] x =

我按开放式卷曲,我明白了:

byte[] x = { _cursor_ };

答案 1 :(得分:1)

这个.emacs摘录(我必须在EmacsWiki前一段时间找到它)会做你需要的:

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

像这样工作:

int main(void)
{
  {
    {
      {

我无处按空格或标签进入。