perl-lsp
A Perl language server with deep semantic intelligence. Built on tree-sitter-perl and tower-lsp.
Install
Editor Setup
Neovim (0.11+)
vim.. =
vim..
Neovim (0.10 or earlier)
vim..
Helix
Add to ~/.config/helix/languages.toml:
[]
= "perl-lsp"
[[]]
= "perl"
= ["perl-lsp"]
Emacs (eglot)
(add-to-list 'eglot-server-programs '(perl-mode . ("perl-lsp")))
Semantic Token Colors (Neovim)
perl-lsp emits rich semantic tokens. Add these to your config for the best experience:
vim.. -- has, with, extends
vim.. -- hash keys
vim.. -- Foo::Bar
vim.. -- sub params
vim.. -- $self/$class
vim.. -- $ blue
vim.. -- @ purple
vim.. -- % gold
vim.. -- writes in red
vim..
vim..
vim.. -- imported functions
Features
Type Inference
No annotations needed. perl-lsp infers types from how your code uses values:
Foo->new()→$objisClassName(Foo)$obj->{key}→$objis HashRef$x + 1→$xis Numeric- Method chains propagate:
$self->get_config()->{host}resolves through return types - Cross-file: return types and parameter types flow across module boundaries
Framework Intelligence
| Framework | What perl-lsp understands |
|---|---|
| Moo/Moose | has accessor synthesis with is/isa type mapping, getter/setter arity, extends/with for inheritance and roles |
| Mojo::Base | Accessor synthesis with default value type inference, fluent setter chaining, parent class detection |
| DBIC | add_columns column accessors, has_many/belongs_to/has_one relationship accessors, load_components mixin resolution |
Perl 5.38 class |
field with :param/:reader/:writer, :isa(Parent), :does(Role), implicit $self |
Framework DSL keywords (has, with, extends, around, etc.) are recognized and won't trigger unresolved-function diagnostics.
Constant Folding + Dynamic Dispatch
my $method = ;
$self->$method();
perl-lsp folds use constant, package-scope variables, string interpolation, and loop variables. Dynamic method calls via $self->$var() resolve to their targets.
Cross-File Intelligence
- Module resolution from
@INC+ cpanfile dependencies - Auto-discovers
lib/andlocal/lib/perl5/relative to workspace root — noPERL5LIBneeded for standard project layouts (cpm, carton, plainlib/) - Inheritance chain walking (DFS, roles, mixins,
load_components) - Return type and parameter type propagation across files
- Cross-file rename: 289 edits across 56 files in Mojolicious in <1 second
- SQLite cache for instant repeat resolution
- Workspace indexing via Rayon: 274-file Mojolicious in 204ms
Module Discovery
perl-lsp finds your modules automatically:
lib/andlocal/lib/perl5/in your project root (auto-discovered)@INCfrom your Perl installation (viaperl -e 'print join "\n", @INC')PERL5LIBif set in your environment- cpanfile dependencies pre-resolved at startup
For non-standard layouts, set PERL5LIB before launching your editor:
PERL5LIB=./my-libs/perl5
LSP Capabilities
| Capability | Highlights |
|---|---|
| Completion | Variables, methods (type-inferred), hash keys, auto-import, module names on use lines, import lists in qw() |
| Go-to-definition | Scope-aware variables, cross-file methods via inheritance, hash keys through expression chains |
| Find references | Scope-aware variables, cross-file functions/methods/packages |
| Rename | Variables (scope-aware), functions/methods/packages (cross-file via workspace index) |
| Hover | Types, POD docs (tree-sitter-pod AST), signatures, class provenance |
| Signature help | Parameter names with inferred types, cross-file parameter types |
| Semantic tokens | 10 types (variable, parameter, $self, function, method, macro, property, namespace, regexp, constant), 9 modifiers |
| Inlay hints | Variable type annotations, sub return types |
| Diagnostics | Unresolved function/method warnings with framework awareness |
| Code actions | Auto-import for unresolved functions |
| Workspace symbol | Search across all indexed project files |
| Document symbols | Nested outline with packages, subs, classes, fields |
| Formatting | perltidy (full document + range) |
| Highlights | Read/write distinction |
| Selection range | Tree-sitter node hierarchy |
| Folding | Blocks, subs, classes, POD |
| Linked editing | Simultaneous editing of references in scope |
POD Documentation
POD is rendered via tree-sitter-pod — proper AST walk, not regex. Handles nested lists, =begin/=end data regions, multi-angle-bracket formatting (C<<< $hash->{key} >>>), bold-italic nesting, L<> links to metacpan, and =item-based method documentation.
CLI Tools
perl-lsp doubles as a command-line analysis toolkit:
# Batch diagnostics (CI-ready — resolves imports, uses SQLite cache)
# Code exploration
# Refactoring
--check resolves modules from @INC, uses the per-project SQLite cache, and exits with code 1 if issues are found. Integrate into CI with:
Building from Source
Testing
&&
License
Artistic License 2.0 — same as Perl itself.