-
Notifications
You must be signed in to change notification settings - Fork 366
feat: add docs for neovim setup #3322
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
-- other packages... | ||
{ | ||
'neovim/nvim-lspconfig', | ||
config = function() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
here, I think we need to set mason = false
. Otherwise it will not work, at least this is how experienced in the past.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh interesting, my current configuration uses Mason alongside ocamllsp. I don't think I've ran into issues compared yet.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, this is probably because ocamllsp is version sensitive as you mentioned, probably at that time the version installed in mason not compatible. So, I decided to install ocaml-lsp-server for each project.
anyway, I think this is look good to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't that option related to LazyVim
and not lazy.nvim
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we really need to explain about lazy.nvim
and neovim/nvim-lspconfig
here? They aren't really a dependency for proper setup so they should be at least less preferred here.
I know many people are still using them, but I think they might introduce too much complexity considering the purpose of this document.
nvim-lspconfig
is already using vim.lsp
internally afaik so I think just directly showing vim.lsp
based config here can actually be enough.
We can let users switch to nvim-lspconfig
for even shorter one-liner setup if they have an existing neovim config with lspconfig
.
-- this should be enough for them. Others are just boilerplates.
require('lspconfig').ocamllsp.setup()
```lua | ||
-- path/to/config/lua/lsp/servers.lua | ||
vim.lsp.config['ocamllsp'] = { | ||
cmd = { 'ocamllsp' }, | ||
filetypes = { 'ocaml', 'ocaml.interface', 'ocaml.menhir', 'reason' }, | ||
root_markers = { { 'dune-project', 'dune-workspace' }, '.git' }, | ||
settings = {}, | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be more idiomatic in Neovim to put lsp server config under lsp/ocamllsp.lua
rather than lua/lsp/*.lua
.
Now even less code and they are in right place rather than imported manually.
:h 'runtimepath'
-- path/to/config/lsp/ocamllsp.lua
return {
cmd = { 'ocamllsp' },
filetypes = { 'ocaml', 'ocaml.interface', 'ocaml.menhir', 'reason' },
root_markers = { { 'dune-project', 'dune-workspace' }, '.git' },
settings = {},
}
-- init.lua
vim.lsp.enable('ocamllsp')
@boltlessengineer Thank you for the review! I made the necessary changes. Let me know if you'd prefer to see an even shorter version. Your point makes a lot of sense in that we shouldn't cover the full setup of package managers and setup, because that's out of scope of this guide. And I like your comment on the I think the notion of adding boilerplate was to give more context to the users, as I used to struggle a lot with terse setup documentation. Call it skill issue but I would've appreciated having a minimal boilerplate in a setup guide, as it's a lot easier to make sense of where to actually put the config😅 I'd rather not assume that all Neovim users are wizards who know the full ins and outs of their config. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While I appreciate the change on nvim-lspconfig
section, the vim.lsp
section... got worse. I should have explained it more clearly.
There are so many ways to configure a LSP with vim.lsp
.
- base configuration defined for the
*
name - configuration defined in
<rtp>/lsp/<name>.lua
- configuration defined by
vim.lsp.config()
in anywhere else
We cannot explain all of these.
So I think separating explanations of configuration and activation(enabling) can be clear enough.
- explain that you should 1) configure and 2) enable the language server.
- show the single
init.lua
example as that is best for copy-pasting - show that you can put configuration table under
<rtp>/lsp/<name>.lua
.
NOTE: this is not a lua module!! it's a rtp file - link to
:h lsp-config
so that users can learn about this from official document. - put common
lazy.nvim
way to do this
Or remove the part 2 and only show runtimepath (lsp/
folder) way. Because that's also what nvim-lspconfig
is using internally.
So:
... explain that you should configure and enable the server.
Using vim.lsp:
See :h lsp-config
for detailed information.
-- in your `init.lua` file
-- configure ocamllsp
vim.lsp.config('ocamllsp', {
-- ...
})
-- enable ocamllsp
vim.lsp.enable('ocamllsp')
placing ocamllsp configuration in separate file
Instead of calling vim.lsp.config
, you can put ocamllsp configuration table in separate file. Neovim will automatically search for lsp/<name>.lua
or after/lsp/<name>.lua
files and merge them all in single config. (see :h lsp-config
and :h 'runtimepath'
)
-- in `lsp/ocamllsp.lua` (not `lua/lsp/ocamllsp.lua`)
return {
-- ...
}
Now you can enable ocamllsp from your init.lua
vim.lsp.enable('ocamllsp')
... show
lazy.nvim
andnvim-lspconfig
way
You can also use `vim.lsp` with a modular config. | ||
|
||
Assume that your config has the following structure. The internal structure of `lua` does not matter much. | ||
```text | ||
. | ||
├── init.lua | ||
└── lua | ||
├── custom | ||
│ └── plugins | ||
│ └── some-plugin.lua | ||
└── kickstart | ||
├── health.lua | ||
└── plugins | ||
└── some-plugin.lua | ||
``` | ||
|
||
Then run the following at the root of your config. | ||
```text | ||
mkdir lsp | ||
touch lsp/ocamllsp.lua | ||
``` | ||
|
||
We now add our LSP configs to `lsp/ocamllsp.lua`... | ||
```lua | ||
return { | ||
cmd = { 'ocamllsp' }, | ||
filetypes = { 'ocaml', 'ocaml.interface', 'ocaml.menhir', 'reason' }, | ||
root_markers = { { 'dune-project', 'dune-workspace' }, '.git' }, | ||
settings = {}, | ||
} | ||
``` | ||
|
||
...and import them in the toplevel `init.lua`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are missunderstanding lsp/
folder.
It's a runtimepath
file. Read automatically by Neovim on startup. It's not a lua module.
When calling vim.lsp.enable
, we aren't importing it. We've already done configuring by placing the lsp config table in <rtp>/lua/<name>.lua
files or by calling/setting vim.lsp.config
directly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@boltlessengineer this correct, my understanding is he mean to create lsp/
folder in root config. It will get installed to ~/.config/nvim/lsp/ocamllsp.lua
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@boltlessengineer should've been more pedantic about the wording here, mb. What I meant by import was to call require.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think I said to add the lsp configs to lua
? But I can see how giving more context on the config folder structure can be potentially misleading.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm saying that we aren't requiring lsp/ocamllsp.lua
by calling vim.lsp.enable()
.
vim.lsp.config
and vim.lsp.enable
are completely different things.
Both term 'import' and 'require' doesn't fit here.
What vim.lsp.enable
is doing is just: Setup that language server with configured value which is pre-merged vim.lsp.config
table. It isn't about loading & merging configs, but about setting up a required autocmds. (to auto-start language server on filetypes)
When someone wants to configure a server, defining a table in <rtp>/lsp/<name>.lua
is just enough. It will be auto-merged whenever you indexed the vim.lsp.config
like vim.lsp.config['ocamllsp']
check this out:
- write
lsp/ocamllsp.lua
and do nothing else, don't enable it yet - open neovim and run `:=vim.lsp.config['ocamllsp']
- see it already contains the merged config.
-- rest of config... | ||
|
||
-- add this line specifically for OCaml | ||
require('lspconfig').ocamllsp.setup {} |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
@boltlessengineer made more edits, lmk if it looks better. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Except for some nits on wording, all seems good now!
I'm curious if mentioning vim.lsp.start
can help here. Do you think it can help? or is it too much?
#### Modular Config With Runtimepath | ||
|
||
You can also use `vim.lsp` with a modular config via `runtimepath`. Putting your config table inside `lsp/<some_name>.lua` or `after/lsp/<some_name>.lua` will allow Neovim to search for them automatically. | ||
|
||
See `:h runtimepath` for more detail. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The term "modular" might confuse users with typical lua modules. They aren't. Lua modules in Neovim config only lives in lua/
directory and lsp/*.lua
are just plain standalone lua files loaded by neovim directly.
I think "multi-file" can be better for clarity.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if that distinction is strictly necessary 🤔 I think most people understand what a modular config means in general and are more familiar with that term. I've seen lots of modular config out there but not a single multi-file config.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
People don't use runtimepath much for lsp/general config because of historical reasons.
But now they are available and is completely different thing from structuring everything under lua/
directory.
Even though we clearly stated that they should put that file under lsp/
and not lua/lsp/
, I think calling it as a "module" or saying this structure "modular" might confuse users between runtimepath and lua-modules.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@boltlessengineer I'll make the changes and request for another review 👍
``` | ||
|
||
...and import them in the toplevel `init.lua`. | ||
Then enable them in the toplevel `init.lua`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
another nit: Can we explain what vim.lsp.enable()
do here? It will help users understand the difference between configuration and enabling.
Then enable them in the toplevel
init.lua
. This will make Neovim to automatically start the ocamllsp for associated filetypes.
..codeblock..
To start ocamllsp manually, you can usevim.lsp.start
. (see:h vim.lsp.start
):lua vim.lsp.start(vim.lsp.config['ocamllsp'])
Not sure if we want to mention vim.lsp.start
here. I think it can help users to understand what vim.lsp.enable
actually does, but it can be yet another code snippet they should read and understand.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like this is a bit out of scope for the purpose of this doc. I think the curious readers will go out and research this further on their own.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe instead of calling lsp.enable
with just ocamllsp
we could show that you only need to call this once, with a list of languages (OCaml being just one of them), but it is fine as it is too.
Maybe add a link to the official NeoVim LSP docs? https://neovim.io/doc/user/lsp.html
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are already mentioning it. :h lsp-config
should be enough.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
```lua | ||
vim.lsp.config['ocamllsp'] = { | ||
cmd = { 'ocamllsp' }, | ||
filetypes = { 'ocaml', 'ocaml.interface', 'ocaml.menhir', 'reason' }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ocamllsp.lua
from nvim-lspconfig
also adds ocaml.ocamllex
, and dune
to this list, but it does it in an awkward way, the filetype is actually called ocamlinterface
and it gets mapped to ocaml.interface
using get_language_id
.
```lua | ||
return { | ||
cmd = { 'ocamllsp' }, | ||
filetypes = { 'ocaml', 'ocaml.interface', 'ocaml.menhir', 'reason' }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as above, this filetype list could probably be longer
``` | ||
|
||
There is no need to pass more settings to `setup` because `nvim-lspconfig` provides reasonable defaults. See [here](https://github.com/neovim/nvim-lspconfig/blob/master/lsp/ocamllsp.lua) for more info. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we explain about tree-sitter? (with nvim-treesitter
)?
local treesitter_langs = {
'menhir', 'ocaml', 'ocaml_interface', 'ocamllex'
}
require('nvim-treesitter').install(treesitter_langs)
It isn't strictly required, although might help with performance on large files, before the LSP finishes parsing it.
Maybe leave it out for now, I'll do some experiments with using just the LSP, and see how well that works.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good. Let me know if you have more updates 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I figured out how to configure tree-sitter for ocamllex, but it is quite complicated: ocaml/vim-ocaml#61 (comment).
For now I'd leave out tree-sitter from the official docs, until that PR is merged (and an equivalent PR is merged into NeoVim).
The workaround is (fixes both picking the right tree-sitter syntax and the LSP errors):
vim.filetype.add({
extension = {
mll = 'ocamllex',
mly = 'menhir',
mli = 'ocamlinterface'
}
})
followed by the usual tree-sitter config:
local treesitter_langs = {
'menhir', 'ocaml', 'ocaml_interface', 'ocamllex'
}
require('nvim-treesitter').install(treesitter_langs)
(This doesn't require a new release of NeoVim to work, but if your tree-sitter grammar fails to install you'll be without syntax highlighting, so I wouldn't propose it in the official docs, even though I'll start using it myself).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, this is a good start!
We can perhaps have a separate section that shows the more advanced features (inlay hints, etc.), I can try to prepare a separate PR about that.
@edwintorok I went ahead and added more filetypes and root path. Could you take another quick look at it please? I'll leave the settings field empty until you play around with more advanced lsp/merlin features. |
'ocaml', | ||
'ocaml.interface', | ||
'ocaml.menhir', | ||
'ocaml.ocamllex', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one doesn't actually seem to work on NeoVim 0.11.4 and ocamllsp 1.23.0.
ocamllsp says 'unsupported file extension'.
But removing it from this list doesn't work either, because then it falls back to the ocaml
filetype on the .mll
file, and calls ocamllsp
anyway.
The rest seems to work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah ocaml.ocamllex
is to future-proof it for ocaml/vim-ocaml#61 (which isn't merged yet)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#3322 (comment) workaround, but ocaml.ocamllex
is fine as it is in the suggested doc, even though it doesn't work yet.
'dune', | ||
'reason' | ||
}, | ||
root_markers = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice!
I proposed this simplification to the upstream nvim-lspconfig
, which was using a root_dir
function and lspconfig.util
instead (which appears deprecated).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey, thanks for adding this @jpoly1219 and thanks for reviewing @edwintorok, @boltlessengineer, @syaiful6!
Since I haven't used neovim, I can't say anything about the instructions, but it's great to have something to help guide new OCaml users on neovim now!
@sabine glad I could help :) |
Closes #3319 .
Added docs for setting up the LSP server on Neovim.
Add docs for using
nvim-lspconfig
andvim.lsp
. Both methods are frequently used, and it's a good idea to add instructions fornvim-lspconfig
becausevim.lsp
only supports Neovim versions 0.11 and above.