DEV Community

Nicholas Hubbard
Nicholas Hubbard

Posted on • Updated on

How I use Emacs to write Perl

This post is about how I use Emacs to write Perl. I do not claim to have the best Perl setup of all time or anything like that. The features I need to write Perl effectively are syntax highlighting, auto-indentation, linting, and code navigation.

I personally like to build my own IDE by bringing together unrelated packages, which is in contrast to full blown IDE packages, such as Devel::PerlySense or Perl::LanguageServer. These packages just aren't for me.


By default Emacs uses perl-mode instead of the more advanced cperl-mode. Both packages are built-in, so to use cperl-mode instead of perl-mode all you have to do is add the following line to your config.

(fset 'perl-mode 'cperl-mode)
Enter fullscreen mode Exit fullscreen mode

The cperl-mode that was released with Emacs 28 improved the syntax highlighting for regular expressions and heredocs, and fixed a few other annoying bugs.

If you are using an Emacs version less than 28 then I would recommend downloading the cperl-mode off the Emacs 28 (at least) branch. I personally place this file in ~/.emacs.d/cperl-mode/cperl-mode.el, then I load it with the following code.

(add-to-list 'load-path "~/.emacs.d/cperl-mode")
(require 'cperl-mode)
Enter fullscreen mode Exit fullscreen mode

By default cperl-mode replaces trailing whitespace with underscores. You can automatically delete this with whitespace-cleanup-mode, or you can use this elisp:

(setq cperl-invalid-face nil)
Enter fullscreen mode Exit fullscreen mode

cperl-mode defaults to indenting blocks by 2 spaces. You can modify this by setting the cperl-indent-level to some value other than 2.

You probably want multi-line statements wrapped in parens to be indented like a block. By default cperl-mode indents this hash declaration in a strange way (to me):

my %hash = (
            'foo' => 1,
            'bar' => 2,
            'baz' => 3
Enter fullscreen mode Exit fullscreen mode

To instead indent like this:

my %hash = (
    'foo' => 1,
    'bar' => 2,
    'baz' => 3
Enter fullscreen mode Exit fullscreen mode

Add this to your config:

(setq cperl-indent-parens-as-block t)
(setq cperl-close-paren-offset (- cperl-indent-level))
Enter fullscreen mode Exit fullscreen mode


Linting Perl code helps to quickly find bugs caused by typos or little errors. My favorite Emacs linting package is Flycheck, which comes with built-in support for Perl.

By default Flycheck checks your code with the Perl interpreter, but it also comes with integration with Perl::Critic.

I like to lint the file everytime I save, and I like to display any errors immediately. Here is how I accomplish this with Flycheck.

(require 'flycheck)
(setq flycheck-check-syntax-automatically '(mode-enabled save))
(setq flycheck-display-errors-delay 0.3)
Enter fullscreen mode Exit fullscreen mode

To enable flycheck mode in cperl-mode, simply turn it on with a hook.

(add-hook 'cperl-mode-hook 'flycheck-mode)
Enter fullscreen mode Exit fullscreen mode

Now Emacs will underline any syntax errors, and you can view the message in the echo area by placing your cursor on the erroneus code.

I cannot tell you how many simple errors you will catch just by using Flycheck!

Code Navigation

For jumping between function definitions I use dumb-jump, which usually just works. I configure dumb-jump to use ag for its searching which makes it work very quickly.

(require 'dumb-jump)
(setq dumb-jump-force-searcher 'ag)
(add-hook 'xref-backend-functions #'dumb-jump-xref-activate)
Enter fullscreen mode Exit fullscreen mode

I can then use dumb-jump by calling the xref-find-definitions function while my cursor is on the symbol I want to search for. This function is bound to M-. by default.


A lot of people use M-x compile to run their code, and one of the various debugger packages to run the Perl debugger. Personally I just use plain old Bash with the built-in M-x shell. This makes my work flow when it comes to running and debugging quite similar to that of a classic Perl vimmer who does all their work in a terminal.

I use the wonderful shx package for making M-x shell a more usable shell interface, and I use shell-pop for popping up shell buffers that are automatically cd'd to the current files directory.

(require 'shx)
(add-hook 'shell-mode-hook 'shx-mode)

(require 'shell-pop)
(setq shell-pop-autocd-to-working-dir t)
(global-set-key (kbd "M-SPC") 'shell-pop)
Enter fullscreen mode Exit fullscreen mode

Closing Thoughts

Every 3rd-party package I described in this post is useful not only for Perl, but for programming in any language. This gives a uniform experience across different programming languages. If I instead used one of the Perl IDE packages then I wouldn't get the same uniform experience when using other languages.

See Also

Top comments (3)

davorg profile image
Dave Cross

By default cperl-mode replaces trailing whitespace with underscores. I cannot imagine why you would want this.

Because trailing whitespace is usually an error. The underscores make it easy to find and remove.

matthewpersico profile image
Matthew O. Persico

Oh. Wow. Yes! How about more articles on how to configure the items in the four links at article’s end? πŸ‘πŸ‘πŸ‘πŸ‘πŸ‘

wilbfcpl profile image

Hello Nicholas,
Nice article. Any use of pretty-printing / indentation like Perl::Tidy or other Perl Best Practices?
Wil B.