This project is young; still at early phases of development, so expect things to change considerably
DISCLAIMER: This offering is not approved or endorsed by OpenCFD Limited, producer and distributor of the OpenFOAM software and owner of the OPENFOAM® and OpenCFD® trade marks.
An implementation of the Language Server Protocol (LSP) for OpenFOAM dictionaries.
Here is a quick demo of the most important features:
For a more detailed explanation, check this slide out.
We're supporting the following features (* for partial or limited support):
- Auto-Completion
- Context-aware keywords (per file kind:
controlDict,fvSchemes,fvSolution, ...) - Valid values for known keywords (
stopAt,writeControl, boundary condition types, ...) - Macro expansion, workspace-wide (
$-triggered) - Boundary patch names inside
boundaryField - Preprocessor directives (
#-triggered) and snippets with documentation - Passive "Banana Trick":
Valid optionslists harvested from solver errors are offered as high-priority value completions, scoped to the dict entry the error names (fvSchemes.ddtSchemes.default) - Active "Banana Trick" also probes keywords that have no value yet:
a complete
keyword banana;entry is synthesized in the scratch copy — the user's buffer and case files are never touched - Banana-trick options carry documentation extracted from OpenFOAM
class headers (
data/runtimeSelection.json, regenerable against your OpenFOAM version — see CONTRIBUTING)
- Context-aware keywords (per file kind:
- Diagnostics [layered]
- Instant syntax errors from the Tree-Sitter grammar (on every keystroke, no solver needed)
- Solver-based semantic errors:
FATAL ERRORs,FATAL IO ERRORs, warnings andIOWarningdeprecation notices, multiple errors per run, foundation (.org) and ESI (.com) formats — including their absolute vs case-relative paths - Errors land on the file and the dictionary entry OpenFOAM names
(
system/fvSchemes/ddtSchemes/default), whichever separator the installed version uses - Configurable severities (
fatalError,fatalIOError,warning) and user-supplied regex rules for custom solver output (customRules) - Opt-in utility runs (
utilities, e.g.checkMesh,setFields) against a scratch copy of the case;***-style mesh complaints become warnings - Async and debounced; the solver child process is always killed
- Workspace-wide (errors land on the file they point at)
- LSP 3.17 pull diagnostics with push fallback for older clients
- Rename [workspace-wide, OpenFOAM-aware]
- Boundary patches: renames across
constant/polyMesh/boundary, field files'boundaryField,blockMeshDict,createPatchDict,decomposeParDict, ... - Exact quoted alternations like
"(front|back)"are rewritten member-wise - Patch groups (
inGroups) as their own namespace - Dictionary keys: updates
$macroreferences through#includechains
- Boundary patches: renames across
- Find References / Document Highlight
- Patches, patch groups, macros and dictionary keys
- Jump to Definition
- Macro expansion: absolute (
$:a.b), scoped ($a) and relative ($.a,$..a) paths - Cross-file resolution through
#includechains -
boundaryFieldpatch entry → its declaration inconstant/polyMesh/boundary(falls back toblockMeshDict/createPatchDictwhen the mesh doesn't exist yet) -
#include "file"→ the included file (also exposed as document links)
- Macro expansion: absolute (
- Document symbols [Complete]
- Uses the Tree-Sitter grammar for OpenFOAM
- Can penetrate lists and peek inside
- Workspace-wide symbols from the case index
- Hover Documentation & Signature Help
- Keyword knowledge base in
server/foamfile-language-service/data/keywords.json— one JSON file feeding completion, hover and signature docs; PRs welcome - Hover on runtime-selectable class names (
CrankNicolson,kOmegaSST, boundary condition types, ...) shows the class description harvested from OpenFOAM sources
- Keyword knowledge base in
- Folding, Semantic Tokens, Selection Ranges
- Implemented server-side for clients without the Tree-Sitter grammar;
(Neo)VIM users with
:TSInstall foamalready get folding/highlighting natively
- Implemented server-side for clients without the Tree-Sitter grammar;
(Neo)VIM users with
Not planned:
- Formatting
- Please use external C++/Typescript formatters if you're obsessed with nice-looking code.
Requires Node.js >= 18. On older Node the server exits immediately with a
version message (its dependencies use syntax older Node cannot parse). If your
system Node is older — Ubuntu's apt nodejs, for instance — install a current
one (e.g. nvm install --lts) and make sure your editor or Mason launches the
server with it.
If you want the (somewhat) stable code (from Releases):
npm install foam-language-serverIf you want the bleeding-edge features, with all the bleeding-edge bugs:
git clone --depth 1 --single-branch -b develop https://github.com/FoamScience/foam-language-server
npm install
npm testIt's important that your text editor detects the case directory as the "root directory" because diagnostics will depend on it. Most editors will ask the LSP for the root directory, but for those which don't, you'll have to configure it manually.
Neovim (v0.11+, using vim.lsp.config):
vim.lsp.config('foam_ls', {
cmd = { 'foam-ls', '--stdio' },
filetypes = { 'foam' },
root_markers = { 'system/controlDict' },
settings = {
foam = {
languageserver = {
diagnostics = {
-- "error" | "warning" | "ignore"
fatalError = 'error',
fatalIOError = 'error',
warning = 'warning',
-- extra utilities to diagnose with, run sequentially
-- against a scratch copy of the case (your files are
-- never touched); empty by default. A utility that
-- cannot run at all (setFields with no setFieldsDict)
-- is silent rather than noisy: only complaints naming
-- a case file, and rule matches, become diagnostics
utilities = { 'checkMesh' },
-- regex rules for custom solver output; named groups
-- message, file, line, endLine and options feed the
-- diagnostic (and options feed value completion)
customRules = {
{
name = 'my-solver',
pattern = 'MYSOLVER ERROR: (?<message>.+)',
-- "error" | "warning" | "info" | "hint"
severity = 'error',
},
},
},
completion = {
-- insert FoamExtend absolute macro paths ($:name
-- instead of $name), off by default
absoluteMacroPaths = false,
-- probe the solver for valid values of unknown
-- keywords (spawns solver processes), off by default
bananaTrick = false,
},
},
},
},
})
vim.lsp.enable('foam_ls')Older Neovim with nvim-lspconfig works the same way through lspconfig.foam_ls.setup{}.
Valid entries shipped in custom shared libraries need no extra configuration:
add OpenFOAM's own libs ("libmyModels.so"); to your case's
system/controlDict and every diagnostics run and banana probe loads them
automatically (scratch copies include controlDict).
The server talks standard LSP over stdio, so any LSP client works: point it
at the foam-ls executable and make sure the workspace root is the case
directory. For the full capability list, see the return value of
connection.onInitialize in server/foam-ls.ts.
can I ask WHY?
It is possible to run this LSP implementation with any text editor or IDE which supports LSP (most do), however Neo(VIM) has a clear priority and you may have to give up some features for things to work on other editors.
Sure, you can. It's basically a piece of C++/JavaScript technology which has nothing to do with OpenFOAM code base (other than parsing its file format, of course).
Currently the only feature which has a slim chance of working on Windows
is the "diagnostics" feature, because it needs to fire the case's solver to see if it errors
out (and captures stderr).
If you have solvers on your Windows PATH, and diagnostics are not showing up; please file a bug report.
Please skim through CONTRIBUTING.md if you plan to join on the fun.
