Skip to content

Commit

Permalink
feat: LSP rename converts next word if located in a non word character (
Browse files Browse the repository at this point in the history
  • Loading branch information
johmsalas authored Dec 15, 2023
1 parent 68a0a58 commit 2567488
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 2 deletions.
4 changes: 3 additions & 1 deletion lua/textcase/plugin/conversion.lua
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,10 @@ function M.do_lsp_rename(method)
"method textDocument/rename is not supported by any of the servers registered for the current buffer"
)
else
local current_word = vim.fn.expand("<cword>")
local current_word_info = utils.get_current_word_info()
local current_word = current_word_info.word
local params = lsp.util.make_position_params()
params.position = current_word_info.position
params.newName = method(current_word)

lsp.buf_request_all(0, "textDocument/rename", params, function(results)
Expand Down
26 changes: 26 additions & 0 deletions lua/textcase/shared/utils.lua
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,32 @@ function utils.trim_str(str, _trimmable_chars)
return trim_info, trimmed_str
end

-- Gets the position and text of the current word under the cursor
-- If the cursor is located on a word it returns information about that word
-- If the cursor is not on a word, it returns information about the next word
-- The method could have some validation when there is no word to be returned
-- not required at the moment
-- One of the cases where this method is useful is on LSP rename,
-- If there cursor is not on a word, TextDocument/rename acts on the previous
-- word, while vim.fn.expand returns information about the following word
-- By using this method the plugin has a way of referring to the same word
function utils.get_current_word_info()
local cursor_pos = vim.fn.getpos(".")
-- This could be customized to read exactly the word under the cursor, ignoring
-- close words, or even considering words before the cursor. Consult values like Wn and Wb
local start_the_search_at_cursor_position = "W"
local word = "\\w"
local current_word_pos = vim.fn.searchpos(word, start_the_search_at_cursor_position)
vim.fn.setpos(".", cursor_pos)

local line = current_word_pos[1] - 1
local character = current_word_pos[2]

local position = { line = line, character = character }

return { position = position, word = vim.fn.expand("<cword>") }
end

function utils.get_list(str, mode)
local limit = 0
local initial = nil
Expand Down
17 changes: 17 additions & 0 deletions tests/test_helpers.lua
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,21 @@ M.wait_for_language_server_to_start = function()
end)
end

-- This method duplicates wait_for_language_server_to_start for
-- the destructuring file. Using Write Everything Twice and
-- avoiding to come up with a wrong abstraction too early
M.wait_for_language_server_to_start_on_destructuring_file = function()
M.execute_keys("ww") -- Move to `foovar`
local hover = ""
M.wait_for(30 * 1000, function()
-- This prints one "Error detected while processing command line:" but this can be ignored
vim.lsp.buf_request_all(0, "textDocument/hover", vim.lsp.util.make_position_params(), function(results)
-- Hover will print the type definition of the variable under the cursor. Hence,
-- it should contain "fooVar".
hover = results[1].result.contents.value
end)
return string.find(hover, "fooVar")
end)
end

return M
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
const [fooVar, BAR_VAR] = [0, 1]
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
const [FOO_VAR, barVar] = [0, 1]
1 change: 1 addition & 0 deletions tests/textcase/lsp/fixtures/destructuring.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
const [fooVar, barVar] = [0, 1]
60 changes: 59 additions & 1 deletion tests/textcase/lsp/lsp_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ local test_helpers = require("tests.test_helpers")
local textcase = require("textcase")

describe("LSP", function()
describe("Rename", function()
describe("Rename case conversion", function()
before_each(function()
textcase.setup({})

Expand Down Expand Up @@ -45,4 +45,62 @@ describe("LSP", function()
assert.are.same(table.concat(content, "\n"), expected_code)
end)
end)

describe("Renaming according to cursor position", function()
before_each(function()
textcase.setup({})

local path = "./tests/textcase/lsp/fixtures/destructuring.ts"
local cmd = " silent exe 'e " .. path .. "'"
vim.cmd(cmd)
vim.bo.filetype = "typescript"

test_helpers.wait_for_language_server_to_start_on_destructuring_file()
test_helpers.execute_keys("gg0")
end)

after_each(function()
-- Close the buffer so the next test can open it again.
vim.cmd("silent exe 'bd! %'")
end)

it("Should convert word when cursor is on its last character", function()
test_helpers.execute_keys("12lgaN")
local content = nil
test_helpers.wait_for(5 * 1000, function()
content = test_helpers.get_buf_lines()
local found_modified_variable = not not string.find(content[1], "FOO_VAR")
return found_modified_variable
end)

local expected_code = test_helpers.read_file("./tests/textcase/lsp/fixtures/destructuring-foo-as-constant.ts")
assert.are.same(table.concat(content, "\n") .. "\n", expected_code)
end)

it("Should convert the next word when the cursor isn't on a word", function()
test_helpers.execute_keys("13lgaN")
local content = nil
test_helpers.wait_for(5 * 1000, function()
content = test_helpers.get_buf_lines()
local found_modified_variable = not not string.find(content[1], "BAR_VAR")
return found_modified_variable
end)

local expected_code = test_helpers.read_file("./tests/textcase/lsp/fixtures/destructuring-bar-as-constant.ts")
assert.are.same(table.concat(content, "\n") .. "\n", expected_code)
end)

it("Shouldn't modify variables when the cursor isn't on a word and no word is found next", function()
test_helpers.execute_keys("$gaN")
local content = nil
test_helpers.wait_for(5 * 1000, function()
content = test_helpers.get_buf_lines()
local found_modified_variable = not not string.find(content[1], "BAR_VAR")
return found_modified_variable
end)

local expected_code = test_helpers.read_file("./tests/textcase/lsp/fixtures/destructuring.ts")
assert.are.same(table.concat(content, "\n") .. "\n", expected_code)
end)
end)
end)

0 comments on commit 2567488

Please sign in to comment.