Skip to content
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

LSP: configure inlay hint visualization position #28261

Closed
PPakalns opened this issue Apr 10, 2024 · 27 comments
Closed

LSP: configure inlay hint visualization position #28261

PPakalns opened this issue Apr 10, 2024 · 27 comments
Labels
display redraw, layout, presentation enhancement feature request lsp status:blocked-external Needs a third-party / external change or fix
Milestone

Comments

@PPakalns
Copy link

Problem

With neovim 0.10 support for inlay hints were added and plugin ecosystem is switching to use inbuilt inlay hints. These inlay hints are visualized in middle of lines, which takes up a lot of visual space and displaces editable text.

Before plugins mainly attempted to visualize them at the end of the line where inlay hints are located.

Post that showcases the difference visually (https://vinnymeller.com/posts/neovim_nightly_inlay_hints/) (No inlay hints, plugin supported inlay hints at the end of line, neovim 0.10 behaviour in middle of lines)

Example discussion where plugin has removed support for inlay hints and are redirecting all questions to neovim (mrcjkb/rustaceanvim#46 (comment))

Expected behavior

A configuration option to switch between inlay hint visualization position (inline or at the end of line)

@PPakalns PPakalns added the enhancement feature request label Apr 10, 2024
@zeertzjq zeertzjq added the lsp label Apr 10, 2024
@GitMurf
Copy link

GitMurf commented Apr 14, 2024

I would love this for my TypeScript development. See here for a common problem with typescript (lots of inlay hints and long ones) and moving them to the end of line would help a lot IMO: #27240

@MariaSolOs
Copy link
Member

Hmmm I understand (and support) this issue, yet I don't think it should be filed here.

The thing is that the LSP says that the server indicates the position of the inlay hint (ref). If I understand this request correctly, the position of the inlay hint will depend on the user's preference, so it would be something included in the server's response (yet of course part of an editor setting).

All of this is to say: Yes, I think this is a valid ask, but let's take the discussion to https://github.com/microsoft/language-server-protocol.

@GitMurf
Copy link

GitMurf commented Apr 14, 2024

The thing is that the LSP says that the server indicates the position of the inlay hint (ref)

Ahhh good point.

And for some languages it probably is fine but I know for typescript it is more of a problem. But even with typescript, it really is just a problem with type annotations for variables as function parameter wouldn't really make sense at end of line and are not as disruptive. But the long typescript types / interfaces are the main problem IMHO.

@PPakalns
Copy link
Author

Hmmm I understand (and support) this issue, yet I don't think it should be filed here.

The thing is that the LSP says that the server indicates the position of the inlay hint (ref). If I understand this request correctly, the position of the inlay hint will depend on the user's preference, so it would be something included in the server's response (yet of course part of an editor setting).

All of this is to say: Yes, I think this is a valid ask, but let's take the discussion to https://github.com/microsoft/language-server-protocol.

In neovim this is a lot larger problem due to inlay hints having the same font size, taking up the same space as normal text. In other IDE inlay hints have smaller font size.

I don't think this is a LSP problem, because it is correctly reporting the position of the code/variable/function that needs to be hinted about and how it needs to be processed. It will be very hard to change the protocol to support two wildly different visualization ways.

This is more about how the inlay hint response content is processed and visualized in the editor, all necessary information already is there. As terminals can not support text with different font sizes, it is reasonable for there to be another visualization method to make inlay hints more usable in neovim.

@justinmk justinmk changed the title Add option to choose inlay hint visualization position LSP: configure inlay hint visualization position Apr 14, 2024
@justinmk justinmk added this to the unplanned milestone Apr 14, 2024
@justinmk justinmk added the status:blocked-external Needs a third-party / external change or fix label Apr 14, 2024
@JustLinuxUser
Copy link

I agree that current lsp spec is not made for this, and does not support this feature. However, the support of this feature does not require any additional work from the lsp servers, and is just an unintended way of visualizing the output of the lsp server. rust-tools.nvim only used textDocument/inlayHint to implement this feature, because the lsp protocol does give the clients enough information about hints to make it work.

It doesn't matter that this is not in a protocol, because nothing is needed from the protocol to support it, and it only requires a subset of information currently guaranteed by the protocol

@GitMurf
Copy link

GitMurf commented Apr 16, 2024

It doesn't matter that this is not in a protocol, because nothing is needed from the protocol to support it, and it only requires a subset of information currently guaranteed by the protocol

So is your point that the LSP gives the data and then the client (neovim) can take that data and "transform" it for usage as it seems fit? In other words, LSP is doing its job to provide the superset of data and then a client can decide how to use the whole thing, or a subset of the data. But if the LSP instead transformed the data or made the decision on moving the inlay hints to a different position, all clients would be at the mercy of the LSP decision. Is this your overall point?

I see both sides 🤔 I have a feeling that means the unfortunate solution is going to be someone needing to create a Plugin to implement this behavior.

@justinmk justinmk added the display redraw, layout, presentation label Apr 16, 2024
@JustLinuxUser
Copy link

I have never coded much in lua, or created a plugin, but I will try porting the old rust-tools'es code to make it work as a standalone plugin

@JustLinuxUser
Copy link

JustLinuxUser commented Apr 16, 2024

But if the LSP instead transformed the data or made the decision on moving the inlay hints to a different position, all clients would be at the mercy of the LSP decision. Is this your overall point?

I don't see a possibility of lsp moving that information or position, and if it does, it will break compatibility with all lsp clients that support inlay hints anyway, so breaking this particular styling of it doesn't seem like a big deal, if normal hints would break too

@JustLinuxUser

This comment was marked as off-topic.

@GitMurf

This comment was marked as off-topic.

@lvimuser
Copy link
Contributor

@GitMurf @JustLinuxUser see https://github.com/lvimuser/lsp-inlayhints.nvim. disclaimer: not maintained, core implementation is better/cleaner

@JustLinuxUser

This comment was marked as outdated.

@andrevmatos
Copy link

andrevmatos commented May 24, 2024

It'd also be very useful to have an option in nvim itself to show inlay hints only for current line (maybe after some debounce delay). This is supported by lsp-inlayhints/anticonceal branch, but native always shows for all lines, which can be quite overwhelming. Some LSP servers support this config, but it'd be nice to have this done in neovim for a global option.

Edit: came up with a hacky solution based on @MariaSolOs 's code, if it's of use to anyone:

-- somewhere in config.lua
local methods = vim.lsp.protocol.Methods
local inlay_hint_handler = vim.lsp.handlers[methods["textDocument_inlayHint"]]
vim.lsp.handlers[methods["textDocument_inlayHint"]] = function(err, result, ctx, config)
  local client = vim.lsp.get_client_by_id(ctx.client_id)
  if client then
    local row, col = unpack(vim.api.nvim_win_get_cursor(0))
    result = vim.iter(result)
      :filter(function(hint)
        return hint.position.line + 1 == row
      end)
      :totable()
  end
  inlay_hint_handler(err, result, ctx, config)
end

-- onAttach
local inlay_hints_group = vim.api.nvim_create_augroup('LSP_inlayHints', { clear = false })
vim.api.nvim_create_autocmd({'CursorHold', 'CursorHoldI'}, {
  group = inlay_hints_group,
  desc = 'Update inlay hints on line change',
  buffer = bufnr,
  callback = function()
    vim.lsp.inlay_hint.enable(true, {bufnr = bufnr})
  end,
})

@polak-jan
Copy link
Sponsor

While in theory LSPs are the ones that should dictate the position, one of the main reasons people flock to Neovim is the ability to customize everything. And this particular feature is something many people dislike in other editors/IDEs. So it would be a shame if Neovim refused to implement the option just because it's "not supposed to".

@MariaSolOs
Copy link
Member

@polak-jan It's not about "not being supposed to", but because in order for things not to be a total mess Neovim tries to stick to the LSP as much as possible, avoiding non-documented behaviors like this.

Inlay hints can also be "interactive" (execute commands when clicking them, show a floating window when hovering over them, etc). Although Neovim doesn't support such features today, changing the position that the server sent could break this functionality (if we add it) in the future.

@polak-jan
Copy link
Sponsor

polak-jan commented May 27, 2024

The issue for people like me, who dislike the feature enough to never use it, is that we will now be losing out on a sizable chunk of the ecosystem that we had before, as they phase out the "hacked version" of showing it at the end of the line that we preferred.

I also don't understand how changing the position could break any additional functionality. The only thing it would do is move the actions away from the text they are affecting.

@Andrew15-5
Copy link
Contributor

Andrew15-5 commented May 27, 2024

Although Neovim doesn't support such features today, changing the position that the server sent could break this functionality (if we add it) in the future.

Since it's a cosmetic/visualization change, the underlying position of the hints and other data should be preserved and not changed. This way, nothing should break.


I just found out that ray-x/go.nvim actually has the setting to change between "inlay" and "eol". I tried it today, and it looks like the eol breaks after first edit, but works on the strartup. I honestly didn't even notice that they didn't work, although I didn't code anything big.

I don't want to tug in ThePrimeagen here (and here I am), but we both agree on the fact that "inline" hints are not great, as you have to suddenly jump left and right when you don't do that ever just by pressing l/h (without inlay hints enabled). It greatly disturbs the coding flow. Yet the feature itself is great (when at eol). Really want this feature to be implemented.

@clason
Copy link
Member

clason commented May 27, 2024

Look, the reasoning here is quite simple: We cannot add configuration options for every single thing ("but mom, I just want this single thing!" -- yes, but other people want different single things, and why is yours special?) because the code -- and the configuration, which people already complain about! -- will become a giant mess. So Neovim opted for a simple policy that is a) objective and b) easy to explain: Out of the box, we implement the specification and nothing but the specification -- but we do it in a way that is as easily extensible as possible. This means that you can absolutely have end-of-line hints -- if you override the handler, or install a plugin that does it for you. If that is not good enough for you, lobby Microsoft to include "end-of-line hints" in the spec, ideally with a well thought-through proposal how the feature should behave in all relevant aspects. Then we'll add support for it. But we will not change the fundamental policy, which has served us very well so far.

@Andrew15-5
Copy link
Contributor

But mo-o-om! /j

It's great if this is totally hackable through the Lua API. Then there will definitely be a solution whether it's a native one or via plugin.

P.S. I will say that it is sad that Neovim has to adapt to how exactly things are done in VS Code because everything is controlled by Microsoft (editor, protocol etc.) I would be very surprised and happy if such addition to the protocol can and will be added in the future.

@clason
Copy link
Member

clason commented May 27, 2024

I will say that it is sad that Neovim has to adapt to how exactly things are done in VS Code because everything is controlled by Microsoft (editor, protocol etc.)

But that's precisely the point here: we are not doing "how exactly things are done in VS Code" and instead stick to the specs in order to force people to take it seriously. The specification is intended to be editor-independent, but any changes have to be driven by a reference editor implementation. That implementation can absolutely be in Neovim.

Still, it's important to observe the proper procedure:

  1. Propose an addition to the specification.
  2. Discuss and come up with a reasonable and acceptable proposal.
  3. Provide a reference implementation of that proposal as a PR to Neovim.
  4. Get the spec change merged.
  5. Get the Neovim PR merged (if necessary, after adaptation to the final version of the spec).

@Andrew15-5
Copy link
Contributor

The specification is intended to be editor-independent, but any changes have to be driven by a reference editor implementation. That implementation can absolutely be in Neovim.

Interesting. I haven't touched LSP personally so this is something new. Can you explain what is the exact purpose of any changes being driven by a reference editor implementation? To prove that it's actually possible to implement the functionality?

Now I'm curious how does the pie chart look like with the amount of changes per (reference) editor (implementation). I would still bet that Neovim and others will get only a tiny portion (naturally?)

Anyway, I'm plenty busy and not well versed with proposals. Hope that someone else will start the ball rolling.

@ofseed
Copy link
Contributor

ofseed commented May 27, 2024

I agree that overriding the handler is a good idea because it only takes dozens of lines of code to implement this feature through overriding (in fact I thought of this method when this issue was created). But currently, it's not possible to expose the handler, because the handler needs to access private variables to implement its function. This cannot be done by just exposing these variables, because the implementation of these variables itself is not stable (that is to say, we cannot expose an unstable API), see #28543 (comment) and #28748.

I may implement this once the implementation of these variables is thoroughly determined.

@ofseed
Copy link
Contributor

ofseed commented May 27, 2024

btw, I also disagree with officially providing inlay hints at the end of the line and then providing them through configuration, because the implementation is too subjective. For example, what symbols do we need to use to identify types and parameters? How many spaces are there at the end of lines in these inlay hints? This requires too many meaningless configuration items to be added to the codebase. Implementing through overriding can avoid all problems.

@polak-jan
Copy link
Sponsor

Agreed. I wasn't really advocating for a specific "move inlay hints to the end" feature. More for some way to solve it. And allowing us to override a function that decides the position of the a hint would be perfect IMO.

@adiSuper94
Copy link

adiSuper94 commented May 31, 2024

It will be nice to have the ability to choose between eol and inlay option per language.
I like the way inlay is shown in go and rust. But for ts/js it gets too unwieldy.

The thing is that the LSP says that the server indicates the position of the inlay hint (ref). If I understand this request correctly, the position of the inlay hint will depend on the user's preference, so it would be something included in the server's response (yet of course part of an editor setting).

@MariaSolOs how do I check what the lsp-server returns for inlayHints.position? It might be worth checking if sticking to the current spec actually can fix the problem.

ragu-manjegowda added a commit to ragu-manjegowda/config that referenced this issue May 31, 2024
This reverts commit 249b333.

Sticking to plugin until neovim/neovim#28261
resolved.

Signed-off-by: Ragu Manjegowda <raghavendrahm0410@gmail.com>
@aniketfuryrocks

This comment was marked as off-topic.

@clason
Copy link
Member

clason commented Jun 27, 2024

Resolution

The LSP specification is unambiguous about inlay hints having a specified position where they should appear (even declaring where multiple hints with the same position should be rendered). So a Neovim option is out of the question. If "end-of-line hints" are added to the spec, we'll implement them as well.

Of course, it's always possible to override the textDocument/inlayHint in your config or a plugin, but for the core implementation this is out of scope.

@clason clason closed this as not planned Won't fix, can't repro, duplicate, stale Jun 27, 2024
@neovim neovim locked as resolved and limited conversation to collaborators Jun 27, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
display redraw, layout, presentation enhancement feature request lsp status:blocked-external Needs a third-party / external change or fix
Projects
None yet
Development

No branches or pull requests