7

I am trying to add a comment feature to Pod documentation for Perl scripts, and I would like to highligh Pod comments with a special face. A simple prototype Perl script could be:

#! /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 */

As we see, a Pod comment is surronded by /* */ as in C programming language. However, only the part below the line __END__ is Pod documentation. The part above that line is regular Perl code. Now, if I try to add syntax highlighting to the Pod comment using for example (called from cperl-mode-hook):

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

I get the following using cperl-mode as major mode:

enter image description here

So Pod comments are highlighted also in a regular Perl comment (a Perl comment starts with a # character), which is not desired (Pod comments should only be highlighted in Pod sections, not in regular Perl code).

For simplicity, for this question, we can assume that the Pod documentation is confined to the end of the document, starting with the lines after the __END__ tag. Is it possible to check the position of the current comment and relate that to the position of the __END__ line, and from that information determine if we are inside a Pod block or not (and then add syntax highlighting only if we are inside a Pod block) when running the font lock code?

Håkon Hægland
  • 3,608
  • 1
  • 20
  • 51
  • I haven't used [`mmm-mode`](https://github.com/purcell/mmm-mode) but I think this might be the solution for you. – Kaushal Modi Jan 20 '15 at 14:17
  • If there is a `pod-mode` major mode which would be suitable for the Pod comment regions, then `mmm-mode` might be applicable. I'm not sure that's the case. Probably what you need here is just additional font-lock config. – sanityinc Jan 20 '15 at 14:51

1 Answers1

8

Updated Solution

There is a built in way to do this with font-lock (thank you sanityinc)

This answer has all the details about how this style of font-lock-keywords work: 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)))

The result is the same as the original solution.

Here it is in action:

enter image description here

Original solution using jit-lock-functions (not ideal)

I believe you'll need to do the fontification manually in a function added to the jit-lock-functions.

jit-lock-functions are the functions that actually do the fontification and area called with BEG and END parameters to denote the region they are supposed to apply text properties to.

For this scenario your function will first see if the region to color is after the __END__ in your buffer, and if so, manually search for /* comments */ and apply text properties to them.

Here is an implementation:

(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)

For your scenario you may want to add the jit lock function inside a perl-mode-hook

Also note that this function isn't "smart" it just looks for END anywhere int he buffer, so if it occurs in a string or a perl comment where it shouldn't have effect, it actually will. You can extend the function to look at the context of where END occurs if you need to.

Jordon Biondo
  • 12,332
  • 2
  • 41
  • 62