Comprehensive Neovim plugin for Lingua Franca with syntax highlighting, LSP support, and interactive diagram viewing.
- Tree-sitter powered - Accurate highlighting from a grammar auto-generated from upstream Xtext
- Zero-config install - Parser and queries are downloaded automatically on first open of a
.lffile (requirescurl) - Embedded language support - Proper highlighting for C/C++, Python, TypeScript, and Rust code blocks
- Automatic target detection - Detects target language from
targetdeclarations - Textobjects ready - Ships
textobjects.scmqueries for use with nvim-treesitter-textobjects - Cross-platform - Pre-built parsers for Linux, macOS, and Windows (x64 + ARM64)
Note: LSP features require Mac or Linux as Lingua Franca doesn't support Windows
- Full LSP Support - Diagnostics, completion, hover, go-to-definition, references
- Build Integration - Build and run LF programs from Neovim with progress reporting
- Interactive Diagrams - View and interact with KLighD reactor diagrams in browser
- Jump to Source - Click diagram elements to jump to code locations
- Library Browser - Browse and import reactor libraries with Telescope
- AST Viewer - Inspect abstract syntax tree
- Real-time Validation - Auto-validate on save with quickfix integration
For users who only want syntax highlighting. No dependencies required β the parser and queries are downloaded automatically on first open of a .lf file (requires curl):
-- lazy.nvim
{
"remifan/lf.nvim",
ft = "lf",
config = function()
require("lf").setup({
enable_lsp = false, -- Disable LSP features
syntax = {
auto_detect_target = true,
indent = { size = 4, use_tabs = false },
},
})
end,
}For the complete experience with LSP, diagrams, and all features (Mac/Linux):
-- lazy.nvim
{
"remifan/lf.nvim",
ft = "lf",
dependencies = {
"nvim-telescope/telescope.nvim", -- Optional: enhanced library browser
},
-- Note: Diagram dependencies build automatically on first use
-- No need to specify build command!
config = function()
require("lf").setup({
enable_lsp = true,
-- Syntax highlighting
syntax = {
auto_detect_target = true,
target_language = nil, -- or "C", "Cpp", "Python", "Rust", "TypeScript"
indent = { size = 4, use_tabs = false },
},
-- LSP configuration
lsp = {
-- Auto-detected if nil. Priority order:
-- 1. Environment variable: LF_LSP_JAR
-- 2. Explicit jar_path config below
-- 3. Common locations (~/lingua-franca/lsp/build/libs/, etc.)
jar_path = nil, -- or vim.fn.expand("~/lingua-franca/lsp/build/libs/lsp-*-all.jar")
java_cmd = "java",
java_args = { "-Xmx2G" },
auto_start = true,
},
-- Build settings
build = {
auto_validate = true,
show_progress = true,
open_quickfix = true,
},
-- Keymaps
keymaps = {
build = "<leader>lb",
run = "<leader>lr",
diagram = "<leader>ld",
library = "<leader>ll",
show_ast = "<leader>la",
},
-- Diagram settings
diagram = {
no_browser = true, -- Default: show URL without auto-opening browser (good for SSH)
-- Set to false to auto-open browser locally
auto_update = true, -- Auto-refresh diagram when switching between LF files
},
})
end,
}The tree-sitter parser is automatically installed the first time you open a .lf file (requires curl). You can also install or reinstall manually:
:LFTSInstallPre-built parser binaries are downloaded from GitHub for Linux, macOS, and Windows (x64 and ARM64). Falls back to local compilation if the download fails.
Textobjects: The parser ships textobjects.scm queries at tree-sitter-lf/queries/textobjects.scm, usable with nvim-treesitter-textobjects (@function.*, @class.*, @parameter.*, @block.*, @assignment.*, etc.).
LSP features require the Lingua Franca LSP server JAR and Java 17+.
:LFLspInstallThis downloads a pre-built JAR from the lf.nvim releases and stores it in ~/.local/share/nvim/lf-lsp/. The plugin auto-detects it on next startup.
git clone --recursive https://github.com/lf-lang/lingua-franca.git
cd lingua-franca
./gradlew :lsp:shadowJar
# JAR location: lsp/build/libs/lsp-VERSION-all.jarThe plugin finds the LSP JAR in this priority order:
1. Environment Variable
# In ~/.bashrc, ~/.zshrc, or shell config
export LF_LSP_JAR="$HOME/.local/share/nvim/lf-lsp/lsp-*-all.jar"2. Explicit Configuration
lsp = {
jar_path = vim.fn.expand("~/lingua-franca/lsp/build/libs/lsp-*-all.jar"),
}3. Auto-Detection
If neither above is set, searches common locations:
~/.local/share/nvim/lf-lsp/lsp-*-all.jar(downloaded by:LFLspInstall)~/lingua-franca/lsp/build/libs/lsp-*-all.jar./lsp/build/libs/lsp-*-all.jar(current directory)../lingua-franca/lsp/build/libs/lsp-*-all.jar(parent directory)
:checkhealth lfAvailable when LSP is enabled (Mac/Linux):
| Command | Description |
|---|---|
:LFBuild [args] |
Build current LF program |
:LFRun [args] |
Build and run current LF program |
:LFCancel |
Cancel current build |
:LFValidate |
Validate current file (no compilation) |
:LFInfo |
Show LSP server status and capabilities |
:LFStart |
Start LSP server |
:LFStop |
Stop LSP server |
:LFRestart |
Restart LSP server |
| Command | Description |
|---|---|
:LFDiagramOpen |
Open interactive KLighD diagram in browser |
:LFDiagram |
Alias for :LFDiagramOpen |
:LFDiagramClose |
Close diagram viewer |
:LFDiagramToggle |
Toggle diagram viewer on/off |
:LFDiagramBuild |
Manually build diagram dependencies |
:LFDiagramExport |
Generate and view static diagram |
:LFExportDiagram [file] [format] |
Export diagram to file (svg, png, pdf) |
| Command | Description |
|---|---|
:LFLspInstall |
Download pre-built LSP server jar from GitHub releases |
:LFLspStatus |
Show LSP server installation status |
:LFTSInstall |
Install LF tree-sitter parser and queries |
:LFTSInstall! |
Force reinstall (with bang) |
:LFTSUninstall |
Remove LF tree-sitter parser |
:LFTSStatus |
Show tree-sitter installation status |
| Command | Description |
|---|---|
:LFShowAST |
Show abstract syntax tree |
:LFExportAST [file] |
Export AST to file (default: <filename>.sexp) |
:LFLibrary |
Browse reactor library (uses Telescope if available) |
:LFTargetPosition |
Jump to target declaration |
When in a .lf buffer with LSP enabled:
<leader>lb- Build current file<leader>lr- Build and run<leader>ld- View interactive diagram<leader>ll- Browse reactor library<leader>la- Show AST
Standard LSP keybindings:
gd- Go to definitiongr- Show referencesK- Hover documentation
The diagram viewer provides an interactive browser-based view of your reactors:
- Open a
.lffile - Run
:LFDiagramOpen - First time only: Dependencies build automatically (may take a few minutes)
- Browser opens with interactive diagram at
http://localhost:8765/ - Click elements to jump to source code in Neovim
- Switch files in Neovim - diagram auto-updates (with
auto_update = true) - Zoom, pan, and explore reactor structure
Features:
- Interactive KLighD diagram rendering in browser
- Diagram β Code: Click reactor instances to jump to definition in Neovim
- Auto-refresh diagram when switching between LF files
- Code β Diagram: Sync cursor position to highlight elements in diagram
- Diagram element search/filter
Requirements: Node.js must be installed for diagram features.
Troubleshooting: If auto-build fails, run :LFDiagramBuild manually to retry.
Architecture: Uses Node.js sidecar to bridge browser β Neovim communication. The browser connects to a singleton server, and diagrams reactively update as you navigate files.
By default, diagrams show a URL without auto-opening the browser. Use SSH port forwarding:
# On your local machine
ssh -L 8765:localhost:8765 user@remote-serverWhen you run :LFDiagramOpen, Neovim displays the URL. Open it in your local browser at http://localhost:8765/
The diagram will show the current file and auto-update as you switch between files (no file parameter needed in the URL).
To auto-open browser locally (disable no-browser mode):
require("lf").setup({
diagram = {
no_browser = false, -- Auto-open browser
},
})Comprehensive help documentation:
:help lfTopics include:
- Installation and configuration
- Syntax highlighting groups
- LSP features and commands
- Diagram interaction
- Target language detection
- Troubleshooting
Contributions welcome! This plugin combines:
- Tree-sitter grammar auto-generated from the official Lingua Franca Xtext grammar via
xtext2ts - LSP server from Lingua Franca compiler
A weekly GitHub Action checks for upstream grammar changes, regenerates the tree-sitter grammar, validates against all upstream test files, and opens a PR automatically.
If you encounter:
- Missing keyword highlighting
- Incorrect syntax highlighting
- LSP connection issues
- Diagram rendering problems
Please open an issue with:
- Example
.lffile demonstrating the problem - Expected vs actual behavior
- Neovim version (
:version) - Platform (Mac/Linux/Windows)
- For LSP issues: output of
:checkhealth lfand:LspLog
# Clone the repository
git clone https://github.com/remifan/lf.nvim.git
cd lf.nvim
# Regenerate tree-sitter grammar from upstream Xtext
python -m xtext2ts \
--xtext /path/to/LinguaFranca.xtext \
--output tree-sitter-lf/grammar.js
cd tree-sitter-lf && tree-sitter generate
# Test locally (syntax only)
nvim -u NONE -c "set rtp+=." test.lf
# Install diagram dependencies (for LSP features)
cd diagram-server && npm install- Verify filetype is detected:
:set ft?should showfiletype=lf - Check tree-sitter status:
:LFTSStatus - Try reinstalling tree-sitter:
:LFTSInstall! - Check for conflicting plugins
- Verify Java is installed:
java -version(requires Java 17+) - Install or check JAR:
:LFLspInstallor:LFLspStatus - Check health:
:checkhealth lf - Manually test server:
java -jar /path/to/lsp-*-all.jar - Check Neovim LSP logs:
:LspLog
- Ensure Node.js is installed:
node --version - Install dependencies:
cd diagram-server && npm install - Check sidecar logs in
:messages
- Increase JVM heap:
java_args = {"-Xmx4G"} - Disable auto-validation:
build.auto_validate = false
- Lingua Franca: https://www.lf-lang.org/
- LF Documentation: https://www.lf-lang.org/docs/
- LF Compiler: https://github.com/lf-lang/lingua-franca
- VSCode Extension: https://github.com/lf-lang/vscode-lingua-franca
MIT License - see LICENSE file for details.
- Tree-sitter grammar generated from the official Lingua Franca Xtext grammar
- LSP server from the Lingua Franca compiler project
- Built for the Lingua Franca community
