Como posso detectar se o caractere atual é um caractere de comentário para esse modo principal?

12

Estou trabalhando nessa pequena função que puxa a próxima linha para a linha atual. Desejo adicionar uma funcionalidade para que, se a linha atual for um comentário de linha e a próxima linha também for um comentário de linha, os caracteres do comentário sejam removidos após a ação "pull-up".

Exemplo:

Antes

;; comment 1▮
;; comment 2

Chamando M-x modi/pull-up-line

Depois de

;; comment 1▮comment 2

Observe que os ;;caracteres foram removidos 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)))))

A função acima funciona, mas por agora, independentemente do major-mode, que irá considerar /ou ;ou #como um caractere de comentário: (looking-at "/\\|;\\|#").

Eu gostaria de tornar essa linha mais inteligente; modo principal específico.

Solução

Graças à solução @ericstokes, acredito que o abaixo agora cobre todos os meus 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
fonte
Deseja que isso seja inteligente o suficiente para lidar com diferentes caracteres de início e fim de comentários e comentários com vários caracteres (por exemplo, C /* ... */)?
precisa saber é o seguinte
Não, isso era tudo que eu precisava. Obrigado!
precisa saber é o seguinte
@erikstokes Por curiosidade, como você lidaria com comentários no estilo C?
Pradhan
Essa solução funciona com comentários de várias linhas também imediatamente, nada de especial precisa ser feito, porque não precisamos excluir nenhum caractere ao ingressar em comentários de várias linhas.
precisa saber é o seguinte
2
@ Pradhan Existem as strings comment-starte comment-enddefinidas como "/ *" e "* /" em c-mode(mas não c++-mode). E tem c-comment-start-regexpisso que combina com os dois estilos. Você exclui os caracteres finais e o início após a junção. Mas eu acho que a minha solução seria uncomment-region, join-lineo comment-regione deixe Emacs preocupação sobre o caractere de comentário é o que.
precisa saber é o seguinte

Respostas:

12

Você pode verificar se o caráter atual é um caractere de comentário utilizando a tabela de sintaxe: (looking-at "\\s<"). O regexp \\s<corresponderá a qualquer caractere com a sintaxe "comment start"; \\s>corresponderá àqueles com a sintaxe "fim do comentário".

Outra opção é a variável comment-start, que é a string inserida porcomment-dwim e amigos. Geralmente, é definido como o caractere de início do comentário mais algum espaço.

erikstokes
fonte
2

Existe um solução muito mais simples , por favor estude meu código em https://github.com/redguardtoo/evil-nerd-commenter/blob/master/evil-nerd-commenter.el

Não vou copiar / colar todo o código aqui. mas aqui estão os pontos principais:

  • comment tem sua própria fonte, procure font-lock-comment-face e font-lock-comment-delimiter-face no meu código

  • use a própria API do Emacs para descomentar a segunda linha e depois junte-a à primeira linha

Ele deve funcionar em quaisquer modos principais sensíveis.

Este truque não é inventado por mim. Na verdade, é do próprio código do Emacs (mais especificamente, flyspell). Portanto, a solução deve suportar todos os modos principais de flyspell

Chen Bin
fonte
3
Para destacar algo como comentário, é necessário que a tabela de sintaxe seja configurada adequadamente, por isso duvido que seja mais inteligente que a alternativa de analisar a sintaxe.
wasamasa
Eu aprendi esse truque lendo o código do Emacs (na verdade, é flyspell), conforme documentado no meu código.
Chen bin
0

Se você está procurando esse recurso por código lisp (Elisp, Clojure, Scheme e Common Lisp), tente o lispy , uma função chamada lispy-fillfaz esse tipo de coisa.

Se você estiver procurando esse recurso por outro idioma, deverá rebox2 (verificado para Ce Python), uma função chamada rebox-fillou outra função chamadarebox-dwim fazer esse tipo de coisa.

Os dois são ótimos pacotes e não conflitam entre si, pois são usados ​​para modos principais diferentes e estão ambos ( lispy-fille rebox-dwim) vinculados a eles M-q, bem legais.

CodyChan
fonte