From a4cb23613edfe952cdc98cb6b4f47b23f1bc8718 Mon Sep 17 00:00:00 2001 From: s1n7ax Date: Mon, 13 Nov 2023 23:57:37 +0530 Subject: [PATCH 1/2] refactor!: make current project to core module --- lua/java-core.lua | 25 -- lua/java-core/config.lua | 20 -- lua/java-core/dap.lua | 240 +++++++----------- lua/java-core/ls/adapters/test-adapter.lua | 33 ++- .../ls/clients/java-debug-client.lua | 2 +- lua/java-core/ls/clients/java-test-client.lua | 2 +- lua/java-core/ls/clients/jdtls-client.lua | 2 +- lua/java-core/ls/helpers/java-test-helper.lua | 184 -------------- lua/java-core/ls/helpers/test-helper.lua | 100 +++----- lua/java-core/server.lua | 1 + lua/java-core/utils/list.lua | 21 ++ lua/java-core/utils/log.lua | 2 +- lua/java-core/utils/lsp.lua | 1 + lua/java-core/utils/notify.lua | 26 ++ plugin/java.lua | 1 - 15 files changed, 209 insertions(+), 451 deletions(-) delete mode 100644 lua/java-core/config.lua delete mode 100644 lua/java-core/ls/helpers/java-test-helper.lua create mode 100644 lua/java-core/utils/notify.lua delete mode 100644 plugin/java.lua diff --git a/lua/java-core.lua b/lua/java-core.lua index 6f5fcdc..5044d6f 100644 --- a/lua/java-core.lua +++ b/lua/java-core.lua @@ -1,28 +1,3 @@ -local server = require('java-core.server') -local config = require('java-core.config') -local lsp = require('java-core.utils.lsp') - ----@class Java ----@field config JavaConfig local M = {} ----Setup the plugin ----@param args JavaConfig -M.setup = function(args) - config = vim.tbl_deep_extend('force', config, args or {}) -end - ----Returns the jdtls config ----@param root_markers? string[] list of files to find the root dir of a project ----@return LSPSetupConfig -function M.get_config(root_markers) - return server.get_config({ - root_markers = root_markers or config.root_markers, - }) -end - -M.__run = function() - print('>>>>>') -end - return M diff --git a/lua/java-core/config.lua b/lua/java-core/config.lua deleted file mode 100644 index 3d13fb6..0000000 --- a/lua/java-core/config.lua +++ /dev/null @@ -1,20 +0,0 @@ ----@class JavaConfig ----@field workspace_root string path to the root of workspaces ----@field root_markers string[] list of files that indicates the project root -local config = { - workspace_root = vim.fn.stdpath('data') .. '/nvim-java/workspaces', - - root_markers = { - 'settings.gradle', - 'settings.gradle.kts', - 'pom.xml', - 'build.gradle', - 'mvnw', - 'gradlew', - 'build.gradle', - 'build.gradle.kts', - '.git', - }, -} - -return config diff --git a/lua/java-core/dap.lua b/lua/java-core/dap.lua index 74565af..b0f5dc4 100644 --- a/lua/java-core/dap.lua +++ b/lua/java-core/dap.lua @@ -1,56 +1,29 @@ local log = require('java-core.utils.log') -local lsp = require('java-core.utils.lsp') +local adapters = require('java-core.ls.adapters.test-adapter') +local List = require('java-core.utils.list') local JavaDebug = require('java-core.ls.clients.java-debug-client') local Promise = require('java-core.utils.promise') +---@class JavaCoreDap +---@field client LSPClient +---@field java_debug JavaCoreDebugClient local M = {} -function M.setup_dap_on_attach() - vim.api.nvim_create_autocmd('LspAttach', { - pattern = '*', - callback = function(a) - local client = vim.lsp.get_client_by_id(a.data.client_id) - - if client.name == 'jdtls' then - Promise.all({ - M.set_dap_config(), - M.set_dap_adapter(), - }):catch(function(err) - local msg = [[Faild to set DAP configuration & adapter]] - - error(msg, err) - log.error(msg, err) - end) - end - end, - }) -end - -function M.set_dap_config() - log.info('setting dap configurations for java') - - local dap = require('dap') - - return M.get_dap_config():thenCall( - ---@type JavaDapConfigurationList - function(res) - dap.configurations.java = res - end - ) -end - -function M.set_dap_adapter() - log.info('setting dap adapter for java') +---Returns a new dap instance +---@param args { client: LSPClient } +---@return JavaCoreDap +function M:new(args) + local o = { + client = args.client, + } - local dap = require('dap') + o.java_debug = JavaDebug:new({ + client = args.client, + }) - return M.get_dap_adapter():thenCall( - ---@type JavaDapAdapter - function(res) - log.debug('adapter settings: ', res) - dap.adapters.java = res - end - ) + setmetatable(o, self) + self.__index = self + return o end ---@class JavaDapAdapter @@ -60,25 +33,10 @@ end ---Returns the dap adapter config ---@return Promise -function M.get_dap_adapter() +function M:get_dap_adapter() log.info('creating dap adapter for java') - local client = lsp.get_jdtls_client() - - --@TODO when thrown from the function instead of the promise, - --error handling has to be done in two places - if not client then - local msg = 'no active jdtls client was found' - - log.error(msg) - error(msg) - end - - local jdtlsClient = JavaDebug:new({ - client = client, - }) - - return jdtlsClient:start_debug_session():thenCall( + return self.java_debug:start_debug_session():thenCall( ---@param port JavaDebugStartDebugSessionResponse function(port) return { @@ -90,106 +48,92 @@ function M.get_dap_adapter() ) end ----@class JavaDapConfiguration ----@field name string ----@field projectName string ----@field mainClass string ----@field javaExec string ----@field modulePaths string[] ----@field classPaths string[] ----@field request string - ---@alias JavaDapConfigurationList JavaDapConfiguration[] ---Returns the dap configuration for the current project ---@return Promise -function M.get_dap_config() +function M:get_dap_config() log.info('creating dap configuration for java') - local client = lsp.get_jdtls_client() + return self.java_debug:resolve_main_class():thenCall( + ---@param mains JavaDebugResolveMainClassResponse + function(mains) + local config_promises = List:new(mains):map(function(main) + return self:get_dap_config_record(main) + end) - if not client then - local msg = 'no active jdtls client was found' + return Promise.all(config_promises) + end + ) +end - log.error(msg) - error(msg) - end +---Returns the dap config for the given main class +---@param main JavaDebugResolveMainClassRecord +---@return Promise +function M:get_dap_config_record(main) + return Promise.all({ + self.java_debug:resolve_classpath(main.mainClass, main.projectName), + self.java_debug:resolve_java_executable(main.mainClass, main.projectName), + }):thenCall(function(res) + ---@type JavaDebugResolveClasspathResponse + local classpaths = res[1] + + ---@type JavaDebugResolveJavaExecutableResponse + local java_exec = res[2] + + return adapters.get_dap_config(main, classpaths, java_exec) + end) +end - local jdtlsClient = JavaDebug:new({ - client = client, - }) +---Dap run with given config +---@param config JavaDapConfiguration +function M.dap_run(config) + log.info('running dap with config: ', config) + + local function get_stream_reader(conn) + return vim.schedule_wrap(function(err, buffer) + assert(not err, err) - ---@type JavaDebugResolveMainClassResponse - local main_classes_info_list - - return jdtlsClient - :resolve_main_class() - :thenCall( - ---@param main_classes_info JavaDebugResolveMainClassResponse - function(main_classes_info) - main_classes_info_list = main_classes_info - - ---@type Promise[] - local classpath_promises = {} - ---@type Promise[] - local java_exec_promises = {} - - for _, single_class_info in ipairs(main_classes_info) do - table.insert( - classpath_promises, - jdtlsClient:resolve_classpath( - single_class_info.mainClass, - single_class_info.projectName - ) - ) - - table.insert( - java_exec_promises, - jdtlsClient:resolve_java_executable( - single_class_info.mainClass, - single_class_info.projectName - ) - ) - end - - return Promise.all({ - Promise.all(classpath_promises), - Promise.all(java_exec_promises), - }) + if buffer then + vim.print(buffer) + else + conn:close() end - ) - :thenCall(function(result) - return M.__get_dap_java_config( - main_classes_info_list, - result[1], - result[2] - ) end) -end - -function M.__get_dap_java_config(main_classes, classpaths, java_execs) - local len = #main_classes - local dap_config_list = {} - - for i = 1, len do - local main_class = main_classes[i].mainClass - local project_name = main_classes[i].projectName - local module_paths = classpaths[i][1] - local class_paths = classpaths[i][2] - - table.insert(dap_config_list, { - name = string.format('%s -> %s', project_name, main_class), - projectName = project_name, - mainClass = main_class, - javaExec = java_execs[i], - request = 'launch', - type = 'java', - modulePaths = module_paths, - classPaths = class_paths, - }) end - return dap_config_list + ---@type uv_tcp_t + local server + + require('dap').run(config, { + before = function(conf) + log.debug('running before dap callback') + + server = assert(vim.loop.new_tcp(), 'uv.new_tcp() must return handle') + server:bind('127.0.0.1', 0) + server:listen(128, function(err) + assert(not err, err) + + local sock = assert(vim.loop.new_tcp(), 'uv.new_tcp must return handle') + server:accept(sock) + sock:read_start(get_stream_reader(sock)) + end) + + conf.args = + conf.args:gsub('-port ([0-9]+)', '-port ' .. server:getsockname().port) + + return conf + end, + + after = function() + vim.debug('running after dap callback') + + if server then + server:shutdown() + server:close() + end + end, + }) end return M diff --git a/lua/java-core/ls/adapters/test-adapter.lua b/lua/java-core/ls/adapters/test-adapter.lua index ea716bb..0dd8975 100644 --- a/lua/java-core/ls/adapters/test-adapter.lua +++ b/lua/java-core/ls/adapters/test-adapter.lua @@ -24,7 +24,6 @@ local M = {} ---@field postDebugTask? string ---Returns the launcher config ----@param test_details JavaTestDetails | JavaTestDetails[] ---@param launch_args JavaTestJunitLaunchArguments ---@param java_exec JavaDebugResolveJavaExecutableResponse ---@param config { debug: boolean, label: string } @@ -93,4 +92,36 @@ function M.get_test_names(tests) end) end +---@class JavaDapConfiguration +---@field name string +---@field projectName string +---@field mainClass string +---@field javaExec string +---@field modulePaths string[] +---@field classPaths string[] +---@field request string + +---Returns the dap config record +---@param main JavaDebugResolveMainClassRecord +---@param classpath JavaDebugResolveClasspathResponse +---@param java_exec JavaDebugResolveJavaExecutableResponse +---@return JavaDapConfiguration +function M.get_dap_config(main, classpath, java_exec) + local project_name = main.projectName + local main_class = main.mainClass + local module_paths = classpath[1] + local class_paths = classpath[2] + + return { + request = 'launch', + type = 'java', + name = string.format('%s -> %s', project_name, main_class), + projectName = project_name, + mainClass = main_class, + javaExec = java_exec, + modulePaths = module_paths, + classPaths = class_paths, + } +end + return M diff --git a/lua/java-core/ls/clients/java-debug-client.lua b/lua/java-core/ls/clients/java-debug-client.lua index 0ea9457..d21db4e 100644 --- a/lua/java-core/ls/clients/java-debug-client.lua +++ b/lua/java-core/ls/clients/java-debug-client.lua @@ -1,6 +1,6 @@ local JDTLSClient = require('java-core.ls.clients.jdtls-client') ----@class JavaDebugClient: JDTLSClient +---@class JavaCoreDebugClient: JavaCoreJdtlsClient local M = JDTLSClient:new() ---@class JavaDebugResolveMainClassRecord diff --git a/lua/java-core/ls/clients/java-test-client.lua b/lua/java-core/ls/clients/java-test-client.lua index 4718927..5cfe3ea 100644 --- a/lua/java-core/ls/clients/java-test-client.lua +++ b/lua/java-core/ls/clients/java-test-client.lua @@ -29,7 +29,7 @@ local JDTLSClient = require('java-core.ls.clients.jdtls-client') ---@field line integer ---@field character integer ----@class JavaTestClient: JDTLSClient +---@class JavaCoreTestClient: JavaCoreJdtlsClient local M = JDTLSClient:new() ---@alias JavaTestFindJavaProjectsResponse JavaTestDetails[] diff --git a/lua/java-core/ls/clients/jdtls-client.lua b/lua/java-core/ls/clients/jdtls-client.lua index d32ec9d..a8c08c5 100644 --- a/lua/java-core/ls/clients/jdtls-client.lua +++ b/lua/java-core/ls/clients/jdtls-client.lua @@ -1,7 +1,7 @@ local log = require('java-core.utils.log') local Promise = require('java-core.utils.promise') ----@class JDTLSClient +---@class JavaCoreJdtlsClient ---@field client LSPClient local M = {} diff --git a/lua/java-core/ls/helpers/java-test-helper.lua b/lua/java-core/ls/helpers/java-test-helper.lua deleted file mode 100644 index 61aae60..0000000 --- a/lua/java-core/ls/helpers/java-test-helper.lua +++ /dev/null @@ -1,184 +0,0 @@ -local lsp = require('java-core.utils.lsp') -local log = require('java-core.utils.log') -local java_test_adapter = require('java-core.ls.adapters.test-adapter') - -local List = require('java-core.utils.list') -local Promise = require('java-core.utils.promise') -local JavaTestClient = require('java-core.ls.clients.java-test-client') -local JavaDebugClient = require('java-core.ls.clients.java-debug-client') - -local M = {} - ----Runs a given test ----@param test JavaTestDetails -function M.run_test(test) end - -function M.run_current_test_file() - log.info('running the current test file') - - local jdtls = lsp.get_jdtls_client() - - local test_client = JavaTestClient:new({ - client = jdtls, - }) - - ---@type JavaDebugClient - local debug_client = JavaDebugClient:new({ - client = jdtls, - }) - - local buffer = vim.api.nvim_get_current_buf() - local uri = vim.uri_from_bufnr(buffer) - - ---@type JavaTestDetails - local test_details - ---@type JavaTestJunitLaunchArguments - local launch_args - - return test_client - :find_test_types_and_methods(uri) - :thenCall( - ---@param test_classes JavaTestFindJavaProjectsResponse - function(test_classes) - log.debug('following test classses', test_classes) - test_details = test_classes[1] - - return test_client:resolve_junit_launch_arguments( - java_test_adapter.get_junit_launch_argument_params(test_details) - ) - end - ) - :thenCall( - ---@param res_launch_args JavaTestJunitLaunchArguments - function(res_launch_args) - log.debug('generated launch args ', res_launch_args) - - launch_args = res_launch_args - - return debug_client:resolve_java_executable( - launch_args.mainClass, - launch_args.projectName - ) - end - ) - :thenCall( - ---@param res_java_exec JavaDebugResolveJavaExecutableResponse - function(res_java_exec) - log.debug('resolved java executable', res_java_exec) - - local dap_launcher_config = java_test_adapter.get_dap_launcher_config( - test_details, - launch_args, - res_java_exec, - { - debug = true, - } - ) - - log.debug('dap launcher config is: ', dap_launcher_config) - - return M.dap_run(dap_launcher_config) - end - ) -end - -function M.dap_run(config) - log.info('running dap with config: ', config) - - local function get_stream_reader(conn) - return vim.schedule_wrap(function(err, buffer) - assert(not err, err) - - if buffer then - vim.print(buffer) - else - conn:close() - end - end) - end - - ---@type uv_tcp_t - local server - - require('dap').run(config, { - before = function(conf) - log.debug('running before dap callback') - - server = assert(vim.loop.new_tcp(), 'uv.new_tcp() must return handle') - server:bind('127.0.0.1', 0) - server:listen(128, function(err) - assert(not err, err) - - local sock = assert(vim.loop.new_tcp(), 'uv.new_tcp must return handle') - server:accept(sock) - sock:read_start(get_stream_reader(sock)) - end) - - conf.args = - conf.args:gsub('-port ([0-9]+)', '-port ' .. server:getsockname().port) - - return conf - end, - - after = function() - vim.debug('running after dap callback') - - if server then - server:shutdown() - server:close() - end - end, - }) -end - ----Returns all test methods in the current workspace ----@return Promise -function M.get_all_test_methods() - local java_test_client = M.get_java_test_client() - - return java_test_client - :find_java_projects() - :thenCall( - ---@param projects JavaTestFindJavaProjectsResponse - function(projects) - projects = List:new(projects) - - local pkg_promises = projects:map(function(project) - return java_test_client:find_test_packages_and_types( - project.jdtHandler - ) - end) - - return Promise.all(pkg_promises) - end - ) - :thenCall( - ---@param pkgs JavaTestFindTestPackagesAndTypesResponse[] - function(pkgs) - ---@type List - local test_promises = List:new(pkgs) - :flatten() - :map(function(pkg) - return pkg.children - end) - :flatten() - :map(function(pkg) - return java_test_client:find_test_types_and_methods(pkg.uri) - end) - - return Promise.all(test_promises) - end - ) - :thenCall(function(tests) - tests = List:new(tests) - - return tests - :flatten() - :map(function(test_classes) - return test_classes.children - end) - :flatten() - end) -end - -return M diff --git a/lua/java-core/ls/helpers/test-helper.lua b/lua/java-core/ls/helpers/test-helper.lua index 4bf93ea..78e4211 100644 --- a/lua/java-core/ls/helpers/test-helper.lua +++ b/lua/java-core/ls/helpers/test-helper.lua @@ -5,16 +5,17 @@ local List = require('java-core.utils.list') local Promise = require('java-core.utils.promise') local JavaTestClient = require('java-core.ls.clients.java-test-client') local JavaDebugClient = require('java-core.ls.clients.java-debug-client') +local JavaDap = require('java-core.dap') ----@class JavaTestHelper ----@field client JDTLSClient ----@field debug_client JavaDebugClient ----@field test_client JavaTestClient +---@class JavaCoreTestHelper +---@field client JavaCoreJdtlsClient +---@field debug_client JavaCoreDebugClient +---@field test_client JavaCoreTestClient local M = {} ---Returns a new test helper client ---@param args { client: LSPClient } ----@return JavaTestHelper +---@return JavaCoreTestHelper function M:new(args) local o = { client = args.client, @@ -31,19 +32,6 @@ function M:new(args) return o end -function M:run_current_test_class() - local buffer = vim.api.nvim_get_current_buf() - local uri = vim.uri_from_bufnr(buffer) - - log.info('running current class at: ', uri) - - return self.test_client - :find_test_types_and_methods(uri) - :thenCall(function(test_classes) - return self:run_test(test_classes[1]) - end) -end - --@TODO all_tests are not running --https://github.com/nvim-java/java-core/issues/9 ---Running all tests @@ -86,6 +74,31 @@ function M:__run_all() ) end +---Returns test classes in the given buffer +---@param buffer integer +---@return Promise +function M:get_test_class_by_buffer(buffer) + log.info('finding test class by buffer') + + return Promise.resolve() + :thenCall(function() + if not vim.api.nvim_buf_is_valid(buffer) then + local msg = ('passed buffer %s is not valid'):format(buffer) + + log.fmt_error(msg) + error(msg) + end + + return vim.uri_from_bufnr(buffer) + end) + :thenCall(function(uri) + return self.test_client:find_test_types_and_methods(uri) + end) +end + +---Run the given test +---@param tests JavaTestFindJavaProjectsResponse +---@return Promise function M:run_test(tests) ---@type JavaTestJunitLaunchArguments local launch_args @@ -116,58 +129,9 @@ function M:run_test(tests) log.debug('dap launcher config is: ', dap_launcher_config) - return M.dap_run(dap_launcher_config) + return JavaDap.dap_run(dap_launcher_config) end ) end -function M.dap_run(config) - log.info('running dap with config: ', config) - - local function get_stream_reader(conn) - return vim.schedule_wrap(function(err, buffer) - assert(not err, err) - - if buffer then - vim.print(buffer) - else - conn:close() - end - end) - end - - ---@type uv_tcp_t - local server - - require('dap').run(config, { - before = function(conf) - log.debug('running before dap callback') - - server = assert(vim.loop.new_tcp(), 'uv.new_tcp() must return handle') - server:bind('127.0.0.1', 0) - server:listen(128, function(err) - assert(not err, err) - - local sock = assert(vim.loop.new_tcp(), 'uv.new_tcp must return handle') - server:accept(sock) - sock:read_start(get_stream_reader(sock)) - end) - - conf.args = - conf.args:gsub('-port ([0-9]+)', '-port ' .. server:getsockname().port) - - return conf - end, - - after = function() - vim.debug('running after dap callback') - - if server then - server:shutdown() - server:close() - end - end, - }) -end - return M diff --git a/lua/java-core/server.lua b/lua/java-core/server.lua index 8b040e7..92cd453 100644 --- a/lua/java-core/server.lua +++ b/lua/java-core/server.lua @@ -76,6 +76,7 @@ function M.get_config(opts) end ---Returns a function that finds the java project root +---@private ---@param root_markers string[] list of files to find the root dir of a project ---@return function function M.get_root_finder(root_markers) diff --git a/lua/java-core/utils/list.lua b/lua/java-core/utils/list.lua index fcf34c8..8722563 100644 --- a/lua/java-core/utils/list.lua +++ b/lua/java-core/utils/list.lua @@ -91,4 +91,25 @@ function M:join(separator) return table.concat(self, separator) end +---Calls the given callback for each element +---@param callback fun(value: any, index: integer) +function M:for_each(callback) + for i, v in ipairs(self) do + callback(v, i) + end +end + +---Returns true if every element in the list passes the validation +---@param validator fun(value: any, index: integer): boolean +---@return boolean +function M:every(validator) + for i, v in ipairs(self) do + if not validator(v, i) then + return false + end + end + + return true +end + return M diff --git a/lua/java-core/utils/log.lua b/lua/java-core/utils/log.lua index ea2a441..e97837e 100644 --- a/lua/java-core/utils/log.lua +++ b/lua/java-core/utils/log.lua @@ -13,7 +13,7 @@ -- User configuration section local default_config = { -- Name of the plugin. Prepended to log messages - plugin = 'nvim-java', + plugin = 'nvim-java-core', -- Should print the output to neovim while running use_console = true, diff --git a/lua/java-core/utils/lsp.lua b/lua/java-core/utils/lsp.lua index 72fc12d..cb379d4 100644 --- a/lua/java-core/utils/lsp.lua +++ b/lua/java-core/utils/lsp.lua @@ -21,6 +21,7 @@ function M.get_jdtls_client() if not client then local msg = 'No active jdtls client found' + log.error(msg) error(msg) end diff --git a/lua/java-core/utils/notify.lua b/lua/java-core/utils/notify.lua new file mode 100644 index 0000000..6a4ac77 --- /dev/null +++ b/lua/java-core/utils/notify.lua @@ -0,0 +1,26 @@ +local M = { + opts = {}, +} + +local function index(this, level) + return function(msg, opts) + vim.notify( + msg, + vim.log.levels[level:upper()], + vim.tbl_deep_extend('force', this.opts or {}, opts or {}) + ) + end +end + +setmetatable(M, { + __index = index, + __call = function(_, opts) + return setmetatable({ opts = opts or {} }, { + __index = index, + }) + end, +}) + +return M({ + title = 'Java', +}) diff --git a/plugin/java.lua b/plugin/java.lua deleted file mode 100644 index 587f642..0000000 --- a/plugin/java.lua +++ /dev/null @@ -1 +0,0 @@ --- vim.api.nvim_create_user_command('JavaRun', require('java-core').__run, {}) From dec55dace315504965cdd9652ff16dbb4f72ad6e Mon Sep 17 00:00:00 2001 From: s1n7ax Date: Tue, 14 Nov 2023 00:10:01 +0530 Subject: [PATCH 2/2] fix(test): get_config API is no longer available --- tests/java/java_spec.lua | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/java/java_spec.lua b/tests/java/java_spec.lua index c4568cc..a041c5f 100644 --- a/tests/java/java_spec.lua +++ b/tests/java/java_spec.lua @@ -1,7 +1,5 @@ -local java = require('java-core') - describe('setup', function() it('get_config API is available', function() - assert(java.get_config, 'get_config API not found') + assert(require('java-core.dap'), 'dap module is available') end) end)