Comment puis-je détecter si le caractère actuel est un caractère de commentaire pour ce mode principal?

12

Je travaille sur cette petite fonction qui tire la ligne suivante vers la ligne actuelle. Je veux ajouter une fonctionnalité de sorte que si la ligne actuelle est un commentaire de ligne et la ligne suivante est également un commentaire de ligne, les caractères de commentaire sont supprimés après l'action "pull-up".

Exemple:

Avant

;; comment 1▮
;; comment 2

Appel M-x modi/pull-up-line

Après

;; comment 1▮comment 2

Notez que les ;;caractères sont supprimés avant 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 fonction ci - dessus fonctionne , mais pour l' instant, quel que soit le principal mode, il considérera /ou ;ou #comme caractère de commentaire: (looking-at "/\\|;\\|#").

Je voudrais rendre cette ligne plus intelligente; spécifique au mode majeur.

Solution

Grâce à la solution de @ericstokes, je pense que ce qui suit couvre désormais tous mes cas d'utilisation :)

(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
la source
Voulez-vous que cela soit suffisamment intelligent pour gérer différents caractères de début et de fin de commentaire et des commentaires à plusieurs caractères (par exemple, des C /* ... */)?
erikstokes
Non, c'était tout ce dont j'avais besoin. Merci!
Kaushal Modi
@erikstokes Par curiosité, comment géreriez-vous les commentaires de style C?
Pradhan
Cette solution fonctionne tout de suite avec les commentaires sur plusieurs lignes, rien de spécial ne doit être fait car nous n'avons pas besoin de supprimer de caractères lors de la jonction de commentaires multilignes.
Kaushal Modi
2
@Pradhan Il y a les chaînes comment-startet comment-endqui sont définies sur "/ *" et "* /" dans c-mode(mais pas c++-mode). Et il y a c-comment-start-regexpcela qui correspond aux deux styles. Vous supprimez les caractères de fin puis le début après avoir rejoint. Mais je pense que ma solution serait uncomment-region, join-linele comment-regionet laissez Emacs vous inquiétez pas au sujet de ce caractère de commentaire est quoi.
erikstokes

Réponses:

12

Vous pouvez vérifier si le caractère actuel est un caractère de commentaire en utilisant la table de syntaxe: (looking-at "\\s<"). L'expression régulière \\s<correspondra à n'importe quel caractère avec la syntaxe "début de commentaire"; \\s>correspondra à ceux avec la syntaxe "comment end".

Une autre option est la variable comment-start, qui est la chaîne insérée par comment-dwimet amis. Il est généralement défini sur le caractère de début de commentaire plus un espace.

erikstokes
la source
2

Il existe une solution beaucoup plus simple , veuillez étudier mon code sur https://github.com/redguardtoo/evil-nerd-commenter/blob/master/evil-nerd-commenter.el

Je ne vais pas copier / coller tout le code ici. mais voici les points clés:

  • commentaire a sa propre face de police, recherche font-lock-comment-face et font-lock-comment-delimiter-face dans mon code

  • utiliser la propre API d'Emacs pour décommenter la deuxième ligne, puis la joindre à la première ligne

Il devrait fonctionner sur tous les modes majeurs sensibles.

Ce truc n'est pas inventé par moi. Il s'agit en fait du propre code d'Emacs (plus précisément, flyspell). La solution doit donc prendre en charge tous les supports de flyspell en modes majeurs

chen bin
la source
3
Pour mettre en évidence quelque chose en tant que commentaire, il faut que la table de syntaxe soit correctement configurée, donc je doute que ce soit plus intelligent que l'alternative de regarder la syntaxe.
wasamasa
J'ai appris cette astuce en lisant le propre code d'Emacs (en fait, c'est flyspell), comme je l'ai documenté dans mon code.
chen bin
0

Si vous recherchez cette fonctionnalité pour du code lisp (Elisp, Clojure, Scheme et Common Lisp), alors vous devriez essayer lispy , une fonction appelée lispy-fillfait ce genre de chose.

Si vous recherchez cette fonctionnalité pour une autre langue, vous devez alors rebox2 (vérifié pour Cet Python), une fonction appelée rebox-fillou une autre fonction appelée rebox-dwimfaire ce genre de chose.

Ce sont tous les deux d'excellents packages, et ils ne sont pas en conflit les uns avec les autres car ils sont utilisés pour différents modes majeurs, et ils sont tous les deux ( lispy-fillet rebox-dwim) liés M-q, assez soignés.

CodyChan
la source