Skip to content

dcermak/rpm-spec-language-server

Repository files navigation

RPM Spec File Language Server

CI Status VSCode CI Status Code Coverage Chat on - Matrix

This is a proof of concept implementation of a server implementing the Language Server Protocol for RPM Spec files.

Please share your feature requests with us by opening an issue, creating a discussion or chat with us on matrix in #rpm-spec-language-server:matrix.org.

Supported LSP endpoints

  • autocompletion of macro names, spec sections and preamble keywords
  • jump to macro definition
  • expand macros on hover
  • breadcrumbs/document sections

Requirements

Running the server

  • Install the dependencies via poetry install
  • Launch the server in tcp mode (binds to `127.0.0.1:2087 by default) via poetry run rpm_lsp_server

Alternatively, you can build the python package, install the wheel and run the module directly:

poetry build
pip install --user dist/rpm_spec_language_server-*.whl
python -m rpm_spec_language_server

The server requires the spec.md file. It can either use the locally installed copy from the rpm package or (if the documentation has not been installed) from a locally cached version in ~/.cache/rpm/spec.md. The language server will fetch the spec.md from the upstream github repository if neither of the previous options.

Container Mode

The rpm-spec-language-server is a server that supports an experimental container mode. In this mode, the server is launched inside a container with the package directory mounted into the running container. This allows you to have access to a different distribution than your current one.

The container mode can currently handle only one package open. The RPM spec file must be in the top-level directory. Additionally, the server must communicate via TCP. This means that you might have to reconfigure your lsp-client, if it assumes to communicate via stdio.

To enable the container mode with Podman, proceed as follows:

$ cd ~/path/to/my/package
$ # ensure that the spec file is in the current working directory!
$ podman container runlabel run \
      ghcr.io/dcermak/rpm-spec-lang-server:$distri

where you replace $distri with one of tumbleweed, leap-15.5, leap-15.6, fedora or centos.

To use Docker, get the exact launch command as shown below:

$ docker inspect -f '{{index .Config.Labels "run"}}' \
      ghcr.io/dcermak/rpm-spec-lang-server:$distri | \
      sed -e 's/podman/docker/' -e 's|$IMAGE|ghcr.io/dcermak/rpm-spec-lang-server:$distri|'

In the example above, replace $distri with the desired distribution.

Supported distributions/tags

  • fedora: based on fedora:latest
  • tumbleweed: based on tumbleweed:latest
  • centos: based on centos:stream9
  • leap-15.5: based on leap:15.5
  • leap-15.6: based on leap:15.6

Clients

VSCode

A very simple VSCode client is available in clients/vscode/. Building requires nodejs and the npm package manager:

$ npm install
$ npm run package

Install the created rpm-spec-language-server-$VERSION.vsix and launch the language server in tcp mode.

vis with vis-lspci

Add to your ~/.config/vis/visrc.lua this code:

lsp = require('plugins/vis-lspc')
lsp.ls_map['rpmspec'] = {
    name = 'RPMSpec',
    cmd = 'python3 -mrpm_spec_language_server --stdio'
}

Neovim with built-in LSP client

local lspconfig = require("lspconfig")
local util = require("lspconfig.util")
local configs = require("lspconfig.configs")
configs.rpmspec = {
    default_config = {
      cmd = { 'python3', '-mrpm_spec_language_server', '--stdio' },
      filetypes = { 'spec' },
      single_file_support = true,
      root_dir = util.find_git_ancestor,
      settings = {},
    },
    docs = {
      description = [[
  https://github.com/dcermak/rpm-spec-language-server

  Language server protocol (LSP) support for RPM Spec files.
  ]],
    },
}

lspconfig["rpmspec"].setup({})

Neovim with coc.nvim plugin

Warning

coc.nvim is licensed under the non-free "activist" Anti 996 License

Open nvim, run :CocConfig, and merge the following JSON into your configuration

{
    "languageserver": {
        "spec": {
            "command": "rpm_lsp_server",
            "args": ["--stdio"],
            "filetypes": ["spec"]
        }
    }
}

Emacs with lsp-mode.el

lsp-mode has builtin support for the rpm-spec-language-server. All you have to do is to require 'lsp-rpm-spec and launching lsp-mode. With use-package, this can be implemented as follows utilizing rpm-spec-mode:

(use-package lsp-mode
  :ensure t
  :commands (lsp lsp-deferred)
  :hook ((rpm-spec-mode . lsp-deferred)))

(use-package rpm-spec-mode
  :ensure t
  :mode "\\.spec'"
  :config (require 'lsp-rpm-spec))

Emacs with eglot.el

eglot is the builtin LSP Client for Emacs. Support for the rpm-spec-language-server can be added by evaluating the following snippet (e.g. in your init.el or directly in the scratch buffer):

(require 'eglot)
(add-to-list 'eglot-server-programs
               '(rpm-spec-mode . ("localhost" 2087)))

Then start the language server in tcp mode and invoke eglot via M-x eglot.