-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #109 from skx/108-lsp
108 lsp
- Loading branch information
Showing
13 changed files
with
494 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
|
||
* [Language Server Provider](#language-server-provider) | ||
* [Our LSP Features](#our-lsp-features) | ||
* [Configuration](#configuration) | ||
* [Emacs](#configuration-emacs) | ||
* [NeoVim](#configuration-neovim) | ||
* [Screenshots](#screenshots) | ||
* [Notes](#notes) | ||
* [See Also](#see-also) | ||
|
||
|
||
# Language Server Provider | ||
|
||
Adding features like auto complete, go to definition, or documentation | ||
on hover for a programming language takes significant effort. Traditionally | ||
this work had to be repeated for each development tool, as each tool | ||
provides different APIs for implementing the same feature. | ||
|
||
A Language Server is meant to provide the language-specific smarts and | ||
communicate with development tools over a protocol that enables | ||
inter-process communication. | ||
|
||
The idea behind the Language Server Protocol (LSP) is to standardize | ||
the protocol for how such servers and development tools communicate. | ||
This way, a single Language Server can be re-used in multiple | ||
development tools, which in turn can support multiple languages with | ||
minimal effort. | ||
|
||
|
||
## Our LSP Features | ||
|
||
We only support the bare minimum LSP features: | ||
|
||
* Provide completion for the names of all standard-library functions. | ||
* Shows information on standard-library functions, on hover. | ||
|
||
|
||
|
||
|
||
# Configuration | ||
|
||
To use our LSP implementation you'll need to configure your editor, IDE, or environment appropriately. Configuration will vary depending on what you're using. | ||
|
||
Typically configuration will involve at least: | ||
|
||
* Specifying the type of files that hould use LSP (i.e. a filename suffixes). | ||
* Specifying the name/arguments to use for the LSP server. | ||
|
||
For our implementation you'll need to launch "`yal -lsp`" to startup the LSP-process. | ||
|
||
|
||
## Configuration: Emacs | ||
|
||
For GNU Emacs the following file should provide all the help you need: | ||
|
||
* [_misc/yal.el](_misc/yal.el) | ||
|
||
|
||
## Configuration: neovim | ||
|
||
Create the file `~/.config/nvim/init.lua` with contents as below: | ||
|
||
* [_misc/init.lua](_misc/init.lua) | ||
|
||
|
||
|
||
# Screenshots | ||
|
||
Here we see what completion might look like: | ||
|
||
![Completion](_misc/complete.png?raw=true "Completion") | ||
|
||
Here's our help-text being displayed on-hover: | ||
|
||
![Help](_misc/help.png?raw=true "Help") | ||
|
||
|
||
|
||
# Notes | ||
|
||
As stated above we only support hover-text, and completion, from the | ||
standard library. Supporting the users' own code is harder because that | ||
would involve evaluating it - and that might cause side-effects. | ||
|
||
It should be noted that our completion-support is very naive - it literally | ||
returns the names of __all__ available methods, and relies upon the editor | ||
to narrow down the selection - that seems to work though. | ||
|
||
|
||
|
||
# See Also | ||
|
||
* [README.md](README.md) | ||
* More details of the project. | ||
* [PRIMITIVES.md](PRIMITIVES.md) | ||
* The list of built-in functions, whether implemented in Golang or YAL. | ||
* [INTRODUCTION.md](INTRODUCTION.md) | ||
* Getting started setting variables, defining functions, etc. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
-- | ||
-- ~/.config/nvim/init.lua | ||
-- | ||
---- | ||
|
||
-- | ||
-- I used two references to build up this "solution": | ||
-- | ||
-- https://vonheikemen.github.io/devlog/tools/manage-neovim-lsp-client-without-plugins/ | ||
-- | ||
-- Then for the completion I added the "config.on_attach" section, via this comment: | ||
-- | ||
-- https://www.reddit.com/r/neovim/comments/rs47cx/tsserver_and_vimlspomnifunc/ | ||
-- | ||
-- I'm sure there are other approaches, but neovim is new to me. | ||
-- | ||
|
||
|
||
-- | ||
-- Define a helper function which will associate our LSP | ||
-- magic with the appropriate filenames. | ||
-- | ||
local launch_yal_server = function() | ||
local autocmd | ||
local filetypes = { | ||
'lisp', | ||
'yal', | ||
'*.lisp', | ||
'*.yal', | ||
} | ||
|
||
local config = { | ||
cmd = {'yal', '-lsp'}, | ||
name = 'yal', | ||
root_dir = vim.fn.getcwd(), | ||
capabilities = vim.lsp.protocol.make_client_capabilities(), | ||
} | ||
|
||
-- This gives completion. | ||
config.on_attach = function(client, bufnr) | ||
vim.api.nvim_buf_set_option(bufnr, 'omnifunc', 'v:lua.vim.lsp.omnifunc') | ||
end | ||
|
||
config.on_init = function(client, results) | ||
local buf_attach = function() | ||
vim.lsp.buf_attach_client(0, client.id) | ||
end | ||
|
||
autocmd = vim.api.nvim_create_autocmd('FileType', { | ||
desc = string.format('Attach LSP: %s', client.name), | ||
pattern = filetypes, | ||
callback = buf_attach | ||
}) | ||
|
||
if vim.v.vim_did_enter == 1 and | ||
vim.tbl_contains(filetypes, vim.bo.filetype) | ||
then | ||
buf_attach() | ||
end | ||
end | ||
|
||
config.on_exit = vim.schedule_wrap(function(code, signal, client_id) | ||
vim.api.nvim_del_autocmd(autocmd) | ||
end) | ||
|
||
vim.lsp.start_client(config) | ||
end | ||
|
||
|
||
-- | ||
-- When an LSP attachment happens then ensure we bind | ||
-- a key for hover-information | ||
-- | ||
vim.api.nvim_create_autocmd('LspAttach', { | ||
desc = 'LSP actions', | ||
callback = function() | ||
local bufmap = function(mode, lhs, rhs) | ||
local opts = {buffer = true} | ||
vim.keymap.set(mode, lhs, rhs, opts) | ||
end | ||
|
||
-- Displays hover information about the symbol | ||
-- under the cursor when you press "K". | ||
bufmap('n', 'K', '<cmd>lua vim.lsp.buf.hover()<cr>') | ||
|
||
end }) | ||
|
||
|
||
-- | ||
-- Invoke our helper function to start the server. | ||
-- | ||
-- NOTE: This runs every time you launch neovim, even if you're not opening | ||
-- a yal/lisp file. | ||
-- | ||
launch_yal_server() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
;;; yal.el -- Sample configuration for using Emacs LSP-mode with YAL | ||
|
||
|
||
;; Create a keyboard-map for use within YAL files | ||
(defvar yal-mode-map | ||
(let ((map (make-sparse-keymap))) | ||
(define-key map (kbd "C-c TAB") 'completion-at-point) | ||
map)) | ||
|
||
;; Define a hook which will run when entering YAL mode. | ||
(add-hook 'yal-mode-hook 'lsp-deferred) | ||
|
||
;; Now create a trivial "yal-mode" | ||
(define-derived-mode yal-mode | ||
lisp-mode "YAL" | ||
"Major mode for working with yet another lisp, YAL.") | ||
|
||
;; yal-mode will be invoked for *.yal files | ||
(add-to-list 'auto-mode-alist '("\\.yal\\'" . yal-mode)) | ||
|
||
;; Load the library | ||
(require 'lsp-mode) | ||
|
||
;; Register an LSP helper | ||
(lsp-register-client | ||
(make-lsp-client :new-connection (lsp-stdio-connection '("yal" "-lsp")) | ||
:major-modes '(yal-mode) | ||
:priority -1 | ||
:server-id 'yal-ls)) | ||
|
||
;; Not sure what this does, but it seems to be necessary | ||
(add-to-list 'lsp-language-id-configuration '(yal-mode . "yal")) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,28 @@ | ||
module github.com/skx/yal | ||
|
||
go 1.18 | ||
|
||
require ( | ||
github.com/tliron/glsp v0.1.1 | ||
github.com/tliron/kutil v0.1.63 | ||
go.lsp.dev/uri v0.3.0 | ||
) | ||
|
||
require ( | ||
github.com/gorilla/websocket v1.5.0 // indirect | ||
github.com/iancoleman/strcase v0.2.0 // indirect | ||
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect | ||
github.com/mattn/go-isatty v0.0.14 // indirect | ||
github.com/mattn/go-runewidth v0.0.13 // indirect | ||
github.com/muesli/termenv v0.12.0 // indirect | ||
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect | ||
github.com/pkg/errors v0.9.1 // indirect | ||
github.com/rivo/uniseg v0.2.0 // indirect | ||
github.com/sasha-s/go-deadlock v0.3.1 // indirect | ||
github.com/sourcegraph/jsonrpc2 v0.1.0 // indirect | ||
github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect | ||
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect | ||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect | ||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 // indirect | ||
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035 // indirect | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= | ||
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= | ||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= | ||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= | ||
github.com/iancoleman/strcase v0.2.0 h1:05I4QRnGpI0m37iZQRuskXh+w77mr6Z41lwQzuHLwW0= | ||
github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= | ||
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= | ||
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= | ||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= | ||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= | ||
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= | ||
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= | ||
github.com/muesli/termenv v0.12.0 h1:KuQRUE3PgxRFWhq4gHvZtPSLCGDqM5q/cYr1pZ39ytc= | ||
github.com/muesli/termenv v0.12.0/go.mod h1:WCCv32tusQ/EEZ5S8oUIIrC/nIuBcxCVqlN4Xfkv+7A= | ||
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 h1:q2e307iGHPdTGp0hoxKjt1H5pDo6utceo3dQVK3I5XQ= | ||
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= | ||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= | ||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | ||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= | ||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= | ||
github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71efZx0= | ||
github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= | ||
github.com/sourcegraph/jsonrpc2 v0.1.0 h1:ohJHjZ+PcaLxDUjqk2NC3tIGsVa5bXThe1ZheSXOjuk= | ||
github.com/sourcegraph/jsonrpc2 v0.1.0/go.mod h1:ZafdZgk/axhT1cvZAPOhw+95nz2I/Ra5qMlU4gTRwIo= | ||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | ||
github.com/tliron/glsp v0.1.1 h1:GNNgUX9p1Q9MoPQooJoZ0+WaLL03EkhcKZUYJAtiNqs= | ||
github.com/tliron/glsp v0.1.1/go.mod h1:RVyVKeY3U+Nlc3DRklUiaegNsQyjzNTEool6YWh1v7g= | ||
github.com/tliron/kutil v0.1.63 h1:/xOqEShxPymwhcVcPFAks8zj43HU+NljbmzYjNXIO+Y= | ||
github.com/tliron/kutil v0.1.63/go.mod h1:Mo1pAtg/9yG3ClnUv32Hrl+t0BFFCg49RpCjHG3sY7c= | ||
github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU= | ||
github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= | ||
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= | ||
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= | ||
go.lsp.dev/uri v0.3.0 h1:KcZJmh6nFIBeJzTugn5JTU6OOyG0lDOo3R9KwTxTYbo= | ||
go.lsp.dev/uri v0.3.0/go.mod h1:P5sbO1IQR+qySTWOCnhnK7phBx+W3zbLqSMDJNTw88I= | ||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c= | ||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= | ||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg= | ||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035 h1:Q5284mrmYTpACcm+eAKjKJH48BBwSyfJqmmGDTtT8Vc= | ||
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= | ||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
Oops, something went wrong.