• Stars
    star
    157
  • Rank 238,399 (Top 5 %)
  • Language
    Scheme
  • License
    Other
  • Created over 2 years ago
  • Updated about 1 month ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Scheme language server

Scheme-langserver

NOTE: There're many many bugs in scheme-langserver, and parts of them may be lead from the high-level functions like identifier catching in incomplete code and type inference. I'm just fixing and appealing help from the community. Please be patient.

NOTE: you can find the auto generated type information here. It's now mainly used for next-stage-development (maybe include AKKU) and debugging.

Implementing support like autocomplete, goto definition, or documentation on hover is a significant effort for programming. However, comparing to other language like java, python, javascript and c, language server protocol implementation for lisp language are just made in a vacuum. Geiser, racket langserver and swish-lint etc., their works are all based on repl(Read-Eval-Print Loop) or keyword tokenizer instead of programming. For example, if a programmer was coding on an unaccomplished project, in which the codes were not fully runnable, Geiser or any others would only complete top-level binding identifiers listed by environment-symbols procedure (for Chez). Which means for local bindings and unaccomplished codes, though making effort for programming is supposed of the importance mostly, Geiser and its counterparts help nothing. Familiar cases occur with goto definition and many other functionalities.

A primary cause is, for scheme and other lisp dialects, their abundant data sets and flexible control structures raise program analysis a big challenge. Especially the dynamic type system and macro, it seems like that scheme is mainly used for genius and meta/macro programming. But I say no. Scheme can make many interesting things if a better programming environment is provided. And now I'll work on this.

This package is a language server protocol implementation helping scheme programming. It provides completion, definition and type inference. These functionalities are established on static code analysis with r6rs standard and some obvious rules for unaccomplished codes. This package itself and related libraries are published or going to be published with Akku, which is a package manager for Scheme.

This package also has been tested with Chez Scheme versions 9.4 and 9.5. A detailed test on version 10.0.0 will be done after upgrading my laptop with nixOS.

I do this open source work just in my spare time and I can contribute many splendid ideas to the community like embedding data flow analysis into scheme-langserver or many other things. And I'm continuously asking for much more donation or funding. You can click this patreon page or 爱发电 to donate monthly, or just donate 10 USD just once time with the following paypal link.

paypal

Recent Status

I'll keep fixing bugs, profiling the code, and collecting information for my giant book on homemade type inference system. This will take me about 1 or 2 years. Further developments including a VScode plugin and data flow analysis. But actually, I'm now setting this open source work a part-time job, and I can not guarantee a schedule.

I'm now visiting Coimbra University, would anyone visit me?

Release

1.1.1: Scheme-langserver now releases type information used in corresponding libraries! Its soundness is still not guaranteed! A detailed outline should be referred in documentation.

Previous releases please refer to this file.

Setup

Building

Pre-require

  1. Chez Scheme;

NOTE Scheme-langserver's muti-threaded feature requires Chez Scheme to have been compiled with the --threads option. For Chez Scheme version after 10.0.0, there're some differents now.

  1. Akku
  2. chez-exe

NOTE chez-exe requires boot files and kernel files of Chez Scheme. So, the compile command maybe like follows:scheme --script gen-config.ss --bootpath /path-to-ChezScheme/{machine-type}/boot/{machine-type}

For Linux

git clone https://github.com/ufo5260987423/scheme-langserver
cd scheme-langserver
akku install
bash .akku/env
compile-chez-program run.ss
./run path-to-logfile

TODO: for Windows

The run file is also executable in Windows WSL environment.

As for native on Windows, scheme-langserver requires AKKU to be native on Windows first now. An essential barrier is the srfi, whose library path can't be handled in Windows7. Further discussion is on tihs page.

Installation for LunarVim(1.3)

I have pull request to mason.nvim and mason-lspconfig.nvim. In that case, you can get this implementation automatically with LunarVim.

But now, above configuration haven't been tested. So, manual installation is still needed: for installed plugin nvim-lspconfig, after manually building from above step Building, an executable file run would be available at {path-to-run}. Then, create file ~/.local/share/lunarvim/site/pack/lazy/opt/nvim-lspconfig/lua/lspconfig/server_configurations/scheme_langserver.lua as follows:

local util = require 'lspconfig.util'
local bin_name = '{path-to-run}'
local cmd = { bin_name }

return {
  default_config = {
    cmd = cmd,
    filetypes = { 'scheme' },
    root_dir = util.find_git_ancestor,
    single_file_support = true,
  },
  docs = {
    description = [[
https://github.com/ufo5260987423/scheme-langserver
`scheme-langserver`, a language server protocol implementation for scheme
]]   ,
  },
}

Then configure your ~/.config/lvim/config.lua and add following codes like:

vim.cmd [[ au BufRead,BufNewFile *.sld set filetype=scheme ]]
vim.cmd [[ au BufRead,BufNewFile *.sls set filetype=scheme ]]

vim.api.nvim_create_autocmd('LspAttach', {
  group = vim.api.nvim_create_augroup('UserLspConfig', {}),
  callback = function(ev)
    -- Enable completion triggered by <c-x><c-o>
    vim.bo[ev.buf].omnifunc = 'v:lua.vim.lsp.omnifunc'

    -- Buffer local mappings.
    -- See `:help vim.lsp.*` for documentation on any of the below functions
    local opts = { buffer = ev.buf }
    vim.keymap.set('n', 'gD', vim.lsp.buf.declaration, opts)
    vim.keymap.set('n', 'gd', vim.lsp.buf.definition, opts)
    vim.keymap.set('n', 'K', vim.lsp.buf.hover, opts)
    vim.keymap.set('n', 'gr', vim.lsp.buf.references, opts)
  end,
})

-- local capabilities = vim.lsp.protocol.make_client_capabilities()
-- capabilities = require("cmp_nvim_lsp").default_capabilities(capabilities)
local lspconfig = require('lspconfig')
lspconfig.scheme_langserver.setup {}
lvim.builtin.cmp.enabled()
lvim.builtin.cmp.sources = {
  { name = 'nvim_lsp' },
  { name = 'luasnip' },
  { name = 'buffer' },
}

NOTE: detailed configuration for lvim.builtin.cmp.sources and LspAttach can refer this page and this page.

Enable multi-thread, ss/scm-import-rnrs or type-inference

Scheme-langserver has facilitated many higher level functions, but they shouldn't be fully convinced and tested. If you want to have a try, just step above instructions and rewrite file ~/.local/share/lunarvim/site/pack/lazy/opt/nvim-lspconfig/lua/lspconfig/server_configurations/scheme_langserver.lua as follows:

local util = require 'lspconfig.util'
local bin_name = '{path-to-run}'

--the first 'enable' is for multi-thread mechanism. 
local cmd = { bin_name ,'{path-to-log}','enable'}
--the second 'enable' is for for extensions SS, and SCM. Most programmers suppose their codes are writing for a running environment and don't provide any library information. However, some issues request for adding basic default context, so advanced language features could be used.
-- local cmd = { bin_name ,'{path-to-log}','disable', 'enable'}
-- the third 'enable' is for type inference.
-- local cmd = { bin_name ,'{path-to-log}','disable', 'disable' ,'enable'}

return {
  default_config = {
    cmd = cmd,
    filetypes = { 'scheme' },
    root_dir = util.find_git_ancestor,
    single_file_support = true,
  },
  docs = {
    description = [[
https://github.com/ufo5260987423/scheme-langserver
`scheme-langserver`, a language server protocol implementation for scheme
]]   ,
  },
}

NOTE: the type inference is in its very early stage. Even for small code file it may take much more time than your expectation.

TODO: Installation for VScode

Features

  1. Top-level and local identifiers binding completion. Top-level and local identifiers binding
  2. Goto definition. Goto definition with telescope.nvim
  3. Compatible with package manager: Akku.
  4. File changes synchronizing and corresponding index changing.
  5. Hover.
  6. References and document highlight (document-scoped references). Find references with telescope.nvim
  7. Document symbol. Find document symbols with telescope.nvim
  8. Catching *-syntax(define-syntax, let-syntax, etc.) based local identifier binding.
  9. Cross-platform parallel indexing.
  10. Self-made source code annotator to be compatible with .sps files.
  11. Peephole optimization for API requests.
  12. Type inference with a homemade DSL interpreter(I'm very proud of it!). And now it has been embedded into the auto-completion. As the following figure indicated, the "length-b" and "length-a" having "integer?" type are in the front of those recommended options because they can match the parameter type requiring from "<=". Autocompletion with type inference A test in can prove this result, just run scheme --script tests/protocol/apis/test-completion.sps and the log file scheme-langserver.log would contain results like this:
send-message
2023 11 21 11 26 41 967266866
{"jsonrpc":"2.0","id":"3","result":[{"label":"length-a"},{"label":"length-b"},{"label":"lambda"},{"label":"latin-1-codec"},{"label":"lcm"},{"label":"least-fixnum"},{"label":"length"},{"label":"let"},{"label":"let*"},{"label":"let*-values"},{"label":"let-syntax"},{"label":"let-values"},{"label":"letrec"},{"label":"letrec*"},{"label":"letrec-syntax"},{"label":"lexical-violation?"},{"label":"list"},{"label":"list->string"},{"label":"list->vector"},{"label":"list-ref"},{"label":"list-sort"},{"label":"list-tail"},{"label":"list?"},{"label":"log"},{"label":"lookahead-char"},{"label":"lookahead-u8"}]}
  1. Virtual identifier catching machine for .sps, .ss, .scm files.

TODOs

  1. Renaming.
  2. Fully compatible with r6rs standard.
  3. Macro expanding.
  4. Code eval.
  5. Code diagnostic.
  6. Add cross-language semantic supporting. Well, would java, c, python and many other languages can be supported with an AST transformer?
  7. Extract expression/statements into a procedure()

TODO:Contributing

Debug

How to Debug

https://www.scheme.com/debug/debug.html#g1

Output Log

Following tips from Building, Installation for Lunar Vim and Installation for VScode, if anyone wants to do some developing and log something, it will be convenient to add path-to-log-file and re-write file ~/.local/share/lunarvim/site/pack/packer/start/nvim-lspconfig/lua/lspconfig/server_configurations/scheme_langserver.lua as follows:

local util = require 'lspconfig.util'
local bin_name = '{path-to-run}'
local cmd = { bin_name ,"path-to-log-file"}

return {
  default_config = {
    cmd = cmd,
    filetypes = { 'scheme' },
    root_dir = util.find_git_ancestor,
    single_file_support = true,
  },
  docs = {
    description = [[
https://github.com/ufo5260987423/scheme-langserver
`scheme-langserver`, a language server protocol implementation for scheme
]]   ,
  },
}

Recurring with Log

With above output log, you may use tests/log-debug.sps recurring bugs:

  1. Rename {path-to-log}(usually ~/scheme-langserver.log) as ~/ready-for-analyse.log;
  2. run scheme --script tests/log-debug.sps. If you want to re-produce the multi-thread environment, it would also be available to run scheme --script tests/log-debug.sps.

Test

Almost all key procedures and APIs are tested. My work is just so rough but useful, maybe you would like to find what I've done in tests directory or just run following command in {scheme-langserver-root-directory}

bash test.sh

NOTE It's hard to do test with threaded environment. So, current tests focus on single thread.

Code Count

find . -name "*.sls" ! -path "./.akku/*" |xargs wc -l

Detailed Document

  1. Catching identifier bindings
  2. Synchronizing
  3. Type inference,类型推断(Deprecated, and I'm writing a Chinese book for it)
  4. API Analysis

Star History

Star History Chart

Contributors

Contributors