A Go-based Language Server for QML (Qt Meta-Object Language) that provides intelligent code editing features.
- Pure-Go Parser - Powered by gotreesitter with an embedded tree-sitter-qmljs grammar; no CGO, no external tree-sitter install
- Incremental Parsing - Reparses only the affected regions on each
didChange - Workspace Indexing - Scans the project on startup to resolve cross-file symbols, imports, and IDs
- Qt Module Discovery - Parses
.qmltypesandqmldirfiles from your Qt installation to provide completions, hover, and signatures for the full Qt API — not just a hard-coded subset
- Hover - Type documentation, property info, and signal/method details with fallbacks through the workspace index
- Completions - Context-aware completions for:
- QML types — all types from installed Qt modules (QtQuick, QtQml, QtQuick.Controls, QtQuick.Layouts, QtMultimedia, Qt3D, and more)
- Imports (
import QtQuick) - Properties — generic (
width,height,color,anchors) and type-specific (Window.title,Text.wrapMode,Image.fillMode); includes inheritance - Type-aware member completion on ids —
root.whereid: rootis aRectangleoffers Rectangle + Item properties, not the generic list - Signal handlers (
onClicked,onPressed, etc.) - Methods and enums from Qt type info
- Values (
true,false, colors,parent,this) - Anchor completions (
fill,centerIn,top,bottom, etc.) - Quickshell types, imports, singletons, and boilerplate snippets
- Workspace components (user-defined
.qmlfiles)
- Go to Definition - Jumps to ids in the current file, cross-file to workspace components (e.g.
MyButton→MyButton.qml), and to the originatingimportline for built-in types - Document Links -
importstatements are clickable — named modules jump to theqmldirdiscovered at startup; relativeimport "./components"jumps to the target directory'sqmldir - Find References - Find all uses of an identifier
- Diagnostics - Parse error highlighting from tree-sitter
- Document Symbols - File outline with hierarchical structure (properties, bindings, nested objects)
- Workspace Symbol Search - Find QML components across the workspace by name
- Semantic Tokens - Tree-sitter-driven semantic highlighting for imports, types, properties, signal handlers, keywords, strings, numbers, and comments
- Document Formatting - Re-indent based on brace depth, trim trailing whitespace, collapse blank lines, ensure final newline; honours
tabSizeandinsertSpaces - Code Actions - Quick fixes
- Rename - Rename identifiers across a document
- Signature Help - Function parameter hints for
Qt.rect(),Qt.rgba(),console.log(),String(),parseInt(), and more - Inlay Hints - Parameter name hints on function call arguments
# Prebuilt binary (recommended)
yay -S qml-language-server-bin
# Or build from latest main
yay -S qml-language-server-git# Run directly
nix run github:cushycush/qml-language-server
# Or add to your flake inputs
inputs.qml-language-server.url = "github:cushycush/qml-language-server";Download the latest release for your platform from the Releases page.
Requires Go 1.26.1+.
git clone https://github.com/cushycush/qml-language-server.git
cd qml-language-server
make buildmake install will build the binary and copy it to ~/.local/bin.
- Install the "Local LSP" extension or create a custom extension
- Add to your settings.json:
{
"languageServers": {
"qml": {
"command": "qml-language-server",
"filetypes": ["qml"]
}
}
}For Neovim 0.11+, use the built-in LSP configuration:
vim.lsp.config("qml-language-server", {
cmd = { "qml-language-server" },
filetypes = { "qml" },
root_markers = { { "qmldir", "shell.qml" }, ".git" },
})
vim.lsp.enable("qml-language-server")Note:
shell.qmlis specific to Quickshell and can be omitted if you are only concerned with QML development only.
For Neovim 0.10 and earlier, use lspconfig:
local lspconfig = require('lspconfig')
lspconfig.qmlls.setup {
cmd = { "qml-language-server" },
filetypes = { "qml" },
root_dir = function(fname)
return lspconfig.util.find_git_roots(fname) or lspconfig.util.find_root({ '*.qml' }, fname)
end,
}For a modern completion experience with fuzzy matching and snippets, use blink.cmp:
{
'saghen/blink.cmp',
opts = {
sources = {
default = { 'lsp' },
},
completion = {
documentation = {
auto_show = true,
},
},
},
}make test # run tests with race detector
make lint # golangci-lint
make coverage # generate coverage report
make build # compile binary- go-lsp - LSP protocol implementation
- gotreesitter - Pure-Go tree-sitter runtime
MIT License - See LICENSE file for details
Contributions welcome! Please open an issue or submit a pull request.
- gotreesitter - Pure-Go tree-sitter runtime
- tree-sitter-qmljs - QML grammar for tree-sitter
- go-lsp - Go LSP library