Skip to content

Repository files navigation

QML Language Server

A Go-based Language Server for QML (Qt Meta-Object Language) that provides intelligent code editing features.

Features

Core Language 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 .qmltypes and qmldir files from your Qt installation to provide completions, hover, and signatures for the full Qt API — not just a hard-coded subset

LSP Features

  • 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. where id: root is a Rectangle offers 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 .qml files)
  • Go to Definition - Jumps to ids in the current file, cross-file to workspace components (e.g. MyButtonMyButton.qml), and to the originating import line for built-in types
  • Document Links - import statements are clickable — named modules jump to the qmldir discovered at startup; relative import "./components" jumps to the target directory's qmldir
  • 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 tabSize and insertSpaces
  • 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

Installation

Arch Linux (AUR)

# Prebuilt binary (recommended)
yay -S qml-language-server-bin

# Or build from latest main
yay -S qml-language-server-git

Nix

# 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";

Prebuilt Binaries

Download the latest release for your platform from the Releases page.

Build from Source

Requires Go 1.26.1+.

git clone https://github.com/cushycush/qml-language-server.git
cd qml-language-server
make build

make install will build the binary and copy it to ~/.local/bin.

Editor Configuration

VS Code

  1. Install the "Local LSP" extension or create a custom extension
  2. Add to your settings.json:
{
  "languageServers": {
    "qml": {
      "command": "qml-language-server",
      "filetypes": ["qml"]
    }
  }
}

Neovim

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.qml is 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,
}

Neovim with blink.cmp

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,
      },
    },
  },
}

Development

make test       # run tests with race detector
make lint       # golangci-lint
make coverage   # generate coverage report
make build      # compile binary

Project Dependencies

License

MIT License - See LICENSE file for details

Contributing

Contributions welcome! Please open an issue or submit a pull request.

Acknowledgments

About

No description, website, or topics provided.

Resources

Stars

97 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages