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
Top comments (3)
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.
Oh. Wow. Yes! How about more articles on how to configure the items in the four links at article’s end? 👏👏👏👏👏
Hello Nicholas,
Nice article. Any use of pretty-printing / indentation like Perl::Tidy or other Perl Best Practices?
Thanks,
Wil B.