and readded mlsp
parent
a8c20f979a
commit
b252e63580
|
|
@ -0,0 +1,223 @@
|
||||||
|
-- globals from micro: https://github.com/zyedidia/micro/blob/master/runtime/help/plugins.md
|
||||||
|
|
||||||
|
read_globals = {
|
||||||
|
"import",
|
||||||
|
}
|
||||||
|
|
||||||
|
globals = {
|
||||||
|
"VERSION",
|
||||||
|
"init",
|
||||||
|
"preinit",
|
||||||
|
"postinit",
|
||||||
|
"onSetActive",
|
||||||
|
"onBufferOpen",
|
||||||
|
"onBufPaneOpen",
|
||||||
|
"onRune",
|
||||||
|
"preRune",
|
||||||
|
|
||||||
|
"onCursorUp",
|
||||||
|
"onCursorDown",
|
||||||
|
"onCursorPageUp",
|
||||||
|
"onCursorPageDown",
|
||||||
|
"onCursorLeft",
|
||||||
|
"onCursorRight",
|
||||||
|
"onCursorStart",
|
||||||
|
"onCursorEnd",
|
||||||
|
"onSelectToStart",
|
||||||
|
"onSelectToEnd",
|
||||||
|
"onSelectUp",
|
||||||
|
"onSelectDown",
|
||||||
|
"onSelectLeft",
|
||||||
|
"onSelectRight",
|
||||||
|
"onSelectToStartOfText",
|
||||||
|
"onSelectToStartOfTextToggle",
|
||||||
|
"onWordRight",
|
||||||
|
"onWordLeft",
|
||||||
|
"onSelectWordRight",
|
||||||
|
"onSelectWordLeft",
|
||||||
|
"onMoveLinesUp",
|
||||||
|
"onMoveLinesDown",
|
||||||
|
"onDeleteWordRight",
|
||||||
|
"onDeleteWordLeft",
|
||||||
|
"onSelectLine",
|
||||||
|
"onSelectToStartOfLine",
|
||||||
|
"onSelectToEndOfLine",
|
||||||
|
"onInsertNewline",
|
||||||
|
"onInsertSpace",
|
||||||
|
"onBackspace",
|
||||||
|
"onDelete",
|
||||||
|
"onCenter",
|
||||||
|
"onInsertTab",
|
||||||
|
"onSave",
|
||||||
|
"onSaveAll",
|
||||||
|
"onSaveAs",
|
||||||
|
"onFind",
|
||||||
|
"onFindLiteral",
|
||||||
|
"onFindNext",
|
||||||
|
"onFindPrevious",
|
||||||
|
"onDiffPrevious",
|
||||||
|
"onDiffNext",
|
||||||
|
"onUndo",
|
||||||
|
"onRedo",
|
||||||
|
"onCopy",
|
||||||
|
"onCopyLine",
|
||||||
|
"onCut",
|
||||||
|
"onCutLine",
|
||||||
|
"onDuplicateLine",
|
||||||
|
"onDeleteLine",
|
||||||
|
"onIndentSelection",
|
||||||
|
"onOutdentSelection",
|
||||||
|
"onOutdentLine",
|
||||||
|
"onIndentLine",
|
||||||
|
"onPaste",
|
||||||
|
"onSelectAll",
|
||||||
|
"onOpenFile",
|
||||||
|
"onStart",
|
||||||
|
"onEnd",
|
||||||
|
"onPageUp",
|
||||||
|
"onPageDown",
|
||||||
|
"onSelectPageUp",
|
||||||
|
"onSelectPageDown",
|
||||||
|
"onHalfPageUp",
|
||||||
|
"onHalfPageDown",
|
||||||
|
"onStartOfLine",
|
||||||
|
"onEndOfLine",
|
||||||
|
"onStartOfText",
|
||||||
|
"onStartOfTextToggle",
|
||||||
|
"onParagraphPrevious",
|
||||||
|
"onParagraphNext",
|
||||||
|
"onToggleHelp",
|
||||||
|
"onToggleDiffGutter",
|
||||||
|
"onToggleRuler",
|
||||||
|
"onJumpLine",
|
||||||
|
"onClearStatus",
|
||||||
|
"onShellMode",
|
||||||
|
"onCommandMode",
|
||||||
|
"onQuit",
|
||||||
|
"onQuitAll",
|
||||||
|
"onAddTab",
|
||||||
|
"onPreviousTab",
|
||||||
|
"onNextTab",
|
||||||
|
"onNextSplit",
|
||||||
|
"onUnsplit",
|
||||||
|
"onVSplit",
|
||||||
|
"onHSplit",
|
||||||
|
"onPreviousSplit",
|
||||||
|
"onToggleMacro",
|
||||||
|
"onPlayMacro",
|
||||||
|
"onSuspend",
|
||||||
|
"onScrollUp",
|
||||||
|
"onScrollDown",
|
||||||
|
"onSpawnMultiCursor",
|
||||||
|
"onSpawnMultiCursorUp",
|
||||||
|
"onSpawnMultiCursorDown",
|
||||||
|
"onSpawnMultiCursorSelect",
|
||||||
|
"onRemoveMultiCursor",
|
||||||
|
"onRemoveAllMultiCursors",
|
||||||
|
"onSkipMultiCursor",
|
||||||
|
"onJumpToMatchingBrace",
|
||||||
|
"onAutocomplete",
|
||||||
|
|
||||||
|
"preCursorUp",
|
||||||
|
"preCursorDown",
|
||||||
|
"preCursorPageUp",
|
||||||
|
"preCursorPageDown",
|
||||||
|
"preCursorLeft",
|
||||||
|
"preCursorRight",
|
||||||
|
"preCursorStart",
|
||||||
|
"preCursorEnd",
|
||||||
|
"preSelectToStart",
|
||||||
|
"preSelectToEnd",
|
||||||
|
"preSelectUp",
|
||||||
|
"preSelectDown",
|
||||||
|
"preSelectLeft",
|
||||||
|
"preSelectRight",
|
||||||
|
"preSelectToStartOfText",
|
||||||
|
"preSelectToStartOfTextToggle",
|
||||||
|
"preWordRight",
|
||||||
|
"preWordLeft",
|
||||||
|
"preSelectWordRight",
|
||||||
|
"preSelectWordLeft",
|
||||||
|
"preMoveLinesUp",
|
||||||
|
"preMoveLinesDown",
|
||||||
|
"preDeleteWordRight",
|
||||||
|
"preDeleteWordLeft",
|
||||||
|
"preSelectLine",
|
||||||
|
"preSelectToStartOfLine",
|
||||||
|
"preSelectToEndOfLine",
|
||||||
|
"preInsertNewline",
|
||||||
|
"preInsertSpace",
|
||||||
|
"preBackspace",
|
||||||
|
"preDelete",
|
||||||
|
"preCenter",
|
||||||
|
"preInsertTab",
|
||||||
|
"preSave",
|
||||||
|
"preSaveAll",
|
||||||
|
"preSaveAs",
|
||||||
|
"preFind",
|
||||||
|
"preFindLiteral",
|
||||||
|
"preFindNext",
|
||||||
|
"preFindPrevious",
|
||||||
|
"preDiffPrevious",
|
||||||
|
"preDiffNext",
|
||||||
|
"preUndo",
|
||||||
|
"preRedo",
|
||||||
|
"preCopy",
|
||||||
|
"preCopyLine",
|
||||||
|
"preCut",
|
||||||
|
"preCutLine",
|
||||||
|
"preDuplicateLine",
|
||||||
|
"preDeleteLine",
|
||||||
|
"preIndentSelection",
|
||||||
|
"preOutdentSelection",
|
||||||
|
"preOutdentLine",
|
||||||
|
"preIndentLine",
|
||||||
|
"prePaste",
|
||||||
|
"preSelectAll",
|
||||||
|
"preOpenFile",
|
||||||
|
"preStart",
|
||||||
|
"preEnd",
|
||||||
|
"prePageUp",
|
||||||
|
"prePageDown",
|
||||||
|
"preSelectPageUp",
|
||||||
|
"preSelectPageDown",
|
||||||
|
"preHalfPageUp",
|
||||||
|
"preHalfPageDown",
|
||||||
|
"preStartOfLine",
|
||||||
|
"preEndOfLine",
|
||||||
|
"preStartOfText",
|
||||||
|
"preStartOfTextToggle",
|
||||||
|
"preParagraphPrevious",
|
||||||
|
"preParagraphNext",
|
||||||
|
"preToggleHelp",
|
||||||
|
"preToggleDiffGutter",
|
||||||
|
"preToggleRuler",
|
||||||
|
"preJumpLine",
|
||||||
|
"preClearStatus",
|
||||||
|
"preShellMode",
|
||||||
|
"preCommandMode",
|
||||||
|
"preQuit",
|
||||||
|
"preQuitAll",
|
||||||
|
"preAddTab",
|
||||||
|
"prePreviousTab",
|
||||||
|
"preNextTab",
|
||||||
|
"preNextSplit",
|
||||||
|
"preUnsplit",
|
||||||
|
"preVSplit",
|
||||||
|
"preHSplit",
|
||||||
|
"prePreviousSplit",
|
||||||
|
"preToggleMacro",
|
||||||
|
"prePlayMacro",
|
||||||
|
"preSuspend",
|
||||||
|
"preScrollUp",
|
||||||
|
"preScrollDown",
|
||||||
|
"preSpawnMultiCursor",
|
||||||
|
"preSpawnMultiCursorUp",
|
||||||
|
"preSpawnMultiCursorDown",
|
||||||
|
"preSpawnMultiCursorSelect",
|
||||||
|
"preRemoveMultiCursor",
|
||||||
|
"preRemoveAllMultiCursors",
|
||||||
|
"preSkipMultiCursor",
|
||||||
|
"preJumpToMatchingBrace",
|
||||||
|
"preAutocomplete",
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2023 Andriamanitra
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
@ -0,0 +1,122 @@
|
||||||
|
# List of language servers & how to get them
|
||||||
|
|
||||||
|
* [C/C++](#cc)
|
||||||
|
* [Clojure](#clojure)
|
||||||
|
* [Crystal](#crystal)
|
||||||
|
* [Go](#go)
|
||||||
|
* [Haskell](#haskell)
|
||||||
|
* [JavaScript/TypeScript](#javascripttypescript)
|
||||||
|
* [JSON](#json)
|
||||||
|
* [Lua](#lua)
|
||||||
|
* [Markdown](#markdown)
|
||||||
|
* [Python](#python)
|
||||||
|
* [Ruby](#ruby)
|
||||||
|
* [Rust](#rust)
|
||||||
|
* [Zig](#zig)
|
||||||
|
|
||||||
|
## C/C++
|
||||||
|
|
||||||
|
- [Clangd](https://clangd.llvm.org/)
|
||||||
|
- Installation: [instructions](https://clangd.llvm.org/installation.html)
|
||||||
|
- Command: `clangd`
|
||||||
|
|
||||||
|
## Clojure
|
||||||
|
|
||||||
|
- [clojure-lsp](https://github.com/clojure-lsp/clojure-lsp)
|
||||||
|
- Installation: [instructions](https://clojure-lsp.io/installation/)
|
||||||
|
- Command: `clojure-lsp`
|
||||||
|
|
||||||
|
## Crystal
|
||||||
|
|
||||||
|
- [Crystalline](https://github.com/elbywan/crystalline)
|
||||||
|
- Installation:
|
||||||
|
[instructions](https://github.com/elbywan/crystalline#global-install)
|
||||||
|
- Command: `crystalline`
|
||||||
|
|
||||||
|
## Go
|
||||||
|
|
||||||
|
- [gopls](https://pkg.go.dev/golang.org/x/tools/gopls)
|
||||||
|
- Installation:
|
||||||
|
[instructions](https://pkg.go.dev/golang.org/x/tools/gopls#readme-installation)
|
||||||
|
- Command: `gopls`
|
||||||
|
|
||||||
|
## Haskell
|
||||||
|
|
||||||
|
- [HLS](https://github.com/haskell/haskell-language-server)
|
||||||
|
- Installation: use [ghcup](https://www.haskell.org/ghcup/)
|
||||||
|
- Command: `haskell-language-server-wrapper --lsp`
|
||||||
|
|
||||||
|
## JavaScript/TypeScript
|
||||||
|
|
||||||
|
- [deno](https://github.com/denoland/deno)
|
||||||
|
- Installation:
|
||||||
|
[instructions](https://github.com/denoland/deno_install/blob/master/README.md#deno_install)
|
||||||
|
- Command: `deno lsp`
|
||||||
|
|
||||||
|
- [quick-lint-js](https://github.com/quick-lint/quick-lint-js)
|
||||||
|
- Only diagnostics (no formatting, hover information or code navigation)
|
||||||
|
- Installation: `npm install -g quick-lint-js`
|
||||||
|
- Command: `quick-lint-js --lsp`
|
||||||
|
|
||||||
|
## JSON
|
||||||
|
|
||||||
|
- [deno](https://github.com/denoland/deno)
|
||||||
|
- Installation:
|
||||||
|
[instructions](https://github.com/denoland/deno_install/blob/master/README.md#deno_install)
|
||||||
|
- Command: `deno lsp`
|
||||||
|
|
||||||
|
## Lua
|
||||||
|
|
||||||
|
- [luals](https://github.com/luals/lua-language-server)
|
||||||
|
- Installation: [instructions](https://luals.github.io/#other-install)
|
||||||
|
- Command: `lua-language-server` (make sure the executable was installed in your $PATH)
|
||||||
|
- [lua-lsp](https://github.com/Alloyed/lua-lsp)
|
||||||
|
- Unmaintained. You are in for trouble if you want to get it to work with Lua
|
||||||
|
5.4.
|
||||||
|
- Installation: `luarocks install lua-lsp`
|
||||||
|
([luarocks](https://github.com/luarocks/luarocks))
|
||||||
|
- Command: `lua-lsp`
|
||||||
|
|
||||||
|
## Markdown
|
||||||
|
|
||||||
|
- [deno](https://github.com/denoland/deno)
|
||||||
|
- Installation:
|
||||||
|
[instructions](https://github.com/denoland/deno_install/blob/master/README.md#deno_install)
|
||||||
|
- Command: `deno lsp`
|
||||||
|
|
||||||
|
## Python
|
||||||
|
|
||||||
|
- [pylsp](https://github.com/python-lsp/python-lsp-server)
|
||||||
|
- Installation: `pip install python-lsp-server[all]`
|
||||||
|
- Command: `pylsp`
|
||||||
|
|
||||||
|
- [Pyright](https://github.com/microsoft/pyright)
|
||||||
|
- Installation: `npm install -g pyright`
|
||||||
|
- Command: `pyright-langserver --stdio`
|
||||||
|
|
||||||
|
- [ruff](https://github.com/astral-sh/ruff)
|
||||||
|
- Only diagnostics, formatting and code actions (no hover information or code navigation)
|
||||||
|
- Installation: `pip install ruff`
|
||||||
|
- Command: `ruff server`
|
||||||
|
|
||||||
|
## Ruby
|
||||||
|
|
||||||
|
- [ruby-lsp](https://github.com/Shopify/ruby-lsp)
|
||||||
|
- Installation: `gem install ruby-lsp`
|
||||||
|
- Command: `ruby-lsp`
|
||||||
|
|
||||||
|
- [solargraph](https://github.com/castwide/solargraph)
|
||||||
|
- Installation: `gem install solargraph`
|
||||||
|
- Command: `solargraph stdio`
|
||||||
|
|
||||||
|
## Rust
|
||||||
|
|
||||||
|
- [rust-analyzer](https://github.com/rust-lang/rust-analyzer)
|
||||||
|
- Installation: `rustup component add rust-analyzer`
|
||||||
|
- Command: `rust-analyzer`
|
||||||
|
|
||||||
|
## Zig
|
||||||
|
|
||||||
|
- [zls](https://github.com/zigtools/zls)
|
||||||
|
- Installation: [instructions](https://github.com/zigtools/zls#installation)
|
||||||
|
- Command: `zls`
|
||||||
|
|
@ -0,0 +1,99 @@
|
||||||
|
# µlsp
|
||||||
|
|
||||||
|
LSP client for [micro-editor](https://github.com/zyedidia/micro).
|
||||||
|
Note that this is a work in progress and has not yet been tested extensively – expect there to be some bugs.
|
||||||
|
Please [open an issue](https://github.com/Andriamanitra/mlsp/issues/new) if you run into any!
|
||||||
|
|
||||||
|
|
||||||
|
## Demo
|
||||||
|
|
||||||
|
[https://asciinema.org/a/610761](https://asciinema.org/a/610761)
|
||||||
|
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Simply clone the repository to your micro plugins directory:
|
||||||
|
|
||||||
|
```
|
||||||
|
git clone https://github.com/Andriamanitra/mlsp ~/.config/micro/plug/mlsp
|
||||||
|
```
|
||||||
|
|
||||||
|
You will also need to install [language servers](LanguageServers.md) for the
|
||||||
|
programming languages you want to use.
|
||||||
|
|
||||||
|
The plugin currently provides following commands:
|
||||||
|
|
||||||
|
- `lsp start deno lsp` starts a language server by executing command `deno lsp`.
|
||||||
|
Without arguments the `lsp start` command will try to guess the right server by
|
||||||
|
looking at the currently open filetype.
|
||||||
|
- `lsp stop deno` stops the language server with name `deno`. Without arguments
|
||||||
|
the `lsp stop` command will stop _all_ currently running language servers.
|
||||||
|
- `lsp hover` shows hover information for the code under cursor.
|
||||||
|
- `lsp format` formats the buffer that is currently open.
|
||||||
|
- `lsp autocomplete` for code completion suggestions. PROTIP: If you wish to use the
|
||||||
|
same key as micro's autocompletion (tab by default), enable `tabAutocomplete`
|
||||||
|
in `config.lua` instead of binding `command:lsp autocomplete` to a key!
|
||||||
|
- `lsp goto-definition` – open the definition for the symbol under cursor
|
||||||
|
- `lsp goto-declaration` – open the declaration for the symbol under cursor
|
||||||
|
- `lsp goto-typedefinition` – open the type definition for the symbol under cursor
|
||||||
|
- `lsp goto-implementation` – open the implementation for the symbol under cursor
|
||||||
|
- `lsp find-references` - find all references to the symbol under cursor (shows the results in a new pane)
|
||||||
|
- `lsp document-symbols` - list all symbols in the current document
|
||||||
|
- `lsp diagnostic-info` - show more information about a diagnostic on the current line (useful for multiline diagnostic messages)
|
||||||
|
|
||||||
|
You can type the commands on micro command prompt or bind them to keys by adding
|
||||||
|
something like this to your `bindings.json`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"F7": "command:lsp start",
|
||||||
|
"F8": "command:lsp format",
|
||||||
|
"Alt-h": "command:lsp hover",
|
||||||
|
"Alt-d": "command:lsp goto-definition",
|
||||||
|
"Alt-r": "command:lsp find-references"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Supported features
|
||||||
|
|
||||||
|
- [x] get hover information
|
||||||
|
- [x] show diagnostics (disabled by default, edit `config.lua` to enable)
|
||||||
|
- [x] autocomplete using tab (disabled by default, edit `config.lua` to enable)
|
||||||
|
- [x] format document
|
||||||
|
- [x] format selection
|
||||||
|
- [x] go to definition
|
||||||
|
- [x] go to declaration
|
||||||
|
- [x] go to implementation
|
||||||
|
- [x] go to type definition
|
||||||
|
- [x] find references
|
||||||
|
- [x] list document symbols
|
||||||
|
- [ ] rename symbol
|
||||||
|
- [ ] code actions
|
||||||
|
- [x] incremental document synchronization (better performance when editing large files)
|
||||||
|
- [ ] [suggest a feature](https://github.com/Andriamanitra/mlsp/issues/new)
|
||||||
|
|
||||||
|
|
||||||
|
## Showing LSP information on statusline
|
||||||
|
|
||||||
|
The plugin provides a function `mlsp.status` that can be used in the status line format.
|
||||||
|
Here is an example configuration (`~/.config/micro/settings.json`) that uses it:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"statusformatl": "$(filename) $(modified)($(line),$(col)) | ft:$(opt:filetype) | µlsp:$(mlsp.status)"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
See [micro documentation](https://github.com/zyedidia/micro/blob/master/runtime/help/options.md)
|
||||||
|
and the built-in [status plugin](https://github.com/zyedidia/micro/blob/master/runtime/plugins/status/help/status.md)
|
||||||
|
for more information on customizing the statusline.
|
||||||
|
|
||||||
|
|
||||||
|
## Known issues
|
||||||
|
|
||||||
|
- The very first autocompletion with `rust-analyzer` after initialization is very slow (it can take multiple seconds).
|
||||||
|
|
||||||
|
## Other similar projects
|
||||||
|
|
||||||
|
* [AndCake/micro-plugin-lsp](https://github.com/AndCake/micro-plugin-lsp) is another LSP plugin for micro-editor.
|
||||||
|
|
@ -0,0 +1,154 @@
|
||||||
|
-- defaults for omitted server options (you probably don't want to change these)
|
||||||
|
local defaultLanguageServerOptions = {
|
||||||
|
-- Unique name for the server to be shown in statusbar and logs
|
||||||
|
-- Defaults to the same as cmd if omitted
|
||||||
|
shortName = nil,
|
||||||
|
|
||||||
|
-- (REQUIRED) command to execute the language server
|
||||||
|
cmd = "",
|
||||||
|
|
||||||
|
-- Arguments for the above command
|
||||||
|
args = {},
|
||||||
|
|
||||||
|
-- Language server specific options that are sent to the server during
|
||||||
|
-- initialization – you can usually omit this field
|
||||||
|
initializationOptions = nil,
|
||||||
|
|
||||||
|
-- callback function that is called when language server is initialized
|
||||||
|
-- (useful for debugging and disabling server capabilities)
|
||||||
|
-- For example to disable getting hover information from a server:
|
||||||
|
-- onInitialized = function(client)
|
||||||
|
-- client.serverCapabilities.hoverProvider = false
|
||||||
|
-- end
|
||||||
|
onInitialized = nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Pre-made configurations for commonly used language servers – you can also
|
||||||
|
-- define your own servers to be used in settings at the bottom of this file.
|
||||||
|
-- See defaultLanguageServerOptions above for the available options.
|
||||||
|
languageServer = {
|
||||||
|
clangd = {
|
||||||
|
cmd = "clangd"
|
||||||
|
},
|
||||||
|
clojurelsp = {
|
||||||
|
cmd = "clojure-lsp"
|
||||||
|
},
|
||||||
|
crystalline = {
|
||||||
|
cmd = "crystalline"
|
||||||
|
},
|
||||||
|
deno = {
|
||||||
|
cmd = "deno",
|
||||||
|
args = {"lsp"}
|
||||||
|
},
|
||||||
|
gopls = {
|
||||||
|
cmd = "gopls"
|
||||||
|
},
|
||||||
|
hls = {
|
||||||
|
shortName = "hls",
|
||||||
|
cmd = "haskell-language-server-wrapper",
|
||||||
|
args = {"--lsp"}
|
||||||
|
},
|
||||||
|
julials = {
|
||||||
|
shortName = "julials",
|
||||||
|
cmd = "julia",
|
||||||
|
args = {"--startup-file=no", "--history-file=no", "-e", "using LanguageServer; runserver()"}
|
||||||
|
},
|
||||||
|
lualsp = {
|
||||||
|
cmd = "lua-lsp"
|
||||||
|
},
|
||||||
|
luals = {
|
||||||
|
cmd = "lua-language-server"
|
||||||
|
},
|
||||||
|
pylsp = {
|
||||||
|
cmd = "pylsp"
|
||||||
|
},
|
||||||
|
pyright = {
|
||||||
|
shortName = "pyright",
|
||||||
|
cmd = "pyright-langserver",
|
||||||
|
args = {"--stdio"}
|
||||||
|
},
|
||||||
|
quicklintjs = {
|
||||||
|
cmd = "quick-lint-js",
|
||||||
|
args = {"--lsp"}
|
||||||
|
},
|
||||||
|
rubocop = {
|
||||||
|
cmd = "rubocop",
|
||||||
|
args = {"--lsp"}
|
||||||
|
},
|
||||||
|
rubylsp = {
|
||||||
|
cmd = "ruby-lsp"
|
||||||
|
},
|
||||||
|
ruff = {
|
||||||
|
cmd = "ruff",
|
||||||
|
args = {"server"},
|
||||||
|
onInitialized = function(client)
|
||||||
|
-- does not give useful results
|
||||||
|
client.serverCapabilities.hoverProvider = false
|
||||||
|
end
|
||||||
|
},
|
||||||
|
rustAnalyzer = {
|
||||||
|
shortName = "rust",
|
||||||
|
cmd = "rust-analyzer"
|
||||||
|
},
|
||||||
|
solargraph = {
|
||||||
|
cmd = "solargraph",
|
||||||
|
args = {"stdio"}
|
||||||
|
},
|
||||||
|
zls = {
|
||||||
|
cmd = "zls"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-- you don't need to care about this part but it's basically filling in defaults
|
||||||
|
-- for all missing fields in language servers defined above
|
||||||
|
defaultLanguageServerOptions.__index = defaultLanguageServerOptions
|
||||||
|
for _, server in pairs(languageServer) do
|
||||||
|
setmetatable(server, defaultLanguageServerOptions)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
settings = {
|
||||||
|
|
||||||
|
-- Use LSP completion in place of micro's default Autocomplete action when
|
||||||
|
-- available (you can bind `command:autocomplete` command to a different
|
||||||
|
-- key in ~/.config/micro/bindings.json even if this setting is false)
|
||||||
|
tabAutocomplete = true,
|
||||||
|
|
||||||
|
-- Automatically start language server(s) when a buffer with matching
|
||||||
|
-- filetype is opened
|
||||||
|
autostart = {
|
||||||
|
-- Example #1: Start gopls when editing .go files:
|
||||||
|
-- go = { languageServer.gopls },
|
||||||
|
|
||||||
|
-- Example #2: Start pylsp AND ruff-lsp when editing Python files:
|
||||||
|
-- python = { languageServer.pylsp, languageServer.ruff },
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Language server to use when `lsp` command is executed without args
|
||||||
|
defaultLanguageServer = {
|
||||||
|
c = languageServer.clangd,
|
||||||
|
["c++"] = languageServer.clangd,
|
||||||
|
clojure = languageServer.clojurelsp,
|
||||||
|
crystal = languageServer.crystalline,
|
||||||
|
go = languageServer.gopls,
|
||||||
|
haskell = languageServer.hls,
|
||||||
|
javascript = languageServer.deno,
|
||||||
|
julia = languageServer.julials,
|
||||||
|
json = languageServer.deno,
|
||||||
|
lua = languageServer.luals,
|
||||||
|
markdown = languageServer.deno,
|
||||||
|
python = languageServer.pylsp,
|
||||||
|
ruby = languageServer.rubylsp,
|
||||||
|
rust = languageServer.rustAnalyzer,
|
||||||
|
typescript = languageServer.deno,
|
||||||
|
zig = languageServer.zls,
|
||||||
|
},
|
||||||
|
|
||||||
|
-- Which kinds of diagnostics to show in the gutter
|
||||||
|
showDiagnostics = {
|
||||||
|
error = false,
|
||||||
|
warning = false,
|
||||||
|
information = false,
|
||||||
|
hint = false
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,396 @@
|
||||||
|
--
|
||||||
|
-- json.lua
|
||||||
|
--
|
||||||
|
-- Copyright (c) 2020 rxi
|
||||||
|
--
|
||||||
|
-- Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
-- this software and associated documentation files (the "Software"), to deal in
|
||||||
|
-- the Software without restriction, including without limitation the rights to
|
||||||
|
-- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
-- of the Software, and to permit persons to whom the Software is furnished to do
|
||||||
|
-- so, subject to the following conditions:
|
||||||
|
--
|
||||||
|
-- The above copyright notice and this permission notice shall be included in all
|
||||||
|
-- copies or substantial portions of the Software.
|
||||||
|
--
|
||||||
|
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
-- SOFTWARE.
|
||||||
|
--
|
||||||
|
|
||||||
|
|
||||||
|
-- by default the empty table ({} in lua) gets serialized into json array
|
||||||
|
-- this hack allows us to use json.object when we want to emit an empty object
|
||||||
|
-- instead
|
||||||
|
local emptyMap_metatable = {}
|
||||||
|
emptyMap_metatable.__index = emptyMap_metatable
|
||||||
|
local emptyMap = {}
|
||||||
|
setmetatable(emptyMap, emptyMap_metatable)
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
-- Encode
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
local encode
|
||||||
|
|
||||||
|
local escape_char_map = {
|
||||||
|
[ "\\" ] = "\\",
|
||||||
|
[ "\"" ] = "\"",
|
||||||
|
[ "\b" ] = "b",
|
||||||
|
[ "\f" ] = "f",
|
||||||
|
[ "\n" ] = "n",
|
||||||
|
[ "\r" ] = "r",
|
||||||
|
[ "\t" ] = "t",
|
||||||
|
}
|
||||||
|
|
||||||
|
local escape_char_map_inv = { [ "/" ] = "/" }
|
||||||
|
for k, v in pairs(escape_char_map) do
|
||||||
|
escape_char_map_inv[v] = k
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function escape_char(c)
|
||||||
|
return "\\" .. (escape_char_map[c] or string.format("u%04x", c:byte()))
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function encode_nil(val)
|
||||||
|
return "null"
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function encode_table(val, stack)
|
||||||
|
local res = {}
|
||||||
|
stack = stack or {}
|
||||||
|
|
||||||
|
-- Circular reference?
|
||||||
|
if stack[val] then error("circular reference") end
|
||||||
|
|
||||||
|
stack[val] = true
|
||||||
|
|
||||||
|
if (rawget(val, 1) ~= nil or next(val) == nil) and (getmetatable(val) ~= emptyMap_metatable) then
|
||||||
|
-- Treat as array -- check keys are valid and it is not sparse
|
||||||
|
local n = 0
|
||||||
|
for k in pairs(val) do
|
||||||
|
if type(k) ~= "number" then
|
||||||
|
error("invalid table: mixed or invalid key types")
|
||||||
|
end
|
||||||
|
n = n + 1
|
||||||
|
end
|
||||||
|
if n ~= #val then
|
||||||
|
error("invalid table: sparse array")
|
||||||
|
end
|
||||||
|
-- Encode
|
||||||
|
for i, v in ipairs(val) do
|
||||||
|
table.insert(res, encode(v, stack))
|
||||||
|
end
|
||||||
|
stack[val] = nil
|
||||||
|
return "[" .. table.concat(res, ",") .. "]"
|
||||||
|
|
||||||
|
else
|
||||||
|
-- Treat as an object
|
||||||
|
for k, v in pairs(val) do
|
||||||
|
if type(k) ~= "string" then
|
||||||
|
error("invalid table: mixed or invalid key types")
|
||||||
|
end
|
||||||
|
table.insert(res, encode(k, stack) .. ":" .. encode(v, stack))
|
||||||
|
end
|
||||||
|
stack[val] = nil
|
||||||
|
return "{" .. table.concat(res, ",") .. "}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function encode_string(val)
|
||||||
|
return '"' .. val:gsub('[%z\1-\31\\"]', escape_char) .. '"'
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function encode_number(val)
|
||||||
|
-- Check for NaN, -inf and inf
|
||||||
|
if val ~= val or val <= -math.huge or val >= math.huge then
|
||||||
|
error("unexpected number value '" .. tostring(val) .. "'")
|
||||||
|
end
|
||||||
|
return string.format("%.14g", val)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local type_func_map = {
|
||||||
|
[ "nil" ] = encode_nil,
|
||||||
|
[ "table" ] = encode_table,
|
||||||
|
[ "string" ] = encode_string,
|
||||||
|
[ "number" ] = encode_number,
|
||||||
|
[ "boolean" ] = tostring,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
encode = function(val, stack)
|
||||||
|
local t = type(val)
|
||||||
|
local f = type_func_map[t]
|
||||||
|
if f then
|
||||||
|
return f(val, stack)
|
||||||
|
end
|
||||||
|
error("unexpected type '" .. t .. "'")
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
-- Decode
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
local parse
|
||||||
|
|
||||||
|
local function create_set(...)
|
||||||
|
local res = {}
|
||||||
|
for i = 1, select("#", ...) do
|
||||||
|
res[ select(i, ...) ] = true
|
||||||
|
end
|
||||||
|
return res
|
||||||
|
end
|
||||||
|
|
||||||
|
local space_chars = create_set(" ", "\t", "\r", "\n")
|
||||||
|
local delim_chars = create_set(" ", "\t", "\r", "\n", "]", "}", ",")
|
||||||
|
local escape_chars = create_set("\\", "/", '"', "b", "f", "n", "r", "t", "u")
|
||||||
|
local literals = create_set("true", "false", "null")
|
||||||
|
|
||||||
|
local literal_map = {
|
||||||
|
[ "true" ] = true,
|
||||||
|
[ "false" ] = false,
|
||||||
|
[ "null" ] = nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
local function next_char(str, idx, set, negate)
|
||||||
|
for i = idx, #str do
|
||||||
|
if set[str:sub(i, i)] ~= negate then
|
||||||
|
return i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return #str + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function decode_error(str, idx, msg)
|
||||||
|
local line_count = 1
|
||||||
|
local col_count = 1
|
||||||
|
for i = 1, idx - 1 do
|
||||||
|
col_count = col_count + 1
|
||||||
|
if str:sub(i, i) == "\n" then
|
||||||
|
line_count = line_count + 1
|
||||||
|
col_count = 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
error( string.format("%s at line %d col %d", msg, line_count, col_count) )
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function codepoint_to_utf8(n)
|
||||||
|
-- http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=iws-appendixa
|
||||||
|
local f = math.floor
|
||||||
|
if n <= 0x7f then
|
||||||
|
return string.char(n)
|
||||||
|
elseif n <= 0x7ff then
|
||||||
|
return string.char(f(n / 64) + 192, n % 64 + 128)
|
||||||
|
elseif n <= 0xffff then
|
||||||
|
return string.char(f(n / 4096) + 224, f(n % 4096 / 64) + 128, n % 64 + 128)
|
||||||
|
elseif n <= 0x10ffff then
|
||||||
|
return string.char(f(n / 262144) + 240, f(n % 262144 / 4096) + 128,
|
||||||
|
f(n % 4096 / 64) + 128, n % 64 + 128)
|
||||||
|
end
|
||||||
|
error( string.format("invalid unicode codepoint '%x'", n) )
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function parse_unicode_escape(s)
|
||||||
|
local n1 = tonumber( s:sub(1, 4), 16 )
|
||||||
|
local n2 = tonumber( s:sub(7, 10), 16 )
|
||||||
|
-- Surrogate pair?
|
||||||
|
if n2 then
|
||||||
|
return codepoint_to_utf8((n1 - 0xd800) * 0x400 + (n2 - 0xdc00) + 0x10000)
|
||||||
|
else
|
||||||
|
return codepoint_to_utf8(n1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function parse_string(str, i)
|
||||||
|
local res = ""
|
||||||
|
local j = i + 1
|
||||||
|
local k = j
|
||||||
|
|
||||||
|
while j <= #str do
|
||||||
|
local x = str:byte(j)
|
||||||
|
|
||||||
|
if x < 32 then
|
||||||
|
decode_error(str, j, "control character in string")
|
||||||
|
|
||||||
|
elseif x == 92 then -- `\`: Escape
|
||||||
|
res = res .. str:sub(k, j - 1)
|
||||||
|
j = j + 1
|
||||||
|
local c = str:sub(j, j)
|
||||||
|
if c == "u" then
|
||||||
|
local hex = str:match("^[dD][89aAbB]%x%x\\u%x%x%x%x", j + 1)
|
||||||
|
or str:match("^%x%x%x%x", j + 1)
|
||||||
|
or decode_error(str, j - 1, "invalid unicode escape in string")
|
||||||
|
res = res .. parse_unicode_escape(hex)
|
||||||
|
j = j + #hex
|
||||||
|
else
|
||||||
|
if not escape_chars[c] then
|
||||||
|
decode_error(str, j - 1, "invalid escape char '" .. c .. "' in string")
|
||||||
|
end
|
||||||
|
res = res .. escape_char_map_inv[c]
|
||||||
|
end
|
||||||
|
k = j + 1
|
||||||
|
|
||||||
|
elseif x == 34 then -- `"`: End of string
|
||||||
|
res = res .. str:sub(k, j - 1)
|
||||||
|
return res, j + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
j = j + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
decode_error(str, i, "expected closing quote for string")
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function parse_number(str, i)
|
||||||
|
local x = next_char(str, i, delim_chars)
|
||||||
|
local s = str:sub(i, x - 1)
|
||||||
|
local n = tonumber(s)
|
||||||
|
if not n then
|
||||||
|
decode_error(str, i, "invalid number '" .. s .. "'")
|
||||||
|
end
|
||||||
|
return n, x
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function parse_literal(str, i)
|
||||||
|
local x = next_char(str, i, delim_chars)
|
||||||
|
local word = str:sub(i, x - 1)
|
||||||
|
if not literals[word] then
|
||||||
|
decode_error(str, i, "invalid literal '" .. word .. "'")
|
||||||
|
end
|
||||||
|
return literal_map[word], x
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function parse_array(str, i)
|
||||||
|
local res = {}
|
||||||
|
local n = 1
|
||||||
|
i = i + 1
|
||||||
|
while 1 do
|
||||||
|
local x
|
||||||
|
i = next_char(str, i, space_chars, true)
|
||||||
|
-- Empty / end of array?
|
||||||
|
if str:sub(i, i) == "]" then
|
||||||
|
i = i + 1
|
||||||
|
break
|
||||||
|
end
|
||||||
|
-- Read token
|
||||||
|
x, i = parse(str, i)
|
||||||
|
res[n] = x
|
||||||
|
n = n + 1
|
||||||
|
-- Next token
|
||||||
|
i = next_char(str, i, space_chars, true)
|
||||||
|
local chr = str:sub(i, i)
|
||||||
|
i = i + 1
|
||||||
|
if chr == "]" then break end
|
||||||
|
if chr ~= "," then decode_error(str, i, "expected ']' or ','") end
|
||||||
|
end
|
||||||
|
return res, i
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function parse_object(str, i)
|
||||||
|
local res = {}
|
||||||
|
i = i + 1
|
||||||
|
while 1 do
|
||||||
|
local key, val
|
||||||
|
i = next_char(str, i, space_chars, true)
|
||||||
|
-- Empty / end of object?
|
||||||
|
if str:sub(i, i) == "}" then
|
||||||
|
i = i + 1
|
||||||
|
break
|
||||||
|
end
|
||||||
|
-- Read key
|
||||||
|
if str:sub(i, i) ~= '"' then
|
||||||
|
decode_error(str, i, "expected string for key")
|
||||||
|
end
|
||||||
|
key, i = parse(str, i)
|
||||||
|
-- Read ':' delimiter
|
||||||
|
i = next_char(str, i, space_chars, true)
|
||||||
|
if str:sub(i, i) ~= ":" then
|
||||||
|
decode_error(str, i, "expected ':' after key")
|
||||||
|
end
|
||||||
|
i = next_char(str, i + 1, space_chars, true)
|
||||||
|
-- Read value
|
||||||
|
val, i = parse(str, i)
|
||||||
|
-- Set
|
||||||
|
res[key] = val
|
||||||
|
-- Next token
|
||||||
|
i = next_char(str, i, space_chars, true)
|
||||||
|
local chr = str:sub(i, i)
|
||||||
|
i = i + 1
|
||||||
|
if chr == "}" then break end
|
||||||
|
if chr ~= "," then decode_error(str, i, "expected '}' or ','") end
|
||||||
|
end
|
||||||
|
return res, i
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local char_func_map = {
|
||||||
|
[ '"' ] = parse_string,
|
||||||
|
[ "0" ] = parse_number,
|
||||||
|
[ "1" ] = parse_number,
|
||||||
|
[ "2" ] = parse_number,
|
||||||
|
[ "3" ] = parse_number,
|
||||||
|
[ "4" ] = parse_number,
|
||||||
|
[ "5" ] = parse_number,
|
||||||
|
[ "6" ] = parse_number,
|
||||||
|
[ "7" ] = parse_number,
|
||||||
|
[ "8" ] = parse_number,
|
||||||
|
[ "9" ] = parse_number,
|
||||||
|
[ "-" ] = parse_number,
|
||||||
|
[ "t" ] = parse_literal,
|
||||||
|
[ "f" ] = parse_literal,
|
||||||
|
[ "n" ] = parse_literal,
|
||||||
|
[ "[" ] = parse_array,
|
||||||
|
[ "{" ] = parse_object,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
parse = function(str, idx)
|
||||||
|
local chr = str:sub(idx, idx)
|
||||||
|
local f = char_func_map[chr]
|
||||||
|
if f then
|
||||||
|
return f(str, idx)
|
||||||
|
end
|
||||||
|
decode_error(str, idx, "unexpected character '" .. chr .. "'")
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function decode(str)
|
||||||
|
if type(str) ~= "string" then
|
||||||
|
error("expected argument of type string, got " .. type(str))
|
||||||
|
end
|
||||||
|
local res, idx = parse(str, next_char(str, 1, space_chars, true))
|
||||||
|
idx = next_char(str, idx, space_chars, true)
|
||||||
|
if idx <= #str then
|
||||||
|
decode_error(str, idx, "trailing garbage")
|
||||||
|
end
|
||||||
|
return res
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
json = {
|
||||||
|
_version = "0.2.0",
|
||||||
|
object = emptyMap,
|
||||||
|
decode = function(s) return decode(s) end,
|
||||||
|
encode = function(o) return encode(o) end
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue