c++ emacs

Plantillas C++ y Emacs: Personalizando la sangría



(3)

Comentarios

Creo que parte del problema que experimenta es que cuando crea una instancia de las plantillas, el modo CC de emacs las ve con la misma estructura template-args-cont . Así que, teniendo esto en cuenta, amplié su idea original y traté de hacerla a mi gusto; Hice el código detallado para que, con suerte, todos puedan entender mi intención. :) ¡Esto no debería causar problemas al crear una instancia, y también parece funcionar para los parámetros de plantilla de plantilla! ¡Prueba esto hasta que alguien con más habilidades de Elisp pueda proporcionar una mejor solución!

Si experimenta algún ''combate'' (es decir, sangría alternativa o rota), intente volver a cargar el archivo cpp Cx Cv Enter y volver a sangrar. A veces, con los parámetros de la plantilla de plantilla, emacs muestra los argumentos internos como arglist-cont-nonempty e incluso alterna con la template-args-const , pero la recarga siempre se restablece.

Uso

Para hacer lo que quiera, intente esto utilizando el código a continuación y agregue a su c-offsets-alist una entrada:

(template-args-cont . brian-c-lineup-template-args)

y establece la variable

(setq brian-c-lineup-template-closebracket t)

De hecho, prefiero una alineación ligeramente diferente:

(setq brian-c-lineup-template-closebracket ''under)

Código

(defvar brian-c-lineup-template-closebracket ''under "Control the indentation of the closing template bracket, >. Possible values and consequences: ''under : Align directly under (same column) the opening bracket. t : Align at the beginning of the line (or current indentation level. nil : Align at the same column of previous types (e.g. col of class T).") (defun brian-c-lineup-template--closebracket-p () "Return t if the line contains only a template close bracket, >." (save-excursion (beginning-of-line) ;; Check if this line is empty except for the trailing bracket, > (looking-at (rx (zero-or-more blank) ">" (zero-or-more blank))))) (defun brian-c-lineup-template--pos-to-col (pos) (save-excursion (goto-char pos) (current-column))) (defun brian-c-lineup-template--calc-open-bracket-pos (langelem) "Calculate the position of a template declaration opening bracket via LANGELEM." (save-excursion (c-with-syntax-table c++-template-syntax-table (goto-char (c-langelem-pos langelem)) (1- (re-search-forward "<" (point-max) ''move))))) (defun brian-c-lineup-template--calc-indent-offset (ob-pos) "Calculate the indentation offset for lining up types given the opening bracket position, OB-POS." (save-excursion (c-with-syntax-table c++-template-syntax-table ;; Move past the opening bracket, and check for types (basically not space) ;; if types are on the same line, use their starting column for indentation. (goto-char (1+ ob-pos)) (cond ((re-search-forward (rx (or "class" "typename" (one-or-more (not blank)))) (c-point ''eol) ''move) (goto-char (match-beginning 0)) (current-column)) (t (back-to-indentation) (+ c-basic-offset (current-column))))))) (defun brian-c-lineup-template-args (langelem) "Align template arguments and the closing bracket in a semi-custom manner." (let* ((ob-pos (brian-c-lineup-template--calc-open-bracket-pos langelem)) (ob-col (brian-c-lineup-template--pos-to-col ob-pos)) (offset (brian-c-lineup-template--calc-indent-offset ob-pos))) ;; Optional check for a line consisting of only a closebracket and ;; line it up either at the start of indentation, or underneath the ;; column of the opening bracket (cond ((and brian-c-lineup-template-closebracket (brian-c-lineup-template--closebracket-p)) (cond ((eq brian-c-lineup-template-closebracket ''under) (vector ob-col)) (t 0))) (t (vector offset)))))

Por lo que sé en emacs, no hay forma de personalizar el nivel de sangría del carácter ''>'' de cierre de una lista de plantillas en C ++. Actualmente mi esquema de sangrado de emacs hace esto:

template < typename T1, typename T2, typename T3 > class X;

Lo que quiero es algo como esto:

template < typename T1, typename T2, typename T3 > class X;

Establecer la variable de sangría template-args-cont en cero sangrará el carácter ''>'' correctamente, pero al costo de desentrañar el cuerpo real de la lista de argumentos de la plantilla.

¿Alguna sugerencia de los gurús de emacs por ahí?

EDITAR:

Lo tengo trabajando un poco con el siguiente hack:

(defun indent-templates (elem) (c-langelem-col elem t) (let ((current-line (buffer-substring-no-properties (point-at-bol) (point-at-eol)))) (if (string-match-p "^//s-*>" current-line) 0 ''+)))

Y luego configurando template-args-cont para indent-templates en mi tema personalizado, ala:

(c-add-style "my-style" ''("stroustrup" ;; ... Other stuff ... (template-args-cont . indent-templates))))

Pero sigue siendo bastante buggy. Funciona la mayor parte del tiempo, pero a veces emacs se confunde al pensar que una lista de plantillas es un arglista, y luego se produce la hilaridad.


Es un enfoque diferente que cambiar las pestañas, pero ¿qué pasa con el uso de un sistema de fragmento de Yasnippet como Yasnippet (ver ejemplos here )?

El único problema es que si reformatea el documento "Mx index-region" (o esa sección), probablemente volverá a las otras reglas de la pestaña.


La mejor solución que he encontrado es escribir una función de sangría personalizada (y relativamente sencilla).

El código

(defun c++-template-args-cont (langelem) "Control indentation of template parameters handling the special case of ''>''. Possible Values: 0 : The first non-ws character is ''>''. Line it up under ''template''. nil : Otherwise, return nil and run next lineup function." (save-excursion (beginning-of-line) (if (re-search-forward "^[/t ]*>" (line-end-position) t) 0))) (add-hook ''c++-mode-hook (lambda () (c-set-offset ''template-args-cont ''(c++-template-args-cont c-lineup-template-args +))))

Esto maneja todos los casos que he encontrado, incluso con plantillas anidadas en varios niveles.

Cómo funciona

Para el código de sangría, si se proporciona una lista de funciones de sangría, Emacs las probará en orden y si la que se está ejecutando actualmente devuelve nil , invocará la siguiente. Lo que he hecho es agregar una nueva función de sangría al principio de la lista que detecta si el primer carácter que no es un espacio en blanco en la línea es ''>'', y si lo está, establezca la sangría en la posición 0 (que lo alineará con la plantilla de apertura). Esto también cubre el caso en el que tiene parámetros de plantilla de plantilla de la siguiente manera:

template < template < typename T, typename U, typename... Args > class... CS >

porque no le importa lo que está después del ''>''. Entonces, como resultado de cómo funciona la lista de funciones de sangría, si ''>'' no es el primer carácter, la función devuelve nil y se invoca la función de sangría habitual.