From c4819d1625c59747d4a6c3de8c86e62bc2ca84ab Mon Sep 17 00:00:00 2001 From: rayx Date: Tue, 31 Oct 2023 16:30:38 +1100 Subject: [PATCH] CLI refact (#391) * some refact of gotest * issue #376 add handlers to async formatting * issue #343 title length * add parallel flag * disable trace log * Error lines output in github action * Go mod update in fixtures --- README.md | 6 +- lua/go.lua | 1 + lua/go/asyncmake.lua | 165 ++++----- lua/go/format.lua | 30 +- lua/go/gopls.lua | 22 +- lua/go/gotest.lua | 326 ++++++++---------- lua/go/lsp.lua | 11 - lua/go/term.lua | 3 +- lua/tests/fixtures/coverage/go.mod | 4 +- lua/tests/fixtures/fill/go.mod | 4 +- lua/tests/fixtures/fixplurals/go.mod | 4 +- lua/tests/fixtures/fmt/go.mod | 4 +- lua/tests/fixtures/ts/go.mod | 4 +- lua/tests/go_test_spec.lua | 70 ++-- playground/sampleApp/pkg/fib_test.go | 24 ++ playground/sampleApp/pkg/findAllSubStr.go | 4 + .../sampleApp/pkg/findAllSubStr_test.go | 6 + 17 files changed, 366 insertions(+), 322 deletions(-) create mode 100644 playground/sampleApp/pkg/fib_test.go diff --git a/README.md b/README.md index 63cfde5..e8364e5 100644 --- a/README.md +++ b/README.md @@ -292,7 +292,8 @@ first run of `GoFmt` may fail. Recommended to run `GoInstallBinaries` to install | GoTest -n | test nearest, see GoTestFunc | | GoTest -f | test current file, see GoTestFile | | GoTest -n 1 | -count=1 flag | -| GoTest -p | test current package, see GoTestPkg | +| GoTest -p {pkgname} | test package, see GoTestPkg, test current package if {pkgname} not specified | +| GoTest -parallel {number} | test current package with parallel number | | GoTest -b {build_flags} | run `go test` with build flags e.g. `-gcflags=.` | | GoTest -t yourtags | go test ./... -tags=yourtags, see notes | | GoTest -a your_args | go test ./... -args=yourargs, see notes | @@ -843,6 +844,9 @@ require('go').setup({ posititon = 'auto', -- one of {`top`, `bottom`, `left`, `right`, `center`, `auto`} width = 0.45, -- width of float window if not auto height = 0.98, -- height of float window if not auto + title_colors = 'nord', -- default to nord, one of {'nord', 'tokyo', 'dracula', 'rainbow', 'solarized ', 'monokai'} + -- can also set to a list of colors to define colors to choose from + -- e.g {'#D8DEE9', '#5E81AC', '#88C0D0', '#EBCB8B', '#A3BE8C', '#B48EAD'} }, trouble = false, -- true: use trouble to open quickfix test_efm = false, -- errorfomat for quickfix, default mix mode, set to true will be efm only diff --git a/lua/go.lua b/lua/go.lua index 1a1670a..2728a74 100644 --- a/lua/go.lua +++ b/lua/go.lua @@ -125,6 +125,7 @@ _GO_NVIM_CFG = { posititon = 'auto', -- one of {`top`, `bottom`, `left`, `right`, `center`, `auto`} width = 0.45, -- width of float window if not auto height = 0.98, -- height of float window if not auto + title_colors = 'nord', -- table of colors for title, 'rainbow' for system default of rainbow colors }, trouble = false, -- true: use trouble to open quickfix test_efm = false, -- errorfomat for quickfix, default mix mode, set to true will be efm only diff --git a/lua/go/asyncmake.lua b/lua/go/asyncmake.lua index 2e3d32b..68e82c8 100644 --- a/lua/go/asyncmake.lua +++ b/lua/go/asyncmake.lua @@ -37,13 +37,11 @@ local long_opts = { fuzz = 'f', } -local short_opts = 'a:vcC:f:t:b:n:Fr:g' +local short_opts = 'a:ct:b:Fg' local bench_opts = { '-benchmem', '-cpuprofile', 'profile.out' } function M.make(...) local args = { ... } - local lines = {} - local errorlines = {} local winnr = vim.fn.win_getid() local bufnr = vim.api.nvim_win_get_buf(winnr) local makeprg = vim.api.nvim_buf_get_option(bufnr, 'makeprg') @@ -151,46 +149,46 @@ function M.make(...) local bench = false if makeprg:find('go test') then - log('go test') - runner = 'go test' - efm = compile_efm() - if optarg['c'] then - log('compile test') - compile_test = true - end - for _, arg in ipairs(args) do - --check if it is bench test - if arg:find('-bench') then - bench = true - end - end - - if optarg['v'] then - table.insert(cmd, '-v') - end - - if optarg['C'] then - table.insert(cmd, '-coverprofile=' .. optarg['C']) - end - if optarg['f'] then - log('fuzz test') - table.insert(cmd, '-fuzz') - end - if optarg['n'] then - table.insert(cmd, '-count=' .. optarg['n']) - end - if not bench and compile_test then - table.insert(cmd, '-c') - end - if optarg['r'] then - log('run test', optarg['r']) - table.insert(cmd, '-run') - table.insert(cmd, optarg['r']) - end - if optarg['b'] then - log('build test flags', optarg['b']) - table.insert(cmd, optarg['b']) - end + -- log('go test') + -- runner = 'go test' + -- efm = compile_efm() + -- if optarg['c'] then + -- log('compile test') + -- compile_test = true + -- end + -- for _, arg in ipairs(args) do + -- --check if it is bench test + -- if arg:find('-bench') then + -- bench = true + -- end + -- end + + -- if optarg['v'] then + -- table.insert(cmd, '-v') + -- end + + -- if optarg['C'] then + -- table.insert(cmd, '-coverprofile=' .. optarg['C']) + -- end + -- if optarg['f'] then + -- log('fuzz test') + -- table.insert(cmd, '-fuzz') + -- end + -- if optarg['n'] then + -- table.insert(cmd, '-count=' .. optarg['n']) + -- end + -- if not bench and compile_test then + -- table.insert(cmd, '-c') + -- end + -- if optarg['r'] then + -- log('run test', optarg['r']) + -- table.insert(cmd, '-run') + -- table.insert(cmd, optarg['r']) + -- end + -- if optarg['b'] then + -- log('build test flags', optarg['b']) + -- table.insert(cmd, optarg['b']) + -- end end if bench then @@ -208,29 +206,36 @@ function M.make(...) end end - local function handle_color(line) - if _GO_NVIM_CFG.run_in_floaterm or optarg['F'] then - return line - end - if tonumber(vim.fn.match(line, '\\%x1b\\[[0-9;]\\+')) < 0 then - return line - end - if type(line) ~= 'string' then - return line - end - line = vim.fn.substitute(line, '\\%x1b\\[[0-9;]\\+[mK]', '', 'g') - log(line) - return line - end - if _GO_NVIM_CFG.run_in_floaterm or optarg['F'] then local term = require('go.term').run - cmd = table.concat(cmd, ' ') - term({ cmd = cmd, autoclose = false }) - return + local cmdstr = table.concat(cmd, ' ') + term({ cmd = cmdstr, autoclose = false }) + return cmd + end + return M.runjob(cmd, runner, efm, args) +end + +local function handle_color(line) + if tonumber(vim.fn.match(line, '\\%x1b\\[[0-9;]\\+')) < 0 then + return line + end + if type(line) ~= 'string' then + return line end + line = vim.fn.substitute(line, '\\%x1b\\[[0-9;]\\+[mK]', '', 'g') + log(line) + return line +end + +M.runjob = function(cmd, runner, args, efm) + vim.validate({ cmd = { cmd, 't' }, runner = { runner, 's' } }) + + efm = efm or compile_efm() local failed = false local itemn = 1 + local lines = {} + local errorlines = {} + local cmdstr = vim.fn.join(cmd, ' ') -- cmd list run without shell, cmd string run with shell local package_path = (cmd[#cmd] or '') if package_path ~= nil then @@ -243,8 +248,6 @@ function M.make(...) else package_path = '' end - - local cmdstr = vim.fn.join(cmd, ' ') -- cmd list run without shell, cmd string run with shell local Sprite = util.load_plugin('guihua.lua', 'guihua.sprite') local sprite if Sprite then @@ -281,7 +284,7 @@ function M.make(...) if vim.fn.empty(vim.fn.glob(args[#args])) == 0 then -- pkg name in args changed = true if value:find('FAIL') == nil then - local p, fn, ln = extract_filepath(value, package_path) + local p, _, _ = extract_filepath(value, package_path) if p == true then -- path existed, but need to attach the pkg name -- log(fn, ln, package_path, package_path:gsub('%.%.%.', '')) -- remove ... in package path @@ -299,8 +302,8 @@ function M.make(...) log(value) end end - log(value, #lines) table.insert(lines, value) + log(value, #lines) if itemn == 1 and failed and changed then itemn = #lines end @@ -330,11 +333,9 @@ function M.make(...) end if event == 'exit' then + log('exit') sprite.on_close() - if type(cmd) == 'table' then - cmd = table.concat(cmd, ' ') - end - local info = cmd + local info = cmdstr local level = vim.log.levels.INFO if #errorlines > 0 then if #lines > 0 then @@ -342,26 +343,28 @@ function M.make(...) end trace(errorlines) vim.fn.setqflist({}, ' ', { - title = cmd, + title = info, lines = errorlines, efm = efm, }) failed = true log(errorlines[1], job_id) - vim.cmd([[echo v:shell_error]]) + vim.schedule(function() + vim.cmd([[echo v:shell_error]]) + end) elseif #lines > 0 then trace(lines) local opts = {} if _GO_NVIM_CFG.test_efm == true then efm = require('go.gotest').efm() opts = { - title = cmd, + title = info, lines = lines, efm = efm, } else opts = { - title = cmd, + title = info, lines = lines, } end @@ -370,12 +373,12 @@ function M.make(...) if tonumber(data) ~= 0 then failed = true - info = info .. ' exited with code: ' .. tostring(data) + info = info .. ' exited with code: ' .. tostring(data) .. vim.inspect(errorlines) level = vim.log.levels.ERROR end _GO_NVIM_CFG.job_id = nil if failed then - cmd = cmd .. ' go test failed' + info = info .. ' go test failed' level = vim.log.levels.WARN util.quickfix('botright copen') end @@ -385,6 +388,7 @@ function M.make(...) vim.notify(info .. ' failed', level) else vim.notify(info .. ' succeed', level) + vim.notify(table.concat(lines, '\n\r'), level) end failed = false _GO_NVIM_CFG.on_exit(event, data) @@ -393,17 +397,18 @@ function M.make(...) -- releative dir does not work without shell log('cmd ', cmdstr) - if is_windows then -- gitshell is more like cmd.exe - cmdstr = cmd + local runcmd = cmdstr + if is_windows then -- gitshell & cmd.exe prefer list + runcmd = cmd end - _GO_NVIM_CFG.job_id = vim.fn.jobstart(cmdstr, { + _GO_NVIM_CFG.job_id = vim.fn.jobstart(runcmd, { on_stderr = on_event, on_stdout = on_event, on_exit = on_event, stdout_buffered = true, stderr_buffered = true, }) - _GO_NVIM_CFG.on_jobstart(cmdstr) + _GO_NVIM_CFG.on_jobstart(runcmd) return cmd end @@ -419,5 +424,5 @@ M.stopjob = function(id) util.warn('failed to stop job ' .. tostring(id)) end end - +M.compile_efm = compile_efm return M diff --git a/lua/go/format.lua b/lua/go/format.lua index dd5c3e5..962cf8d 100644 --- a/lua/go/format.lua +++ b/lua/go/format.lua @@ -6,6 +6,11 @@ local log = utils.log local max_len = _GO_NVIM_CFG.max_line_len or 120 local gofmt = _GO_NVIM_CFG.gofmt or 'gofumpt' local vfn = vim.fn +local write_delay = 10 +if _GO_NVIM_CFG.lsp_fmt_async then + write_delay = 200 +end + local install = require('go.install').install local gofmt_args = _GO_NVIM_CFG.gofmt_args or { @@ -41,18 +46,19 @@ local run = function(fmtargs, bufnr, cmd) bufnr = bufnr, name = 'gopls', }) - vim.defer_fn(function() - if vfn.getbufinfo('%')[1].changed == 1 then - vim.cmd('noautocmd write') - end - end, 200) + if not _GO_NVIM_CFG.lsp_fmt_async then + vim.defer_fn(function() + if vfn.getbufinfo('%')[1].changed == 1 then + vim.cmd('noautocmd write') + end + end, write_delay) + end end local args = vim.deepcopy(fmtargs) table.insert(args, api.nvim_buf_get_name(bufnr)) log('formatting buffer... ' .. vim.inspect(args), vim.log.levels.DEBUG) - local old_lines = api.nvim_buf_get_lines(0, 0, -1, true) if cmd then table.insert(args, 1, cmd) @@ -93,7 +99,7 @@ local run = function(fmtargs, bufnr, cmd) if vfn.getbufinfo('%')[1].changed == 1 then vim.cmd('noautocmd write') end - end, 300) + end, 200) end, stdout_buffered = true, stderr_buffered = true, @@ -155,9 +161,13 @@ M.org_imports = function() bufnr = vim.api.nvim_get_current_buf(), name = 'gopls', }) - vim.defer_fn(function() - vim.cmd('noautocmd write') - end, 200) + if not _GO_NVIM_CFG.lsp_fmt_async then + vim.defer_fn(function() + if vfn.getbufinfo('%')[1].changed == 1 then + vim.cmd('noautocmd write') + end + end, write_delay) + end end) end diff --git a/lua/go/gopls.lua b/lua/go/gopls.lua index 1b40aa4..aa91df1 100644 --- a/lua/go/gopls.lua +++ b/lua/go/gopls.lua @@ -201,7 +201,8 @@ local function get_build_flags() return nil end end - +local range_format = 'textDocument/rangeFormatting' +local formatting = 'textDocument/formatting' M.setups = function() local setups = { capabilities = { @@ -279,6 +280,23 @@ M.setups = function() buildFlags = { '-tags', 'integration' }, }, }, + -- NOTE: it is important to add handler to formatting handlers + -- the async formatter will call these handlers when gopls responed + -- without these handlers, the file will not be saved + handlers = { + [range_format] = function(...) + vim.lsp.handlers[range_format](...) + if vfn.getbufinfo('%')[1].changed == 1 then + vim.cmd('noautocmd write') + end + end, + [formatting] = function(...) + vim.lsp.handlers[formatting](...) + if vfn.getbufinfo('%')[1].changed == 1 then + vim.cmd('noautocmd write') + end + end, + }, } setups.settings.gopls.semanticTokens = true local v = M.version() @@ -298,7 +316,7 @@ M.setups = function() setups.settings.gopls.buildFlags = { tags } end - if ver > 90 and _GO_NVIM_CFG.lsp_inlay_hints.enable then + if ver > 90 and _GO_NVIM_CFG.lsp_inlay_hints.enable and vim.fn.has('nvim-0.10') then setups.settings.gopls = vim.tbl_deep_extend('force', setups.settings.gopls, { hints = { assignVariableTypes = true, diff --git a/lua/go/gotest.lua b/lua/go/gotest.lua index fccfb69..7c86632 100644 --- a/lua/go/gotest.lua +++ b/lua/go/gotest.lua @@ -26,12 +26,13 @@ local long_opts = { } local sep = require('go.utils').sep() -local short_opts = 'a:cC:t:bsFmpn:v' +local short_opts = 'a:cC:b:fFmn:pst:rv' local bench_opts = { '-benchmem', '-cpuprofile', 'profile.out' } local os_name = vim.loop.os_uname().sysname local is_windows = os_name == 'Windows' or os_name == 'Windows_NT' -local is_git_shell = is_windows and (vim.fn.exists('$SHELL') and vim.fn.expand('$SHELL'):find('bash.exe') ~= nil) +local is_git_shell = is_windows + and (vim.fn.exists('$SHELL') and vim.fn.expand('$SHELL'):find('bash.exe') ~= nil) M.efm = function() local indent = [[%\\%( %\\)]] local efm = [[%-G=== RUN %.%#]] @@ -72,11 +73,10 @@ end -- return "-tags=tag1,tag2" M.get_build_tags = function(args, tbl) - -- local tags = "-tags" args = args or {} local tags = {} if _GO_NVIM_CFG.build_tags ~= '' then - tags = { _GO_NVIM_CFG.build_tags } + table.insert(tags, _GO_NVIM_CFG.build_tags) end local optarg, _, reminder = getopt.get_opts(args, short_opts, long_opts) @@ -90,13 +90,16 @@ M.get_build_tags = function(args, tbl) vim.list_extend(tags, rt) end + local t = '-tags' + if _GO_NVIM_CFG.test_runner == 'dlv' then + t = '--build-flags' + end if #tags > 0 then if tbl then - return { '-tags', table.concat(tags, ',') }, reminder, optarg + return { t, table.concat(tags, ',') }, reminder, optarg end - return '-tags=' .. table.concat(tags, ','), reminder, optarg + return t .. '=' .. table.concat(tags, ','), reminder, optarg end - return end function M.get_test_path() @@ -137,21 +140,25 @@ local function get_test_filebufnr() return bufnr end --- {-c: compile, -v: verbose, -t: tags, -b: bench, -s: select} -local function run_test(path, args) +local function cmd_builder(path, args) log(args) local compile = false local bench = false local extra_args = '' + for i, arg in ipairs(args) do + --check if it is bench test + if arg:find('-bench') then + bench = true + table.remove(args, i) + break + end + end local optarg, oid, reminder = getopt.get_opts(args, short_opts, long_opts) trace(optarg, oid, reminder) if optarg['c'] then path = utils.rel_path(true) -- vfn.expand("%:p:h") can not resolve releative path compile = true end - if optarg['b'] then - bench = true - end if reminder and #reminder > 0 then --if % in args expand to current file @@ -162,10 +169,6 @@ local function run_test(path, args) end end - if optarg['a'] then - extra_args = optarg['a'] - end - if next(reminder) then path = reminder[1] table.remove(reminder, 1) @@ -174,49 +177,56 @@ local function run_test(path, args) if _GO_NVIM_CFG.test_runner ~= test_runner then test_runner = _GO_NVIM_CFG.test_runner if not install(test_runner) then + vim.notify('test runner not found', vim.log.levels.INFO) test_runner = 'go' end end local tags = M.get_build_tags(args) - log(tags) - local cmd = {} + log('tags', tags) + local cmd = { 'go', 'test' } local run_in_floaterm = optarg['F'] or _GO_NVIM_CFG.run_in_floaterm if run_in_floaterm then - table.insert(cmd, test_runner or 'go') - table.insert(cmd, 'test') + cmd[1] = test_runner or 'go' end if not empty(tags) then cmd = vim.list_extend(cmd, { tags }) end - if optarg['C'] then - if run_in_floaterm then - table.insert(cmd, '-coverprofile=' .. optarg['C']) - else - table.insert(cmd, '-C') - table.insert(cmd, optarg['C']) - end + if optarg['c'] then + compile = true end - if optarg['n'] then - if run_in_floaterm then - table.insert(cmd, '-count=' .. optarg['n']) - else - table.insert(cmd, '-n') - table.insert(cmd, optarg['n']) - end + table.insert(cmd, '-count=' .. optarg['n']) end if (optarg['v'] or _GO_NVIM_CFG.verbose_tests) and _GO_NVIM_CFG.test_runner == 'go' then table.insert(cmd, '-v') end - if not empty(reminder) then - cmd = vim.list_extend(cmd, reminder) - log('****', reminder, cmd) + + if optarg['f'] then + log('fuzz test') + table.insert(cmd, '-fuzz') + end + + if optarg['P'] then + table.insert(cmd, '-parallel') + table.insert(cmd, optarg['P']) + end + + if optarg['r'] then + log('run test', optarg['r']) + table.insert(cmd, '-run') + table.insert(cmd, optarg['r']) + end + + if optarg['b'] and optarg['b'] ~= '' then + log('build test flags', optarg['b']) + assert(type(optarg['b']) == 'string', 'build flags must be string') + table.insert(cmd, optarg['b']) end if compile == true then @@ -240,11 +250,27 @@ local function run_test(path, args) end end - if #extra_args > 0 then - table.insert(cmd, '-a') - table.insert(cmd, extra_args) + if optarg['C'] then + table.insert(cmd, '-coverprofile=' .. optarg['C']) + end + + if not empty(reminder) then + cmd = vim.list_extend(cmd, reminder) + log('****', reminder, cmd) end - utils.log(cmd, args) + if optarg['a'] then + table.insert(cmd, '-args') + table.insert(cmd, optarg['a']) + end + return cmd, optarg, tags +end + +-- {-c: compile, -v: verbose, -t: tags, -b: bench, -s: select} +local function run_test(path, args) + log(args) + local cmd, optarg = cmd_builder(path, args) + log(cmd, args) + local run_in_floaterm = _GO_NVIM_CFG.run_in_floaterm or optarg['F'] if run_in_floaterm then install('richgo') local term = require('go.term').run @@ -257,7 +283,8 @@ local function run_test(path, args) vim.cmd([[setl makeprg=]] .. _GO_NVIM_CFG.go .. [[\ test]]) utils.log('test cmd', cmd) - return require('go.asyncmake').make(unpack(cmd)) + local asyncmake = require('go.asyncmake') + return asyncmake.runjob(cmd, 'go test', args) end M.test = function(...) @@ -278,8 +305,23 @@ M.test = function(...) package = 'p', } + local parallel = 0 + for i, arg in ipairs(args) do + --check if it is bench test + if arg:find('-parallel') then + parallel = args[i + 1]:match('%d+') + table.remove(args, i) + table.remove(args, i) + break + end + end local test_short_opts = 'a:vcC:t:bsfmnpF' local optarg, _, reminder = getopt.get_opts(args, test_short_opts, test_opts) + if parallel ~= 0 then + optarg['P'] = parallel + table.insert(args, '-P') + table.insert(args, parallel) + end -- if % in reminder expand to current file for i, v in ipairs(reminder) do @@ -383,11 +425,8 @@ M.get_testcase_name = function() end local function run_tests_with_ts_node(args, func_node, tblcase_ns) - local optarg, _, reminder = getopt.get_opts(args, short_opts, long_opts) - local tags = M.get_build_tags(args) - utils.log('args: ', args) - utils.log('tags: ', tags) - utils.log('parnode' .. vim.inspect(func_node)) + local fpath = M.get_test_path() + local cmd, optarg, tags = cmd_builder(fpath, args) local test_runner = _GO_NVIM_CFG.test_runner or 'go' @@ -395,54 +434,19 @@ local function run_tests_with_ts_node(args, func_node, tblcase_ns) if not install(test_runner) then test_runner = 'go' end - if test_runner == 'ginkgo' then - ginkgo.test_func(args) - end end - local run_flags = '-r' - - local cmd = {} - local run_in_floaterm = optarg['F'] or _GO_NVIM_CFG.run_in_floaterm - if run_in_floaterm then - table.insert(cmd, test_runner) - table.insert(cmd, 'test') - run_flags = '-run' + if test_runner == 'ginkgo' then + return ginkgo.test_func(args) end if optarg['s'] then return M.select_tests() end - if (optarg['v'] or _GO_NVIM_CFG.verbose_tests) and _GO_NVIM_CFG.test_runner == 'go' then - table.insert(cmd, '-v') - end - - if tags and tags ~= '' then - table.insert(cmd, tags) - end if func_node == nil or func_node.name == nil then return end - if optarg['n'] then - if run_in_floaterm then - table.insert(cmd, '-count') - table.insert(cmd, (optarg['n'] or '1')) - else - table.insert(cmd, '-n') - table.insert(cmd, (optarg['n'] or '1')) - end - end - - if optarg['C'] then - if run_in_floaterm then - table.insert(cmd, '-count') - table.insert(cmd, optarg['C']) - else - table.insert(cmd, '-C') - table.insert(cmd, optarg['C']) - end - end local tbl_name = '' if tblcase_ns then tbl_name = tblcase_ns:gsub('/', '//') @@ -452,50 +456,39 @@ local function run_tests_with_ts_node(args, func_node, tblcase_ns) end if func_node.name:find('Bench') then - if run_in_floaterm then - local bench = '-bench=' .. func_node.name .. tbl_name - table.insert(cmd, bench) - else - table.insert(cmd, '-b') - table.insert(cmd, func_node.name) + local bench = '-bench=' .. func_node.name .. tbl_name + for i, v in ipairs(cmd) do + if v:find('-bench') then + cmd[i] = bench + break + end + if i == #cmd then + table.insert(cmd, bench) + end end vim.list_extend(cmd, bench_opts) elseif func_node.name:find('Fuzz') then - if run_in_floaterm then - table.insert(cmd, '-fuzz=func_node.name') - else - table.insert(cmd, '-f') - table.insert(cmd, func_node.name) - end + table.insert(cmd, '-fuzz=' .. func_node.name) else - table.insert(cmd, run_flags) + table.insert(cmd, '-run') if is_windows then - table.insert(cmd, [[^]] .. func_node.name .. [[$]] .. tbl_name) + table.insert(cmd, [["^]] .. func_node.name .. [[$"]] .. tbl_name) else table.insert(cmd, [['^]] .. func_node.name .. [[$']] .. tbl_name) end end - local fpath = M.get_test_path() - table.insert(cmd, fpath) - - if optarg['a'] then - table.insert(cmd, '-a') - table.insert(cmd, optarg['a']) - end - if test_runner == 'dlv' then local runflag = string.format("-test.run='^%s$'%s", func_node.name, tbl_name) - if tags and #tags > 0 then - cmd = { 'dlv', 'test', fpath, '--build-flags', tags, '--', runflag } - else - cmd = { 'dlv', 'test', fpath, '--', runflag } - end + table.insert(cmd, 3, fpath) + table.insert(cmd, '--') + table.insert(cmd, runflag) log(cmd) local term = require('go.term').run term({ cmd = cmd, autoclose = false }) return end + local run_in_floaterm = optarg['F'] or _GO_NVIM_CFG.run_in_floaterm if run_in_floaterm then utils.log(cmd) @@ -505,13 +498,12 @@ local function run_tests_with_ts_node(args, func_node, tblcase_ns) term({ cmd = cmd, autoclose = false }) return end - vim.list_extend(cmd, reminder) vim.cmd([[setl makeprg=]] .. test_runner .. [[\ test]]) -- set_efm() utils.log('test cmd', cmd) - return require('go.asyncmake').make(unpack(cmd)) + return require('go.asyncmake').runjob(cmd, 'go test', args) end --options {s:select, F: floaterm} @@ -524,8 +516,7 @@ M.test_func = function(...) return M.select_tests() end - local parser_path = vim.api.nvim_get_runtime_file('parser' .. sep .. 'go.so', false)[1] - if not parser_path then + if not vim.api.nvim_get_runtime_file('parser' .. sep .. 'go.so', false)[1] then -- require('nvim-treesitter.install').commands.TSInstallSync['run!']('go') vim.notify( 'go treesitter parser not found, please Run `:TSInstallSync go`', @@ -566,18 +557,18 @@ M.get_test_cases = function() .. [[| sed -n 's/func\s\+\(Test.*\)(.*/\1/p' | xargs | sed 's/ /\\|/g']] -- TODO maybe with treesitter or lsp list all functions in current file and regex with Test if vfn.executable('sed') == 0 then + vim.notify('sed not found', vim.log.levels.WARN) return end - local tests = vfn.systemlist(cmd) + local tests_results = vfn.systemlist(cmd) if vim.v.shell_error ~= 0 then - utils.warn('go test failed' .. vim.inspect(tests)) + utils.warn('go test failed' .. vim.inspect(tests_results)) return end - return tests[1] + return tests_results[1] end - local sep = '|' - local testsstr = vim.fn.join(tests, sep) + local testsstr = vim.fn.join(tests, '|') utils.log(tests, testsstr) return testsstr, tests end @@ -593,18 +584,12 @@ M.test_file = function(...) return M.test_package(...) end - local optarg, _, reminder = getopt.get_opts(args, short_opts, long_opts) - - local run_in_floaterm = optarg['F'] or _GO_NVIM_CFG.run_in_floaterm - if vfn.empty(tests) == 1 then vim.notify('no test found fallback to package test', vim.log.levels.DEBUG) M.test_package(...) return end - local tags = M.get_build_tags(args) - local test_runner = _GO_NVIM_CFG.go if _GO_NVIM_CFG.test_runner ~= 'go' then test_runner = _GO_NVIM_CFG.test_runner @@ -618,79 +603,70 @@ M.test_file = function(...) local relpath = utils.rel_path(true) log(relpath) + -- + -- local optarg, _, reminder = getopt.get_opts(args, short_opts, long_opts) + -- + -- local run_in_floaterm = optarg['F'] or _GO_NVIM_CFG.run_in_floaterm + -- local tags = M.get_build_tags(args) + -- + -- local cmd_args = { 'go', 'test' } + -- if run_in_floaterm then + -- cmd_args[1] = test_runner or 'go' + -- end + -- + -- if (optarg['v'] or _GO_NVIM_CFG.verbose_tests) and _GO_NVIM_CFG.test_runner == 'go' then + -- table.insert(cmd_args, '-v') + -- end + -- + -- if tags ~= nil then + -- table.insert(cmd_args, tags) + -- end + -- + -- if next(reminder) then + -- vim.list_extend(cmd_args, reminder) + -- end + -- if optarg['n'] then + -- table.insert(cmd_args, '-count=' .. (optarg['n'] or '1')) + -- table.insert(cmd_args, optarg['n'] or '1') + -- end + -- + -- if optarg['C'] then + -- table.insert(cmd_args, '-coverprofile=' .. optarg['C']) + -- end + -- + local cmd_args, optarg = cmd_builder(relpath, args) - local cmd_args = {} - if run_in_floaterm then - table.insert(cmd_args, test_runner) - table.insert(cmd_args, 'test') - end - - if (optarg['v'] or _GO_NVIM_CFG.verbose_tests) and _GO_NVIM_CFG.test_runner == 'go' then - table.insert(cmd_args, '-v') - end - - if tags ~= nil then - table.insert(cmd_args, tags) - end - - if next(reminder) then - vim.list_extend(cmd_args, reminder) - end - if optarg['n'] then - if run_in_floaterm then - table.insert(cmd_args, '-count=' .. (optarg['n'] or '1')) - table.insert(cmd_args, optarg['n'] or '1') - else - table.insert(cmd_args, '-n') - table.insert(cmd_args, optarg['n'] or '1') - end - end - - if optarg['C'] then - if run_in_floaterm then - table.insert(cmd_args, '-coverprofile=' .. optarg['C']) - else - table.insert(cmd_args, '-C') - table.insert(cmd_args, optarg['C']) - end - end - - if run_in_floaterm then - table.insert(cmd_args, '-run') - else - table.insert(cmd_args, '-r') - end + table.insert(cmd_args, '-run') if is_windows then - tests = tests + tests = '"' .. tests .. '"' else tests = "'" .. tests .. "'" end table.insert(cmd_args, tests) -- shell script | is a pipe - table.insert(cmd_args, relpath) - if run_in_floaterm then + if optarg['F'] or _GO_NVIM_CFG.run_in_floaterm then install('richgo') local term = require('go.term').run cmd_args = richgo(cmd_args) - cmd_args = table.concat(cmd_args, ' ') + local cmd_args_str = table.concat(cmd_args, ' ') log(cmd_args) - term({ cmd = cmd_args, autoclose = false }) + term({ cmd = cmd_args_str, autoclose = false }) return cmd_args end if _GO_NVIM_CFG.test_runner == 'dlv' then cmd_args = { 'dlv', 'test', relpath, '--', '-test.run', tests } - cmd_args = table.concat(cmd_args, ' ') local term = require('go.term').run - term({ cmd = cmd_args, autoclose = false }) + term({ cmd = table.concat(cmd_args, ' '), autoclose = false }) + log(cmd_args) return cmd_args end vim.cmd([[setl makeprg=]] .. _GO_NVIM_CFG.go .. [[\ test]]) log(cmd_args) - local cmdret = require('go.asyncmake').make(unpack(cmd_args)) + local cmdret = require('go.asyncmake').runjob(cmd_args, 'go test', args) utils.log('test cmd: ', cmdret, ' finished') return cmdret diff --git a/lua/go/lsp.lua b/lua/go/lsp.lua index 0955776..7ffc7e5 100644 --- a/lua/go/lsp.lua +++ b/lua/go/lsp.lua @@ -7,17 +7,6 @@ local diagnostic_map = function(bufnr) api.nvim_buf_set_keymap(bufnr, 'n', ']O', ':lua vim.diagnostic.setloclist()', opts) end -if vim.lsp.buf.format == nil then - -- neovim < 0.8 only - vim.lsp.buf.format = function(options) - if options.async then - vim.lsp.buf.formatting() - else - vim.lsp.buf.formatting_sync() - end - end -end - if vim.fn.has('nvim-0.8.3') ~= 1 then return vim.notify( 'Please upgrade to neovim 0.8.3 or above', diff --git a/lua/go/term.lua b/lua/go/term.lua index e845850..537e3b6 100644 --- a/lua/go/term.lua +++ b/lua/go/term.lua @@ -88,6 +88,7 @@ local term = function(opts) opts.win_height = opts.win_height or win_height opts.win_width = opts.win_width or win_width opts.border = opts.border or 'single' + opts.title_colors = _GO_NVIM_CFG.floaterm.title_colors if opts.autoclose == nil then opts.autoclose = true end @@ -95,7 +96,7 @@ local term = function(opts) if type(opts.cmd) == 'table' then opts.cmd = table.concat(opts.cmd, ' ') end - opts.title = opts.title or opts.cmd:sub(1, 40) + opts.title = opts.title or opts.cmd:sub(1, win_width - 4) utils.log(opts) local buf, win, closer = guihua_term.floating_term(opts) diff --git a/lua/tests/fixtures/coverage/go.mod b/lua/tests/fixtures/coverage/go.mod index f6b500b..ecf962e 100644 --- a/lua/tests/fixtures/coverage/go.mod +++ b/lua/tests/fixtures/coverage/go.mod @@ -1,3 +1,3 @@ -module github.com/go.nvim +module github.com/ray-x/go.nvim/lua/tests/fixtures/coverage -go 1.17 +go 1.21.1 diff --git a/lua/tests/fixtures/fill/go.mod b/lua/tests/fixtures/fill/go.mod index cc124e1..7192272 100644 --- a/lua/tests/fixtures/fill/go.mod +++ b/lua/tests/fixtures/fill/go.mod @@ -1,3 +1,3 @@ -module fill +module github.com/ray-x/go.nvim/lua/tests/fixtures/fill -go 1.17 +go 1.21.1 diff --git a/lua/tests/fixtures/fixplurals/go.mod b/lua/tests/fixtures/fixplurals/go.mod index e126006..c39324e 100644 --- a/lua/tests/fixtures/fixplurals/go.mod +++ b/lua/tests/fixtures/fixplurals/go.mod @@ -1,3 +1,3 @@ -module github.com/go.nvim +module github.com/ray-x/go.nvim/lua/tests/fixtures/fixplurals -go 1.18 +go 1.21.1 diff --git a/lua/tests/fixtures/fmt/go.mod b/lua/tests/fixtures/fmt/go.mod index f6b500b..e54882e 100644 --- a/lua/tests/fixtures/fmt/go.mod +++ b/lua/tests/fixtures/fmt/go.mod @@ -1,3 +1,3 @@ -module github.com/go.nvim +module github.com/ray-x/go.nvim/lua/tests/fixtures/fmt -go 1.17 +go 1.21.1 diff --git a/lua/tests/fixtures/ts/go.mod b/lua/tests/fixtures/ts/go.mod index 6967dfd..1c26e8a 100644 --- a/lua/tests/fixtures/ts/go.mod +++ b/lua/tests/fixtures/ts/go.mod @@ -1,3 +1,3 @@ -module main +module github.com/ray-x/go.nvim/lua/tests/fixtures/ts -go 1.18 +go 1.21.1 diff --git a/lua/tests/go_test_spec.lua b/lua/tests/go_test_spec.lua index cba4a88..f353095 100644 --- a/lua/tests/go_test_spec.lua +++ b/lua/tests/go_test_spec.lua @@ -22,7 +22,7 @@ describe('should run func test', function() vim.fn.setpos('.', { 0, 5, 11, 0 }) local cmd = require('go.gotest').test_func() - eq({ 'go', 'test', '-run', [['^Test_branch$']], './lua/tests/fixtures/coverage' }, cmd) + eq({ 'go', 'test', './lua/tests/fixtures/coverage', '-run', [['^Test_branch$']] }, cmd) end) it('should test function inside a source code', function() -- @@ -40,7 +40,7 @@ describe('should run func test', function() vim.fn.setpos('.', { 0, 6, 11, 0 }) local cmd = require('go.gotest').test_func() - eq({ 'go', 'test', '-run', [['^Test_branch$']], './lua/tests/fixtures/coverage' }, cmd) + eq({ 'go', 'test', './lua/tests/fixtures/coverage', '-run', [['^Test_branch$']] }, cmd) end) it('should test function with additional args to test binary', function() -- @@ -58,18 +58,15 @@ describe('should run func test', function() vim.fn.setpos('.', { 0, 5, 11, 0 }) local cmd = require('go.gotest').test_func('-a', 'mock=true') - eq( - { - 'go', - 'test', - '-run', - [['^Test_branch$']], - './lua/tests/fixtures/coverage', - '-args', - 'mock=true', - }, - cmd - ) + eq({ + 'go', + 'test', + './lua/tests/fixtures/coverage', + '-args', + 'mock=true', + '-run', + [['^Test_branch$']], + }, cmd) end) end) @@ -93,7 +90,13 @@ describe('should run test file', function() vim.fn.setpos('.', { 0, 5, 11, 0 }) local cmd = require('go.gotest').test_file() - eq({ 'go', 'test', '-run', [['Test_branch|TestBranch|TestBranchSubTest']], 'lua/tests/fixtures/coverage' }, cmd) + eq({ + 'go', + 'test', + 'lua/tests/fixtures/coverage', + '-run', + [['Test_branch|TestBranch|TestBranchSubTest']], + }, cmd) end) end) @@ -116,17 +119,14 @@ describe('should run test file with flags', function() vim.fn.setpos('.', { 0, 5, 11, 0 }) local cmd = require('go.gotest').test_file('-t', 'tag1') - eq( - { - 'go', - 'test', - '-tags=tag1', - '-run', - [['Test_branch|TestBranch|TestBranchSubTest']], - 'lua/tests/fixtures/coverage', - }, - cmd - ) + eq({ + 'go', + 'test', + '-tags=tag1', + 'lua/tests/fixtures/coverage', + '-run', + [['Test_branch|TestBranch|TestBranchSubTest']], + }, cmd) end) end) @@ -172,7 +172,7 @@ describe('should run test ', function() local cmd = require('go.gotest').test('-n', '-t', 'tags1') eq( - { 'go', 'test', '-tags=tags1', '-run', [['^Test_branch$']], './lua/tests/fixtures/coverage' }, + { 'go', 'test', '-tags=tags1', './lua/tests/fixtures/coverage', '-run', [['^Test_branch$']] }, cmd ) end) @@ -225,9 +225,9 @@ describe('should run test file with flags inside file', function() 'go', 'test', '-tags=tag1,integration,unit', + 'lua/tests/fixtures/coverage', '-run', [['TestTag']], - 'lua/tests/fixtures/coverage', }, cmd) end) end) @@ -248,7 +248,7 @@ describe('should run subcase test', function() vim.cmd("silent exe 'e " .. path .. "'") vim.fn.setpos('.', { 1, 18, 11, 0 }) local cmd = require('go.gotest').test_tblcase() - eq({ 'go', 'test', '-run', [['^Test_branch$'/"a10"]], './lua/tests/fixtures/coverage' }, cmd) + eq({ 'go', 'test', './lua/tests/fixtures/coverage', '-run', [['^Test_branch$'/"a10"]] }, cmd) end) it('should test subcase in table test style when cursor inside test block', function() @@ -264,7 +264,7 @@ describe('should run subcase test', function() vim.cmd("silent exe 'e " .. path .. "'") vim.fn.setpos('.', { 1, 29, 12, 0 }) local cmd = require('go.gotest').test_tblcase() - eq({ 'go', 'test', '-run', [['^Test_branch$'/"b10"]], './lua/tests/fixtures/coverage' }, cmd) + eq({ 'go', 'test', './lua/tests/fixtures/coverage', '-run', [['^Test_branch$'/"b10"]] }, cmd) end) it('should test subcase in subtest style', function() @@ -280,7 +280,10 @@ describe('should run subcase test', function() vim.cmd("silent exe 'e " .. path .. "'") vim.fn.setpos('.', { 1, 75, 11, 0 }) local cmd = require('go.gotest').test_tblcase() - eq({ 'go', 'test', '-run', [['^TestBranchSubTest$'/"a11"]], './lua/tests/fixtures/coverage' }, cmd) + eq( + { 'go', 'test', './lua/tests/fixtures/coverage', '-run', [['^TestBranchSubTest$'/"a11"]] }, + cmd + ) end) it('should test subcase in subtest style when cursor insde test block', function() @@ -296,6 +299,9 @@ describe('should run subcase test', function() vim.cmd("silent exe 'e " .. path .. "'") vim.fn.setpos('.', { 1, 82, 7, 0 }) local cmd = require('go.gotest').test_tblcase() - eq({ 'go', 'test', '-run', [['^TestBranchSubTest$'/"b11"]], './lua/tests/fixtures/coverage' }, cmd) + eq( + { 'go', 'test', './lua/tests/fixtures/coverage', '-run', [['^TestBranchSubTest$'/"b11"]] }, + cmd + ) end) end) diff --git a/playground/sampleApp/pkg/fib_test.go b/playground/sampleApp/pkg/fib_test.go new file mode 100644 index 0000000..1118286 --- /dev/null +++ b/playground/sampleApp/pkg/fib_test.go @@ -0,0 +1,24 @@ +package pkg + +import ( + "strconv" + "testing" +) + +func Fib(n string) string { + nn, _ := strconv.Atoi(n) + if nn < 2 { + r := strconv.Itoa(nn) + return r + } + n1, _ := strconv.Atoi(Fib(strconv.Itoa(nn - 1))) + n2, _ := strconv.Atoi(Fib(strconv.Itoa(nn - 2))) + return strconv.Itoa(n1 + n2) +} + +func BenchmarkFib10(b *testing.B) { + // run the Fib function b.N times + for n := 0; n < b.N; n++ { + Fib("10") + } +} diff --git a/playground/sampleApp/pkg/findAllSubStr.go b/playground/sampleApp/pkg/findAllSubStr.go index 55048a0..54b4d14 100644 --- a/playground/sampleApp/pkg/findAllSubStr.go +++ b/playground/sampleApp/pkg/findAllSubStr.go @@ -2,6 +2,7 @@ package pkg import ( "strings" + "sync" ) func FindAllSubStr(stack, niddle string) (result []int) { @@ -19,10 +20,13 @@ func FindAllSubStr(stack, niddle string) (result []int) { func FindSubStr(stack, niddle string) (result int) { stack = strings.ToLower(stack) niddle = strings.ToLower(niddle) + mu := sync.Mutex{} for idx := 1; idx >= 0; { + mu.Lock() if idx = strings.Index(stack, niddle); idx != -1 { return idx } + mu.Unlock() } return -1 } diff --git a/playground/sampleApp/pkg/findAllSubStr_test.go b/playground/sampleApp/pkg/findAllSubStr_test.go index 148d69d..3a52eb0 100644 --- a/playground/sampleApp/pkg/findAllSubStr_test.go +++ b/playground/sampleApp/pkg/findAllSubStr_test.go @@ -64,3 +64,9 @@ func TestFindSubStr(t *testing.T) { }) } } + +func BenchmarkPrimeNumbers(b *testing.B) { + for i := 0; i < b.N; i++ { + FindSubStr("Foobarfobafoooo", "foo") + } +}