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?

  • I haven't used 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
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.

  • 1
    It wouldn't normally be good to modify jit-lock-function. That's an internal implementation detail of font-lock. There should be a plain font-lock way to achieve this. – sanityinc Jan 20 '15 at 14:48
  • 1
    You are right @sanityinc, I've found the more standardized way to do it in font lock, thank you. I've used jit-lock-functions in the past, so this is very nice to know! – Jordon Biondo Jan 20 '15 at 15:08
  • Ah yes, that looks better! – sanityinc Jan 21 '15 at 16:20
  • Thanks @JordonBiondo! This was a very instructive answer. It works perfectly! – Håkon Hægland Jan 21 '15 at 19:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.