php-regex / regex-language-server
A Language Server for the regex patterns of PHP files: diagnostics, hovers, completions and code actions in any LSP editor.
Package info
github.com/php-regex/regex-language-server
pkg:composer/php-regex/regex-language-server
Fund package maintenance!
Requires
- php: >=8.1
- ext-mbstring: *
- ext-tokenizer: *
- php-regex/regex-explain: 2.x-dev
- php-regex/regex-linter: 2.x-dev
- php-regex/regex-parser: 2.x-dev
- php-regex/regex-redos: 2.x-dev
- php-regex/regex-toolkit: 2.x-dev
Requires (Dev)
None
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-27 10:05:56 UTC
README
PHPRegex Language Server
A language server for the regex patterns of PHP files: diagnostics, hovers, completions and code actions in any LSP editor.
The server reads PHP source over stdio, finds the regex literals in it — the patterns of preg_* calls, of library calls such as Preg::match() or $this->assertMatchesRegularExpression(), and of the calls to functions whose parameter is marked #[RegexPattern] — and answers in JSON-RPC, so every LSP editor can check patterns while you type.
Documentation: php-regex.com — the LSP guide gets diagnostics into your editor.
Features
- Diagnostics on open and on change: every pattern of the file is parsed, validated and linted, and the findings are published to the editor; a pattern PCRE refuses gets that error alone.
- Hovers in plain English: hold the pointer on a pattern to read what it matches, token by token.
- Completions inside patterns: shorthands after a backslash, Unicode properties after
\p{, POSIX classes after[:, groups after(?, flags after the closing delimiter. - Code actions: one action adds the
uflag a Unicode pattern lacks, one applies the optimizer's rewrite —/[0-9]{1,}/becomes/\d+/— and two lay a long pattern out over lines underxor compact it back to one line. - The calls
regex lintreads: the native ones (preg_*,RegexIterator,filter_var()), the presetsextraction.interopinregex.jsonnames (every one by default; an unknown name is an error, shown, and the server reads as withoutregex.json), the helpersextraction.functionsnames, and a pattern held in a constant, a variable or a property of the same file, diagnosed at its literal;@regex-ignoreworks as in the lint. A pattern assembled from several pieces at the call, or written as a heredoc, is reported byregex lintbut gets no diagnostic in the editor. - Functions marked
#[RegexPattern](or PhpStorm's#[Language('RegExp')]): their calls are checked at that argument, the declarations read at start-up from the workspace's PHP files (underpaths, out ofexcludeinregex.json) and fromvendor/whateverexcludesays (read again when the editor reportsvendor/composer/installed.jsonchanged), and from the open documents as you type. A document invendor/gets no diagnostics. - One target per workspace: patterns are judged for one PHP and PCRE2 pair, resolved from the editor settings,
regex.json,composer.jsonor the running PHP.
Installation
composer require --dev php-regex/regex-language-server
Requires PHP 8.1+ with the tokenizer extension. The binary is installed as vendor/bin/regex-lsp; --help prints its options, --version the release it was built from.
Configuration
Every pattern of the workspace is judged for one target, a PHP and PCRE2 pair, resolved once at initialize and logged where the editor shows the server output (Target: PHP 8.4.26, PCRE2 10.49 (running PHP)).
| Option | Accepts | When absent |
|---|---|---|
initializationOptions.phpVersion |
"8.2", "8.2.4" or 80200 |
phpVersion in regex.json, then composer.json, then the running PHP |
initializationOptions.pcreVersion |
a PCRE2 release, "10.42" for instance |
pcreVersion in regex.json, then the release the target PHP bundles |
initializationOptions.locale |
an LC_CTYPE locale this machine can set, "tr_TR.UTF-8" for instance |
locale in regex.json, then the one of the PHP running the server |
initializationOptions.redos |
true or false: run the ReDoS analysis and publish its verdict on each pattern, with the mode and the threshold of checks.redos in regex.json |
checks.redos.enabled in regex.json, then off |
initializationOptions.trace |
"off", "messages" or "verbose": log every frame read and written on stderr |
the trace of the initialize request, then "off"; $/setTrace changes it during the session |
regex.json (and regex.dist.json) sits at the root of the first workspace folder. A value the server cannot read is logged as a warning and the next source is used. Changing the target or the ReDoS analysis takes a server restart.
Usage
A file opens, and a broken pattern is reported where it sits. This notification was captured from a live session:
{"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"uri":"file:///demo/Mailer.php","diagnostics":[
{"range":{"start":{"line":2,"character":13},"end":{"line":2,"character":16}},"severity":1,"code":"regex.delimiter.unclosed",
"source":"php-regex","message":"No closing delimiter \"/\" found. You opened with \"/\"; expected closing \"/\". Tip: escape \"/\" inside the pattern (\\/) or use a different delimiter, e.g. #[a-#."}]}}
Hovering the pattern /^\w+@\w+\.\w+$/ returns this markdown (abridged):
**Regex Pattern**
```
/^\w+@\w+\.\w+$/
```
**Explanation**
Regex matches
Anchor: the start of the subject
Character Type: A word character: [a-zA-Z_0-9], and the letters of the LC_CTYPE locale when it is not C (one or more times)
…
Anchor: the end of the subject, or just before a newline (\n) that ends it
Code actions are offered on the pattern they fix:
/\p{L}+/without theuflag gets "Add /u flag for Unicode support", rewriting the literal to'/\p{L}+/u'./[0-9]{1,}/gets "Apply regex optimization", rewriting the literal to'/\d+/'; a rewrite is offered only once the automata prove it, asregex lintchecks its suggestions.- A pattern too long for its line gets "Format pattern over lines", which lays it out under
x, its continuation lines indented four spaces past the literal's line; a laid-out pattern gets "Compact pattern to one line". Each is offered only when it changes the literal.
Integration
VS Code
VS Code has no setting that points at an arbitrary language server: a small
extension built on
vscode-languageclient
starts vendor/bin/regex-lsp for PHP files. The
editor guide shows the whole client.
PhpStorm
Install LSP4IJ from the JetBrains Marketplace, then Settings → Languages & Frameworks → Language Servers: a server definition named PHPRegex, command vendor/bin/regex-lsp, file mappings *.php.
Neovim
init.lua with nvim-lspconfig:
local lspconfig = require('lspconfig') local configs = require('lspconfig.configs') if not configs.php_regex then configs.php_regex = { default_config = { cmd = { 'vendor/bin/regex-lsp' }, filetypes = { 'php' }, root_dir = lspconfig.util.root_pattern('composer.json', '.git'), }, } end lspconfig.php_regex.setup({})
Vim, Emacs, Sublime Text, Helix, Zed and the OpenCode coding agent are wired the same way; the LSP guide holds each snippet.
Documentation
- LSP guide — editor configurations, supported methods, troubleshooting.
- Diagnostics reference — the codes the server publishes and how to read them.
- Backward compatibility promise — what stays stable across releases.
Resources
- Upgrading from 1.x — moving from
yoeunes/regex-parser1.3 to 2.0, every change that needs one on your side - Documentation
- Report issues and send pull requests in the main PHPRegex repository
- Changelog
Sponsors
If PHPRegex saves you time, consider sponsoring its maintenance.
License
MIT. See LICENSE.