Nicholas Hubbard
Posted on August 24, 2022
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.
Basics
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)
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)
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)
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
);
To instead indent like this:
my %hash = (
'foo' => 1,
'bar' => 2,
'baz' => 3
);
Add this to your config:
(setq cperl-indent-parens-as-block t)
(setq cperl-close-paren-offset (- cperl-indent-level))
Linting
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)
To enable flycheck mode in cperl-mode, simply turn it on with a hook.
(add-hook 'cperl-mode-hook 'flycheck-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)
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.
Shell
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)
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
- CPerl Documentation - Offical documentation for cperl-mode
- Perl::LanguageServer - Language server for Perl
- Devel::PerlySense - Perl IDE features for Emacs
- Emacs::PDE - Elisp extensions for Perl development
Posted on August 24, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.