Use o modo de bloqueio de fonte em apenas parte do buffer

7

Estou tentando adicionar um recurso de comentário à documentação do Pod para scripts Perl, e gostaria de destacar os comentários do Pod com uma face especial. Um protótipo simples de script Perl poderia ser:

#! /usr/bin/env perl

use strict;
use warnings;

print "Hello\n"; # a Perl comment /* hello */

__END__

=head1 SYNOPSIS

my_program <arg1> [OPTIONS]

/* this is a Pod comment */

Como vemos, um comentário de um pod é substituído por uma /* */linguagem de programação C. No entanto, apenas a parte abaixo da linha __END__é a documentação do Pod. A parte acima dessa linha é um código Perl comum. Agora, se eu tentar adicionar destaque de sintaxe ao comentário do Pod usando, por exemplo (chamado de cperl-mode-hook):

(font-lock-add-keywords nil '(("\\(/\\*.*?\\*/\\)" 1 'font-lock-warning-face t)))

Recebo o seguinte usando cperl-modecomo modo principal:

insira a descrição da imagem aqui

Portanto, os comentários do Pod também são destacados em um comentário Perl comum (um comentário do Perl começa com um #caractere), o que não é desejado (os comentários do Pod devem ser destacados apenas nas seções do Pod, e não no código Perl comum).

Para simplificar, para esta pergunta, podemos assumir que a documentação do Pod está confinada ao final do documento, começando pelas linhas após a __END__tag. É possível verificar a posição do comentário atual e relacioná-lo à posição da __END__linha e, a partir dessas informações, determinar se estamos dentro de um bloco de Pod ou não (e adicionar sintaxe destacando apenas se estiver dentro de um bloco de Pod) ao executar o código de bloqueio da fonte?

Håkon Hægland
fonte
Não usei, mmm-modemas acho que essa pode ser a solução para você.
precisa saber é o seguinte
Se houver um pod-modemodo principal que seja adequado para as regiões de comentários do Pod, mmm-modepoderá ser aplicável. Não sei se é esse o caso. Provavelmente o que você precisa aqui é apenas uma configuração adicional de bloqueio de fonte.
precisa saber é

Respostas:

8

Solução atualizada

Existe uma maneira integrada de fazer isso com o bloqueio de fonte (obrigado sanityinc)

Esta resposta tem todos os detalhes sobre como esse estilo de fonte-lock-keywords funciona: https://stackoverflow.com/a/14675550

(defun pod-comment-highlighter (limit)
  "If looking after __END__ or __END__ is before LIMIT, set match-data to a the location of the pod comment."
  (when (or (save-excursion (search-backward "__END__" (point-min) t 1))
            (search-forward "__END__" limit t 1))
    (re-search-forward "\\(/\\*.*?\\*/\\)" limit t 1)))

(font-lock-add-keywords
 'perl-mode
 '((pod-comment-highlighter 0 font-lock-warning-face t)))

O resultado é o mesmo que a solução original.

Aqui está em ação:

insira a descrição da imagem aqui

Solução original usando funções jit-lock (não é o ideal)

Eu acredito que você precisará fazer a fontificação manualmente em uma função adicionada ao jit-lock-functions.

jit-lock-functions são as funções que realmente executam a fonte e a área chamadas com os parâmetros BEG e END para indicar a região à qual eles devem aplicar propriedades de texto.

Nesse cenário, sua função primeiro verificará se a região a ser colorida está __END__em seu buffer e, nesse caso, pesquise manualmente / * comments * / e aplique propriedades de texto a elas.

Aqui está uma implementação:

(defun pod-comment-highlighter (beg end)
  "Highlight /* this style */ of comments but only if they appear after __END__ in the buffer."
  (save-excursion
    (save-match-data
      (goto-char beg)
      ;; only fontify if __END__ appears before the given region, or, if
      ;; __END__ is inside the region, then start fontifiying after __END__
      (when (or (save-excursion (search-backward "__END__" (point-min) t 1))
                (search-forward "__END__" end t 1))
        (while (re-search-forward "\\(/\\*.*?\\*/\\)" end t 1)
          (add-text-properties (match-beginning 0) (match-end 0) '(face font-lock-warning-face)))))))


;; `jit-lock-register' is normally used to add a jit-lock-function, 
;; but I want to make sure this function is the last function to run and
;; color the buffer so font-lock doesn't undo my applied properties.
;; So add-hook works nicely by passing t in the APPEND parameter
(add-hook 'jit-lock-functions 'pod-comment-highlighter t)

Para o seu cenário, você pode adicionar a função jit lock dentro de um gancho no modo perl

Observe também que essa função não é "inteligente", apenas procura END em qualquer lugar do buffer, portanto, se ocorrer em uma string ou um comentário perl onde não deveria ter efeito, na verdade ocorrerá. Você pode estender a função para examinar o contexto de onde END ocorre, se necessário.

Jordon Biondo
fonte
11
Normalmente não seria bom modificar jit-lock-function. Esse é um detalhe interno da implementação font-lock. Deve haver uma font-lockmaneira simples de conseguir isso.
precisa saber é
11
Você está certo @sanityinc, encontrei a maneira mais padronizada de fazer isso no bloqueio de fontes, obrigado. Eu usei funções jit-lock-anteriormente, então é muito bom saber!
22815 Jordon Biondo
Ah sim, isso parece melhor!
Sanityinc
Obrigado @JordonBiondo! Essa foi uma resposta muito instrutiva. Funciona perfeitamente!
Håkon Hægland