2011-10-20 20 views
44

Hasta donde 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 emacs muesca hace esto:Plantillas C++ y Emacs: Personalización de sangría

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

Lo que yo quiero es algo como esto:

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

definición de la sangría plantilla-args-CONT a cero será sangrar el carácter '>' adecuadamente variables, pero a costa de eliminar el verdadero cuerpo de la lista de argumentos de la plantilla.

¿Alguna sugerencia de los gurús de emacs que hay?

EDIT:

lo tengo un poco de trabajo con el siguiente truco:

(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 poner plantilla-args-CONT para sangrar las plantillas en mi tema personalizado, Ala:

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

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

+1

No estoy seguro de si es posible, pero si es usted puede encontrar información en esta página: http://www.gnu.org/software/emacs/manual/html_mono/ccmode.html#Internet de Customizing – rve

+0

En realidad , Creo que podría ser posible si escribes tu propia función de alineación. El documento de mi comentario anterior brinda más información sobre esto. – rve

+6

Tenga en cuenta que el modo C++ de Emacs tiende a confundirse periódicamente sobre los argumentos de la plantilla en general, por lo que puede no ser realmente un problema con su código ... [para ser justos, en realidad es bastante difícil hacerlo bien, debido a los múltiples significados de '<' and '>' en C++ (a veces como delimitador equilibrado, a veces como operador), a menos que realice mucho más análisis que el modo C++ - ...] – snogglethorpe

Respuesta

2

La mejor solución que he encontrado es escribir una costumbre (y relativamente sencillo) función de sangrado.

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

Este se encarga de todos los casos que he encontrado incluso con plantillas anidadas varios niveles de profundidad.

Cómo funciona

Para sangría al código, si se proporciona una lista de las funciones de sangría, entonces Emacs tratarán en orden y si el que está siendo ejecutado vuelve nil, se invocará el 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 de 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 usted tiene parámetros de plantilla plantilla de la siguiente manera:

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

porque no le importa lo que está después de la '>'. Entonces, como resultado de la función de 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.

0

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

El único problema es que si reformatea el documento "M-x index-region" (o esa sección), probablemente regrese a las otras reglas de pestañas.

1

Comentarios

creo parte de el problema que experimenta es que cuando usted instancia plantillas, el modo CC emacs lo ve con la misma estructura template-args-cont. Entonces, teniendo esto en cuenta, amplié su idea original e intenté que fuera de mi agrado; Hice el código detallado para que todos puedan entender mi intención. :) Esto no debería causar problemas cuando crea instancias, ¡y también parece funcionar para los parámetros de la plantilla de plantilla! ¡Pruebe esto hasta que alguien con más habilidades de Elisp pueda proporcionar una mejor solución!

Si experimenta cualquier 'lucha' (es decir, alterna o muesca roto), intente volver a cargar el archivo CPP C-xC-vIntroduzca y sangría de nuevo. Algunas veces, con los parámetros de plantilla de plantilla, emacs muestra los argumentos internos como arglist-cont-nonempty e incluso alterna de ida y vuelta con template-args-const, pero el estado de recarga siempre se restablece.

Uso

para hacer lo que quiere probar esto utilizando el código de abajo y añadiendo a su c-offsets-alist una entrada:

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

y establezca 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))))) 
+0

Wow, gracias por esto. Lo intentaré durante el fin de semana si tengo algo de tiempo (en el proceso de mover casas). – bstamour

Cuestiones relacionadas