Formateo automático de paréntesis

9

Estoy tratando de crear una función que coloque / alinee / sangra las llaves según el formato de estilo Allman (para codificar en C).

En términos generales, soy fanático de la interfaz de Smartparens disponible para los usuarios para personalizar la funcionalidad. He escrito un montón de otras funciones utilizando la interfaz Smartparens, por lo que preferiría no cambiar los paquetes en este momento. Dicho esto, estoy abierto a implementaciones independientes del paquete (por ejemplo, ¿podría defadviceser relevante aquí?).

Sobre el problema en cuestión. ¿Cuál es el objetivo final? Supongamos que estamos codificando y alcanzamos el estado representado a continuación. El símbolo de la tubería representa el cursor; Escribí el encabezado de la función y la llave de apertura {, y Smartparens agregó automáticamente la llave de cierre }. En este punto, me gustaría que presionar RET...

int main {|}

... lleva a lo siguiente:

int main
{
    |
}

He podido escribir la función que produce este comportamiento, pero solo funciona para el primer nivel de sangría (por ejemplo, para nuestra función principal en el ejemplo anterior). No puedo hacer que funcione para los niveles posteriores de sangría (ver gif):

ingrese la descripción de la imagen aquí

El código relevante está debajo. La función no es bonita, pero creo que debería funcionar ... La última línea es la interfaz de Smartparens.

¿Alguna sugerencia?


(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")))
repartidor de hielo
fuente

Respuestas:

11

Emacs-24.4 ya electric-pair-modehace una parte de lo que desea (este modo es muy similar a autopair.el, no estoy seguro de cómo se compara con los smartparens). Y c-toggle-auto-newlinehace la otra parte.

Pero lamentablemente no funcionan bien juntos. Por favor, M-x report-emacs-bugpara que podamos arreglar eso.

En lugar de c-toggle-auto-newline, también puede usar electric-layout-modecon una configuración como (setq electric-layout-rules '((?\{ . around) (?\} . around))).

Stefan
fuente
1
informó! de hecho sería bueno si los dos pudieran trabajar juntos.
iceman
7

Resuelto La secuencia de movimientos del cursor de mi primera versión (en la publicación original) fue funky.

Como referencia para futuros lectores, el siguiente código debería funcionar. Obv necesita el paquete Smartparens (que puede obtener de git-hub). Estoy ejecutando Emacs 24.4. Funciona con el modo de sangría eléctrica habilitado o deshabilitado.

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

Y también deberá incluir lo siguiente en su archivo de inicio, en algún lugar después de cargar el paquete Smartparens:

(sp-local-pair '(c-mode) "{" nil :post-handlers '((my-create-newline-and-allman-format "RET")))
repartidor de hielo
fuente
2
En lugar de usar cosas como previous-linela search-forwardde tratar de re-descubrir dónde estaba usted, usted es mucho mejor recordar su posición en una variable y luego sólo tiene que utilizar goto-char.
Stefan
Esa es probablemente la ruta más robusta. ¿Hay alguna función / variable / etc. que creas que podría ser útil en este contexto? Solo puedo pensar save-excursionpero estoy seguro de que hay otros que no conozco.
Iceman
0

Aquí está el código que uso, solo para darle más ideas para enmendar su código:

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

Prefiero el estilo de abrazadera colgante, ya que ahorra espacio.

abo-abo
fuente