-
-
Notifications
You must be signed in to change notification settings - Fork 6.3k
feat(lsp): utility functions for getting and showing tokens #21373
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
7343b15
to
58d87a2
Compare
a2bca5a
to
5f91c9f
Compare
Changed modifiers to have a higher priority than types. (This will prevent us from applying types and tokens as a single extmark later, although we can still combine all modifiers into a single extmark.) Feedback on whether the priority is needed/wanted @lewis6991 @mfussenegger @bfredl |
It might make sense to only expose one highlight priority for now so we have the option of having a more complicated resolve algorithm down the line when we add the more expressive modifier highlight support. If we keep them as higher priority we shoehorn ourselves into only being able to add highlight attributes to base token type groups without a breaking change then. Makes sense to expose as little as possible now. |
3f5a74f
to
393a8cf
Compare
OK, kept everything at the same priority for now. Let's wait until someone reports an actual problem with this before deciding what to do. |
393a8cf
to
d7230d2
Compare
e8b669f
to
05a719d
Compare
5729f7a
to
dd37376
Compare
d1aa95c
to
1ffdd33
Compare
Can't approve PRs but this LGTM. |
---@param col number|nil Position column (default cursor position) | ||
--- | ||
---@return table[]|nil tokens Table of tokens at position | ||
function M.get_tokens_at_pos(bufnr, row, col) |
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.
What do you think of calling this get
and move the args into an opts
table, treating each option like an additive filter? Similar to diagnostic.get
: get(bufnr, { lnum = ..., col = ... })
(not sure about row vs. lnum, there's afaik already both used)
The tokens
is a bit redundant as it's already in the semantics_token module.
show_tokens_at_cursor
could then be changed to either show(tokens)
or print(tokens)
. I'd tend to print
to mirror vim.pretty_print
. Show has some "special display" behavior in other places (.e.g diagnostic.show
doesn't print diagnostics)
One would need to compose them to print: M.print(M.get())
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.
Hmm, not a fan, I have to admit, but will think about it.
Note that show uses nvim_echo
to style the tokens and not just prints them. It's also meant to be used as an interactive (cursor hold) tool, so I want it to be directly callable. That's the big selling point here.
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.
But I agree that we're in a bit of a bind here, API wise, between diagnostics and treesitter. Personally, I think that treesitter is the closer relative even though as an LSP module there's a relationship to diagnostics.
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.
Setting aside the show
vs. print
question, .get()
seems like a vast improvement over get_tokens_at_pos()
and I strongly prefer that. As @mfussenegger said having tokens
in the function name is repetitive, as is _at_pos()
since we can just use a table argument for the position.
Pre vim.diagnostic
the diagnostic functions were something like vim.lsp.diagnostic.get_line_diagnostics()
which has many of the same issues that we're discussing here. I think we should stick with the get()
pattern which is versatile enough to cover many different use cases.
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.
But should the behavior be changed for that? Or still just return the one token (per server) for a single position?
Because I think there's a fundamental difference here between diagnostics (where what is more fundamental than where) and extmarks (where it's the opposite).
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.
To be clear, the difference to me here is that it might make sense to get all diagnostics, but it doesn't make sense to get all tokens/captures/extmarks.
(As diagnostics are the exception, but highlighting is the rule.)
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.
Absolutely no objection to shortening these to get_at_pos
and show_at_cursor
, though.
useful for debugging; marked private for now
Apply semantic token modifiers as separate extmarks with corresponding highlight groups (e.g., `@readonly`). This is a low-effort PR to enable the most common use cases (applying, e.g., italics or backgrounds on top of type highlights; language-specific fallbacks like `@global.lua` are also available). This can be replaced by more complicated selector-style themes later on.
61449d4
to
fd27aab
Compare
fd27aab
to
b6e8558
Compare
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.
Left another question/suggestion, but also fine as is.
end | ||
|
||
--- Show the semantic token(s) under the cursor | ||
function M.show_at_cursor() |
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.
Would it be worth to keep the tokens
argument and have M.get_at_pos()
as fallback? Would make the function more generally usable. (But I guess the name wouldn't fit that well anymore)
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 quite understand what the signature and the behavior would be? Can you give an example use case (useful for me to see how to best refactor this)?
--- Show the semantic token(s) under the cursor | ||
function M.show_at_cursor() | ||
local tokens = M.get_at_pos() | ||
if not tokens then | ||
return | ||
end |
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.
--- Show the semantic token(s) under the cursor | |
function M.show_at_cursor() | |
local tokens = M.get_at_pos() | |
if not tokens then | |
return | |
end | |
--- Show the semantic token(s) under the cursor | |
---@param tokens table[]|nil tokens to print, defaults to tokens at cursor | |
function M.show(tokens) | |
tokens = tokens or M.get_at_pos() | |
if not tokens then | |
return | |
end |
This is what I had in mind - it would allow to combine it with M.get_at_pos
to print the tokens from another position.
But I don't really have a concrete use-case for it.
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.
Agreed, these "at cursor" functions keep popping up but they really shouldn't. It's easy for callers to provide the cursor position, and taking a position arg is more flexible.
end | ||
msg[#msg + 1] = { ' ' } | ||
end | ||
api.nvim_echo(msg, false, {}) |
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.
what is the difference between "show", "echo", "print", and for some reason "vim.notify"?
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.
vim.notify
is an interface which plugins can use to implement fancy ui's for notifications. See https://github.com/rcarriga/nvim-notify.
Not sure myself on the difference between show
, echo
and print
.
Yes for sure. I was hoping to have the |
@clason thanks. Added the commit |
Added two utility functions:
get_at_pos(bufnr, row, col)
: returns a table of tokens (to account for possibly multiple servers); defaults to cursor position if called with empty argumentsshow_at_cursor()
: prints the styled token type and modifiers (using above function)This is consistent with similar
vim.treesitter
functions (see feat(treesitter)!: consolidateget_{node,captures}
functions #21374).(Originally done while adding simple implementation of token modifiers, but that was split off to #21390 so it won't get blocked by the API discussion here.)