Fennel-ls now can receive options from the language client over the protocol. Future work still necessary to have project-local files. |
||
|---|---|---|
| src | ||
| test | ||
| .gitignore | ||
| fennel | ||
| LICENSE | ||
| Makefile | ||
| README.md | ||
fennel-ls
A language server for fennel-ls. Uses static analysis, and doesn't actually run your code, which makes it perfect for analyzing your (os.execute "rm -rf") code. If you want live analysis of your code as it runs, consider using a REPL.
For now, you can ask fennel-ls to treat your file as a macro file if the very first characters in the file exactly match ;; fennel-ls: macro-file. Expect this to break at some point in the future when I come up with a better way to specify which files are meant to be macro files.
Features / To Do List / Things I would enjoy patches for: ([X] = complete, [ ] = planned)
- Able to connect to a client
- Support for UTF-8 characters that aren't just plain ASCII. (especially
λ) - Settings to configure lua / fennel path, allowed globals, etc
- Supporting builds for anything other than arch linux
- Testing/support/instructions for any clients: (LSP is supposed to be editor-agnostic, but that's only if you're able to actually follow the spec, and I'm not sure that fennel-ls is compliant)
- Neovim (This project isn't a neovim plugin, but there are instructions on how to inform neovim of the fennel-ls binary once you build it.)
- emacs
- vscode
- vim+coc
- Go-to-definition:
- literal table constructor
- table destructuring
- multisyms
.special form (when called with constants)doandletspecial formrequireand cross-module definition lookups- goes to a.method on
(: a :method)when triggered at:method - expanded macros (a little bit)
- table mutation via
fnspecial:(fn obj.new-field []) - macro calls / which macros are in scope
- setmetatable
- function arguments / function calls
- local/table mutation via set/tset
- .lua files (antifennel decompiler)
- mutation on aliased tables (difficult)
- Completion Suggestions
- from globals
- from current scope
- from macros (only on first form in a list)
- from specials (only on first form in a list)
- "dot completion" for table fields
- dot completion is aware of a stdlib
- from anywhere else that I'm forgetting right now
- actually compliant rules about lexical scope (only see things declared before, not after)
- show docs/icons on each suggestion
- "dot completion" for metatable
__indexfields (. obj :string completions(: "foo" :string completions(require :module completions- snippets? I guess?
- Reports compiler errors
- [.] Report more than one error per top-level form
- Reports linting issues
- Unused locals
- Discarding results from pcall/xpcall/other functions
unpackorvaluesinto an operator specialdo/valueswith only one inner form- redundant
doas the last/only item in a form that accepts a "body" varforms that could belocal- Dead code (I'm not sure what sort of things cause dead code)
- Unused fields (difficult)
- unification in a
matchpattern (difficult) - Brainstorm more linting patterns (I spent a couple minutes brainstorming these ideas, other ideas are welcome of course)
- Hover over a symbol for documentation
- Signature help
- Regular help
- hide or grey out the
selfin ana:bmultisym call
- Go-to-references
- lexical scope in the same file
- fields
- go to references of fields when tables are aliased
- global search across other files
- Options / Configuration
- Configure over LSP
- Configure with some sort of per-project config file
- Configure with environment variables I guess??
- fennel/lua path
- lua version
- allowed global list
- enable/disable various linters
- rename
- local symbols
- module fields (may affect code behavior, may modify other files)
- arbitrary fields (may affect code behavior, may modify other files)
- formatting with fnlfmt
- Type annotations? Global type inference?
Setup:
You can match my environment to develop with the following steps.
- Build the binary
make && sudo make install # to install into /usr/local/bin
make install PREFIX=$HOME # if you have ~/bin on your $PATH
- Configure your editor to use this language server LSP is editor-agnostic, but that's only if you're able to actually follow the spec, and I'm not sure if fennel-ls is compliant.
So far, I've only ever tested it with Neovim using the native language client and lspconfig.
If you know what that means, here's the relevant code to help you set up Neovim in the same way:
local lspconfig = require('lspconfig')
-- inform lspconfig about fennel-ls
require("lspconfig.configs")["fennel-ls"] = {
default_config = {
cmd = {"/path/to/fennel-ls/fennel-ls"},
filetypes = {"fennel"},
root_dir = function(dir) return lspconfig.util.find_git_ancestor(dir) end,
settings = {}
}
}
-- setup fennel-ls
-- If you're using a completion system like nvim-cmp, you probably need to modify this line.
lspconfig["fennel-ls"].setup(
vim.lsp.protocol.make_client_capabilities()
)
For Emacs, (eglot, built-in to 29+) put this in your config:
(with-eval-after-load 'eglot
(add-to-list 'eglot-server-programs '(fennel-mode . ("fennel-ls"))))
It should be possible to set up for other clients, but I haven't looked into these steps. If you get it working in any other environments, I'd love to know! It would be great to have instructions on how to set up other editors!
Caveats
So far, I am only testing this project with Neovim. Since Neovim also uses Lua, there may be instances where fennel-ls encodes JSON incorrectly which may be compatible with Neovim, but not other editors. (ie, a json field that is supposed to be null may be missing, or [] and {} may be conflated). User beware!
If you want to help fix this, ./src/fennel-ls/message.fnl is where messages are being constructed,
and ./src/fennel-ls/json-rpc.fnl is where messages are being converted to json. I suspect a different json library will be necessary.
License
fennel-ls is licensed under the MIT license. See LICENSE for more info. However, this project contains files from other projects:
- test/pl comes from Penlight [MIT license]
- src/json comes from json.lua [MIT license]
- fennel and src/fennel.lua are compiled from fennel [MIT license]
fennel-ls's license may not apply to these files; check those projects for more details.