An LSP server for Scheme.
Find a file
2024-12-03 01:28:27 +01:00
chicken gracefully handle out of range position; bump version (0.4.7) 2024-11-16 12:32:44 +01:00
gambit add missing call to main 2023-06-06 19:16:10 +02:00
geiser update geiser/guile 2024-12-03 01:28:27 +01:00
guile gracefully handle out of range position; bump version (0.4.7) 2024-11-16 12:32:44 +01:00
lsp-server/private dont fallback to load; fix formatting 2024-11-19 20:12:00 +01:00
tests remove non-used srfi-130 dependency 2024-09-29 21:06:22 +02:00
.gitignore change .gitignore 2023-11-23 21:44:11 +01:00
.gitmodules switch to json-rpc high-level API; some refactoring 2021-04-16 18:25:35 +02:00
_setup_.scm fix refactoring problem for gambit 2023-04-26 22:22:40 +02:00
config.el fix clean call 2023-06-03 00:17:44 +02:00
guix.scm guix.scm: fix git show layout 2023-11-05 18:35:07 +01:00
irregex.scm get fetch-signature working for gambit 2022-08-15 18:11:55 +02:00
LICENSE Initial commit 2021-04-14 22:15:06 +02:00
lsp-server-impl.scm remove parameters from shutdown/exit handlers 2024-11-19 19:50:21 +01:00
lsp-server.egg gracefully handle out of range position; bump version (0.4.7) 2024-11-16 12:32:44 +01:00
lsp-server.sld fix out-of-array bug when dealing with utf8 documents 2023-12-22 21:33:07 +01:00
main.scm fix out-of-array bug when dealing with utf8 documents 2023-12-22 21:33:07 +01:00
pre-inst-env.in comment-out debugging code 2022-01-08 18:19:32 +01:00
README.md README.md aktualisiert 2023-11-05 20:13:35 +00:00
VERSION Autotools for Guile; refactor for guile 2021-05-05 21:21:43 +02:00

scheme-lsp-server

Table of contents

  1. Introduction
  2. Installing
  3. API
  4. Command-line tool
  5. Supported features
  6. Notes to specific implementations
  7. Known issues
  8. Existing clients
  9. Contributing

Introduction

** EXPERIMENTAL **

An LSP (Language Server Protocol) server for Scheme.

This software aims to support several Scheme implementations. To achieve this, the code is designed to contain as much logic as possible in R7RS Scheme, separating implementation-specific code in different directories.

Note: this code is still in an early development stage and the API may change. Change suggestions are welcome.

Supported implementations

Currently CHICKEN 5, Gambit 4.9.4+ and Guile 3+ are supported. See Supported features, Notes to specific implementations and Known issues for more information.

Installing

First a remark. Some LSP clients (like lsp-scheme and vscode-scheme-lsp) will install an LSP server automatically. If you prefer to install it manually, please follow the instructions below.

CHICKEN

First install some dependencies, including chicken-doc's documentation:

$ chicken-install -s apropos chicken-doc srfi-18
$ cd `csi -R chicken.platform -p '(chicken-home)'`
$ curl http://3e8.org/pub/chicken-doc/chicken-doc-repo.tgz | sudo tar zx

Then install the LSP server with

chicken-install lsp-server

Gambit

Note that you need Gambit 4.9.4 or later in order to use this lib. You can install the library and its dependencies by running

$ gsi -install \
      codeberg.org/rgherdt/srfi \
      github.com/ashinn/irregex \
      github.com/rgherdt/chibi-scheme \
      codeberg.org/rgherdt/scheme-json-rpc/json-rpc \
      codeberg.org/rgherdt/scheme-lsp-server/lsp-server

You can now import the library using its fully qualified name

> (import (codeberg.org/rgherdt/scheme-lsp-server lsp-server))

Instead of installing it, you can also call it by invoking gsi with -:whitelist

$ gsi -:whitelist=codeberg.org/rgherdt/scheme-lsp-server
> (import (codeberg.org/rgherdt/scheme-lsp-server lsp-server))

The command-line tool is available as a script gambit/gambit-lsp-server.scm, which you can put in your PATH. Alternatively, you can compile it for better performance (see next).

Improving performance through compilation

You may notice that gambit-lsp-server takes some seconds to start. This can be annoying, since some LSP clients fire up the client for each .scm file or project. You can improve performance by compiling the library. For this you need to compile Gambit using it's current master branch, since the 4.9.4 release contains bugs regarding some R7RS forms. You can compile the library and the executable by running the script gambit/compile.sh

$ cd ~/.gambit_userlib/codeberg.org/rgherdt/scheme-lsp-server/@/gambit
$ ./compile.sh

Guile

Installation with Guix

The recommended way is to install this library using Guix. Unfortunately it is still not available at the official Guix channels, but you can use the provided channel guix.scm:

guix package -f guix.scm

The executable should now be available at ${HOME}/.guix-profile/bin/guile-lsp-server.

If you get an error that some module couldn't be opened, check if Guix-installed modules are on your Guile's load path. This can be achieved by setting the corresponding environment variables, for example:

export GUILE_LOAD_PATH=...:${HOME}/.guix-profile/share/guile/site/3.0:$GUILE_LOAD_PATH
export GUILE_LOAD_COMPILED_PATH=...:${HOME}/.guix-profile/lib/guile/3.0/site-ccache:$GUILE_LOAD_COMPILED_PATH

Manual installation

Guile's version of the LSP server is packaged using automake. Make sure Guile 3 AND its development libraries are installed. On Debian you can install it using:

# apt install guile-3.0 guile-3.0-dev

guile-lsp-server has following dependencies:

  • srfi-145
  • srfi-180
  • guile-irregex

You may use following script to install them automatically.

./guile/scripts/install-deps.sh --prefix=<PREFIX>

Finally, switch to the ./guile folder and run:

./configure && make && sudo make install

Note: Make sure the PREFIX (installation directory) is in your %load-path and %load-compiled-path. For example, under Linux, add the following to your ./bashrc file

export GUILE_LOAD_COMPILED_PATH=...:/usr/local/lib/guile/3.0/site-ccache
export GUILE_LOAD_PATH=...:/usr/local/share/guile/site/3.0

Let your LSP client install it

Currently both emacs-lsp and vscode-scheme-lsp will try to install the LSP server in a local directory if none is found.

API

[parameter] (lsp-server-log-level)

A symbol to control the server's verbosity. It can be either 'error, 'warning, 'info or 'debug.

[procedure] (lsp-server-start/stdio)

Start an LSP server listening on stdio.

[procedure] (lsp-server-start/tcp tcp-port-number)

Start an LSP server listening on tcp-port-number.

Command-line tool

This programs also comes with command line tools to start the server. They are called chicken-lsp-server, guile-lsp-server etc. All of them provide the same interface. Run guile-lsp-server --help for more information.

Supported features

  CHICKEN Gambit Guile
Find signature X X X
Find documentation X X
Autocomplete identifier X X X
Jump to definition X X X
Diagnostics X X X

Notes to specific implementations

CHICKEN

The implementation for "jump to definition" is for now quite limited. I wrote a ctags-inspired code for CHICKEN that scans the project files for definitions. Additionally, the user can set the environment variable CHICKEN_SOURCE_PATH to a directory containing the installer's source, so that the server can provide information to internally defined functions.

In the future we can refine this solution to be more "project-aware". Ideas are welcome.

GUILE

Most of the current implementation relies on Geiser. We include the corresponding Scheme files in our repository (git submodules was discarded to simplify packaging and automatic installation from LSP clients).

Known issues

Diagnostics show too many errors/warnings

Currently diagnostics are computed by calling the implementation compiler. When code is split in a library definition and an implementation file, we have a problem that the LSP server is not able to provide correct information when opening only the implementation file. I still didn't find an elegant way to solve this. An workaround is that while opening a file, the LSP server tries to find different files with the same base name but different extension (.sld, .ss, .scm). If one of them contains a library definition, that file is compiled instead, providing the correct information.

Existing clients

VSCodium: https://codeberg.org/rgherdt/vscode-scheme-lsp

Emacs lsp-mode: https://codeberg.org/rgherdt/emacs-lsp-scheme

Emacs Eglot: https://github.com/joaotavora/eglot

Add the following to your .emacs configuration:

(require 'eglot)
(add-to-list 'eglot-server-programs
             `(scheme-mode . ("guile-lsp-server")))
(add-hook 'scheme-mode-hook 'eglot-ensure)

Replace "guile-lsp-server" by your chosen scheme implementation.

Contributing

Creating an LSP client

scheme-lsp-server supports two modes. It can either operate by listening on stdio (using lsp-server-start/stdio) or TCP (using lsp-server-start/tcp). A command-line tool is available that you can call from your client. Here an example call (analogous to chicken-lsp-server):

guile-lsp-server --tcp 4242

Leaving out the --tcp flag starts the server in stdio mode. More information can be obtained with the guile-lsp-server --help command as usual.

If you create an LSP client using this server, please let me know so we can keep this list up-to-date.

Ideas on extending support to other Schemes

Here are some ideas on how to add support to other Scheme implementation without increasing much code complexity:

decide which build system to use.

Currently we use two build systems: chicken-install with its egg definitions, and autotools for Guile. Ideally we should come up with a solution that can be used across all supported implementations. Possible candidates are Snow or Akku. Alternatively we could consider extending the existing autotools based scripts.

Note that this may be irrelevant in some cases. Gambit, for instance, now supports loading libraries directly from git repositories.

create needed portable libraries

This library relies on non-standardized features, like TCP support and JSON (indirectly through scheme-json-rpc (https://codeberg.org/rgherdt/scheme-json-rpc/). It would be extremely helpful if those bits are solved by separate libraries or SRFIs. Guile's version for JSON-RPC already uses SRFI 180, that can solve the JSON problem.

contribute to Geiser

Since scheme-lsp-server uses Geiser, we can get better LSP support by help improving it.