From dbb728b689089db49cf97a3a651c38ed3723b0d3 Mon Sep 17 00:00:00 2001 From: tobiaszimmermann Date: Fri, 12 Aug 2022 22:45:33 +0200 Subject: [PATCH 01/14] feat(goto_test): can find all test class referenes using find. This is the same functionality IntelliJ provides when finding test classes --- lua/java_util/lsp/internal/create_test.lua | 20 +--------- lua/java_util/lsp/internal/goto_test.lua | 44 ++++++++++++++++++++++ lua/java_util/lsp/util.lua | 16 ++++++++ lua/java_util/plenary_util.lua | 31 +++++++++++++++ 4 files changed, 93 insertions(+), 18 deletions(-) create mode 100644 lua/java_util/lsp/internal/goto_test.lua create mode 100644 lua/java_util/plenary_util.lua diff --git a/lua/java_util/lsp/internal/create_test.lua b/lua/java_util/lsp/internal/create_test.lua index 1086e72..5d5f9be 100644 --- a/lua/java_util/lsp/internal/create_test.lua +++ b/lua/java_util/lsp/internal/create_test.lua @@ -4,22 +4,6 @@ local values = require("java_util.config").values local create_test = {} -local function up_directory(path) - return vim.fn.fnamemodify(path, ":h") -end - -local function get_src_root(path) - while not vim.endswith(path, "/src") do - path = up_directory(path) - - if path == "/" then - error("unable to find src root") - end - end - - return path -end - --- Changes /src/main to /src/test in the closest src_root to the current class local function get_test_location(src_root, filepath) local root_split = vim.split(string.sub(src_root, 2), "/") @@ -114,8 +98,8 @@ function create_test.create_test(opts) local bufname = vim.api.nvim_buf_get_name(vim.api.nvim_get_current_buf()) local default_filename = string.format("%sTest", string.sub(bufname, string.find(bufname, "/[^/]*$") + 1, -6)) - local removed_filename = up_directory(bufname) - local src_root = get_src_root(removed_filename) + local removed_filename = lsp_util.up_directory(bufname) + local src_root = lsp_util.get_src_root(removed_filename) local location = get_test_location(src_root, removed_filename) with_filepath({ diff --git a/lua/java_util/lsp/internal/goto_test.lua b/lua/java_util/lsp/internal/goto_test.lua new file mode 100644 index 0000000..59174a1 --- /dev/null +++ b/lua/java_util/lsp/internal/goto_test.lua @@ -0,0 +1,44 @@ +local lsp_util = require("java_util.lsp.util") +local plenary_util = require("java_util.plenary_util") + +local goto_test = {} + +local function goto_test_class(opts) + goto_test.with_test_classes(opts, function(test_classes) + print(vim.inspect(test_classes)) + end) +end + +function goto_test.with_test_classes(opts, callback) + local test_classes = {} + plenary_util.execute_with_results({ + cmd = "find", + args = { + opts.src_root .. "/test", + "-name", + string.format("%s*", opts.current_class), + }, + process_result = function(line) + table.insert(test_classes, line) + end, + process_complete = function() + callback(test_classes) + end, + }) +end + +function goto_test.goto_test(opts) + opts = opts or {} + local bufname = vim.api.nvim_buf_get_name(vim.api.nvim_get_current_buf()) + local src_root = lsp_util.get_src_root(bufname) + local current_class = string.sub(bufname, string.find(bufname, "/[^/]*$") + 1, -6) + + local is_in_main = string.find(bufname, src_root .. "/main") ~= nil + if is_in_main then + goto_test_class({ src_root = src_root, current_class = current_class }) + else + print("in test") + end +end + +return goto_test diff --git a/lua/java_util/lsp/util.lua b/lua/java_util/lsp/util.lua index a0060e8..2d52c3b 100644 --- a/lua/java_util/lsp/util.lua +++ b/lua/java_util/lsp/util.lua @@ -34,6 +34,22 @@ function lsp_util.get_main_package(src_root, file_location) return get_package(src_root, file_location, false) end +function lsp_util.up_directory(path) + return vim.fn.fnamemodify(path, ":h") +end + +function lsp_util.get_src_root(path) + while not vim.endswith(path, "/src") do + path = lsp_util.up_directory(path) + + if path == "/" then + error("unable to find src root") + end + end + + return path +end + function lsp_util.jump_to_file(uri) vim.lsp.util.jump_to_location({ range = { diff --git a/lua/java_util/plenary_util.lua b/lua/java_util/plenary_util.lua new file mode 100644 index 0000000..882f75b --- /dev/null +++ b/lua/java_util/plenary_util.lua @@ -0,0 +1,31 @@ +local Job = require("plenary.job") + +local plenary_util = {} + +---Executes any command through plenary +---@param opts table: the options +---@field cmd string: the command you want to run +---@field cwd string|nil: the current working directory to run the command from +---@field process_result function: will be called whenever the process outputs something +---@field process_complete function: will be called when the process is finished +function plenary_util.execute_with_results(opts) + Job + :new({ + command = opts.cmd, + cwd = opts.cwd, + args = opts.args, + on_stdout = function(_, line, _) + if not line or line == "" then + return + end + + opts.process_result(line) + end, + on_exit = function() + opts.process_complete() + end, + }) + :start() +end + +return plenary_util From 857e690b6c18510aca96ffa8991e045473b23b3d Mon Sep 17 00:00:00 2001 From: tobiaszimmermann Date: Sat, 13 Aug 2022 00:15:21 +0200 Subject: [PATCH 02/14] feat(goto_test): when only finding a single test goes to it, when finding multiple shows picker to select --- lua/java_util/lsp/internal/goto_test.lua | 46 ++++++++++++++++++------ lua/java_util/lsp/internal/rename.lua | 4 +-- 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/lua/java_util/lsp/internal/goto_test.lua b/lua/java_util/lsp/internal/goto_test.lua index 59174a1..5f2e4cb 100644 --- a/lua/java_util/lsp/internal/goto_test.lua +++ b/lua/java_util/lsp/internal/goto_test.lua @@ -3,26 +3,52 @@ local plenary_util = require("java_util.plenary_util") local goto_test = {} -local function goto_test_class(opts) - goto_test.with_test_classes(opts, function(test_classes) - print(vim.inspect(test_classes)) - end) +local function handle_results(test_classes) + local found_len = vim.tbl_count(test_classes) + if found_len == 0 then + return + elseif found_len == 1 then + local first = test_classes[vim.tbl_keys(test_classes)[1]] + lsp_util.jump_to_file(string.format("file://%s", first)) + else + -- TODO: tbl_keys should be sorted by classname length. Smallest should be on top + vim.ui.select( + vim.tbl_keys(test_classes), + { prompt = string.format("Choose class (%d, found)", found_len) }, + function(item) + local choosen = test_classes[item] + lsp_util.jump_to_file(string.format("file://%s", choosen)) + end + ) + end end -function goto_test.with_test_classes(opts, callback) +function goto_test.__with_test_results(opts, callback) + local cwd = vim.fn.getcwd() local test_classes = {} plenary_util.execute_with_results({ cmd = "find", + cwd = opts.src_root .. "/test", args = { - opts.src_root .. "/test", + string.format("%s/test", opts.src_root), "-name", string.format("%s*", opts.current_class), }, process_result = function(line) - table.insert(test_classes, line) + -- make the result start from src/... + local shortened = string.sub(line, string.len(cwd) + 2) + if opts.filter and type(opts.filter) == "function" then + if not opts.filter(shortened) then + return + end + end + + test_classes[shortened] = line end, process_complete = function() - callback(test_classes) + vim.schedule(function() + callback(test_classes) + end) end, }) end @@ -33,9 +59,9 @@ function goto_test.goto_test(opts) local src_root = lsp_util.get_src_root(bufname) local current_class = string.sub(bufname, string.find(bufname, "/[^/]*$") + 1, -6) - local is_in_main = string.find(bufname, src_root .. "/main") ~= nil + local is_in_main = string.find(bufname, string.format("%s/main", src_root)) ~= nil if is_in_main then - goto_test_class({ src_root = src_root, current_class = current_class }) + goto_test.__with_test_results({ src_root = src_root, current_class = current_class }, handle_results) else print("in test") end diff --git a/lua/java_util/lsp/internal/rename.lua b/lua/java_util/lsp/internal/rename.lua index 11febb8..d7b30f1 100644 --- a/lua/java_util/lsp/internal/rename.lua +++ b/lua/java_util/lsp/internal/rename.lua @@ -28,7 +28,7 @@ function rename.rename(new_name, opts) if vim.o.filetype == "java" then local node_at_cursor = ts_utils.get_node_at_cursor(0) if is_field(node_at_cursor) then - rename._rename_field({ new_name = new_name, opts = opts, node_at_cursor = node_at_cursor }) + rename.__rename_field({ new_name = new_name, opts = opts, node_at_cursor = node_at_cursor }) return end end @@ -49,7 +49,7 @@ local function with_name(new_name, callback) end end -function rename._rename_field(opts) +function rename.__rename_field(opts) local params = vim.lsp.util.make_position_params(0) params.context = { includeDeclaration = true } lsp_util.request_all({ From 8ae6a33ed6f4bfb4ed05248c87fac659785e7434 Mon Sep 17 00:00:00 2001 From: tobiaszimmermann Date: Sat, 13 Aug 2022 14:22:51 +0200 Subject: [PATCH 03/14] feat: correctly sorts the found results to show the closest match as the top result --- .github/ISSUE_TEMPLATE/feature_request.md | 2 +- lua/java_util/lsp/internal/goto_test.lua | 40 ++++++++++++++++++----- lua/java_util/lsp/util.lua | 1 + lua/java_util/string_util.lua | 4 +++ 4 files changed, 37 insertions(+), 10 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 9e3f17e..d883b8f 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -2,7 +2,7 @@ name: Feature request about: Suggest an idea for this project title: "" -labels: feature +labels: enhancement assignees: "" --- diff --git a/lua/java_util/lsp/internal/goto_test.lua b/lua/java_util/lsp/internal/goto_test.lua index 5f2e4cb..cbe113c 100644 --- a/lua/java_util/lsp/internal/goto_test.lua +++ b/lua/java_util/lsp/internal/goto_test.lua @@ -1,22 +1,42 @@ local lsp_util = require("java_util.lsp.util") local plenary_util = require("java_util.plenary_util") +local string_util = require("java_util.string_util") local goto_test = {} -local function handle_results(test_classes) - local found_len = vim.tbl_count(test_classes) +--- Sorts the classes by classname length, smallest should be on top +--- So the closest match is always the top one +local function get_sorted_classes(classes) + local keys = vim.tbl_keys(classes) + return vim.fn.sort(keys, function(c1, c2) + local c1_len = string.len(string.sub(c1, string_util.last_index_of(c1, "/") + 1)) + local c2_len = string.len(string.sub(c2, string_util.last_index_of(c2, "/") + 1)) + if c1_len > c2_len then + return 1 + elseif c1_len == c2_len then + return 0 + else + return -1 + end + end) +end + +local function handle_results(opts, classes) + local found_len = vim.tbl_count(classes) if found_len == 0 then + if opts.on_no_results then + opts.on_no_results(opts) + end return elseif found_len == 1 then - local first = test_classes[vim.tbl_keys(test_classes)[1]] + local first = classes[vim.tbl_keys(classes)[1]] lsp_util.jump_to_file(string.format("file://%s", first)) else - -- TODO: tbl_keys should be sorted by classname length. Smallest should be on top vim.ui.select( - vim.tbl_keys(test_classes), + get_sorted_classes(classes), { prompt = string.format("Choose class (%d, found)", found_len) }, function(item) - local choosen = test_classes[item] + local choosen = classes[item] lsp_util.jump_to_file(string.format("file://%s", choosen)) end ) @@ -47,7 +67,7 @@ function goto_test.__with_test_results(opts, callback) end, process_complete = function() vim.schedule(function() - callback(test_classes) + callback(opts, test_classes) end) end, }) @@ -58,10 +78,12 @@ function goto_test.goto_test(opts) local bufname = vim.api.nvim_buf_get_name(vim.api.nvim_get_current_buf()) local src_root = lsp_util.get_src_root(bufname) local current_class = string.sub(bufname, string.find(bufname, "/[^/]*$") + 1, -6) - local is_in_main = string.find(bufname, string.format("%s/main", src_root)) ~= nil if is_in_main then - goto_test.__with_test_results({ src_root = src_root, current_class = current_class }, handle_results) + goto_test.__with_test_results( + vim.tbl_extend("force", { src_root = src_root, current_class = current_class }, opts), + handle_results + ) else print("in test") end diff --git a/lua/java_util/lsp/util.lua b/lua/java_util/lsp/util.lua index 2d52c3b..74170c6 100644 --- a/lua/java_util/lsp/util.lua +++ b/lua/java_util/lsp/util.lua @@ -51,6 +51,7 @@ function lsp_util.get_src_root(path) end function lsp_util.jump_to_file(uri) + -- TODO: should check if buffer already is open. If it is, just go to it vim.lsp.util.jump_to_location({ range = { start = { diff --git a/lua/java_util/string_util.lua b/lua/java_util/string_util.lua index b4b3a61..e1dea94 100644 --- a/lua/java_util/string_util.lua +++ b/lua/java_util/string_util.lua @@ -4,4 +4,8 @@ function string_util.first_to_upper(str) return str:gsub("^%l", string.upper) end +function string_util.last_index_of(str, pattern) + return string.match(str, "^.*()" .. pattern) +end + return string_util From f3603aaf12e9f11544ca5ab497b00ee95ed782cc Mon Sep 17 00:00:00 2001 From: tobiaszimmermann Date: Sat, 13 Aug 2022 14:47:18 +0200 Subject: [PATCH 04/14] feat: going to the test portion of goto_test completed. --- lua/java_util/lsp/internal/goto_test.lua | 2 ++ lua/java_util/lsp/util.lua | 9 +++++- lua/java_util/plenary_util.lua | 31 +++++++++---------- .../snapshots/RenameLombokField.snapshot | 8 ++--- 4 files changed, 29 insertions(+), 21 deletions(-) diff --git a/lua/java_util/lsp/internal/goto_test.lua b/lua/java_util/lsp/internal/goto_test.lua index cbe113c..4f0adf6 100644 --- a/lua/java_util/lsp/internal/goto_test.lua +++ b/lua/java_util/lsp/internal/goto_test.lua @@ -21,6 +21,8 @@ local function get_sorted_classes(classes) end) end +---@param opts table +---@param classes table: key is shortened classpath, value is full path local function handle_results(opts, classes) local found_len = vim.tbl_count(classes) if found_len == 0 then diff --git a/lua/java_util/lsp/util.lua b/lua/java_util/lsp/util.lua index 74170c6..cdedb52 100644 --- a/lua/java_util/lsp/util.lua +++ b/lua/java_util/lsp/util.lua @@ -50,8 +50,15 @@ function lsp_util.get_src_root(path) return path end +--- Checks if the uri is already loaded in a buffer. If it is it will just load it. +--- If the uri is not loaded it will open it function lsp_util.jump_to_file(uri) - -- TODO: should check if buffer already is open. If it is, just go to it + local bufnr = vim.uri_to_bufnr(uri) + if vim.api.nvim_buf_is_loaded(bufnr) then + vim.api.nvim_win_set_buf(vim.api.nvim_get_current_win(), bufnr) + return + end + vim.lsp.util.jump_to_location({ range = { start = { diff --git a/lua/java_util/plenary_util.lua b/lua/java_util/plenary_util.lua index 882f75b..4be10c2 100644 --- a/lua/java_util/plenary_util.lua +++ b/lua/java_util/plenary_util.lua @@ -9,23 +9,22 @@ local plenary_util = {} ---@field process_result function: will be called whenever the process outputs something ---@field process_complete function: will be called when the process is finished function plenary_util.execute_with_results(opts) - Job - :new({ - command = opts.cmd, - cwd = opts.cwd, - args = opts.args, - on_stdout = function(_, line, _) - if not line or line == "" then - return - end + -- TODO: plenary should maybe not be a requirement + Job:new({ + command = opts.cmd, + cwd = opts.cwd, + args = opts.args, + on_stdout = function(_, line, _) + if not line or line == "" then + return + end - opts.process_result(line) - end, - on_exit = function() - opts.process_complete() - end, - }) - :start() + opts.process_result(line) + end, + on_exit = function() + opts.process_complete() + end, + }):start() end return plenary_util diff --git a/lua/tests/java_util/snapshots/RenameLombokField.snapshot b/lua/tests/java_util/snapshots/RenameLombokField.snapshot index 7a827c2..c5f0961 100644 --- a/lua/tests/java_util/snapshots/RenameLombokField.snapshot +++ b/lua/tests/java_util/snapshots/RenameLombokField.snapshot @@ -9,12 +9,12 @@ import lombok.Setter; @Builder public class RenameLombokField { - private String changed; + private String username; public static void testMethod() { RenameLombokField renameLombokField = - RenameLombokField.builder().changed("username").build(); - renameLombokField.setChanged("bob"); - System.out.println(renameLombokField.getChanged()); + RenameLombokField.builder().username("username").build(); + renameLombokField.setUsername("bob"); + System.out.println(renameLombokField.getUsername()); } } From 27813f1e91387ad497b5d5ec31efa7b1266103e0 Mon Sep 17 00:00:00 2001 From: tobiaszimmermann Date: Sat, 13 Aug 2022 14:53:58 +0200 Subject: [PATCH 05/14] fix: up the wait time for snapshot building --- lua/java_util/lsp/init.lua | 3 +++ lua/tests/java_util/snapshots/RenameLombokField.snapshot | 8 ++++---- scripts/build-snapshot.sh | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/lua/java_util/lsp/init.lua b/lua/java_util/lsp/init.lua index f6b16c1..d42ba05 100644 --- a/lua/java_util/lsp/init.lua +++ b/lua/java_util/lsp/init.lua @@ -50,4 +50,7 @@ lsp.rename = require_on_exported_call("java_util.lsp.internal.rename").rename ---@field testname string|nil: The name of the test you want to create. This will skip the prompt to select a testname. lsp.create_test = require_on_exported_call("java_util.lsp.internal.create_test").create_test +-- TODO: document this +lsp.goto_test = require_on_exported_call("java_util.lsp.internal.goto_test").goto_test + return lsp diff --git a/lua/tests/java_util/snapshots/RenameLombokField.snapshot b/lua/tests/java_util/snapshots/RenameLombokField.snapshot index c5f0961..7a827c2 100644 --- a/lua/tests/java_util/snapshots/RenameLombokField.snapshot +++ b/lua/tests/java_util/snapshots/RenameLombokField.snapshot @@ -9,12 +9,12 @@ import lombok.Setter; @Builder public class RenameLombokField { - private String username; + private String changed; public static void testMethod() { RenameLombokField renameLombokField = - RenameLombokField.builder().username("username").build(); - renameLombokField.setUsername("bob"); - System.out.println(renameLombokField.getUsername()); + RenameLombokField.builder().changed("username").build(); + renameLombokField.setChanged("bob"); + System.out.println(renameLombokField.getChanged()); } } diff --git a/scripts/build-snapshot.sh b/scripts/build-snapshot.sh index 46890ff..64e0f2e 100644 --- a/scripts/build-snapshot.sh +++ b/scripts/build-snapshot.sh @@ -13,5 +13,5 @@ nvim lua/tests/testproject/src/main/java/io/github/tobiasz/testproject/builders/ -c "set filetype=java" \ -c "lua require('tests.java_util.util.helpers').wait_for_ready_lsp()" \ -c "luafile lua/tests/java_util/builders/$lua_builder.lua" \ - -c "lua vim.wait(2000)" \ + -c "lua vim.wait(4000)" \ -c "wq! lua/tests/java_util/snapshots/$java_builder.snapshot" From 28bf2c346a61e0c587f2b23ef0c5ff811e859388 Mon Sep 17 00:00:00 2001 From: tobiaszimmermann Date: Sat, 13 Aug 2022 21:48:37 +0200 Subject: [PATCH 06/14] feat(goto_test): can go to the main class from test if you are currently in a test class --- lua/java_util/lsp/internal/goto_test.lua | 75 ++++++++++++++++++++---- 1 file changed, 63 insertions(+), 12 deletions(-) diff --git a/lua/java_util/lsp/internal/goto_test.lua b/lua/java_util/lsp/internal/goto_test.lua index 4f0adf6..8fddddd 100644 --- a/lua/java_util/lsp/internal/goto_test.lua +++ b/lua/java_util/lsp/internal/goto_test.lua @@ -45,17 +45,55 @@ local function handle_results(opts, classes) end end -function goto_test.__with_test_results(opts, callback) +local function get_search_classes(classname) + local searches = {} + local cur = "" + for c in classname:gmatch(".") do + local ascii = string.byte(c) + local is_uppercase = ascii >= 65 and ascii <= 90 + if is_uppercase then + if cur ~= "" then + table.insert(searches, cur) + end + end + cur = cur .. c + end + table.insert(searches, classname) + + -- Only search for 50% of the class names + -- UserServiceImpl becomes { "UserServiceImpl", "UserService" } and ignores the User part + local search_items_rounded = math.floor((vim.tbl_count(searches) / 2) + 0.5) + local results = {} + for i = search_items_rounded + 0, 1, -1 do + table.insert(results, searches[i + 1]) + end + + if vim.tbl_count(results) == 0 then + table.insert(results, classname) + end + + return results +end + +function goto_test.__with_found_classes(opts, callback) local cwd = vim.fn.getcwd() local test_classes = {} + local args = { + opts.cwd, + "-type", + "f", + } + + local searches = get_search_classes(opts.current_class) + for _, search_item in ipairs(searches) do + table.insert(args, "-name") + table.insert(args, string.format("%s*", search_item)) + end + plenary_util.execute_with_results({ cmd = "find", - cwd = opts.src_root .. "/test", - args = { - string.format("%s/test", opts.src_root), - "-name", - string.format("%s*", opts.current_class), - }, + cwd = opts.cwd, + args = args, process_result = function(line) -- make the result start from src/... local shortened = string.sub(line, string.len(cwd) + 2) @@ -80,14 +118,27 @@ function goto_test.goto_test(opts) local bufname = vim.api.nvim_buf_get_name(vim.api.nvim_get_current_buf()) local src_root = lsp_util.get_src_root(bufname) local current_class = string.sub(bufname, string.find(bufname, "/[^/]*$") + 1, -6) + local combined_opts = vim.tbl_extend("force", { src_root = src_root, current_class = current_class }, opts) local is_in_main = string.find(bufname, string.format("%s/main", src_root)) ~= nil if is_in_main then - goto_test.__with_test_results( - vim.tbl_extend("force", { src_root = src_root, current_class = current_class }, opts), - handle_results - ) + combined_opts.cwd = string.format("%s/test", src_root) + goto_test.__with_found_classes(combined_opts, handle_results) else - print("in test") + combined_opts.cwd = string.format("%s/main", src_root) + if vim.endswith(combined_opts.current_class, "Test") then + combined_opts.current_class = string.sub(combined_opts.current_class, 0, -5) + end + goto_test.__with_found_classes(combined_opts, function(_, classes) + -- If we found a resulting class called the same as test class without Test in the end, we will simply use that as out result + for key, result in pairs(classes) do + if vim.endswith(result, string.format("%s.java", combined_opts.current_class)) then + handle_results(combined_opts, { [key] = result }) + return + end + end + + handle_results(combined_opts, classes) + end) end end From b1dbf2707e70d2dcc02d269a264dc7cbd9730bdd Mon Sep 17 00:00:00 2001 From: Tobias Zimmermann Date: Thu, 18 Aug 2022 14:02:47 +0200 Subject: [PATCH 07/14] fix: only look for classes that end with Test --- lua/java_util/lsp/internal/goto_test.lua | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lua/java_util/lsp/internal/goto_test.lua b/lua/java_util/lsp/internal/goto_test.lua index 8fddddd..05d941b 100644 --- a/lua/java_util/lsp/internal/goto_test.lua +++ b/lua/java_util/lsp/internal/goto_test.lua @@ -87,7 +87,7 @@ function goto_test.__with_found_classes(opts, callback) local searches = get_search_classes(opts.current_class) for _, search_item in ipairs(searches) do table.insert(args, "-name") - table.insert(args, string.format("%s*", search_item)) + table.insert(args, string.format("%s*Test.java", search_item)) end plenary_util.execute_with_results({ @@ -116,9 +116,11 @@ end function goto_test.goto_test(opts) opts = opts or {} local bufname = vim.api.nvim_buf_get_name(vim.api.nvim_get_current_buf()) + local combined_opts = vim.tbl_extend("force", { + current_class = string.sub(bufname, string.find(bufname, "/[^/]*$") + 1, -6), + }, opts) local src_root = lsp_util.get_src_root(bufname) - local current_class = string.sub(bufname, string.find(bufname, "/[^/]*$") + 1, -6) - local combined_opts = vim.tbl_extend("force", { src_root = src_root, current_class = current_class }, opts) + local is_in_main = string.find(bufname, string.format("%s/main", src_root)) ~= nil if is_in_main then combined_opts.cwd = string.format("%s/test", src_root) From a80f06506d5dfa69dc5192285f7f15ce60a74d67 Mon Sep 17 00:00:00 2001 From: Tobias Zimmermann Date: Thu, 18 Aug 2022 15:08:33 +0200 Subject: [PATCH 08/14] feat: create documentation for the goto_test function + create test for the goto_test function --- Makefile | 1 + README.md | 9 +++++---- lua/java_util/lsp/init.lua | 10 +++++++++- lua/java_util/lsp/internal/goto_test.lua | 3 +-- lua/java_util/plenary_util.lua | 1 - .../java_util/automated/lsp/goto_test_spec.lua | 15 +++++++++++++++ lua/tests/java_util/builders/goto_test.lua | 3 +++ lua/tests/java_util/snapshots/GotoTest.snapshot | 3 +++ .../tobiasz/testproject/builders/GotoTest.java | 3 +++ 9 files changed, 40 insertions(+), 8 deletions(-) create mode 100644 lua/tests/java_util/automated/lsp/goto_test_spec.lua create mode 100644 lua/tests/java_util/builders/goto_test.lua create mode 100644 lua/tests/java_util/snapshots/GotoTest.snapshot create mode 100644 lua/tests/testproject/src/main/java/io/github/tobiasz/testproject/builders/GotoTest.java diff --git a/Makefile b/Makefile index b058c28..1d4d315 100644 --- a/Makefile +++ b/Makefile @@ -19,3 +19,4 @@ snapshots: sh ./scripts/build-snapshot.sh CreateTestStringClassSnippets create_test_string_class_snippets sh ./scripts/build-snapshot.sh CreateTestLuasnipClassSnippets create_test_luasnip_class_snippets sh ./scripts/build-snapshot.sh CreateTestAfterSnippetRun create_test_after_snippet_run + sh ./scripts/build-snapshot.sh GotoTest goto_test diff --git a/README.md b/README.md index 8c4ea30..7cfff11 100644 --- a/README.md +++ b/README.md @@ -87,10 +87,11 @@ For more in depth information about specific functions see `:help java_util` ### LSP -| Functions | Description | -| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `lsp.rename` | Renames the word you are hovering. Supports lombok renaming | -| `lsp.create_test` | Creates a test class for the current class you are in. Allows for multiple test class configurations. For more information see [Creating Tests](https://github.com/tobias-z/java-util.nvim/wiki/Creating-Tests) | +| Functions | Description | +| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `lsp.rename` | Renames the word you are hovering. Supports lombok renaming | +| `lsp.create_test` | Creates a test class for the current class you are in. Allows for multiple test class configurations. For more information see [Test Management](https://github.com/tobias-z/java-util.nvim/wiki/Test-Management) | +| `lsp.goto_test` | Bidirectional test movement, will either to go test or main class, depending on where you are. For more information see [ ] | ## Configuration diff --git a/lua/java_util/lsp/init.lua b/lua/java_util/lsp/init.lua index d42ba05..a489c82 100644 --- a/lua/java_util/lsp/init.lua +++ b/lua/java_util/lsp/init.lua @@ -50,7 +50,15 @@ lsp.rename = require_on_exported_call("java_util.lsp.internal.rename").rename ---@field testname string|nil: The name of the test you want to create. This will skip the prompt to select a testname. lsp.create_test = require_on_exported_call("java_util.lsp.internal.create_test").create_test --- TODO: document this +--- Bidirectional test movement +--- 1. If you are in a none test class, it will go to the test of your current class. If multiple are found, a prompt is shown for you to choose +--- 2. If you are in a test class, it will go the the class you testing. If a direct match is found, it will take you directly there otherwise, it will prompt you with a list of possible matches. +--- An example of a direct match would be, you are currently in a class called UserServiceImplTest. Here a direct match would be if a class is found called UserServiceImpl +---@param opts table|nil: options to specify the goto_test behaviour. +---@field on_no_results function|nil: Called if no results are found. Could be used to create a test if no class is found +---@field current_class string|nil: Specifies the class used to search for tests/classes. Default is the current class you are in. If empty string is passed, it will show all tests found from the `opts.cwd` +---@field filter function|nil: Predicate to filter the test results. Could be used if there are some tests you always don't want to see. +---@field cwd string|nil: Specifies the cwd you want to search from. Default is the src root of the current module or project you are in. lsp.goto_test = require_on_exported_call("java_util.lsp.internal.goto_test").goto_test return lsp diff --git a/lua/java_util/lsp/internal/goto_test.lua b/lua/java_util/lsp/internal/goto_test.lua index 05d941b..ed3c120 100644 --- a/lua/java_util/lsp/internal/goto_test.lua +++ b/lua/java_util/lsp/internal/goto_test.lua @@ -89,7 +89,6 @@ function goto_test.__with_found_classes(opts, callback) table.insert(args, "-name") table.insert(args, string.format("%s*Test.java", search_item)) end - plenary_util.execute_with_results({ cmd = "find", cwd = opts.cwd, @@ -121,7 +120,7 @@ function goto_test.goto_test(opts) }, opts) local src_root = lsp_util.get_src_root(bufname) - local is_in_main = string.find(bufname, string.format("%s/main", src_root)) ~= nil + local is_in_main = vim.startswith(string.sub(bufname, string.len(src_root) + 1), "/main") if is_in_main then combined_opts.cwd = string.format("%s/test", src_root) goto_test.__with_found_classes(combined_opts, handle_results) diff --git a/lua/java_util/plenary_util.lua b/lua/java_util/plenary_util.lua index 4be10c2..ddf8224 100644 --- a/lua/java_util/plenary_util.lua +++ b/lua/java_util/plenary_util.lua @@ -9,7 +9,6 @@ local plenary_util = {} ---@field process_result function: will be called whenever the process outputs something ---@field process_complete function: will be called when the process is finished function plenary_util.execute_with_results(opts) - -- TODO: plenary should maybe not be a requirement Job:new({ command = opts.cmd, cwd = opts.cwd, diff --git a/lua/tests/java_util/automated/lsp/goto_test_spec.lua b/lua/tests/java_util/automated/lsp/goto_test_spec.lua new file mode 100644 index 0000000..7d727d1 --- /dev/null +++ b/lua/tests/java_util/automated/lsp/goto_test_spec.lua @@ -0,0 +1,15 @@ +local helpers = require("tests.java_util.util.helpers") + +local ok = assert.is_true + +describe("goto_test", function() + it("can go to a test from none test class", function() + ok(helpers.snapshot_matches( + "GotoTest", + [[ +package io.github.tobiasz.testproject.builders; + +public class GotoTestTest {}]] + )) + end) +end) diff --git a/lua/tests/java_util/builders/goto_test.lua b/lua/tests/java_util/builders/goto_test.lua new file mode 100644 index 0000000..46fc806 --- /dev/null +++ b/lua/tests/java_util/builders/goto_test.lua @@ -0,0 +1,3 @@ +require("java_util").setup({}) + +require("java_util.lsp").goto_test() diff --git a/lua/tests/java_util/snapshots/GotoTest.snapshot b/lua/tests/java_util/snapshots/GotoTest.snapshot new file mode 100644 index 0000000..73eb3de --- /dev/null +++ b/lua/tests/java_util/snapshots/GotoTest.snapshot @@ -0,0 +1,3 @@ +package io.github.tobiasz.testproject.builders; + +public class GotoTestTest {} diff --git a/lua/tests/testproject/src/main/java/io/github/tobiasz/testproject/builders/GotoTest.java b/lua/tests/testproject/src/main/java/io/github/tobiasz/testproject/builders/GotoTest.java new file mode 100644 index 0000000..93b3b31 --- /dev/null +++ b/lua/tests/testproject/src/main/java/io/github/tobiasz/testproject/builders/GotoTest.java @@ -0,0 +1,3 @@ +package io.github.tobiasz.testproject.builders; + +public class GotoTest {} From 0396c7c02a5b9400ac7385a1784723af8deb8403 Mon Sep 17 00:00:00 2001 From: Github Actions Date: Thu, 18 Aug 2022 13:09:31 +0000 Subject: [PATCH 09/14] [docgen] Update doc/java-util.txt skip-checks: true --- doc/java_util.txt | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/doc/java_util.txt b/doc/java_util.txt index c21265a..08ed132 100644 --- a/doc/java_util.txt +++ b/doc/java_util.txt @@ -117,5 +117,36 @@ lsp.create_test({opts}) *java_util.lsp.create_test()* testname. +lsp.goto_test({opts}) *java_util.lsp.goto_test()* + Bidirectional test movement + 1. If you are in a none test class, it will go to the test of your current + class. If multiple are found, a prompt is shown for you to choose + 2. If you are in a test class, it will go the the class you testing. If a + direct match is found, it will take you directly there otherwise, it + will prompt you with a list of possible matches. An example of a direct + match would be, you are currently in a class called UserServiceImplTest. + Here a direct match would be if a class is found called UserServiceImpl + + + Parameters: ~ + {opts} (table|nil) options to specify the goto_test behaviour. + + Options: ~ + {on_no_results} (function|nil) Called if no results are found. Could + be used to create a test if no class + is found + {current_class} (string|nil) Specifies the class used to search for + tests/classes. Default is the current + class you are in. If empty string is + passed, it will show all tests found + from the `opts.cwd` + {filter} (function|nil) Predicate to filter the test results. + Could be used if there are some tests + you always don't want to see. + {cwd} (string|nil) Specifies the cwd you want to search + from. Default is the src root of the + current module or project you are in. + + vim:tw=78:ts=8:ft=help:norl: From 546f43e7b612ab9eb9676ab88f7283ca7f4e0758 Mon Sep 17 00:00:00 2001 From: Tobias Zimmermann Date: Thu, 18 Aug 2022 16:03:25 +0200 Subject: [PATCH 10/14] docs: add link to the goto_test wiki --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 7cfff11..07f712e 100644 --- a/README.md +++ b/README.md @@ -87,11 +87,11 @@ For more in depth information about specific functions see `:help java_util` ### LSP -| Functions | Description | -| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `lsp.rename` | Renames the word you are hovering. Supports lombok renaming | -| `lsp.create_test` | Creates a test class for the current class you are in. Allows for multiple test class configurations. For more information see [Test Management](https://github.com/tobias-z/java-util.nvim/wiki/Test-Management) | -| `lsp.goto_test` | Bidirectional test movement, will either to go test or main class, depending on where you are. For more information see [ ] | +| Functions | Description | +| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `lsp.rename` | Renames the word you are hovering. Supports lombok renaming | +| `lsp.create_test` | Creates a test class for the current class you are in. Allows for multiple test class configurations. For more information see [Test Management](https://github.com/tobias-z/java-util.nvim/wiki/Test-Management) | +| `lsp.goto_test` | Bidirectional test movement, will either to go test or main class, depending on where you are. For more information see [Going to Tests](https://github.com/tobias-z/java-util.nvim/wiki/Test-Management#going-to-tests) | ## Configuration From 9606b104c3fd16814450d88436fbe74284286f9e Mon Sep 17 00:00:00 2001 From: Tobias Zimmermann Date: Thu, 18 Aug 2022 16:33:08 +0200 Subject: [PATCH 11/14] fix: only add the Test.java in the end if we are searching for test files --- lua/java_util/lsp/internal/goto_test.lua | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lua/java_util/lsp/internal/goto_test.lua b/lua/java_util/lsp/internal/goto_test.lua index ed3c120..b57f306 100644 --- a/lua/java_util/lsp/internal/goto_test.lua +++ b/lua/java_util/lsp/internal/goto_test.lua @@ -75,7 +75,7 @@ local function get_search_classes(classname) return results end -function goto_test.__with_found_classes(opts, callback) +local function with_found_classes(opts, callback) local cwd = vim.fn.getcwd() local test_classes = {} local args = { @@ -87,7 +87,7 @@ function goto_test.__with_found_classes(opts, callback) local searches = get_search_classes(opts.current_class) for _, search_item in ipairs(searches) do table.insert(args, "-name") - table.insert(args, string.format("%s*Test.java", search_item)) + table.insert(args, string.format("%s*%s", search_item, opts.is_test and "" or "Test.java")) end plenary_util.execute_with_results({ cmd = "find", @@ -115,21 +115,18 @@ end function goto_test.goto_test(opts) opts = opts or {} local bufname = vim.api.nvim_buf_get_name(vim.api.nvim_get_current_buf()) + local src_root = lsp_util.get_src_root(bufname) local combined_opts = vim.tbl_extend("force", { current_class = string.sub(bufname, string.find(bufname, "/[^/]*$") + 1, -6), + is_test = vim.startswith(string.sub(bufname, string.len(src_root) + 1), "/test"), }, opts) - local src_root = lsp_util.get_src_root(bufname) - local is_in_main = vim.startswith(string.sub(bufname, string.len(src_root) + 1), "/main") - if is_in_main then - combined_opts.cwd = string.format("%s/test", src_root) - goto_test.__with_found_classes(combined_opts, handle_results) - else + if combined_opts.is_test then combined_opts.cwd = string.format("%s/main", src_root) if vim.endswith(combined_opts.current_class, "Test") then combined_opts.current_class = string.sub(combined_opts.current_class, 0, -5) end - goto_test.__with_found_classes(combined_opts, function(_, classes) + with_found_classes(combined_opts, function(_, classes) -- If we found a resulting class called the same as test class without Test in the end, we will simply use that as out result for key, result in pairs(classes) do if vim.endswith(result, string.format("%s.java", combined_opts.current_class)) then @@ -140,6 +137,9 @@ function goto_test.goto_test(opts) handle_results(combined_opts, classes) end) + else + combined_opts.cwd = string.format("%s/test", src_root) + with_found_classes(combined_opts, handle_results) end end From bba8406a6d1b5ca3eb8fc22922064b3fdeba771e Mon Sep 17 00:00:00 2001 From: Tobias Zimmermann Date: Thu, 18 Aug 2022 16:34:29 +0200 Subject: [PATCH 12/14] fix: remove weird + 0? --- lua/java_util/lsp/internal/goto_test.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/java_util/lsp/internal/goto_test.lua b/lua/java_util/lsp/internal/goto_test.lua index b57f306..73cb5f9 100644 --- a/lua/java_util/lsp/internal/goto_test.lua +++ b/lua/java_util/lsp/internal/goto_test.lua @@ -64,7 +64,7 @@ local function get_search_classes(classname) -- UserServiceImpl becomes { "UserServiceImpl", "UserService" } and ignores the User part local search_items_rounded = math.floor((vim.tbl_count(searches) / 2) + 0.5) local results = {} - for i = search_items_rounded + 0, 1, -1 do + for i = search_items_rounded, 1, -1 do table.insert(results, searches[i + 1]) end From e42d87e85121e42f74e8757f650222cd75992b03 Mon Sep 17 00:00:00 2001 From: Tobias Zimmermann Date: Thu, 18 Aug 2022 16:37:46 +0200 Subject: [PATCH 13/14] docs: add plenary to requirements list --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 07f712e..a9548b5 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,7 @@ The plugin is tested against [Neovim (v0.7.0)](https://github.com/neovim/neovim/ - Jdtls setup using either [lsp-config](https://github.com/neovim/nvim-lspconfig/blob/master/doc/server_configurations.md#jdtls) or [nvim-jdtls](https://github.com/mfussenegger/nvim-jdtls). (or anything that uses the built in neovim lsp) - [nvim-treesitter](https://github.com/nvim-treesitter/nvim-treesitter) +- [Plenary](https://github.com/nvim-lua/plenary.nvim) ### Installation From 9697610d502f15323b46c4e34cd82d328df9c21e Mon Sep 17 00:00:00 2001 From: Tobias Zimmermann Date: Thu, 18 Aug 2022 16:38:57 +0200 Subject: [PATCH 14/14] docs: add plenary to the packer requires table --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a9548b5..bb94c75 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,8 @@ use({ -- or branch = "dev" -- or tag = "0.1.0" requires = { - { "nvim-treesitter/nvim-treesitter" } + { "nvim-treesitter/nvim-treesitter" }, + { "nvim-lua/plenary.nvim" } } }) ```