Use el modo de bloqueo de fuente solo en una parte del búfer

7

Estoy tratando de agregar una función de comentarios a la documentación de Pod para los scripts de Perl, y me gustaría resaltar los comentarios de Pod con una cara especial. Un simple prototipo de script Perl podría 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, un comentario de Pod está rodeado /* */como en el lenguaje de programación C. Sin embargo, solo la parte debajo de la línea __END__es la documentación del Pod. La parte sobre esa línea es el código Perl normal. Ahora, si trato de agregar resaltado de sintaxis al comentario de Pod usando, por ejemplo (llamado desde cperl-mode-hook):

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

Obtengo lo siguiente usando cperl-modecomo modo principal:

ingrese la descripción de la imagen aquí

Por lo tanto, los comentarios de Pod se resaltan también en un comentario de Perl normal (un comentario de Perl comienza con un #carácter), lo que no se desea (los comentarios de Pod solo se deben resaltar en las secciones de Pod, no en el código de Perl normal).

Para simplificar, para esta pregunta, podemos suponer que la documentación del Pod se limita al final del documento, comenzando con las líneas después de la __END__etiqueta. ¿Es posible verificar la posición del comentario actual y relacionarlo con la posición de la __END__línea, y a partir de esa información determinar si estamos dentro de un bloque Pod o no (y luego agregar resaltado de sintaxis solo si estamos dentro de un bloque Pod) cuando se ejecuta el código de bloqueo de fuente?

Håkon Hægland
fuente
No lo he usado, mmm-modepero creo que esta podría ser la solución para ti.
Kaushal Modi
Si hay un pod-modemodo principal que sería adecuado para las regiones de comentarios Pod, entonces mmm-modepodría ser aplicable. No estoy seguro de que sea así. Probablemente lo que necesita aquí es solo una configuración adicional de bloqueo de fuente.
sanityinc

Respuestas:

8

Solución actualizada

Hay una forma integrada de hacer esto con font-lock (gracias sanityinc)

Esta respuesta tiene todos los detalles sobre cómo funciona este estilo de palabras clave de bloqueo de fuente: 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)))

El resultado es el mismo que la solución original.

Aquí está en acción:

ingrese la descripción de la imagen aquí

Solución original usando funciones de bloqueo de jit (no ideal)

Creo que deberá realizar la fuente manualmente en una función agregada a jit-lock-functions.

jit-lock-functions son las funciones que realmente hacen la fuente y el área llamada con los parámetros BEG y END para denotar la región a la que se supone que deben aplicar las propiedades de texto.

Para este escenario, su función primero verá si la región a colorear está después de __END__en su búfer, y si es así, busque manualmente / * comentarios * / y aplique propiedades de texto a ellos.

Aquí hay una implementación:

(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 su escenario, es posible que desee agregar la función de bloqueo de jit dentro de un gancho de modo perl

También tenga en cuenta que esta función no es "inteligente", solo busca END en cualquier lugar del búfer, por lo que si aparece en una cadena o en un comentario en perl donde no debería tener efecto, en realidad lo hará. Puede ampliar la función para ver el contexto de dónde se produce END si es necesario.

Jordon Biondo
fuente
1
Normalmente no sería bueno modificarlo jit-lock-function. Ese es un detalle de implementación interna de font-lock. Debería haber una font-lockmanera simple de lograr esto.
sanityinc
1
Tienes razón @sanityinc, he encontrado la forma más estandarizada de hacerlo en el bloqueo de fuente, gracias. He usado jit-lock-functions en el pasado, ¡así que es muy bueno saberlo!
Jordon Biondo
Ah sí, eso se ve mejor!
sanityinc
¡Gracias @JordonBiondo! Esta fue una respuesta muy instructiva. Funciona perfectamente!
Håkon Hægland