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

feat: implement Move to file code action #224

Merged
merged 6 commits into from
Nov 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lua/typescript-tools/capabilities.lua
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ local function make_capabilities()
c.InternalCommands.CallApiFunction,
c.InternalCommands.RequestReferences,
c.InternalCommands.RequestImplementations,
c.InternalCommands.InteractiveCodeAction,
},
},
renameProvider = {
Expand Down
41 changes: 41 additions & 0 deletions lua/typescript-tools/integrations.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
local M = {}

---@param picker function
---@param callback fun(err: boolean|nil, file: string?)
function M.telescope_picker(picker, callback)
local ok, actions = pcall(require, "telescope.actions")

if not ok then
vim.notify("Telescope need to be installed to call this integration", vim.log.levels.WARN)
callback(true, nil)
return
end

local action_state = require "telescope.actions.state"
picker = picker or require("telescope.builtin").find_files

picker {
attach_mappings = function(prompt_bufnr)
local selected = nil

actions.select_default:replace(function()
local selection = action_state.get_selected_entry()
selected = true

if selection then
selected = vim.fs.joinpath(vim.loop.cwd(), selection.value)
end

actions.close(prompt_bufnr)
end)
actions.close:enhance {
post = function()
callback(nil, selected)
end,
}
return true
end,
}
end

return M
42 changes: 42 additions & 0 deletions lua/typescript-tools/internal_commands.lua
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
local api = vim.api
local a = require "plenary.async"

local c = require "typescript-tools.protocol.constants"
local plugin_api = require "typescript-tools.api"
local async = require "typescript-tools.async"
local integrations = require "typescript-tools.integrations"

local M = {}

Expand Down Expand Up @@ -57,4 +60,43 @@ M[c.InternalCommands.RequestImplementations] = function(params)
vim.lsp.buf_request(0, c.LspMethods.Implementation, params.arguments)
end

M[c.InternalCommands.InteractiveCodeAction] = function(params)
local request = unpack(params.arguments)
a.void(function()
---@type string|boolean|nil
local target_file

local telescope_err, file = a.wrap(integrations.telescope_picker, 2)()

if telescope_err then
target_file = async.ui_input { prompt = "Move to file: " }
else
target_file = file
end

if target_file == nil or not vim.fn.filereadable(target_file) then
vim.notify("This refactor require existing file", vim.log.levels.WARN)
return
end

local err, result = async.buf_request_isomorphic(
false,
0,
c.LspMethods.CodeActionResolve,
vim.tbl_deep_extend(
"force",
request,
{ data = { interactiveRefactorArguments = { targetFile = target_file } } }
)
)

if err or not result or not result.edit or (result.edit and vim.tbl_isempty(result.edit)) then
vim.notify("No refactors available", vim.log.levels.WARN)
return
end

vim.lsp.util.apply_workspace_edit(result.edit, "utf-16")
end)()
end

return M
1 change: 1 addition & 0 deletions lua/typescript-tools/protocol/constants.lua
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ return {
CallApiFunction = "call_api_function",
RequestReferences = "request_references",
RequestImplementations = "request_implementations",
InteractiveCodeAction = "interactive_codeaction",
},
---@enum CommandTypes
CommandTypes = {
Expand Down
30 changes: 25 additions & 5 deletions lua/typescript-tools/protocol/text_document/code_action/init.lua
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
local TsserverProvider = require "typescript-tools.tsserver_provider"
local proto_utils = require "typescript-tools.protocol.utils"
local c = require "typescript-tools.protocol.constants"
local utils = require "typescript-tools.protocol.utils"
local plugin_config = require "typescript-tools.config"
local utils = require "typescript-tools.utils"

local M = {}

local ALL_CODE_ACTIONS_KEY = "all"

local interactive_codeactions = {
"Move to file",
}
utils.add_reverse_lookup(interactive_codeactions)

local internal_commands_map = {
fix_all = { name = "Fix all problems" },
remove_unused = { name = "Remove unused" },
Expand Down Expand Up @@ -33,16 +40,19 @@ end

---@type TsserverProtocolHandler
function M.handler(request, response, params, ctx)
local tsserver_provider = TsserverProvider.get_instance()
local version = tsserver_provider:get_version()
local text_document = params.textDocument

local range = utils.convert_lsp_range_to_tsserver(params.range)
local range = proto_utils.convert_lsp_range_to_tsserver(params.range)

local request_range = {
file = vim.uri_to_fname(text_document.uri),
startLine = range.start.line,
startOffset = range.start.offset,
endLine = range["end"].line,
endOffset = range["end"].offset,
includeInteractiveActions = utils.version_compare("gt", version, { 5, 1 }),
}

ctx.dependent_seq = {
Expand Down Expand Up @@ -74,15 +84,25 @@ function M.handler(request, response, params, ctx)
local kind = make_lsp_code_action_kind(action.kind or "")

if kind and not action.notApplicableReason then
table.insert(code_actions, {
local code_action = {
title = action.description,
kind = kind,
data = vim.tbl_extend("force", request_range, {
action = action.name,
kind = kind,
refactor = refactor.name,
}),
})
}

code_action.command = interactive_codeactions[action.description]
and {
title = action.description,
command = c.InternalCommands.InteractiveCodeAction,
arguments = { vim.tbl_deep_extend("force", {}, code_action) },
}
or nil

table.insert(code_actions, code_action)
end
end
end
Expand All @@ -96,7 +116,7 @@ function M.handler(request, response, params, ctx)
title = fix.description,
kind = c.CodeActionKind.QuickFix,
edit = {
changes = utils.convert_tsserver_edits_to_lsp(fix.changes),
changes = proto_utils.convert_tsserver_edits_to_lsp(fix.changes),
},
})
end
Expand Down
6 changes: 4 additions & 2 deletions tests/requests_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -541,9 +541,11 @@ describe("Lsp request", function()
assert.is.same(result[1].title, "Infer function return type")
assert.is.same(result[2].title, "Remove variable statement")
elseif version and v.gt(version, { 5, 1 }) then
assert.is.same(2, #result)
print(vim.inspect(result))
assert.is.same(3, #result)
assert.is.same(result[1].title, "Move to a new file")
assert.is.same(result[2].title, "Remove variable statement")
assert.is.same(result[2].title, "Move to file")
assert.is.same(result[3].title, "Remove variable statement")
else
assert.is.same(1, #result)
assert.is.same(result[1].title, "Remove variable statement")
Expand Down
Loading