Search code examples
perlemacscperl-mode

ISO Emacs [C]Perl-mode colorize hash references like hashes


I still use Perl, some new code, and maintaining old code. I use emacs and cperl-mode. I like syntax coloring.

At first (many years ago) I disliked cperl-mode's special coloring of arrays and hashes, but it has grown on me. To the point where I will sometimes prefer to use a hash rather than a hash reference, just to get the special coloring. That may not sound so bad - but if I admit to occasionally using a global %hash or $hash{key} rather than an object member $hashref->{key}, just to get the coloring, well, it is bad. I.e. syntax coloring is making me want to follow bad programming practices.

So, my question is: does anyone have emacs/elisp configuration code to get cperl-mode or perl-mode to colorize a hash reference like $hashref->{key} in the same or similar to $hash{key}?

Let me use bold to indicate the places that might be colored:

  • cperl-mode does now: $hash{key}
  • what I would like: $hash->{key}

I have done extensive customization of coloring (faces) in emacs - e.g. colorizing to distinguish DEBUG code from non-debug code, TEST from non-test, etc. - but I have not managed to get this syntax coloring in cperl-mode working. (FOLLOW-ON: I eventually got font-lock-add-keywords working, as shown in my answer to my own question below.)

In the example below, you can see that $hashref->{key} is not colored, while $hash{key} is.

example of cperl-mode syntax coloring

Similarly for array refs, and perhaps other refs.

I realize that coloring refs will only apply to derefs like $hashref->{key}, and not to other stuff like $hashref1 = $hashref2. I think that I can live with that.


Solution

  • I dislike answering my own question, but the wild goose chase answer suggested annoyed me enough to figure out what my attempts were doing wrong.

    (I hate it when I ask for X, somebody answers Y, and disses X. Especially when X is doable, as here.)

    Here is working code from my .emacs:

    (defun ag-extend-cperl-font-lock-keywords ()
      (interactive)
      (font-lock-add-keywords
        'cperl-mode
        '(
           (
             "\\($[a-zA-Z_][a-zA-Z_0-9]*->\\){"
             1 'cperl-hash-face t
             )
           (
             "\\($[a-zA-Z_][a-zA-Z_0-9]*->\\)\\["
             1 'cperl-array-face t
             )
           (
             "\\($[a-zA-Z_][a-zA-Z_0-9]*->\\)("
             1 'font-lock-function-name-face t
             )
           )
        t
        )
      )
    
    (ag-extend-cperl-font-lock-keywords)
    

    giving

    enter image description here

    Just for grins, @choroba's example of multiple types:

    enter image description here

    I haven't decided if I should create separate faces for hashrefs, arrayrefs, and coderefs. For now, just using the same face as their non-ref counterparts. Including -> as part of the text colored provides some distinction between non-ref and ref.

    Nor have I yet decided if I want to extend to the various other Perl syntaxes. From https://perldoc.perl.org/perlref.html:

    enter image description here

    But now that I have the font-lock-add-keywords invocation, those details I can fix at my leisure.