Умная электрическая скобка в cc-режимах (C #, Java и т. Д.) - PullRequest
2 голосов
/ 11 мая 2009

В различных средах IDE ввод с открытыми фигурными скобками приводит к появлению подходящей пары фигурных скобок. Обычно фигурные скобки вставляются каким-либо контекстно-зависимым способом. Внутри строкового литерала между фигурными скобками нет вставляемого символа новой строки. За пределами строкового литерала есть символ новой строки, и все сразу отступает.

{
    _cursor_
}

Когда я продолжаю печатать на курсоре, весь новый код имеет правильный отступ.

В Emacs, однако, по умолчанию в моем cc-режиме (csharp-mode, java-mode и т. Д.) Команда open-curly выполняет команду self-insert, которая просто вставляет открытую скобку без отступа. С-электрическая скобка работает в тесном кудрявом виде, что делает отступ только для близкого вьющегося, а не полного объема. В результате, когда я вписываю внутри фигурной области видимости, все отступы неверны, и мне приходится вручную заново создавать отступ для фигурной области при ее закрытии.

Есть ли простой способ заставить Emacs вести себя как популярные IDE, которые я использовал? Я написал кое-что для Emacs Lisp, но оно не очень общее, и я хочу знать, что я ошибаюсь.

Я знаю о функции скелет-пара-вставка-возможно. Он вставляет согласованные пары независимо от : фигурные скобки, скобки, кавычки, угловые скобки, квадратные скобки. Но эта функция не делает никакого контекстно-зависимого отступа и не дает мне пустую строку. Есть ли способ заставить его отступить или ... есть другая функция, которую я должен привязать к open-curly, чтобы получить то, что я хочу?

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 ]

2 голосов
/ 14 мая 2009

Я принял ответ от 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 я привязываю open-curly '{' к cheeso-insert-open-brace, вот так:

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

В результате получается что-то вроде этого:

for(;;)

и затем введите открытую фигурку, я получаю это:

for(;;)
{
   _cursor_
}

Если у меня есть такой инициализатор:

byte[] x =

и я ввожу открытое фигурное, я получаю это:

byte[] x = { _cursor_ };
1 голос
/ 12 мая 2009

Этот отрывок .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)
{
  {
    {
      {

Нигде мне не пришлось нажимать пробел или вкладку, чтобы ввести его.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...