¿Cómo puedo detectar si el personaje actual es un comentario para ese modo principal?

12

Estoy trabajando en esta pequeña función que muestra la siguiente línea a la línea actual. Quiero agregar una funcionalidad para que si la línea actual es un comentario de línea y la siguiente línea también es un comentario de línea, los caracteres de comentario se eliminan después de la acción "pull-up".

Ejemplo:

antes de

;; comment 1▮
;; comment 2

Vocación M-x modi/pull-up-line

Después

;; comment 1▮comment 2

Tenga en cuenta que ;;se eliminan los caracteres que estaban antes comment 2.

(defun modi/pull-up-line ()
  "Join the following line onto the current one (analogous to `C-e', `C-d') or
`C-u M-^' or `C-u M-x join-line'.

If the current line is a comment and the pulled-up line is also a comment,
remove the comment characters from that line."
  (interactive)
  (join-line -1)
  ;; If the current line is a comment
  (when (nth 4 (syntax-ppss))
    ;; Remove the comment prefix chars from the pulled-up line if present
    (save-excursion
      (forward-char)
      (while (looking-at "/\\|;\\|#")
        (delete-forward-char 1))
      (when (looking-at "\\s-")
        (delete-forward-char 1)))))

La función anterior funciona, pero por ahora, independientemente de la major-mode, se tendrá en cuenta /o ;, o #como un carácter de comentario: (looking-at "/\\|;\\|#").

Me gustaría hacer esta línea más inteligente; modo mayor específico.

Solución

Gracias a la solución de @ericstokes, creo que lo siguiente ahora cubre todos mis casos de uso :)

(defun modi/pull-up-line ()
  "Join the following line onto the current one (analogous to `C-e', `C-d') or
`C-u M-^' or `C-u M-x join-line'.

If the current line is a comment and the pulled-up line is also a comment,
remove the comment characters from that line."
  (interactive)
  (join-line -1)
  ;; If the current line is a comment
  (when (nth 4 (syntax-ppss))
    ;; Remove the comment prefix chars from the pulled-up line if present
    (save-excursion
      (forward-char)
      ;; Delete all comment-start or space characters
      (while (looking-at (concat "\\s<" ; comment-start char as per syntax table
                                 "\\|" (substring comment-start 0 1) ; first char of `comment-start'
                                 "\\|" "\\s-")) ; extra spaces
        (delete-forward-char 1)))))
Kaushal Modi
fuente
¿Desea que esto sea lo suficientemente inteligente como para manejar diferentes caracteres iniciales y finales de comentarios y comentarios de varios caracteres (por ejemplo, C /* ... */)?
erikstokes
No, eso era todo lo que necesitaba. ¡Gracias!
Kaushal Modi
@erikstokes Por curiosidad, ¿cómo manejarías los comentarios de estilo C?
Pradhan
Esta solución también funciona con comentarios de varias líneas de inmediato, no es necesario hacer nada especial porque no necesitamos eliminar ningún carácter al unir comentarios de varias líneas.
Kaushal Modi
2
@Pradhan Existen las cadenas comment-starty comment-endque se establecen en "/ *" y "* /" en c-mode(pero no c++-mode). Y hay c-comment-start-regexpque coincide con ambos estilos. Elimina los caracteres finales y luego el comienzo después de unirse. Pero creo que mi solución sería uncomment-region, join-lineel comment-regiony dejo que Emacs se preocupe por lo que carácter de comentario es qué.
erikstokes

Respuestas:

12

Puede comprobar si el carácter actual es un carácter de comentario mediante el uso de la tabla de sintaxis: (looking-at "\\s<"). La expresión regular \\s<coincidirá con cualquier carácter con la sintaxis "inicio de comentario"; \\s>coincidirá con aquellos con la sintaxis "final de comentario".

Otra opción es la variable comment-start, que es la cadena insertada por comment-dwimy amigos. Por lo general, se establece en el carácter de inicio de comentario más algo de espacio.

erikstokes
fuente
2

Hay una solución mucho más simple , estudie mi código en https://github.com/redguardtoo/evil-nerd-commenter/blob/master/evil-nerd-commenter.el

No copiaré / pegaré todo el código aquí. pero aquí están los puntos clave:

  • el comentario tiene su propia fuente, busque font-lock-comment-face y font-lock-comment-delimiter-face en mi código

  • use la propia API de Emacs para descomentar la segunda línea, luego únala con la primera línea

Debería funcionar en cualquier modo importante sensible.

Este truco no fue inventado por mí. En realidad es del código propio de Emacs (más específicamente, flyspell). Por lo tanto, la solución debe admitir cualquier soporte de flyspell de modos principales

Chen Bin
fuente
3
Para resaltar algo como comentario, requiere que la tabla de sintaxis esté configurada adecuadamente, por lo que dudo que sea más inteligente que la alternativa de mirar la sintaxis.
wasamasa
Aprendí este truco leyendo el propio código de Emacs (en realidad, es un encantamiento de mosca), como lo documenté en mi código.
Chen bin
0

Si está buscando esta función para el código lisp (Elisp, Clojure, Scheme y Common Lisp), entonces debería probar lispy , una función llamada lispy-fillhace este tipo de cosas.

Si está buscando esta característica para otro idioma, entonces debe rebox2 (verificado para Cy Python), una función llamada rebox-fillu otra función llamada rebox-dwimhacer este tipo de cosas.

Ambos son excelentes paquetes, y no están en conflicto entre sí, ya que se usan para diferentes modos principales, y están ( lispy-filly rebox-dwim) obligados M-q, bastante bien.

CodyChan
fuente