-
-
Notifications
You must be signed in to change notification settings - Fork 284
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: Support goToDefinition from a Go file to a templ file #387
Comments
Yes, that would be much more useful! If you're in a templ/cmd/templ/lspcmd/proxy/server.go Lines 507 to 512 in c674f64
But currently, if you start from a It may also possible for the templ LSP to capture |
I know you can have multiple LSPs attached to a file, but I wonder what would happen if you had 2 trying to respond to a jump to definition request. |
I asked the gopls maintainers. Maybe they know a hook which templ could implement: golang/go#65001 |
We have the following issue to implement the line directive #415, and then I think it's a case of closing this ticket and helping the gopls team implement golang/go#65001 |
@joerdav thank you for your work! This is great! |
Thank @af-md ! |
Here's a quick and dirty fix for anyone using neovim. It doesn't go directly to the location of the definition in the file, but at least it opens the correct file. local go_to_definition = function()
if vim.bo.filetype == "go" then
vim.lsp.buf.definition({
on_list = function(options)
if options == nil or options.items == nil or #options.items == 0 then
return
end
local targetFile = options.items[1].filename
local prefix = string.match(targetFile, "(.-)_templ%.go$")
if prefix then
options.items[1].filename = prefix .. ".templ"
end
vim.fn.setqflist({}, ' ', options)
vim.api.nvim_command('cfirst')
end
})
else
vim.lsp.buf.definition()
end
end and then in your key map vim.keymap.set("n", "gd", go_to_definition) Note that the check for being in a go buffer will run every time you try to go to definition. You probably would want to add this modification only if you are using templ a lot and should remember to remove it once the actual fix is implemented. |
does anyone have a workaround in vscode? its not a big deal but a little annoying. |
Quick and dirty addition to @meistertigran's quick and dirty fix, this'll attempt to search for the the line in the templ file local go_to_definition = function()
if vim.bo.filetype == "go" then
vim.lsp.buf.definition({
on_list = function(options)
if options == nil or options.items == nil or #options.items == 0 then
return
end
local targetFile = options.items[1].filename
local prefix = string.match(targetFile, "(.-)_templ%.go$")
if prefix then
local function_name = vim.fn.expand('<cword>')
options.items[1].filename = prefix .. ".templ"
vim.fn.setqflist({}, ' ', options)
vim.api.nvim_command('cfirst')
vim.api.nvim_command('silent! /templ ' .. function_name)
else
vim.lsp.buf.definition()
end
end
})
else
vim.lsp.buf.definition()
end
end |
In Neovim I use Telescope. This works decent enough for me... I might change it since I'm annoyed that the telescope window pops up for a few ms. vim.keymap.set('n', '<leader>gm', function()
local ts_utils = require 'nvim-treesitter.ts_utils'
local node = ts_utils.get_node_at_cursor()
if node == nil then
return
end
if vim.bo.filetype == "go" then
if node:parent():type() == "call_expression" then
local funcName = vim.fn.expand("<cword>")
require("telescope.builtin").live_grep {
default_text = 'templ ' .. funcName .. "\\(",
glob_pattern = '*.templ',
on_complete = {
function(picker)
if picker.manager.linked_states.size == 1 then
require("telescope.actions").select_default(picker.prompt_bufnr)
end
end
}
}
end
end
end), |
Given that the line compiler directive MR has been closed, is there any work being done to address this / new ideas on how this could be tackled properly? In the meantime for VSCode users, I have quickly created a very small extension (with the help of ChatGPT) to redirect definitions in |
My approach is to override local function go_goto_def()
local old = vim.lsp.buf.definition
local opts = {
on_list = function(options)
if options == nil or options.items == nil or #options.items == 0 then
return
end
local targetFile = options.items[1].filename
local prefix = string.match(targetFile, "(.-)_templ%.go$")
if prefix then
local function_name = vim.fn.expand("<cword>")
options.items[1].filename = prefix .. ".templ"
vim.fn.setqflist({}, " ", options)
vim.api.nvim_command("cfirst")
vim.api.nvim_command("silent! /templ " .. function_name)
else
old()
end
end,
}
vim.lsp.buf.definition = function(o)
o = o or {}
o = vim.tbl_extend("keep", o, opts)
old(o)
end
end
vim.api.nvim_create_autocmd("LspAttach", {
group = vim.api.nvim_create_augroup("UserLspConfig", {}),
callback = function(event)
local bufopts = { noremap = true, silent = true, buffer = event.buf }
if vim.bo.filetype == "go" then
go_goto_def()
end
vim.keymap.set, ("n", "gd", vim.lsp.buf.definition, bufopts)
end
} |
https://github.com/catgoose/templ-goto-definition I made this plugin if it makes it easier for anyone. |
I am looking into a different approach. I think it might be easier (and more useful for other tools) to extend your editor to be able to respond to multiple textDocument/definition providers. If a single LSP responds with multiple places (such as typescript showing both the react component and local pickers = require("telescope.pickers")
local finders = require("telescope.finders")
local conf = require("telescope.config").values
local actions = require("telescope.actions")
local action_state = require("telescope.actions.state")
local locations = {}
local params = vim.lsp.util.make_position_params()
local results_lsp = {}
local results = {}
local timeout = 1000 -- ms
for _, client in pairs(vim.lsp.get_active_clients()) do
if client.server_capabilities.definitionProvider then
local request_result =
client.request_sync("textDocument/definition", params, timeout, vim.api.nvim_get_current_buf())
if request_result and request_result.result then
table.insert(results_lsp, request_result.result)
end
end
end
for _, lsp_result in ipairs(results_lsp) do
if lsp_result then
vim.list_extend(results, lsp_result)
end
end
for _, result in ipairs(results) do
if result.targetUri then
table.insert(locations, {
filename = vim.uri_to_fname(result.targetUri),
lnum = result.targetRange.start.line + 1,
col = result.targetRange.start.character + 1,
text = "Definition",
})
elseif result.uri then
table.insert(locations, {
filename = vim.uri_to_fname(result.uri),
lnum = result.range.start.line + 1,
col = result.range.start.character + 1,
text = "Definition",
})
end
end
pickers
.new({}, {
prompt_title = "LSP Definitions",
finder = finders.new_table({
results = locations,
entry_maker = function(entry)
return {
value = entry,
display = entry.filename .. ":" .. entry.lnum .. ":" .. entry.col .. " " .. entry.text,
ordinal = entry.filename .. " " .. entry.lnum .. " " .. entry.col .. " " .. entry.text,
filename = entry.filename,
lnum = entry.lnum,
col = entry.col,
}
end,
}),
sorter = conf.generic_sorter({}),
attach_mappings = function(prompt_bufnr, map)
actions.select_default:replace(function()
actions.close(prompt_bufnr)
local selection = action_state.get_selected_entry()
vim.api.nvim_command("edit " .. selection.filename)
vim.api.nvim_win_set_cursor(0, { selection.lnum, selection.col - 1 })
end)
return true
end,
})
:find() |
But when would you ever want the generated go from a templ file? It should
just take you to the templ definition and not the go file.
I made a plug-in like that for vue:
https://github.com/catgoose/vue-goto-definition.nvim
And one for templ:
https://github.com/catgoose/templ-goto-definition
I know a choice is good, but I prefer to just gd and be where I need to go.
…On Fri, Sep 13, 2024 at 7:35 PM Alex Ott ***@***.***> wrote:
I am looking into a different approach. I think it might be easier (and
more useful for other tools) to extend your editor to be able to respond to
multiple textDocument/definition providers. If a single LSP responds with
multiple places (such as typescript showing both the react component and
memoed component), it will put them in a list where you can select
between them. Here is a very basic lua script for collecting all the
responses from definition requests. you can run it with :luafile
<file>.lua in neovim (same thing as pressing gd)
local pickers = require("telescope.pickers")local finders = require("telescope.finders")local conf = require("telescope.config").valueslocal actions = require("telescope.actions")local action_state = require("telescope.actions.state")
local locations = {}
local params = vim.lsp.util.make_position_params()local results_lsp = {}local results = {}local timeout = 1000 -- ms
for _, client in pairs(vim.lsp.get_active_clients()) do
if client.server_capabilities.definitionProvider then
local request_result =
client.request_sync("textDocument/definition", params, timeout, vim.api.nvim_get_current_buf())
if request_result and request_result.result then
table.insert(results_lsp, request_result.result)
end
endend
for _, lsp_result in ipairs(results_lsp) do
if lsp_result then
vim.list_extend(results, lsp_result)
endend
for _, result in ipairs(results) do
if result.targetUri then
table.insert(locations, {
filename = vim.uri_to_fname(result.targetUri),
lnum = result.targetRange.start.line + 1,
col = result.targetRange.start.character + 1,
text = "Definition",
})
elseif result.uri then
table.insert(locations, {
filename = vim.uri_to_fname(result.uri),
lnum = result.range.start.line + 1,
col = result.range.start.character + 1,
text = "Definition",
})
endend
pickers
.new({}, {
prompt_title = "LSP Definitions",
finder = finders.new_table({
results = locations,
entry_maker = function(entry)
return {
value = entry,
display = entry.filename .. ":" .. entry.lnum .. ":" .. entry.col .. " " .. entry.text,
ordinal = entry.filename .. " " .. entry.lnum .. " " .. entry.col .. " " .. entry.text,
filename = entry.filename,
lnum = entry.lnum,
col = entry.col,
}
end,
}),
sorter = conf.generic_sorter({}),
attach_mappings = function(prompt_bufnr, map)
actions.select_default:replace(function()
actions.close(prompt_bufnr)
local selection = action_state.get_selected_entry()
vim.api.nvim_command("edit " .. selection.filename)
vim.api.nvim_win_set_cursor(0, { selection.lnum, selection.col - 1 })
end)
return true
end,
})
:find()
—
Reply to this email directly, view it on GitHub
<#387 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/AFAJNGFO2BRCXPW5KC37L5LZWOAGDAVCNFSM6AAAAABBKOZJ7CVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDGNJQG42DEMRUGU>
.
You are receiving this because you commented.Message ID:
***@***.***>
|
I'm making an LSP that can jump from generated typescript http functions to the respective api route in go (inspired by how in https://trpc.io/ you can see type errors quickly when you make changes) and thought it was a similar use case. I do agree that in this specific case, you probably wouldn't want to jump to the generated code, but it seemed like a similar problem. |
Another vscode extension, this one nests definition providers and jumps to the templ definition if it finds one. https://marketplace.visualstudio.com/items?itemName=lsl.vscode-templ-go-to-definition https://github.com/lsl/vscode-templ-go-to-definition
|
I use helix. And it only depends on lsp. So how to implement this line option with templ and go lsp ? @joerdav |
I saw your comment in #476 @noor-tg I think the answer will be to run templ lsp on go files. I've been playing around with it to see if that's viable. At the moment the behaviour is odd, a goToDefinition request is handled by both templ lsp and gopls, so you end up with 2 new files open! I imagine there would be similar cases for other LSP actions, but I think this will be the answer. Does helix support assigning multiple lsps to a file? |
Yes helix support multiple lsp to file type |
But when I add templ lsp last it use golsp and go to generated file. And if I set it first, it shows error def not found |
Yes, currently templ lsp rejects gotodefenition requests from anything but templ files. templ/cmd/templ/lspcmd/proxy/server.go Line 619 in 9b77eee
I had to remove this in my local version to get this working, but I think there is more testing to be done to ensure running on go files doesn't have other odd effects. |
I used the same . and it working correctly. thanks @joerdav |
@AlexanderHott any link to the mentioned project ? |
It's on the back burner right now, and not very done. My team paused our migration to a go backend, but when that picks up again, I think I'll start working on it. https://github.com/AlexanderHOtt/longjump |
For any LazyVim users who could not get catgoose's plugin to work, here's a solution that works for me. Put the following in lua/plugins/lsp.lua:
|
If I ctrl-click on
page()
then ...then I get to the autogenerated Go code:
It would be great if I could get to the templ-file instead:
The text was updated successfully, but these errors were encountered: