From 9d6bc761d43c6821ff61ca8aa20cf73b94748201 Mon Sep 17 00:00:00 2001 From: Smirnov Oleksandr Date: Mon, 17 Jul 2023 18:31:21 +0300 Subject: [PATCH 01/24] healthcheck: refactoring, remove deprecation wanings (#35) * refactor(checkhealth): remove deprecation warnings, complete rewrite * refactor(checkhealth): rename util file * style(healthchecker): reformat lua in vim file * refactor(health): move all report function into table --- autoload/health/gopher.vim | 2 +- lua/gopher/_utils/{_health.lua => health.lua} | 0 lua/gopher/health.lua | 79 ++++++++++++------- 3 files changed, 52 insertions(+), 29 deletions(-) rename lua/gopher/_utils/{_health.lua => health.lua} (100%) diff --git a/autoload/health/gopher.vim b/autoload/health/gopher.vim index 7ff5205..4e3c56d 100644 --- a/autoload/health/gopher.vim +++ b/autoload/health/gopher.vim @@ -1,3 +1,3 @@ function! health#gopher#check() - lua require"gopher.health".check() + lua require("gopher.health").check() endfunction diff --git a/lua/gopher/_utils/_health.lua b/lua/gopher/_utils/health.lua similarity index 100% rename from lua/gopher/_utils/_health.lua rename to lua/gopher/_utils/health.lua diff --git a/lua/gopher/health.lua b/lua/gopher/health.lua index 17d76ec..935fbac 100644 --- a/lua/gopher/health.lua +++ b/lua/gopher/health.lua @@ -1,44 +1,67 @@ -local c = require("gopher.config").config.commands +local health = {} +local cmd = require("gopher.config").config.commands +local u = require "gopher._utils.health" -local requried_for_work_msg = "Gopher.nvim will not work without it!" -local M = { - _required = { - plugins = { - { lib = "plenary", help = requried_for_work_msg }, - { lib = "nvim-treesitter", help = requried_for_work_msg }, - { lib = "dap", help = "Required for set upping debugger" }, +local _h = vim.health or require "health" +local h = { + start = _h.start or _h.report_start, + ok = _h.ok or _h.report_ok, + warn = _h.warn or _h.report_warn, + error = _h.error or _h.report_error, + info = _h.info or _h.report_info, +} + +local deps = { + plugin = { + { lib = "dap", msg = "required for `gopher.dap`", optional = true }, + { lib = "plenary", msg = "required for everyting in gopher.nvim", optional = false }, + { lib = "nvim-treesitter", msg = "required for everyting in gopher.nvim", optional = false }, + }, + bin = { + { + bin = cmd.go, + msg = "required for :GoGet, :GoMod, :GoGenerate, :GoWork, :GoInstallDeps", + optional = false, }, - binarys = { - { bin = c.go, help = "required for GoMod, GoGet, GoGenerate command" }, - { bin = c.gomodifytags, help = "required for modify struct tags" }, - { bin = c.impl, help = "required for interface implementing" }, - { bin = c.gotests, help = "required for test(s) generation" }, - { bin = c.dlv, help = "required for debugger(nvim-dap)" }, + { bin = cmd.gomodifytags, msg = "required for :GoTagAdd, :GoTagRm", optional = false }, + { bin = cmd.impl, msg = "required for :GoImpl", optional = false }, + { bin = cmd.iferr, msg = "required for :GoIfErr", optional = false }, + { + bin = cmd.gotests, + msg = "required for :GoTestAdd, :GoTestsAll, :GoTestsExp", + optional = false, }, + { bin = cmd.dlv, msg = "required for debugging, (nvim-dap, `gopher.dap`)", optional = true }, }, } -function M.check() - local health = vim.health or require "health" - local u = require "gopher._utils._health" - - health.report_start "Required plugins" - for _, plugin in ipairs(M._required.plugins) do +function health.check() + h.start "required plugins" + for _, plugin in ipairs(deps.plugin) do if u.lualib_is_found(plugin.lib) then - health.report_ok(plugin.lib .. " installed.") + h.ok(plugin.lib .. " installed") else - health.report_error(plugin.lib .. " not found. " .. plugin.help) + if plugin.optional then + h.warn(plugin.lib .. " not found, " .. plugin.msg) + else + h.error(plugin.lib .. " not found, " .. plugin.msg) + end end end - health.report_start "Required go tools" - for _, binary in ipairs(M._required.binarys) do - if u.binary_is_found(binary.bin) then - health.report_ok(binary.bin .. " installed") + h.start "required binaries" + h.info "all those binaries can be installed by `:GoInstallDeps`" + for _, bin in ipairs(deps.bin) do + if u.binary_is_found(bin.bin) then + h.ok(bin.bin .. " installed") else - health.report_warn(binary.bin .. " is not installed but " .. binary.help) + if bin.optional then + h.warn(bin.bin .. " not found, " .. bin.msg) + else + h.error(bin.bin .. " not found, " .. bin.msg) + end end end end -return M +return health From 94250bb08a2e170d3b495f3c560c5b6e72cdc5db Mon Sep 17 00:00:00 2001 From: Smirnov Oleksandr Date: Mon, 17 Jul 2023 18:32:24 +0300 Subject: [PATCH 02/24] add editorconfig (#36) --- .editorconfig | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..48ce80f --- /dev/null +++ b/.editorconfig @@ -0,0 +1,17 @@ +root = true + +[*] +indent_style = space +indent_size = 4 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace=true +charset = utf-8 +max_line_length = 120 + +[*.{lua,vim}] +max_line_length = 100 +indent_size = 2 + +[*.{md,yml,yaml,toml}] +indent_size = 2 From 26b41bf68cc4882f07a0cc0505a4d3d9f42f0dbf Mon Sep 17 00:00:00 2001 From: Smirnov Oleksandr Date: Wed, 19 Jul 2023 23:38:23 +0300 Subject: [PATCH 03/24] refactor of public plugin's api (#37) * refactor: move all plugin functionality to init.lua * fix(commands): now it uses correct module paths * refactor(config): change way how it handles options * refactor(gotests): use correct config, change way how deps required, fix some typos * fix(healthchecker): use correct config * refactor(iferr): change api * refactor(impl): change api * refactor(installer): change api * refactor(struct_tags): change way of importting deps * refactor(struct_tags): rename M to struct_tags * run stylua * refactor(dap): make it all in one file, and make some refactoring * refactor(_utils): change way how it organizes * fix: use new _utils api * refactor(_utils.health): reorganize module * refactor(_utils.ts): some renameing, moving requires lines * run stylua --- lua/gopher/_utils/commands.lua | 19 +++--- lua/gopher/_utils/health.lua | 41 +++++++----- lua/gopher/_utils/init.lua | 75 ++++++++++----------- lua/gopher/_utils/ts/init.lua | 28 ++++---- lua/gopher/_utils/ts/nodes.lua | 20 +++--- lua/gopher/api.lua | 29 --------- lua/gopher/config.lua | 48 ++++++-------- lua/gopher/dap.lua | 116 +++++++++++++++++++++++++++++++++ lua/gopher/dap/config.lua | 98 ---------------------------- lua/gopher/dap/init.lua | 13 ---- lua/gopher/gotests.lua | 27 ++++---- lua/gopher/health.lua | 33 ++++------ lua/gopher/iferr.lua | 18 +++-- lua/gopher/impl.lua | 22 ++++--- lua/gopher/init.lua | 36 +++++++++- lua/gopher/installer.lua | 21 ++++-- lua/gopher/struct_tags.lua | 30 +++++---- plugin/gopher.vim | 26 ++++---- 18 files changed, 359 insertions(+), 341 deletions(-) delete mode 100644 lua/gopher/api.lua create mode 100644 lua/gopher/dap.lua delete mode 100644 lua/gopher/dap/config.lua delete mode 100644 lua/gopher/dap/init.lua diff --git a/lua/gopher/_utils/commands.lua b/lua/gopher/_utils/commands.lua index 33926a4..447a3af 100644 --- a/lua/gopher/_utils/commands.lua +++ b/lua/gopher/_utils/commands.lua @@ -1,14 +1,14 @@ +local Job = require "plenary.job" +local c = require("gopher.config").commands +local u = require "gopher._utils" + ---Run any go commands like `go generate`, `go get`, `go mod` ---@param cmd string ---@param ... string|string[] return function(cmd, ...) - local Job = require "plenary.job" - local c = require("gopher.config").config.commands - local u = require "gopher._utils" - local args = { ... } if #args == 0 then - u.notify("please provice any arguments", "error") + u.deferred_notify("please provice any arguments", vim.log.levels.ERROR) return end @@ -29,12 +29,15 @@ return function(cmd, ...) args = cmd_args, on_exit = function(_, retval) if retval ~= 0 then - u.notify("command 'go " .. unpack(cmd_args) .. "' exited with code " .. retval, "error") - u.notify(cmd .. " " .. unpack(cmd_args), "debug") + u.deferred_notify( + "command 'go " .. unpack(cmd_args) .. "' exited with code " .. retval, + vim.log.levels.ERROR + ) + u.deferred_notify(cmd .. " " .. unpack(cmd_args), vim.log.levels.DEBUG) return end - u.notify("go " .. cmd .. " was success runned", "info") + u.deferred_notify("go " .. cmd .. " was success runned", vim.log.levels.INFO) end, }):start() end diff --git a/lua/gopher/_utils/health.lua b/lua/gopher/_utils/health.lua index 5b12026..b651fe4 100644 --- a/lua/gopher/_utils/health.lua +++ b/lua/gopher/_utils/health.lua @@ -1,17 +1,26 @@ -return { - ---@param lib string - ---@return boolean - lualib_is_found = function(lib) - local is_found, _ = pcall(require, lib) - return is_found - end, +local h = vim.health or require "health" +local health = {} - ---@param bin string - ---@return boolean - binary_is_found = function(bin) - if vim.fn.executable(bin) == 1 then - return true - end - return false - end, -} +health.start = h.start or h.report_start +health.ok = h.ok or h.report_ok +health.warn = h.warn or h.report_warn +health.error = h.error or h.report_error +health.info = h.info or h.report_info + +---@param module string +---@return boolean +function health.is_lualib_found(module) + local is_found, _ = pcall(require, module) + return is_found +end + +---@param bin string +---@return boolean +function health.is_binary_found(bin) + if vim.fn.executable(bin) == 1 then + return true + end + return false +end + +return health diff --git a/lua/gopher/_utils/init.lua b/lua/gopher/_utils/init.lua index 190574f..a083a78 100644 --- a/lua/gopher/_utils/init.lua +++ b/lua/gopher/_utils/init.lua @@ -1,48 +1,39 @@ ----@diagnostic disable: param-type-mismatch -return { - ---@param t table - ---@return boolean - empty = function(t) - if t == nil then - return true - end +local utils = {} - return next(t) == nil - end, +---@param t table +---@return boolean +function utils.is_tbl_empty(t) + if t == nil then + return true + end + return next(t) == nil +end - ---@param s string - ---@return string - rtrim = function(s) - local n = #s - while n > 0 and s:find("^%s", n) do - n = n - 1 - end +---@param s string +---@return string +function utils.rtrim(s) + local n = #s + while n > 0 and s:find("^%s", n) do + n = n - 1 + end - return s:sub(1, n) - end, + return s:sub(1, n) +end - ---@param msg string - ---@param lvl string|integer - notify = function(msg, lvl) - local l - if lvl == "error" or lvl == 4 then - l = vim.log.levels.ERROR - elseif lvl == "info" or lvl == 2 then - l = vim.log.levels.INFO - elseif lvl == "debug" or lvl == 1 then - l = vim.log.levels.DEBUG - end +---@param msg string +---@param lvl any +function utils.deferred_notify(msg, lvl) + vim.defer_fn(function() + vim.notify(msg, lvl) + end, 0) +end - vim.defer_fn(function() - vim.notify(msg, l) - end, 0) - end, +-- safe require +---@param module string module name +function utils.sreq(module) + local ok, m = pcall(require, module) + assert(ok, string.format("gopher.nvim dependency error: %s not installed", module)) + return m +end - ---safe require - ---@param name string module name - sreq = function(name) - local ok, m = pcall(require, name) - assert(ok, string.format("gopher.nvim dependency error: %s not installed", name)) - return m - end, -} +return utils diff --git a/lua/gopher/_utils/ts/init.lua b/lua/gopher/_utils/ts/init.lua index ee24f49..aba3a94 100644 --- a/lua/gopher/_utils/ts/init.lua +++ b/lua/gopher/_utils/ts/init.lua @@ -1,7 +1,7 @@ ---@diagnostic disable: param-type-mismatch local nodes = require "gopher._utils.ts.nodes" local u = require "gopher._utils" -local M = { +local ts = { querys = { struct_block = [[((type_declaration (type_spec name:(type_identifier) @struct.name type: (struct_type)))@struct.declaration)]], em_struct_block = [[(field_declaration name:(field_identifier)@struct.name type: (struct_type)) @struct.declaration]], @@ -27,14 +27,14 @@ end ---@param bufnr string|nil ---@param do_notify boolean|nil ---@return table|nil -function M.get_struct_node_at_pos(row, col, bufnr, do_notify) +function ts.get_struct_node_at_pos(row, col, bufnr, do_notify) local notify = do_notify or true - local query = M.querys.struct_block .. " " .. M.querys.em_struct_block + local query = ts.querys.struct_block .. " " .. ts.querys.em_struct_block local bufn = bufnr or vim.api.nvim_get_current_buf() local ns = nodes.nodes_at_cursor(query, get_name_defaults(), bufn, row, col) if ns == nil then if notify then - u.notify("struct not found", "warn") + u.deferred_notify("struct not found", vim.log.levels.WARN) end else return ns[#ns] @@ -46,14 +46,14 @@ end ---@param bufnr string|nil ---@param do_notify boolean|nil ---@return table|nil -function M.get_func_method_node_at_pos(row, col, bufnr, do_notify) +function ts.get_func_method_node_at_pos(row, col, bufnr, do_notify) local notify = do_notify or true - local query = M.querys.func .. " " .. M.querys.method_name + local query = ts.querys.func .. " " .. ts.querys.method_name local bufn = bufnr or vim.api.nvim_get_current_buf() local ns = nodes.nodes_at_cursor(query, get_name_defaults(), bufn, row, col) if ns == nil then if notify then - u.notify("function not found", "warn") + u.deferred_notify("function not found", vim.log.levels.WARN) end else return ns[#ns] @@ -65,16 +65,16 @@ end ---@param bufnr string|nil ---@param do_notify boolean|nil ---@return table|nil -function M.get_package_node_at_pos(row, col, bufnr, do_notify) +function ts.get_package_node_at_pos(row, col, bufnr, do_notify) local notify = do_notify or true -- stylua: ignore if row > 10 then return end - local query = M.querys.package + local query = ts.querys.package local bufn = bufnr or vim.api.nvim_get_current_buf() local ns = nodes.nodes_at_cursor(query, get_name_defaults(), bufn, row, col) if ns == nil then if notify then - u.notify("package not found", "warn") + u.deferred_notify("package not found", vim.log.levels.WARN) return nil end else @@ -87,18 +87,18 @@ end ---@param bufnr string|nil ---@param do_notify boolean|nil ---@return table|nil -function M.get_interface_node_at_pos(row, col, bufnr, do_notify) +function ts.get_interface_node_at_pos(row, col, bufnr, do_notify) local notify = do_notify or true - local query = M.querys.interface + local query = ts.querys.interface local bufn = bufnr or vim.api.nvim_get_current_buf() local ns = nodes.nodes_at_cursor(query, get_name_defaults(), bufn, row, col) if ns == nil then if notify then - u.notify("interface not found", "warn") + u.deferred_notify("interface not found", vim.log.levels.WARN) end else return ns[#ns] end end -return M +return ts diff --git a/lua/gopher/_utils/ts/nodes.lua b/lua/gopher/_utils/ts/nodes.lua index 87286a2..e9c730d 100644 --- a/lua/gopher/_utils/ts/nodes.lua +++ b/lua/gopher/_utils/ts/nodes.lua @@ -1,3 +1,7 @@ +local ts_query = require "nvim-treesitter.query" +local parsers = require "nvim-treesitter.parsers" +local locals = require "nvim-treesitter.locals" +local u = require "gopher._utils" local M = {} local function intersects(row, col, sRow, sCol, eRow, eCol) @@ -53,10 +57,6 @@ end ---@param pos_row string ---@return string function M.get_all_nodes(query, lang, _, bufnr, pos_row, _) - local ts_query = require "nvim-treesitter.query" - local parsers = require "nvim-treesitter.parsers" - local locals = require "nvim-treesitter.locals" - bufnr = bufnr or 0 pos_row = pos_row or 30000 @@ -113,8 +113,6 @@ end ---@param col string ---@return table function M.nodes_at_cursor(query, default, bufnr, row, col) - local u = require "gopher._utils" - bufnr = bufnr or vim.api.nvim_get_current_buf() local ft = vim.api.nvim_buf_get_option(bufnr, "ft") if row == nil or col == nil then @@ -123,13 +121,19 @@ function M.nodes_at_cursor(query, default, bufnr, row, col) local nodes = M.get_all_nodes(query, ft, default, bufnr, row, col) if nodes == nil then - u.notify("Unable to find any nodes. Place your cursor on a go symbol and try again", "debug") + u.deferred_notify( + "Unable to find any nodes. Place your cursor on a go symbol and try again", + vim.log.levels.DEBUG + ) return nil end nodes = M.sort_nodes(M.intersect_nodes(nodes, row, col)) if nodes == nil or #nodes == 0 then - u.notify("Unable to find any nodes at pos. " .. tostring(row) .. ":" .. tostring(col), "debug") + u.deferred_notify( + "Unable to find any nodes at pos. " .. tostring(row) .. ":" .. tostring(col), + vim.log.levels.DEBUG + ) return nil end diff --git a/lua/gopher/api.lua b/lua/gopher/api.lua deleted file mode 100644 index 6e854af..0000000 --- a/lua/gopher/api.lua +++ /dev/null @@ -1,29 +0,0 @@ -local API = {} -local tags = require "gopher.struct_tags" -local tests = require "gopher.gotests" -local cmd = require "gopher._utils.commands" - -API.install_deps = require "gopher.installer" -API.tags_add = tags.add -API.tags_rm = tags.remove -API.impl = require "gopher.impl" -API.iferr = require "gopher.iferr" -API.comment = require "gopher.comment" -API.test_add = tests.func_test -API.test_exported = tests.all_exported_tests -API.tests_all = tests.all_tests - -API.get = function(...) - cmd("get", ...) -end -API.mod = function(...) - cmd("mod", ...) -end -API.generate = function(...) - cmd("generate", ...) -end -API.work = function(...) - cmd("work", ...) -end - -return API diff --git a/lua/gopher/config.lua b/lua/gopher/config.lua index a467f83..36b5773 100644 --- a/lua/gopher/config.lua +++ b/lua/gopher/config.lua @@ -1,33 +1,27 @@ ----@class Config ----@field commands ConfigCommands +---@class gopher.Config +local config = {} ----@class ConfigCommands ----@field go string ----@field gomodifytags string ----@field gotests string ----@field impl string ----@field iferr string ----@field dlv string - -local M = { - ---@type Config - config = { - ---set custom commands for tools - commands = { - go = "go", - gomodifytags = "gomodifytags", - gotests = "gotests", - impl = "impl", - iferr = "iferr", - dlv = "dlv", - }, +---@class gopher.Config +---@field commands gopher.ConfigCommands +local default_config = { + ---@class gopher.ConfigCommands + commands = { + go = "go", + gomodifytags = "gomodifytags", + gotests = "gotests", + impl = "impl", + iferr = "iferr", + dlv = "dlv", }, } ----Plugin setup function ----@param opts Config user config -function M.setup(opts) - M.config = vim.tbl_deep_extend("force", M.config, opts or {}) +---@param user_config gopher.Config|nil +function config.setup(user_config) + config = vim.tbl_deep_extend("force", {}, default_config, user_config or {}) end -return M +-- setup ifself, needs for ability to get +-- default config without calling .setup() +config.setup() + +return config diff --git a/lua/gopher/dap.lua b/lua/gopher/dap.lua new file mode 100644 index 0000000..af16438 --- /dev/null +++ b/lua/gopher/dap.lua @@ -0,0 +1,116 @@ +local u = require "gopher._utils" +local dap = {} + +dap.adapter = function(callback, config) + local host = config.host or "127.0.0.1" + local port = config.port or "38697" + local addr = string.format("%s:%s", host, port) + + local handle, pid_or_err + local stdout = assert(vim.loop.new_pipe(false)) + local opts = { + stdio = { nil, stdout }, + args = { "dap", "-l", addr }, + detached = true, + } + + handle, pid_or_err = vim.loop.spawn("dlv", opts, function(status) + if not stdout or not handle then + return + end + + stdout:close() + handle:close() + if status ~= 0 then + print("dlv exited with code", status) + end + end) + + assert(handle, "Error running dlv: " .. tostring(pid_or_err)) + if stdout then + stdout:read_start(function(err, chunk) + assert(not err, err) + if chunk then + vim.schedule(function() + require("dap.repl").append(chunk) + end) + end + end) + end + + -- wait for delve to start + vim.defer_fn(function() + callback { type = "server", host = "127.0.0.1", port = port } + end, 100) +end + +local function args_input() + vim.ui.input({ prompt = "Args: " }, function(input) + return vim.split(input or "", " ") + end) +end + +local function get_arguments() + local co = coroutine.running() + if co then + return coroutine.create(function() + local args = args_input() + coroutine.resume(co, args) + end) + else + return args_input() + end +end + +dap.configuration = { + { + type = "go", + name = "Debug", + request = "launch", + program = "${file}", + }, + { + type = "go", + name = "Debug (Arguments)", + request = "launch", + program = "${file}", + args = get_arguments, + }, + { + type = "go", + name = "Debug Package", + request = "launch", + program = "${fileDirname}", + }, + { + type = "go", + name = "Attach", + mode = "local", + request = "attach", + processId = require("dap.utils").pick_process, + }, + { + type = "go", + name = "Debug test", + request = "launch", + mode = "test", + program = "${file}", + }, + { + type = "go", + name = "Debug test (go.mod)", + request = "launch", + mode = "test", + program = "./${relativeFileDirname}", + }, +} + +---setup `nvim-dap` for Go +function dap.setup() + local d = u.sreq "dap" + + d.adapters.go = dap.adapter + d.configurations.go = dap.configuration +end + +return dap diff --git a/lua/gopher/dap/config.lua b/lua/gopher/dap/config.lua deleted file mode 100644 index 80b2196..0000000 --- a/lua/gopher/dap/config.lua +++ /dev/null @@ -1,98 +0,0 @@ ----@diagnostic disable: param-type-mismatch -local function get_arguments() - local function get() - vim.ui.input({ prompt = "Args: " }, function(input) - return vim.split(input or "", " ") ---@diagnostic disable-line: missing-parameter - end) - end - - local co = coroutine.running() - if co then - return coroutine.create(function() - local args = get() - coroutine.resume(co, args) - end) - else - return get() - end -end - -return { - adapter = function(callback, config) - local handle, pid_or_err - local stdout = vim.loop.new_pipe(false) - local host = config.host or "127.0.0.1" - local port = config.port or "38697" - local addr = string.format("%s:%s", host, port) - local opts = { - stdio = { nil, stdout }, - args = { "dap", "-l", addr }, - detached = true, - } - - handle, pid_or_err = vim.loop.spawn("dlv", opts, function(code) - stdout:close() - handle:close() - if code ~= 0 then - print("dlv exited with code", code) - end - end) - - assert(handle, "Error running dlv: " .. tostring(pid_or_err)) - stdout:read_start(function(err, chunk) - assert(not err, err) - if chunk then - vim.schedule(function() - require("dap.repl").append(chunk) - end) - end - end) - - -- Wait for delve to start - vim.defer_fn(function() - callback { type = "server", host = "127.0.0.1", port = port } - end, 100) - end, - configuration = { - { - type = "go", - name = "Debug", - request = "launch", - program = "${file}", - }, - { - type = "go", - name = "Debug (Arguments)", - request = "launch", - program = "${file}", - args = get_arguments, - }, - { - type = "go", - name = "Debug Package", - request = "launch", - program = "${fileDirname}", - }, - { - type = "go", - name = "Attach", - mode = "local", - request = "attach", - processId = require("dap.utils").pick_process, - }, - { - type = "go", - name = "Debug test", - request = "launch", - mode = "test", - program = "${file}", - }, - { - type = "go", - name = "Debug test (go.mod)", - request = "launch", - mode = "test", - program = "./${relativeFileDirname}", - }, - }, -} diff --git a/lua/gopher/dap/init.lua b/lua/gopher/dap/init.lua deleted file mode 100644 index 9b0b626..0000000 --- a/lua/gopher/dap/init.lua +++ /dev/null @@ -1,13 +0,0 @@ -local M = {} - ----setup nvim-dap for golang using -function M.setup() - local cfg = require "gopher.dap.config" - local u = require "gopher._utils" - - local dap = u.sreq "dap" - dap.adapters.go = cfg.adapter - dap.configurations.go = cfg.configuration -end - -return M diff --git a/lua/gopher/gotests.lua b/lua/gopher/gotests.lua index 724971c..cf9a0f1 100644 --- a/lua/gopher/gotests.lua +++ b/lua/gopher/gotests.lua @@ -1,21 +1,24 @@ +local c = require("gopher.config").commands local u = require "gopher._utils" -local M = {} +local ts_utils = require "gopher._utils.ts" +local Job = require "plenary.job" +local gotests = {} ---@param cmd_args table local function run(cmd_args) - local Job = require "plenary.job" - local c = require("gopher.config").config.commands - Job:new({ command = c.gotests, args = cmd_args, on_exit = function(_, retval) if retval ~= 0 then - u.notify("command 'go " .. unpack(cmd_args) .. "' exited with code " .. retval, "error") + u.deferred_notify( + "command '" .. c.gotests .. " " .. unpack(cmd_args) .. "' exited with code " .. retval, + vim.log.levels.ERROR + ) return end - u.notify("unit test(s) generated", "info") + u.deferred_notify("unit test(s) generated", vim.log.levels.INFO) end, }):start() end @@ -30,12 +33,10 @@ end ---generate unit test for one function ---@param parallel boolean -function M.func_test(parallel) - local ts_utils = require "gopher._utils.ts" - +function gotests.func_test(parallel) local ns = ts_utils.get_func_method_node_at_pos(unpack(vim.api.nvim_win_get_cursor(0))) if ns == nil or ns.name == nil then - u.notify("cursor on func/method and execute the command again", "info") + u.deferred_notify("cursor on func/method and execute the command again", vim.log.levels.INFO) return end @@ -49,7 +50,7 @@ end ---generate unit tests for all functions in current file ---@param parallel boolean -function M.all_tests(parallel) +function gotests.all_tests(parallel) local cmd_args = { "-all" } if parallel then table.insert(cmd_args, "-parallel") @@ -60,7 +61,7 @@ end ---generate unit tests for all exported functions ---@param parallel boolean -function M.all_exported_tests(parallel) +function gotests.all_exported_tests(parallel) local cmd_args = {} if parallel then table.insert(cmd_args, "-parallel") @@ -70,4 +71,4 @@ function M.all_exported_tests(parallel) add_test(cmd_args) end -return M +return gotests diff --git a/lua/gopher/health.lua b/lua/gopher/health.lua index 935fbac..4b3f3a2 100644 --- a/lua/gopher/health.lua +++ b/lua/gopher/health.lua @@ -1,16 +1,7 @@ local health = {} -local cmd = require("gopher.config").config.commands +local cmd = require("gopher.config").commands local u = require "gopher._utils.health" -local _h = vim.health or require "health" -local h = { - start = _h.start or _h.report_start, - ok = _h.ok or _h.report_ok, - warn = _h.warn or _h.report_warn, - error = _h.error or _h.report_error, - info = _h.info or _h.report_info, -} - local deps = { plugin = { { lib = "dap", msg = "required for `gopher.dap`", optional = true }, @@ -36,29 +27,29 @@ local deps = { } function health.check() - h.start "required plugins" + u.start "required plugins" for _, plugin in ipairs(deps.plugin) do - if u.lualib_is_found(plugin.lib) then - h.ok(plugin.lib .. " installed") + if u.is_lualib_found(plugin.lib) then + u.ok(plugin.lib .. " installed") else if plugin.optional then - h.warn(plugin.lib .. " not found, " .. plugin.msg) + u.warn(plugin.lib .. " not found, " .. plugin.msg) else - h.error(plugin.lib .. " not found, " .. plugin.msg) + u.error(plugin.lib .. " not found, " .. plugin.msg) end end end - h.start "required binaries" - h.info "all those binaries can be installed by `:GoInstallDeps`" + u.start "required binaries" + u.info "all those binaries can be installed by `:GoInstallDeps`" for _, bin in ipairs(deps.bin) do - if u.binary_is_found(bin.bin) then - h.ok(bin.bin .. " installed") + if u.is_lualib_found(bin.bin) then + u.ok(bin.bin .. " installed") else if bin.optional then - h.warn(bin.bin .. " not found, " .. bin.msg) + u.warn(bin.bin .. " not found, " .. bin.msg) else - h.error(bin.bin .. " not found, " .. bin.msg) + u.error(bin.bin .. " not found, " .. bin.msg) end end end diff --git a/lua/gopher/iferr.lua b/lua/gopher/iferr.lua index 7f43318..fbeddf7 100644 --- a/lua/gopher/iferr.lua +++ b/lua/gopher/iferr.lua @@ -1,16 +1,18 @@ ----Add iferr declaration ----That's Lua of vimscript implementation of: ----github.com/koron/iferr -return function() - local c = require("gopher.config").config.commands - local u = require "gopher._utils" +local c = require("gopher.config").commands +local u = require "gopher._utils" +local iferr = {} +-- That's Lua of vimscript implementation of: github.com/koron/iferr +iferr.iferr = function() local boff = vim.fn.wordcount().cursor_bytes local cmd = (c.iferr .. " -pos " .. boff) local data = vim.fn.systemlist(cmd, vim.fn.bufnr "%") if vim.v.shell_error ~= 0 then - u.notify("command " .. cmd .. " exited with code " .. vim.v.shell_error, "error") + u.deferred_notify( + "command " .. cmd .. " exited with code " .. vim.v.shell_error, + vim.log.levels.ERROR + ) return end @@ -19,3 +21,5 @@ return function() vim.cmd [[silent normal! j=2j]] vim.fn.setpos(".", pos) end + +return iferr diff --git a/lua/gopher/impl.lua b/lua/gopher/impl.lua index a279889..6eddc0f 100644 --- a/lua/gopher/impl.lua +++ b/lua/gopher/impl.lua @@ -1,12 +1,14 @@ +local c = require("gopher.config").commands +local Job = require "plenary.job" +local ts_utils = require "gopher._utils.ts" local u = require "gopher._utils" +local impl = {} ---@return string local function get_struct() - local ts_utils = require "gopher._utils.ts" - local ns = ts_utils.get_struct_node_at_pos(unpack(vim.api.nvim_win_get_cursor(0))) if ns == nil then - u.notify("put cursor on a struct or specify a receiver", "info") + u.deferred_notify("put cursor on a struct or specify a receiver", vim.log.levels.INFO) return "" end @@ -18,10 +20,7 @@ local function get_struct() return ns.name end -return function(...) - local c = require("gopher.config").config.commands - local Job = require "plenary.job" - +function impl.impl(...) local args = { ... } local iface, recv_name = "", "" local recv = get_struct() @@ -30,7 +29,7 @@ return function(...) iface = vim.fn.input "impl: generating method stubs for interface: " vim.cmd "redraw!" if iface == "" then - u.notify("usage: GoImpl f *File io.Reader", "info") + u.deferred_notify("usage: GoImpl f *File io.Reader", vim.log.levels.INFO) return end elseif #args == 1 then -- :GoImpl io.Reader @@ -61,7 +60,10 @@ return function(...) args = cmd_args, on_exit = function(data, retval) if retval ~= 0 then - u.notify("command 'impl " .. unpack(cmd_args) .. "' exited with code " .. retval, "error") + u.deferred_notify( + "command '" .. c.impl .. " " .. unpack(cmd_args) .. "' exited with code " .. retval, + vim.log.levels.ERROR + ) return end @@ -73,3 +75,5 @@ return function(...) table.insert(res_data, 1, "") vim.fn.append(pos, res_data) end + +return impl diff --git a/lua/gopher/init.lua b/lua/gopher/init.lua index 46b649e..2f6f32e 100644 --- a/lua/gopher/init.lua +++ b/lua/gopher/init.lua @@ -1,5 +1,35 @@ -local GOPHER = {} +local tags = require "gopher.struct_tags" +local tests = require "gopher.gotests" +local uc = require "gopher._utils.commands" +local gopher = {} -GOPHER.setup = require("gopher.config").setup +gopher.setup = require("gopher.config").setup +gopher.install_deps = require("gopher.installer").install_deps +gopher.impl = require("gopher.impl").impl +gopher.iferr = require("gopher.iferr").iferr +gopher.comment = require "gopher.comment" -return GOPHER +gopher.tags_add = tags.add +gopher.tags_rm = tags.remove + +gopher.test_add = tests.func_test +gopher.test_exported = tests.all_exported_tests +gopher.tests_all = tests.all_tests + +gopher.get = function(...) + uc("get", ...) +end + +gopher.mod = function(...) + uc("mod", ...) +end + +gopher.generate = function(...) + uc("generate", ...) +end + +gopher.work = function(...) + uc("work", ...) +end + +return gopher diff --git a/lua/gopher/installer.lua b/lua/gopher/installer.lua index fdd6242..939d50f 100644 --- a/lua/gopher/installer.lua +++ b/lua/gopher/installer.lua @@ -1,3 +1,8 @@ +local Job = require "plenary.job" +local c = require("gopher.config").commands +local u = require "gopher._utils" +local installer = {} + local urls = { gomodifytags = "github.com/fatih/gomodifytags", impl = "github.com/josharian/impl", @@ -8,28 +13,30 @@ local urls = { ---@param pkg string local function install(pkg) - local Job = require "plenary.job" - local u = require "gopher._utils" - local url = urls[pkg] .. "@latest" Job:new({ - command = "go", + command = c.go, args = { "install", url }, on_exit = function(_, retval) if retval ~= 0 then - u.notify("command 'go install " .. url .. "' exited with code " .. retval, "error") + u.deferred_notify( + "command 'go install " .. url .. "' exited with code " .. retval, + vim.log.levels.ERROR + ) return end - u.notify("install " .. url .. " finished", "info ") + u.deferred_notify("install " .. url .. " finished", vim.log.levels.INFO) end, }):start() end ---Install required go deps -return function() +function installer.install_deps() for pkg, _ in pairs(urls) do install(pkg) end end + +return installer diff --git a/lua/gopher/struct_tags.lua b/lua/gopher/struct_tags.lua index a91901a..690eae1 100644 --- a/lua/gopher/struct_tags.lua +++ b/lua/gopher/struct_tags.lua @@ -1,11 +1,10 @@ -local M = {} +local ts_utils = require "gopher._utils.ts" +local Job = require "plenary.job" +local c = require("gopher.config").commands +local u = require "gopher._utils" +local struct_tags = {} local function modify(...) - local ts_utils = require "gopher._utils.ts" - local Job = require "plenary.job" - local c = require("gopher.config").config.commands - local u = require "gopher._utils" - local fpath = vim.fn.expand "%" ---@diagnostic disable-line: missing-parameter local ns = ts_utils.get_struct_node_at_pos(unpack(vim.api.nvim_win_get_cursor(0))) if ns == nil then @@ -47,9 +46,14 @@ local function modify(...) args = cmd_args, on_exit = function(data, retval) if retval ~= 0 then - u.notify( - "command 'gomodifytags " .. unpack(cmd_args) .. "' exited with code " .. retval, - "error" + u.deferred_notify( + "command '" + .. c.gomodifytags + .. " " + .. unpack(cmd_args) + .. "' exited with code " + .. retval, + vim.log.levels.ERROR ) return end @@ -66,7 +70,7 @@ local function modify(...) or tagged["start"] == nil or tagged["start"] == 0 then - u.notify("failed to set tags " .. vim.inspect(tagged), "error") + u.deferred_notify("failed to set tags " .. vim.inspect(tagged), vim.log.levels.ERROR) end for i, v in ipairs(tagged.lines) do @@ -86,7 +90,7 @@ end ---add tags to struct under cursor ---@param ... unknown -function M.add(...) +function struct_tags.add(...) local arg = { ... } if #arg == nil or arg == "" then arg = { "json" } @@ -102,7 +106,7 @@ end ---remove tags to struct under cursor ---@param ... unknown -function M.remove(...) +function struct_tags.remove(...) local arg = { ... } if #arg == nil or arg == "" then arg = { "json" } @@ -116,4 +120,4 @@ function M.remove(...) modify(unpack(cmd_args)) end -return M +return struct_tags diff --git a/plugin/gopher.vim b/plugin/gopher.vim index e797966..bdffbbe 100644 --- a/plugin/gopher.vim +++ b/plugin/gopher.vim @@ -1,13 +1,13 @@ -command! -nargs=* GoTagAdd :lua require"gopher.api".tags_add() -command! -nargs=* GoTagRm :lua require"gopher.api".tags_rm() -command! -nargs=* GoTestAdd :lua require"gopher.api".test_add() -command! -nargs=* GoTestsAll :lua require"gopher.api".tests_all() -command! -nargs=* GoTestsExp :lua require"gopher.api".test_exported() -command! -nargs=* GoMod :lua require"gopher.api".mod() -command! -nargs=* GoGet :lua require"gopher.api".get() -command! -nargs=* GoWork :lua require"gopher.api".work() -command! -nargs=* GoImpl :lua require"gopher.api".impl() -command! -nargs=* GoGenerate :lua require"gopher.api".generate() -command! GoCmt :lua require"gopher.api".comment() -command! GoIfErr :lua require"gopher.api".iferr() -command! GoInstallDeps :lua require"gopher.api".install_deps() +command! -nargs=* GoTagAdd :lua require"gopher".tags_add() +command! -nargs=* GoTagRm :lua require"gopher".tags_rm() +command! -nargs=* GoTestAdd :lua require"gopher".test_add() +command! -nargs=* GoTestsAll :lua require"gopher".tests_all() +command! -nargs=* GoTestsExp :lua require"gopher".test_exported() +command! -nargs=* GoMod :lua require"gopher".mod() +command! -nargs=* GoGet :lua require"gopher".get() +command! -nargs=* GoWork :lua require"gopher".work() +command! -nargs=* GoImpl :lua require"gopher".impl() +command! -nargs=* GoGenerate :lua require"gopher".generate() +command! GoCmt :lua require"gopher".comment() +command! GoIfErr :lua require"gopher".iferr() +command! GoInstallDeps :lua require"gopher".install_deps() From bc3ce343a89a1ab7d9c4b71d89923c670dff69d8 Mon Sep 17 00:00:00 2001 From: Smirnov Oleksandr Date: Thu, 20 Jul 2023 00:11:59 +0300 Subject: [PATCH 04/24] update tooling (#38) * chore: delete pre-commit * chore: switch from makefile to taskfile * chore(ci): update and add one more linter * chore(editorconfig): add config for Go * chore(editorconfig): remove max_line_length * fix: editorconfig-check on README.md --- .editorconfig | 6 ++++-- .github/workflows/ci.yml | 24 ------------------------ .github/workflows/linters.yml | 22 ++++++++++++++++++++++ .pre-commit-config.yaml | 15 --------------- Makefile | 11 ----------- README.md | 2 +- Taskfile.yml | 29 +++++++++++++++++++++++++++++ 7 files changed, 56 insertions(+), 53 deletions(-) delete mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/linters.yml delete mode 100644 .pre-commit-config.yaml delete mode 100644 Makefile create mode 100644 Taskfile.yml diff --git a/.editorconfig b/.editorconfig index 48ce80f..3155057 100644 --- a/.editorconfig +++ b/.editorconfig @@ -7,11 +7,13 @@ end_of_line = lf insert_final_newline = true trim_trailing_whitespace=true charset = utf-8 -max_line_length = 120 [*.{lua,vim}] -max_line_length = 100 indent_size = 2 [*.{md,yml,yaml,toml}] indent_size = 2 + +[*.go] +indent_style = tab +indent_size = 4 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index b1be903..0000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: Format and lint -on: [push, pull_request] - -jobs: - format: - name: stylua - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: JohnnyMorganz/stylua-action@1.0.0 - with: - token: ${{ secrets.GITHUB_TOKEN }} - version: 0.14.0 - args: --check . - - lint: - name: selene - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: NTBBloodbath/selene-action@v1.0.0 - with: - token: ${{ secrets.GITHUB_TOKEN }} - args: --display-style=quiet . diff --git a/.github/workflows/linters.yml b/.github/workflows/linters.yml new file mode 100644 index 0000000..53b28ab --- /dev/null +++ b/.github/workflows/linters.yml @@ -0,0 +1,22 @@ +name: linters +on: [push, pull_request] + +jobs: + linters: + name: linters + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: JohnnyMorganz/stylua-action@v3 + with: + token: ${{ secrets.GITHUB_TOKEN }} + version: latest + args: --check . + + - uses: NTBBloodbath/selene-action@v1.0.0 + with: + token: ${{ secrets.GITHUB_TOKEN }} + args: . + + - uses: editorconfig-checker/action-editorconfig-checker@main + - run: editorconfig-checker diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml deleted file mode 100644 index 464c44d..0000000 --- a/.pre-commit-config.yaml +++ /dev/null @@ -1,15 +0,0 @@ -repos: -- repo: local - hooks: - - id: stylua - name: StyLua - language: rust - entry: stylua - types: [lua] - args: ["--check", "-"] - - id: selene - name: Selene - language: rust - entry: selene - types: [lua] - args: ["-"] diff --git a/Makefile b/Makefile deleted file mode 100644 index 2dc03c4..0000000 --- a/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -.PHONY: -.SILENT: - -format: - stylua **/*.lua - -lint: - selene **/*.lua - -test: - nvim --headless -u ./spec/minimal_init.vim -c "PlenaryBustedDirectory spec {minimal_init='./spec/minimal_init.vim'}" diff --git a/README.md b/README.md index 9809686..3c13fa0 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ It will install next tools: - [iferr](https://github.com/koron/iferr) 2. Modify struct tags: - By default `json` tag will be added/removed, if not set: + By default `json` tag will be added/removed, if not set: ```vim :GoTagAdd json " For add json tag diff --git a/Taskfile.yml b/Taskfile.yml new file mode 100644 index 0000000..2f3b8c4 --- /dev/null +++ b/Taskfile.yml @@ -0,0 +1,29 @@ +version: "3" +tasks: + format: + desc: formats all lua files in repo + cmds: [stylua .] + + lint: + desc: runs all linters + cmds: + - task: lint_lua + - task: lint_editorconfig + + lint_lua: + desc: runs lua linter on all repo + cmds: [selene .] + + lint_editorconfig: + desc: runs editorconfig-checker + cmds: [editorconfig-checker] + + test: + aliases: [tests, spec] + cmds: + - | + nvim --headless \ + -u ./spec/minimal_init.vim\ + -c "PlenaryBustedDirectory spec \ + {minimal_init='./spec/minimal_init.lua'\ + ,sequential=true}" From 3d49d58fd24c5a6aecedf8e8829aa7b2f5c01b2a Mon Sep 17 00:00:00 2001 From: Smirnov Oleksandr Date: Thu, 20 Jul 2023 00:18:13 +0300 Subject: [PATCH 05/24] feat: run tests independent from user's nvim config --- .gitignore | 3 ++- Taskfile.yml | 2 +- spec/minimal_init.lua | 33 +++++++++++++++++++++++++++++++++ spec/minimal_init.vim | 4 ---- 4 files changed, 36 insertions(+), 6 deletions(-) create mode 100644 spec/minimal_init.lua delete mode 100644 spec/minimal_init.vim diff --git a/.gitignore b/.gitignore index a5c9323..df7d859 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -playground/ +/playground/ +/.tests/ diff --git a/Taskfile.yml b/Taskfile.yml index 2f3b8c4..25fdc34 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -23,7 +23,7 @@ tasks: cmds: - | nvim --headless \ - -u ./spec/minimal_init.vim\ + -u ./spec/minimal_init.lua\ -c "PlenaryBustedDirectory spec \ {minimal_init='./spec/minimal_init.lua'\ ,sequential=true}" diff --git a/spec/minimal_init.lua b/spec/minimal_init.lua new file mode 100644 index 0000000..163efc5 --- /dev/null +++ b/spec/minimal_init.lua @@ -0,0 +1,33 @@ +local function root(p) + local f = debug.getinfo(1, "S").source:sub(2) + return vim.fn.fnamemodify(f, ":p:h:h") .. "/" .. (p or "") +end + +local function install_plug(plugin) + local name = plugin:match ".*/(.*)" + local package_root = root ".tests/site/pack/deps/start/" + if not vim.loop.fs_stat(package_root .. name) then + print("Installing " .. plugin) + vim.fn.mkdir(package_root, "p") + vim.fn.system { + "git", + "clone", + "--depth=1", + "https://github.com/" .. plugin .. ".git", + package_root .. "/" .. name, + } + end +end + +vim.cmd [[set runtimepath=$VIMRUNTIME]] +vim.opt.runtimepath:append(root()) +vim.opt.packpath = { root ".tests/site" } +vim.notify = print + +install_plug "nvim-lua/plenary.nvim" +install_plug "nvim-treesitter/nvim-treesitter" + +vim.env.XDG_CONFIG_HOME = root ".tests/config" +vim.env.XDG_DATA_HOME = root ".tests/data" +vim.env.XDG_STATE_HOME = root ".tests/state" +vim.env.XDG_CACHE_HOME = root ".tests/cache" diff --git a/spec/minimal_init.vim b/spec/minimal_init.vim deleted file mode 100644 index e30e21b..0000000 --- a/spec/minimal_init.vim +++ /dev/null @@ -1,4 +0,0 @@ -set rtp+=. -packadd plenary.nvim -packadd nvim-treesitter -packadd nvim-dap From e49f3fadd766732cf66e6c352caafea4ea521c15 Mon Sep 17 00:00:00 2001 From: Smirnov Oleksandr Date: Thu, 20 Jul 2023 00:21:15 +0300 Subject: [PATCH 06/24] remove editorconfig-checker --- .github/workflows/linters.yml | 3 --- Taskfile.yml | 5 ----- 2 files changed, 8 deletions(-) diff --git a/.github/workflows/linters.yml b/.github/workflows/linters.yml index 53b28ab..a78c3c3 100644 --- a/.github/workflows/linters.yml +++ b/.github/workflows/linters.yml @@ -17,6 +17,3 @@ jobs: with: token: ${{ secrets.GITHUB_TOKEN }} args: . - - - uses: editorconfig-checker/action-editorconfig-checker@main - - run: editorconfig-checker diff --git a/Taskfile.yml b/Taskfile.yml index 25fdc34..3daf669 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -8,16 +8,11 @@ tasks: desc: runs all linters cmds: - task: lint_lua - - task: lint_editorconfig lint_lua: desc: runs lua linter on all repo cmds: [selene .] - lint_editorconfig: - desc: runs editorconfig-checker - cmds: [editorconfig-checker] - test: aliases: [tests, spec] cmds: From eac5560200acfe484de1d1f92d44737656469698 Mon Sep 17 00:00:00 2001 From: Smirnov Oleksandr Date: Thu, 20 Jul 2023 00:31:47 +0300 Subject: [PATCH 07/24] fix(config): now it not removes .setup() from itself after calling .setup() --- lua/gopher/config.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/gopher/config.lua b/lua/gopher/config.lua index 36b5773..e616005 100644 --- a/lua/gopher/config.lua +++ b/lua/gopher/config.lua @@ -17,7 +17,7 @@ local default_config = { ---@param user_config gopher.Config|nil function config.setup(user_config) - config = vim.tbl_deep_extend("force", {}, default_config, user_config or {}) + config = vim.tbl_deep_extend("force", config, default_config, user_config or {}) end -- setup ifself, needs for ability to get From 3b0888ab102ef9a6abd423fc8ea470562c2d4d72 Mon Sep 17 00:00:00 2001 From: Smirnov Oleksandr Date: Thu, 20 Jul 2023 19:40:12 +0300 Subject: [PATCH 08/24] fix(config): now it works correctly --- lua/gopher/config.lua | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/lua/gopher/config.lua b/lua/gopher/config.lua index e616005..b6f47d6 100644 --- a/lua/gopher/config.lua +++ b/lua/gopher/config.lua @@ -1,10 +1,9 @@ ----@class gopher.Config +---@type gopher.Config local config = {} ---@class gopher.Config ----@field commands gopher.ConfigCommands local default_config = { - ---@class gopher.ConfigCommands + ---@class gopher.ConfigCommand commands = { go = "go", gomodifytags = "gomodifytags", @@ -15,13 +14,18 @@ local default_config = { }, } ----@param user_config gopher.Config|nil +---@type gopher.Config +local _config = {} + +---@param user_config? gopher.Config function config.setup(user_config) - config = vim.tbl_deep_extend("force", config, default_config, user_config or {}) + _config = vim.tbl_deep_extend("force", default_config, user_config or {}) end --- setup ifself, needs for ability to get --- default config without calling .setup() -config.setup() +setmetatable(config, { + __index = function(_, key) + return _config[key] + end, +}) return config From 1841aede9109533e374ac42bfb2815a81054c1fc Mon Sep 17 00:00:00 2001 From: Smirnov Oleksandr Date: Thu, 20 Jul 2023 19:51:02 +0300 Subject: [PATCH 09/24] chore: update taskfile, and linter config --- Taskfile.yml | 12 +++++++++--- selene.toml | 3 ++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Taskfile.yml b/Taskfile.yml index 3daf669..c4320bd 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -7,13 +7,19 @@ tasks: lint: desc: runs all linters cmds: - - task: lint_lua + - task: lint_selene + - task: lint_stylua - lint_lua: - desc: runs lua linter on all repo + lint_selene: + desc: runs lua linter(selene) cmds: [selene .] + lint_stylua: + desc: runs stylua in check mode + cmds: [stylua --check .] + test: + desc: runs all tests aliases: [tests, spec] cmds: - | diff --git a/selene.toml b/selene.toml index 8117799..9f6f1c4 100644 --- a/selene.toml +++ b/selene.toml @@ -1 +1,2 @@ -std="nvim+lua51" +std = "nvim+lua52" +exclude = [".tests/*"] From b5327cd2ebe3e00718f1f7652978009bd13acf18 Mon Sep 17 00:00:00 2001 From: Smirnov Oleksandr Date: Thu, 20 Jul 2023 19:53:15 +0300 Subject: [PATCH 10/24] feat(config): make it optional to call .setup() --- lua/gopher/config.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/gopher/config.lua b/lua/gopher/config.lua index b6f47d6..68b29e6 100644 --- a/lua/gopher/config.lua +++ b/lua/gopher/config.lua @@ -15,7 +15,7 @@ local default_config = { } ---@type gopher.Config -local _config = {} +local _config = default_config ---@param user_config? gopher.Config function config.setup(user_config) From 5f8466d043d03a84cdee78bade05c5c581c47aa3 Mon Sep 17 00:00:00 2001 From: Smirnov Oleksandr Date: Fri, 21 Jul 2023 02:57:46 +0300 Subject: [PATCH 11/24] run tests independent of user nvim setup (#39) * chore(lua_ls): now lua_ls knows about testing functions * spec: change way how tests srtuctured * test(config): refactor tests * test: utils * refactor(utils): remove not used function * chore(ci): add test runner * chore(ci): remove taskfile from deps * fix: now it works --- .github/workflows/tests.yml | 24 ++++++++++++++++ .luarc.json | 10 +++++++ lua/gopher/_utils/init.lua | 11 ------- spec/gopher_config_spec.lua | 41 -------------------------- spec/gopher_spec.lua | 5 ---- spec/gopher_struct_tags_spec.lua | 49 -------------------------------- spec/gopher_utils_spec.lua | 19 ------------- spec/units/config_spec.lua | 29 +++++++++++++++++++ spec/units/utils_spec.lua | 25 ++++++++++++++++ 9 files changed, 88 insertions(+), 125 deletions(-) create mode 100644 .github/workflows/tests.yml create mode 100644 .luarc.json delete mode 100644 spec/gopher_config_spec.lua delete mode 100644 spec/gopher_spec.lua delete mode 100644 spec/gopher_struct_tags_spec.lua delete mode 100644 spec/gopher_utils_spec.lua create mode 100644 spec/units/config_spec.lua create mode 100644 spec/units/utils_spec.lua diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..b3eecf5 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,24 @@ +name: tests +on: [push, pull_request] + +jobs: + tests: + strategy: + matrix: + os: [ubuntu-latest] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v3 + - name: Install Neovim + shell: bash + run: | + mkdir -p /tmp/nvim + wget -q https://github.com/neovim/neovim/releases/download/nightly/nvim.appimage -O /tmp/nvim/nvim.appimage + cd /tmp/nvim + chmod a+x ./nvim.appimage + ./nvim.appimage --appimage-extract + echo "/tmp/nvim/squashfs-root/usr/bin/" >> $GITHUB_PATH + - name: Run Tests + run: | + nvim --version + nvim --headless -u ./spec/minimal_init.lua -c "PlenaryBustedDirectory spec {minimal_init='./spec/minimal_init.lua', sequential=true}" diff --git a/.luarc.json b/.luarc.json new file mode 100644 index 0000000..a0d5712 --- /dev/null +++ b/.luarc.json @@ -0,0 +1,10 @@ +{ + "diagnostics.globals": [ + "describe", + "it", + "before_each", + "after_each", + "before_all", + "after_all" + ] +} diff --git a/lua/gopher/_utils/init.lua b/lua/gopher/_utils/init.lua index a083a78..4915ab3 100644 --- a/lua/gopher/_utils/init.lua +++ b/lua/gopher/_utils/init.lua @@ -9,17 +9,6 @@ function utils.is_tbl_empty(t) return next(t) == nil end ----@param s string ----@return string -function utils.rtrim(s) - local n = #s - while n > 0 and s:find("^%s", n) do - n = n - 1 - end - - return s:sub(1, n) -end - ---@param msg string ---@param lvl any function utils.deferred_notify(msg, lvl) diff --git a/spec/gopher_config_spec.lua b/spec/gopher_config_spec.lua deleted file mode 100644 index 1d033c0..0000000 --- a/spec/gopher_config_spec.lua +++ /dev/null @@ -1,41 +0,0 @@ -describe("gopher.config", function() - it("can be required", function() - require "gopher.config" - end) - - it(".setup() when gets empty table not edit config", function() - local c = require "gopher.config" - c.setup {} - - assert.are.same(c.config.commands.go, "go") - assert.are.same(c.config.commands.gomodifytags, "gomodifytags") - assert.are.same(c.config.commands.gotests, "gotests") - assert.are.same(c.config.commands.impl, "impl") - end) - - it(".setup() when get one custom value sets that", function() - local c = require "gopher.config" - c.setup { commands = { - go = "custom_go", - } } - - assert.are.same(c.config.commands.go, "custom_go") - end) - - it(".setup() when get all custom values sets it", function() - local c = require "gopher.config" - c.setup { - commands = { - go = "go1.18", - gomodifytags = "user-gomodifytags", - gotests = "gotests", - impl = "goimpl", - }, - } - - assert.are.same(c.config.commands.go, "go1.18") - assert.are.same(c.config.commands.gomodifytags, "user-gomodifytags") - assert.are.same(c.config.commands.gotests, "gotests") - assert.are.same(c.config.commands.impl, "goimpl") - end) -end) diff --git a/spec/gopher_spec.lua b/spec/gopher_spec.lua deleted file mode 100644 index b50b5ea..0000000 --- a/spec/gopher_spec.lua +++ /dev/null @@ -1,5 +0,0 @@ -describe("gopher", function() - it("can be required", function() - require "gopher" - end) -end) diff --git a/spec/gopher_struct_tags_spec.lua b/spec/gopher_struct_tags_spec.lua deleted file mode 100644 index ad8dd6e..0000000 --- a/spec/gopher_struct_tags_spec.lua +++ /dev/null @@ -1,49 +0,0 @@ -local cur_dir = vim.fn.expand "%:p:h" - -describe("gopher.struct_tags", function() - it("can be required", function() - require "gopher.struct_tags" - end) - - it("can add json tag to struct", function() - local tag = require "gopher.struct_tags" - local temp_file = vim.fn.tempname() .. ".go" - local input_file = vim.fn.readfile(cur_dir .. "/spec/fixtures/tags/add_input.go") - local output_file = - vim.fn.join(vim.fn.readfile(cur_dir .. "/spec/fixtures/tags/add_output.go"), "\n") - - vim.fn.writefile(input_file, temp_file) - vim.cmd("silent exe 'e " .. temp_file .. "'") - vim.bo.filetype = "go" - - local bufn = vim.fn.bufnr(0) - vim.fn.setpos(".", { bufn, 3, 6, 0 }) - tag.add() - - vim.wait(100) - assert.are.same(output_file, vim.fn.join(vim.fn.readfile(temp_file), "\n")) - - vim.cmd("bd! " .. temp_file) - end) - - it("can remove json tag from struct", function() - local tag = require "gopher.struct_tags" - local temp_file = vim.fn.tempname() .. ".go" - local input_file = vim.fn.readfile(cur_dir .. "/spec/fixtures/tags/remove_input.go") - local output_file = - vim.fn.join(vim.fn.readfile(cur_dir .. "/spec/fixtures/tags/remove_output.go"), "\n") - - vim.fn.writefile(input_file, temp_file) - vim.cmd("silent exe 'e " .. temp_file .. "'") - vim.bo.filetype = "go" - - local bufn = vim.fn.bufnr() - vim.fn.setpos(".", { bufn, 3, 6, 0 }) - tag.remove() - - vim.wait(100) - assert.are.same(output_file, vim.fn.join(vim.fn.readfile(temp_file), "\n")) - - vim.cmd("bd! " .. temp_file) - end) -end) diff --git a/spec/gopher_utils_spec.lua b/spec/gopher_utils_spec.lua deleted file mode 100644 index f052cff..0000000 --- a/spec/gopher_utils_spec.lua +++ /dev/null @@ -1,19 +0,0 @@ -describe("gopher._utils", function() - it("can be requried", function() - require "gopher._utils" - end) - - it(".empty() with non-empty talbe", function() - local empty = require("gopher._utils").empty - local res = empty { first = "1", second = 2 } - - assert.are.same(res, false) - end) - - it(".empty() with empty talbe", function() - local empty = require("gopher._utils").empty - local res = empty {} - - assert.are.same(res, true) - end) -end) diff --git a/spec/units/config_spec.lua b/spec/units/config_spec.lua new file mode 100644 index 0000000..1fd91dd --- /dev/null +++ b/spec/units/config_spec.lua @@ -0,0 +1,29 @@ +describe("gopher.config", function() + it(".setup() should provide default when .setup() is not called", function() + local c = require "gopher.config" + + assert.are.same(c.commands.go, "go") + assert.are.same(c.commands.gomodifytags, "gomodifytags") + assert.are.same(c.commands.gotests, "gotests") + assert.are.same(c.commands.impl, "impl") + assert.are.same(c.commands.iferr, "iferr") + assert.are.same(c.commands.dlv, "dlv") + end) + + it(".setup() should change options on users config", function() + local c = require "gopher.config" + c.setup { + commands = { + go = "go1.420", + gomodifytags = "iDontUseRustBtw", + }, + } + + assert.are.same(c.commands.go, "go1.420") + assert.are.same(c.commands.gomodifytags, "iDontUseRustBtw") + assert.are.same(c.commands.gotests, "gotests") + assert.are.same(c.commands.impl, "impl") + assert.are.same(c.commands.iferr, "iferr") + assert.are.same(c.commands.dlv, "dlv") + end) +end) diff --git a/spec/units/utils_spec.lua b/spec/units/utils_spec.lua new file mode 100644 index 0000000..dcf94f2 --- /dev/null +++ b/spec/units/utils_spec.lua @@ -0,0 +1,25 @@ +describe("gopher._utils", function() + local u = require "gopher._utils" + + describe(".is_tbl_empty()", function() + it("it is empty", function() + assert.are.same(true, u.is_tbl_empty {}) + end) + + it("it is not empty", function() + assert.are.same(false, u.is_tbl_empty { first = "1", second = 2 }) + end) + end) + + describe(".sreq()", function() + it("can require existing module", function() + assert.are.same(require "gopher", u.sreq "gopher") + end) + + it("cannot require non-existing module", function() + assert.has.errors(function() + u.sreq "iDontExistBtw" + end) + end) + end) +end) From 4af6caed6b8093beda7435c7001647fb8525da1d Mon Sep 17 00:00:00 2001 From: Smirnov Oleksandr Date: Sat, 22 Jul 2023 03:00:00 +0300 Subject: [PATCH 12/24] fix(dap): now dlv uses cmd to run from config --- lua/gopher/dap.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lua/gopher/dap.lua b/lua/gopher/dap.lua index af16438..551416c 100644 --- a/lua/gopher/dap.lua +++ b/lua/gopher/dap.lua @@ -1,4 +1,5 @@ local u = require "gopher._utils" +local c = require "gopher.config" local dap = {} dap.adapter = function(callback, config) @@ -14,7 +15,7 @@ dap.adapter = function(callback, config) detached = true, } - handle, pid_or_err = vim.loop.spawn("dlv", opts, function(status) + handle, pid_or_err = vim.loop.spawn(c.commands.dlv, opts, function(status) if not stdout or not handle then return end From 011769b99b8a786ff7859e300775bf2f904cdafd Mon Sep 17 00:00:00 2001 From: Smirnov Oleksandr Date: Sat, 22 Jul 2023 03:03:09 +0300 Subject: [PATCH 13/24] chore(ci): run tests on many versions of nvim --- .github/workflows/tests.yml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index b3eecf5..9ffb99c 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -6,6 +6,16 @@ jobs: strategy: matrix: os: [ubuntu-latest] + nvim_version: + - nightly + - v0.7.0 + - v0.7.2 + - v0.8.0 + - v0.8.1 + - v0.8.2 + - v0.8.3 + - v0.9.0 + - v0.9.1 runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v3 @@ -13,7 +23,7 @@ jobs: shell: bash run: | mkdir -p /tmp/nvim - wget -q https://github.com/neovim/neovim/releases/download/nightly/nvim.appimage -O /tmp/nvim/nvim.appimage + wget -q https://github.com/neovim/neovim/releases/download/${{ matrix.nvim_version }}/nvim.appimage -O /tmp/nvim/nvim.appimage cd /tmp/nvim chmod a+x ./nvim.appimage ./nvim.appimage --appimage-extract From 2e89cea6f398083bf8aa03b343ddcedf49e2a896 Mon Sep 17 00:00:00 2001 From: Smirnov Oleksandr Date: Thu, 10 Aug 2023 12:04:33 +0300 Subject: [PATCH 14/24] refactor: commands runner (#42) * feat(utils): first impl of own commands runner * refactor(gotests): uses own runner instead of vendored * refactor(utils): back to plenary.job * refactor(gotests): use new runner, clean code * fix(runner): now it returns output correctly * refactor(iferr): use vim.system i have tried to use _utils.runner, but i can't figure out how to make `< file.go` for the command * refactor(impl): use new runner * refactor(installer): use new runner * refactor(struct_tags): use new runner * refactor: commands such as :GoGet runs with new runner * refactor: throw errors in more lua way, i think * refactor(utils): notify now has title * refactor: use more correct way of notifying * refactor(runner): write error message on error --- lua/gopher/_utils/commands.lua | 43 ------------------ lua/gopher/_utils/init.lua | 17 ++++++- lua/gopher/_utils/runner/gocmd.lua | 53 ++++++++++++++++++++++ lua/gopher/_utils/runner/init.lua | 33 ++++++++++++++ lua/gopher/gotests.lua | 71 +++++++++--------------------- lua/gopher/iferr.lua | 14 ++---- lua/gopher/impl.lua | 38 ++++++---------- lua/gopher/init.lua | 10 ++--- lua/gopher/installer.lua | 20 +++------ lua/gopher/struct_tags.lua | 36 ++++----------- plugin/gopher.vim | 6 +-- 11 files changed, 163 insertions(+), 178 deletions(-) delete mode 100644 lua/gopher/_utils/commands.lua create mode 100644 lua/gopher/_utils/runner/gocmd.lua create mode 100644 lua/gopher/_utils/runner/init.lua diff --git a/lua/gopher/_utils/commands.lua b/lua/gopher/_utils/commands.lua deleted file mode 100644 index 447a3af..0000000 --- a/lua/gopher/_utils/commands.lua +++ /dev/null @@ -1,43 +0,0 @@ -local Job = require "plenary.job" -local c = require("gopher.config").commands -local u = require "gopher._utils" - ----Run any go commands like `go generate`, `go get`, `go mod` ----@param cmd string ----@param ... string|string[] -return function(cmd, ...) - local args = { ... } - if #args == 0 then - u.deferred_notify("please provice any arguments", vim.log.levels.ERROR) - return - end - - if cmd == "generate" and #args == 1 and args[1] == "%" then - args[1] = vim.fn.expand "%" ---@diagnostic disable-line: missing-parameter - elseif cmd == "get" then - for i, arg in ipairs(args) do - ---@diagnostic disable-next-line: param-type-mismatch - local m = string.match(arg, "^https://(.*)$") or string.match(arg, "^http://(.*)$") or arg - table.remove(args, i) - table.insert(args, i, m) - end - end - - local cmd_args = vim.list_extend({ cmd }, args) ---@diagnostic disable-line: missing-parameter - Job:new({ - command = c.go, - args = cmd_args, - on_exit = function(_, retval) - if retval ~= 0 then - u.deferred_notify( - "command 'go " .. unpack(cmd_args) .. "' exited with code " .. retval, - vim.log.levels.ERROR - ) - u.deferred_notify(cmd .. " " .. unpack(cmd_args), vim.log.levels.DEBUG) - return - end - - u.deferred_notify("go " .. cmd .. " was success runned", vim.log.levels.INFO) - end, - }):start() -end diff --git a/lua/gopher/_utils/init.lua b/lua/gopher/_utils/init.lua index 4915ab3..136717d 100644 --- a/lua/gopher/_utils/init.lua +++ b/lua/gopher/_utils/init.lua @@ -1,5 +1,7 @@ local utils = {} +local TITLE = "gopher.nvim" + ---@param t table ---@return boolean function utils.is_tbl_empty(t) @@ -10,13 +12,24 @@ function utils.is_tbl_empty(t) end ---@param msg string ----@param lvl any +---@param lvl number function utils.deferred_notify(msg, lvl) vim.defer_fn(function() - vim.notify(msg, lvl) + vim.notify(msg, lvl, { + title = TITLE, + }) end, 0) end +---@param msg string +---@param lvl? number +function utils.notify(msg, lvl) + lvl = lvl or vim.log.levels.INFO + vim.notify(msg, lvl, { + title = TITLE, + }) +end + -- safe require ---@param module string module name function utils.sreq(module) diff --git a/lua/gopher/_utils/runner/gocmd.lua b/lua/gopher/_utils/runner/gocmd.lua new file mode 100644 index 0000000..97323f9 --- /dev/null +++ b/lua/gopher/_utils/runner/gocmd.lua @@ -0,0 +1,53 @@ +local r = require "gopher._utils.runner" +local c = require("gopher.config").commands +local u = require "gopher._utils" +local gocmd = {} + +---@param args string[] +---@return string[] +local function if_get(args) + for i, arg in ipairs(args) do + local m = string.match(arg, "^https://(.*)$") or string.match(arg, "^http://(.*)$") or arg + table.remove(args, i) + table.insert(args, i, m) + end + return args +end + +---@param args unknown[] +---@return string[] +local function if_generate(args) + if #args == 1 and args[1] == "%" then + args[1] = vim.fn.expand "%" + end + return args +end + +---@param subcmd string +---@param args string[] +---@return string[]|nil +function gocmd.run(subcmd, args) + if #args == 0 then + error "please provice any arguments" + end + + if subcmd == "get" then + args = if_get(args) + end + + if subcmd == "generate" then + args = if_generate(args) + end + + return r.sync(c.go, { + args = { subcmd, unpack(args) }, + on_exit = function(data, status) + if status ~= 0 then + error("gocmd failed: " .. data) + end + u.notify(c.go .. " " .. subcmd .. " successful runned") + end, + }) +end + +return gocmd diff --git a/lua/gopher/_utils/runner/init.lua b/lua/gopher/_utils/runner/init.lua new file mode 100644 index 0000000..3c08f7f --- /dev/null +++ b/lua/gopher/_utils/runner/init.lua @@ -0,0 +1,33 @@ +local Job = require "plenary.job" +local runner = {} + +---@class gopher.RunnerOpts +---@field args? string[] +---@field cwd? string? +---@field on_exit? fun(data:string, status:number) + +---@param cmd string +---@param opts gopher.RunnerOpts +---@return string[]|nil +function runner.sync(cmd, opts) + local output + Job:new({ + command = cmd, + args = opts.args, + cwd = opts.cwd, + on_stderr = function(_, data) + vim.print(data) + end, + on_exit = function(data, status) + output = data:result() + vim.schedule(function() + if opts.on_exit then + opts.on_exit(output, status) + end + end) + end, + }):sync(60000 --[[1 min]]) + return output +end + +return runner diff --git a/lua/gopher/gotests.lua b/lua/gopher/gotests.lua index cf9a0f1..942fab3 100644 --- a/lua/gopher/gotests.lua +++ b/lua/gopher/gotests.lua @@ -1,74 +1,45 @@ local c = require("gopher.config").commands -local u = require "gopher._utils" local ts_utils = require "gopher._utils.ts" -local Job = require "plenary.job" +local r = require "gopher._utils.runner" +local u = require "gopher._utils" local gotests = {} ----@param cmd_args table -local function run(cmd_args) - Job:new({ - command = c.gotests, - args = cmd_args, - on_exit = function(_, retval) - if retval ~= 0 then - u.deferred_notify( - "command '" .. c.gotests .. " " .. unpack(cmd_args) .. "' exited with code " .. retval, - vim.log.levels.ERROR - ) - return - end - - u.deferred_notify("unit test(s) generated", vim.log.levels.INFO) - end, - }):start() -end - ---@param args table local function add_test(args) - local fpath = vim.fn.expand "%" ---@diagnostic disable-line: missing-parameter table.insert(args, "-w") - table.insert(args, fpath) - run(args) + table.insert(args, vim.fn.expand "%") + + return r.sync(c.gotests, { + args = args, + on_exit = function(data, status) + if not status == 0 then + error("gotests failed: " .. data) + end + + u.notify "unit test(s) generated" + end, + }) end ---generate unit test for one function ----@param parallel boolean -function gotests.func_test(parallel) +function gotests.func_test() local ns = ts_utils.get_func_method_node_at_pos(unpack(vim.api.nvim_win_get_cursor(0))) if ns == nil or ns.name == nil then - u.deferred_notify("cursor on func/method and execute the command again", vim.log.levels.INFO) + u.notify("cursor on func/method and execute the command again", vim.log.levels.WARN) return end - local cmd_args = { "-only", ns.name } - if parallel then - table.insert(cmd_args, "-parallel") - end - - add_test(cmd_args) + add_test { "-only", ns.name } end ---generate unit tests for all functions in current file ----@param parallel boolean -function gotests.all_tests(parallel) - local cmd_args = { "-all" } - if parallel then - table.insert(cmd_args, "-parallel") - end - - add_test(cmd_args) +function gotests.all_tests() + add_test { "-all" } end ---generate unit tests for all exported functions ----@param parallel boolean -function gotests.all_exported_tests(parallel) - local cmd_args = {} - if parallel then - table.insert(cmd_args, "-parallel") - end - - table.insert(cmd_args, "-exported") - add_test(cmd_args) +function gotests.all_exported_tests() + add_test { "-exported" } end return gotests diff --git a/lua/gopher/iferr.lua b/lua/gopher/iferr.lua index fbeddf7..0898693 100644 --- a/lua/gopher/iferr.lua +++ b/lua/gopher/iferr.lua @@ -1,22 +1,16 @@ local c = require("gopher.config").commands -local u = require "gopher._utils" local iferr = {} -- That's Lua of vimscript implementation of: github.com/koron/iferr -iferr.iferr = function() +function iferr.iferr() local boff = vim.fn.wordcount().cursor_bytes - local cmd = (c.iferr .. " -pos " .. boff) - local data = vim.fn.systemlist(cmd, vim.fn.bufnr "%") + local pos = vim.fn.getcurpos()[2] + local data = vim.fn.systemlist((c.iferr .. " -pos " .. boff), vim.fn.bufnr "%") if vim.v.shell_error ~= 0 then - u.deferred_notify( - "command " .. cmd .. " exited with code " .. vim.v.shell_error, - vim.log.levels.ERROR - ) - return + error("iferr failed: " .. data) end - local pos = vim.fn.getcurpos()[2] vim.fn.append(pos, data) vim.cmd [[silent normal! j=2j]] vim.fn.setpos(".", pos) diff --git a/lua/gopher/impl.lua b/lua/gopher/impl.lua index 6eddc0f..155d6c2 100644 --- a/lua/gopher/impl.lua +++ b/lua/gopher/impl.lua @@ -1,5 +1,5 @@ local c = require("gopher.config").commands -local Job = require "plenary.job" +local r = require "gopher._utils.runner" local ts_utils = require "gopher._utils.ts" local u = require "gopher._utils" local impl = {} @@ -47,33 +47,23 @@ function impl.impl(...) recv = string.format("%s %s", recv_name, recv) end - -- stylua: ignore - local cmd_args = { - "-dir", vim.fn.fnameescape(vim.fn.expand "%:p:h"), ---@diagnostic disable-line: missing-parameter - recv, - iface - } - - local res_data - Job:new({ - command = c.impl, - args = cmd_args, - on_exit = function(data, retval) - if retval ~= 0 then - u.deferred_notify( - "command '" .. c.impl .. " " .. unpack(cmd_args) .. "' exited with code " .. retval, - vim.log.levels.ERROR - ) - return + local output = r.sync(c.impl, { + args = { + "-dir", + vim.fn.fnameescape(vim.fn.expand "%:p:h" --[[@as string]]), + recv, + iface, + }, + on_exit = function(data, status) + if not status == 0 then + error("impl failed: " .. data) end - - res_data = data:result() end, - }):sync() + }) local pos = vim.fn.getcurpos()[2] - table.insert(res_data, 1, "") - vim.fn.append(pos, res_data) + table.insert(output, 1, "") + vim.fn.append(pos, output) end return impl diff --git a/lua/gopher/init.lua b/lua/gopher/init.lua index 2f6f32e..06faf67 100644 --- a/lua/gopher/init.lua +++ b/lua/gopher/init.lua @@ -1,6 +1,6 @@ local tags = require "gopher.struct_tags" local tests = require "gopher.gotests" -local uc = require "gopher._utils.commands" +local gocmd = require("gopher._utils.runner.gocmd").run local gopher = {} gopher.setup = require("gopher.config").setup @@ -17,19 +17,19 @@ gopher.test_exported = tests.all_exported_tests gopher.tests_all = tests.all_tests gopher.get = function(...) - uc("get", ...) + gocmd("get", { ... }) end gopher.mod = function(...) - uc("mod", ...) + gocmd("mod", { ... }) end gopher.generate = function(...) - uc("generate", ...) + gocmd("generate", { ... }) end gopher.work = function(...) - uc("work", ...) + gocmd("work", { ... }) end return gopher diff --git a/lua/gopher/installer.lua b/lua/gopher/installer.lua index 939d50f..2994b8a 100644 --- a/lua/gopher/installer.lua +++ b/lua/gopher/installer.lua @@ -1,5 +1,5 @@ -local Job = require "plenary.job" local c = require("gopher.config").commands +local r = require "gopher._utils.runner" local u = require "gopher._utils" local installer = {} @@ -14,22 +14,16 @@ local urls = { ---@param pkg string local function install(pkg) local url = urls[pkg] .. "@latest" - - Job:new({ - command = c.go, + r.sync(c.go, { args = { "install", url }, - on_exit = function(_, retval) - if retval ~= 0 then - u.deferred_notify( - "command 'go install " .. url .. "' exited with code " .. retval, - vim.log.levels.ERROR - ) + on_exit = function(data, status) + if not status == 0 then + error("go install failed: " .. data) return end - - u.deferred_notify("install " .. url .. " finished", vim.log.levels.INFO) + u.notify("installed: " .. url) end, - }):start() + }) end ---Install required go deps diff --git a/lua/gopher/struct_tags.lua b/lua/gopher/struct_tags.lua index 690eae1..d31ce4b 100644 --- a/lua/gopher/struct_tags.lua +++ b/lua/gopher/struct_tags.lua @@ -1,7 +1,6 @@ local ts_utils = require "gopher._utils.ts" -local Job = require "plenary.job" +local r = require "gopher._utils.runner" local c = require("gopher.config").commands -local u = require "gopher._utils" local struct_tags = {} local function modify(...) @@ -39,45 +38,26 @@ local function modify(...) table.insert(cmd_args, "json") end - -- get result of "gomodifytags" works - local res_data - Job:new({ - command = c.gomodifytags, + local output = r.sync(c.gomodifytags, { args = cmd_args, - on_exit = function(data, retval) - if retval ~= 0 then - u.deferred_notify( - "command '" - .. c.gomodifytags - .. " " - .. unpack(cmd_args) - .. "' exited with code " - .. retval, - vim.log.levels.ERROR - ) - return + on_exit = function(data, status) + if not status == 0 then + error("gotag failed: " .. data) end - - res_data = data:result() end, - }):sync() + }) -- decode goted value - local tagged = vim.json.decode(table.concat(res_data)) + local tagged = vim.json.decode(table.concat(output)) if tagged.errors ~= nil or tagged.lines == nil or tagged["start"] == nil or tagged["start"] == 0 then - u.deferred_notify("failed to set tags " .. vim.inspect(tagged), vim.log.levels.ERROR) + error("failed to set tags " .. vim.inspec(tagged)) end - for i, v in ipairs(tagged.lines) do - tagged.lines[i] = u.rtrim(v) - end - - -- write goted tags vim.api.nvim_buf_set_lines( 0, tagged.start - 1, diff --git a/plugin/gopher.vim b/plugin/gopher.vim index bdffbbe..f54d5dd 100644 --- a/plugin/gopher.vim +++ b/plugin/gopher.vim @@ -1,8 +1,8 @@ command! -nargs=* GoTagAdd :lua require"gopher".tags_add() command! -nargs=* GoTagRm :lua require"gopher".tags_rm() -command! -nargs=* GoTestAdd :lua require"gopher".test_add() -command! -nargs=* GoTestsAll :lua require"gopher".tests_all() -command! -nargs=* GoTestsExp :lua require"gopher".test_exported() +command! GoTestAdd :lua require"gopher".test_add() +command! GoTestsAll :lua require"gopher".tests_all() +command! GoTestsExp :lua require"gopher".test_exported() command! -nargs=* GoMod :lua require"gopher".mod() command! -nargs=* GoGet :lua require"gopher".get() command! -nargs=* GoWork :lua require"gopher".work() From e0a3e70e484f09ac550d78304de9ad2d675d374d Mon Sep 17 00:00:00 2001 From: Smirnov Oleksandr Date: Thu, 17 Aug 2023 19:13:56 +0300 Subject: [PATCH 15/24] add ability for setting custom tools options (#44) * feat(gotests): add custom templates support * feat(struct_tags): add support for custom `transform` option --- lua/gopher/config.lua | 21 +++++++++++++++++++++ lua/gopher/gotests.lua | 14 ++++++++++++-- lua/gopher/struct_tags.lua | 5 +++-- 3 files changed, 36 insertions(+), 4 deletions(-) diff --git a/lua/gopher/config.lua b/lua/gopher/config.lua index 68b29e6..f1cf2ad 100644 --- a/lua/gopher/config.lua +++ b/lua/gopher/config.lua @@ -1,6 +1,14 @@ ---@type gopher.Config local config = {} +---@alias gopher.ConfigGoTagTransform +---| "snakecase" "GopherUser" -> "gopher_user" +---| "camelcase" "GopherUser" -> "gopherUser" +---| "lispcase" "GopherUser" -> "gopher-user" +---| "pascalcase" "GopherUser" -> "GopherUser" +---| "titlecase" "GopherUser" -> "Gopher User" +---| "keep" keeps the original field name + ---@class gopher.Config local default_config = { ---@class gopher.ConfigCommand @@ -12,6 +20,19 @@ local default_config = { iferr = "iferr", dlv = "dlv", }, + ---@class gopjer.ConfigGotests + gotests = { + -- gotests doesn't have template named "default" so this plugin uses "default" to set the default template + template = "default", + -- path to a directory containing custom test code templates + ---@type string|nil + template_dir = nil, + }, + ---@class gopher.ConfigGoTag + gotag = { + ---@type gopher.ConfigGoTagTransform + transform = "snakecase", + }, } ---@type gopher.Config diff --git a/lua/gopher/gotests.lua b/lua/gopher/gotests.lua index 942fab3..f98b365 100644 --- a/lua/gopher/gotests.lua +++ b/lua/gopher/gotests.lua @@ -1,4 +1,4 @@ -local c = require("gopher.config").commands +local c = require "gopher.config" local ts_utils = require "gopher._utils.ts" local r = require "gopher._utils.runner" local u = require "gopher._utils" @@ -6,10 +6,20 @@ local gotests = {} ---@param args table local function add_test(args) + if c.gotests.template_dir then + table.insert(args, "-template_dir") + table.insert(args, c.gotests.template_dir) + end + + if c.gotests.template ~= "default" then + table.insert(args, "-template") + table.insert(args, c.gotests.template) + end + table.insert(args, "-w") table.insert(args, vim.fn.expand "%") - return r.sync(c.gotests, { + return r.sync(c.commands.gotests, { args = args, on_exit = function(data, status) if not status == 0 then diff --git a/lua/gopher/struct_tags.lua b/lua/gopher/struct_tags.lua index d31ce4b..afd4f87 100644 --- a/lua/gopher/struct_tags.lua +++ b/lua/gopher/struct_tags.lua @@ -1,6 +1,6 @@ local ts_utils = require "gopher._utils.ts" local r = require "gopher._utils.runner" -local c = require("gopher.config").commands +local c = require "gopher.config" local struct_tags = {} local function modify(...) @@ -12,6 +12,7 @@ local function modify(...) -- stylua: ignore local cmd_args = { + "-transform", c.gotag.transform, "-format", "json", "-file", fpath, "-w" @@ -38,7 +39,7 @@ local function modify(...) table.insert(cmd_args, "json") end - local output = r.sync(c.gomodifytags, { + local output = r.sync(c.commands.gomodifytags, { args = cmd_args, on_exit = function(data, status) if not status == 0 then From bbe89312c5c8607a06b468c6ea000e49f13ed252 Mon Sep 17 00:00:00 2001 From: Smirnov Oleksandr Date: Fri, 12 Jan 2024 09:01:56 +0200 Subject: [PATCH 16/24] fix(health): check if bin is installed, and added message about treesitter parser --- lua/gopher/health.lua | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/lua/gopher/health.lua b/lua/gopher/health.lua index 4b3f3a2..a7a4d14 100644 --- a/lua/gopher/health.lua +++ b/lua/gopher/health.lua @@ -11,22 +11,24 @@ local deps = { bin = { { bin = cmd.go, - msg = "required for :GoGet, :GoMod, :GoGenerate, :GoWork, :GoInstallDeps", + msg = "required for `:GoGet`, `:GoMod`, `:GoGenerate`, `:GoWork`, `:GoInstallDeps`", optional = false, }, - { bin = cmd.gomodifytags, msg = "required for :GoTagAdd, :GoTagRm", optional = false }, - { bin = cmd.impl, msg = "required for :GoImpl", optional = false }, - { bin = cmd.iferr, msg = "required for :GoIfErr", optional = false }, + { bin = cmd.gomodifytags, msg = "required for `:GoTagAdd`, `:GoTagRm`", optional = false }, + { bin = cmd.impl, msg = "required for `:GoImpl`", optional = false }, + { bin = cmd.iferr, msg = "required for `:GoIfErr`", optional = false }, { bin = cmd.gotests, - msg = "required for :GoTestAdd, :GoTestsAll, :GoTestsExp", + msg = "required for `:GoTestAdd`, `:GoTestsAll`, `:GoTestsExp`", optional = false, }, - { bin = cmd.dlv, msg = "required for debugging, (nvim-dap, `gopher.dap`)", optional = true }, + { bin = cmd.dlv, msg = "required for debugging, (`nvim-dap`, `gopher.dap`)", optional = true }, }, } function health.check() + u.info "install go treesitter parser by `:TSInstall go` if you don't have it already" + u.start "required plugins" for _, plugin in ipairs(deps.plugin) do if u.is_lualib_found(plugin.lib) then @@ -43,7 +45,7 @@ function health.check() u.start "required binaries" u.info "all those binaries can be installed by `:GoInstallDeps`" for _, bin in ipairs(deps.bin) do - if u.is_lualib_found(bin.bin) then + if u.is_binary_found(bin.bin) then u.ok(bin.bin .. " installed") else if bin.optional then From 8a6f7748efb0541d28e1ef5c324ff026fc5572ec Mon Sep 17 00:00:00 2001 From: Arne Van Maele <93863978+arnevm123@users.noreply.github.com> Date: Sat, 10 Feb 2024 18:44:59 -0500 Subject: [PATCH 17/24] fix: fix iferr config (#56) --- lua/gopher/config.lua | 2 +- lua/gopher/iferr.lua | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lua/gopher/config.lua b/lua/gopher/config.lua index f1cf2ad..b6f7b57 100644 --- a/lua/gopher/config.lua +++ b/lua/gopher/config.lua @@ -20,7 +20,7 @@ local default_config = { iferr = "iferr", dlv = "dlv", }, - ---@class gopjer.ConfigGotests + ---@class gopher.ConfigGotests gotests = { -- gotests doesn't have template named "default" so this plugin uses "default" to set the default template template = "default", diff --git a/lua/gopher/iferr.lua b/lua/gopher/iferr.lua index 0898693..1eac0ce 100644 --- a/lua/gopher/iferr.lua +++ b/lua/gopher/iferr.lua @@ -1,4 +1,4 @@ -local c = require("gopher.config").commands +local c = require "gopher.config" local iferr = {} -- That's Lua of vimscript implementation of: github.com/koron/iferr @@ -6,7 +6,7 @@ function iferr.iferr() local boff = vim.fn.wordcount().cursor_bytes local pos = vim.fn.getcurpos()[2] - local data = vim.fn.systemlist((c.iferr .. " -pos " .. boff), vim.fn.bufnr "%") + local data = vim.fn.systemlist((c.commands.iferr .. " -pos " .. boff), vim.fn.bufnr "%") if vim.v.shell_error ~= 0 then error("iferr failed: " .. data) end From cdb1cd05a329c8d5b6a57e2d550852deca572b6a Mon Sep 17 00:00:00 2001 From: Alex <49870662+ysomad@users.noreply.github.com> Date: Sun, 11 Feb 2024 18:35:39 +0400 Subject: [PATCH 18/24] Add support for named tests (#50) * fix(typo): README.md (#47) * feat: add support for named tests * test * tags in table * debug installer msg * test * hardcoded @develop * get gotests tag from setup() * update readme * store install tag in urls table * removed gotests tag * update README.md * remove urls installer index reference * remove named arg from add_test() * . * update README.md * update README.md --------- Co-authored-by: Steve M --- README.md | 40 +++++++++++++++++++++++++++++++++++++++- lua/gopher/config.lua | 4 ++++ lua/gopher/gotests.lua | 4 ++++ 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3c13fa0..3079257 100644 --- a/README.md +++ b/README.md @@ -39,9 +39,47 @@ require("gopher").setup { impl = "impl", iferr = "iferr", }, + gotests = { + -- gotests doesn't have template named "default" so this plugin uses "default" to set the default template + template = "default", + -- path to a directory containing custom test code templates + template_dir = nil, + -- switch table tests from using slice to map (with test name for the key) + -- works only with gotests installed from develop branch + named = false, + }, } ``` +### Named tests with testify (using map instead of slice for test cases) + +```lua +require("gopher").setup({ + gotests = { + template = "testify", + named = true + } +}) +``` + +For named tests to work you have to install gotests from develop branch, for example using [mason-tool-installer](https://github.com/WhoIsSethDaniel/mason-tool-installer.nvim): + +```lua + require('mason-tool-installer').setup({ + ensure_installed = { + { "gotests", version = "develop" }, + } +}) +``` + +Or by calling `vim.fn.jobstart`: + +```lua +vim.fn.jobstart("go install github.com/cweill/gotests/...@develop") +``` + +If you're using `lazy.nvim` you can put in `build` function inside `setup()` + ## Features 1. Installation requires this go tool: @@ -104,7 +142,7 @@ Example of usage: 6. Generate tests with [gotests](https://github.com/cweill/gotests) -Generate one test for spesific function/method: +Generate one test for a specific function/method: ```vim :GoTestAdd diff --git a/lua/gopher/config.lua b/lua/gopher/config.lua index b6f7b57..fca13a7 100644 --- a/lua/gopher/config.lua +++ b/lua/gopher/config.lua @@ -27,6 +27,10 @@ local default_config = { -- path to a directory containing custom test code templates ---@type string|nil template_dir = nil, + -- switch table tests from using slice to map (with test name for the key) + -- works only with gotests installed from develop branch + ---@type boolean + named = false, }, ---@class gopher.ConfigGoTag gotag = { diff --git a/lua/gopher/gotests.lua b/lua/gopher/gotests.lua index f98b365..0ef52cc 100644 --- a/lua/gopher/gotests.lua +++ b/lua/gopher/gotests.lua @@ -6,6 +6,10 @@ local gotests = {} ---@param args table local function add_test(args) + if c.gotests.named then + table.insert(args, "-named") + end + if c.gotests.template_dir then table.insert(args, "-template_dir") table.insert(args, c.gotests.template_dir) From ebb10e9b90da48772ed4145b7558c496f5defa82 Mon Sep 17 00:00:00 2001 From: Smirnov Oleksandr Date: Sun, 11 Feb 2024 17:44:19 +0200 Subject: [PATCH 19/24] reformat .editorconfig config --- .editorconfig | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.editorconfig b/.editorconfig index 3155057..81eca2d 100644 --- a/.editorconfig +++ b/.editorconfig @@ -5,13 +5,10 @@ indent_style = space indent_size = 4 end_of_line = lf insert_final_newline = true -trim_trailing_whitespace=true +trim_trailing_whitespace = true charset = utf-8 -[*.{lua,vim}] -indent_size = 2 - -[*.{md,yml,yaml,toml}] +[*.{md,yml,yaml,toml,lua,vim}] indent_size = 2 [*.go] From 28e1f5689f3be7e0947fd713696ba1360df4cb74 Mon Sep 17 00:00:00 2001 From: Smirnov Oleksandr Date: Sun, 25 Feb 2024 01:18:09 +0200 Subject: [PATCH 20/24] refactor(api)!: mave tags and gotests api into their sub tables --- lua/gopher/init.lua | 14 +++++++++----- plugin/gopher.vim | 10 +++++----- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/lua/gopher/init.lua b/lua/gopher/init.lua index 06faf67..fe86577 100644 --- a/lua/gopher/init.lua +++ b/lua/gopher/init.lua @@ -9,12 +9,16 @@ gopher.impl = require("gopher.impl").impl gopher.iferr = require("gopher.iferr").iferr gopher.comment = require "gopher.comment" -gopher.tags_add = tags.add -gopher.tags_rm = tags.remove +gopher.tags = { + add = tags.add, + rm = tags.remove, +} -gopher.test_add = tests.func_test -gopher.test_exported = tests.all_exported_tests -gopher.tests_all = tests.all_tests +gopher.test = { + add = tests.func_test, + exported = tests.all_exported_tests, + all = tests.all_tests, +} gopher.get = function(...) gocmd("get", { ... }) diff --git a/plugin/gopher.vim b/plugin/gopher.vim index f54d5dd..997ec94 100644 --- a/plugin/gopher.vim +++ b/plugin/gopher.vim @@ -1,8 +1,8 @@ -command! -nargs=* GoTagAdd :lua require"gopher".tags_add() -command! -nargs=* GoTagRm :lua require"gopher".tags_rm() -command! GoTestAdd :lua require"gopher".test_add() -command! GoTestsAll :lua require"gopher".tests_all() -command! GoTestsExp :lua require"gopher".test_exported() +command! -nargs=* GoTagAdd :lua require"gopher".tags.add() +command! -nargs=* GoTagRm :lua require"gopher".tags.rm() +command! GoTestAdd :lua require"gopher".test.add() +command! GoTestsAll :lua require"gopher".test.all() +command! GoTestsExp :lua require"gopher".test.exported() command! -nargs=* GoMod :lua require"gopher".mod() command! -nargs=* GoGet :lua require"gopher".get() command! -nargs=* GoWork :lua require"gopher".work() From 10cec9c6b0156c76f8d30d8aaba5f3d3afe9129c Mon Sep 17 00:00:00 2001 From: Smirnov Oleksandr Date: Thu, 4 Apr 2024 17:15:55 +0300 Subject: [PATCH 21/24] add help file, and docs (#59) * idk how good this idea is * this could be working but i still cant figure out how to run it * ignore tags that mini.doc gens, but why? * chore(taskfile): force exiting after tests because i got infinit ci * chore(ci): add more nvim versions to run on * chore: update taskfile * feat: add docs generator * docs: its only begining * refactor: update docgen script * docs: write some more * docs(config): update * docs: update readme * language * hope it would work * what about that? * maybe this would work? * update md * upd * WHY DOESNT IT WORKING * idk by but 0.9.3 just fails the ci, so i deleted it from suite * again update, why does markdown not work in embeded html * maybe it can help? * upd * again update * kinda fix * fix: formatting * again some updating * some readme updating * fix, this shouldnt be in repo * i finnaly undertood how to fix this fking skill issue * fix(struct_tags): typo * refactor(docs): change the order in generated file * docs: install deps * refactor(scripts): rename doc-gen script * docs(impl): write docs * docs(dap): add doc * stylua . * docs(struct_tags): add doc * docs(gotests): add docs * docs(iferr): add docs * docs(comment): add doc * update CONTRIBUTING.md * docs(README): talk about `develop` branch * docs: update README.md --- .github/workflows/tests.yml | 14 +- CONTRIBUTING.md | 48 +++++- README.md | 266 ++++++++++++++++------------- Taskfile.yml | 39 +++-- doc/.gitignore | 1 + doc/gopher.nvim.txt | 220 ++++++++++++++++++++++++ lua/gopher/comment.lua | 5 + lua/gopher/config.lua | 22 ++- lua/gopher/dap.lua | 7 +- lua/gopher/gotests.lua | 48 +++++- lua/gopher/iferr.lua | 7 +- lua/gopher/impl.lua | 29 ++++ lua/gopher/init.lua | 25 +++ lua/gopher/struct_tags.lua | 34 +++- scripts/docgen.lua | 33 ++++ {spec => scripts}/minimal_init.lua | 1 + 16 files changed, 657 insertions(+), 142 deletions(-) create mode 100644 doc/.gitignore create mode 100644 doc/gopher.nvim.txt create mode 100644 scripts/docgen.lua rename {spec => scripts}/minimal_init.lua (93%) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 9ffb99c..09fb168 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -16,11 +16,20 @@ jobs: - v0.8.3 - v0.9.0 - v0.9.1 + - v0.9.2 + - v0.9.4 + - v0.9.5 runs-on: ${{ matrix.os }} steps: + - name: Install Task + uses: arduino/setup-task@v1 + with: + version: 3.x + repo-token: ${{ secrets.GITHUB_TOKEN }} + - uses: actions/checkout@v3 + - name: Install Neovim - shell: bash run: | mkdir -p /tmp/nvim wget -q https://github.com/neovim/neovim/releases/download/${{ matrix.nvim_version }}/nvim.appimage -O /tmp/nvim/nvim.appimage @@ -28,7 +37,8 @@ jobs: chmod a+x ./nvim.appimage ./nvim.appimage --appimage-extract echo "/tmp/nvim/squashfs-root/usr/bin/" >> $GITHUB_PATH + - name: Run Tests run: | nvim --version - nvim --headless -u ./spec/minimal_init.lua -c "PlenaryBustedDirectory spec {minimal_init='./spec/minimal_init.lua', sequential=true}" + task test diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b3a3c7b..39092b1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,14 @@ # Contributing to `gopher.nvim` -Thank you for looking to contributing +Thank you for taking the time to submit some code to gopher.nvim. It means a lot! + +### Task running + +In this codebase for running tasks is used [Taskfile](https://taskfile.dev). +You can install it with: +```bash +go install github.com/go-task/task/v3/cmd/task@latest +``` ### Styling and formatting @@ -8,6 +16,40 @@ Code is formatted by [stylua](https://github.com/JohnnyMorganz/StyLua) and linte You can install these with: ```bash -cargo install stylua -cargo install selene +sudo pacman -S selene stylua +# or whatever is your package manager +# or way of installing pkgs +``` + +For formatting use this following commands, or setup your editor to integrate with selene/stylua: +```bash +task format +task format:check # will check if your code formatted +task lint +``` + +### Documentation + +Here we are using [mini.doc](https://github.com/echasnovski/mini.nvim/blob/main/readmes/mini-doc.md) +for generating help files based on EmmyLua-like annotations in comments + +You can generate docs with: +```bash +task docgen +``` + +### Commit messages +We use [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/), please follow it. + +### Testing + +For testing this plugins uses [plenary.nvim](https://github.com/nvim-lua/plenary.nvim). +All tests live in [/spec](https://github.com/olexsmir/gopher.nvim/tree/main/spec) dir. + +You can run tests with: +```bash +task test +# also there are some aliases for that +task tests +task spec ``` diff --git a/README.md b/README.md index 3079257..f105a58 100644 --- a/README.md +++ b/README.md @@ -4,40 +4,54 @@ Minimalistic plugin for Go development in Neovim written in Lua. -It's not an LSP tool, the main goal of this plugin is add go tooling support in Neovim. +It's **NOT** an LSP tool, the main goal of this plugin is to add go tooling support in Neovim. -## Install +> If you want to use new and maybe undocumented, and unstable features you might use [develop](https://github.com/olexsmir/gopher.nvim/tree/develop) branch. -Pre-dependency: [go](https://github.com/golang/go) (tested on 1.17 and 1.18) +## Install (using [lazy.nvim](https://github.com/folke/lazy.nvim)) + +Pre-dependency: + +- [Go](https://github.com/golang/go) +- `go` treesitter parser, install by `:TSInstall go` ```lua -use { +{ "olexsmir/gopher.nvim", - requires = { -- dependencies + ft = "go", + -- branch = "develop", -- if you want develop branch + -- keep in mind, it might break everything + dependencies = { "nvim-lua/plenary.nvim", "nvim-treesitter/nvim-treesitter", + "mfussenegger/nvim-dap", -- (optional) only if you use `gopher.dap` }, + -- (optional) will update plugin's deps on every update + build = function() + vim.cmd.GoInstallDeps() + end, + ---@type gopher.Config + opts = {}, } ``` -Also, run `TSInstall go` if `go` parser if isn't installed yet. +## Configuratoin -## Config +> [!IMPORTANT] +> +> If you need more info look `:h gopher.nvim` -By `.setup` function you can configure the plugin. - -Note: - -- `installer` does not install the tool in user set path +**Take a look at default options** ```lua require("gopher").setup { commands = { go = "go", gomodifytags = "gomodifytags", - gotests = "~/go/bin/gotests", -- also you can set custom command path + gotests = "gotests", impl = "impl", iferr = "iferr", + dlv = "dlv", }, gotests = { -- gotests doesn't have template named "default" so this plugin uses "default" to set the default template @@ -48,151 +62,170 @@ require("gopher").setup { -- works only with gotests installed from develop branch named = false, }, + gotag = { + transform = "snakecase", + }, } ``` -### Named tests with testify (using map instead of slice for test cases) - -```lua -require("gopher").setup({ - gotests = { - template = "testify", - named = true - } -}) -``` - -For named tests to work you have to install gotests from develop branch, for example using [mason-tool-installer](https://github.com/WhoIsSethDaniel/mason-tool-installer.nvim): - -```lua - require('mason-tool-installer').setup({ - ensure_installed = { - { "gotests", version = "develop" }, - } -}) -``` - -Or by calling `vim.fn.jobstart`: - -```lua -vim.fn.jobstart("go install github.com/cweill/gotests/...@develop") -``` - -If you're using `lazy.nvim` you can put in `build` function inside `setup()` - ## Features -1. Installation requires this go tool: + -```vim -:GoInstallDeps -``` +
+ + Install plugin's go deps + -It will install next tools: + ```vim + :GoInstallDeps + ``` -- [gomodifytags](https://github.com/fatih/gomodifytags) -- [impl](https://github.com/josharian/impl) -- [gotests](https://github.com/cweill/gotests) -- [iferr](https://github.com/koron/iferr) + This will install the following tools: + + - [gomodifytags](https://github.com/fatih/gomodifytags) + - [impl](https://github.com/josharian/impl) + - [gotests](https://github.com/cweill/gotests) + - [iferr](https://github.com/koron/iferr) + - [dlv](github.com/go-delve/delve/cmd/dlv) +
+ +
+ + Add and remove tags for structs via gomodifytags + -2. Modify struct tags: By default `json` tag will be added/removed, if not set: -```vim -:GoTagAdd json " For add json tag -:GoTagRm yaml " For remove yaml tag -``` + ```vim + " add json tag + :GoTagAdd json -3. Run `go mod` command: + " remove yaml tag + :GoTagRm yaml + ``` -```vim -:GoMod tidy " Runs `go mod tidy` -:GoMod init asdf " Runs `go mod init asdf` -``` + ```lua + -- or you can use lua api + require("gopher").tags.add "xml" + require("gopher").tags.rm "proto" + ``` +
-4. Run `go get` command +
+ + Generating tests via gotests + -Link can have a `http` or `https` prefix. + ```vim + " Generate one test for a specific function/method(one under cursor) + :GoTestAdd -You can provide more than one package url: + " Generate all tests for all functions/methods in the current file + :GoTestsAll -```vim -:GoGet github.com/gorilla/mux -``` + " Generate tests for only exported functions/methods in the current file + :GoTestsExp + ``` -5. Interface implementation + ```lua + -- or you can use lua api + require("gopher").test.add() + require("gopher").test.exported() + require("gopher").test.all() + ``` -Command syntax: + For named tests see `:h gopher.nvim-gotests-named` +
-```vim -:GoImpl [receiver] [interface] +
+ + Run commands like go mod/get/etc inside of nvim + -" Also you can put cursor on the struct and run: -:GoImpl [interface] -``` + ```vim + :GoGet github.com/gorilla/mux -Example of usage: + " Link can have an `http` or `https` prefix. + :GoGet https://github.com/lib/pq -```vim -" Example -:GoImpl r Read io.Reader -" or simply put your cursor in the struct and run: -:GoImpl io.Reader -``` + " You can provide more than one package url + :GoGet github.com/jackc/pgx/v5 github.com/google/uuid/ -6. Generate tests with [gotests](https://github.com/cweill/gotests) + " go mod commands + :GoMod tidy + :GoMod init new-shiny-project -Generate one test for a specific function/method: + " go work commands + :GoWork sync -```vim -:GoTestAdd -``` + " run go generate in cwd + :GoGenerate -Generate all tests for all functions/methods in current file: + " run go generate for the current file + :GoGenerate % + ``` +
-```vim -:GoTestsAll -``` +
+ + Interface implementation via impl + -Generate tests only for exported functions/methods in current file: + Syntax of the command: + ```vim + :GoImpl [receiver] [interface] -```vim -:GoTestsExp -``` + " also you can put a cursor on the struct and run + :GoImpl [interface] + ``` -7. Run `go generate` command; + Usage examples: + ```vim + :GoImpl r Read io.Reader + :GoImpl Write io.Writer -```vim -" Run `go generate` in cwd path -:GoGenerate + " or you can simply put a cursor on the struct and run + :GoImpl io.Reader + ``` +
-" Run `go generate` for current file -:GoGenerate % -``` +
+ + Generate boilerplate for doc comments + -8. Generate doc comment + First set a cursor on **public** package/function/interface/struct and execute: -First set a cursor on **public** package/function/interface/struct and execute: + ```vim + :GoCmt + ``` +
-```vim -:GoCmt -``` -9. Generate `if err` +
+ + Generate if err != nil { via iferr + -Set cursor on the line with **err** and execute: + Set the cursor on the line with `err` and execute -```vim -:GoIfErr -``` + ```vim + :GoIfErr + ``` +
-10. Setup nvim-dap for go in one line. +
+ + Setup nvim-dap for go in one line + -Notice: [nvim-dap](https://github.com/mfussenegger/nvim-dap) is required + note [nvim-dap](https://github.com/mfussenegger/nvim-dap) has to be installed -```lua -require"gopher.dap".setup() -``` + ```lua + require("gopher.dap").setup() + ``` +
## Contributing @@ -202,3 +235,4 @@ PRs are always welcome. See [CONTRIBUTING.md](./CONTRIBUTING.md) - [go.nvim](https://github.com/ray-x/go.nvim) - [nvim-dap-go](https://github.com/leoluz/nvim-dap-go) +- [iferr](https://github.com/koron/iferr) diff --git a/Taskfile.yml b/Taskfile.yml index c4320bd..581f11c 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -2,21 +2,29 @@ version: "3" tasks: format: desc: formats all lua files in repo - cmds: [stylua .] + cmds: + - stylua . lint: desc: runs all linters cmds: - - task: lint_selene - - task: lint_stylua + - task: selene + - task: stylua:check - lint_selene: + selene: desc: runs lua linter(selene) - cmds: [selene .] + cmds: + - selene . - lint_stylua: + stylua:check: desc: runs stylua in check mode - cmds: [stylua --check .] + cmds: + - stylua --check . + + stylua: + desc: runs lua formatter + cmds: + - stylua . test: desc: runs all tests @@ -24,7 +32,18 @@ tasks: cmds: - | nvim --headless \ - -u ./spec/minimal_init.lua\ + -u ./scripts/minimal_init.lua \ -c "PlenaryBustedDirectory spec \ - {minimal_init='./spec/minimal_init.lua'\ - ,sequential=true}" + {minimal_init='./scripts/minimal_init.lua' \ + ,sequential=true}" \ + -c ":qa!" + + docgen: + desc: generate vimhelp + cmds: + - | + nvim --noplugin \ + --headless \ + -u "./scripts/minimal_init.lua" \ + -c "luafile ./scripts/docgen.lua" \ + -c ":qa!" diff --git a/doc/.gitignore b/doc/.gitignore new file mode 100644 index 0000000..61ffc7c --- /dev/null +++ b/doc/.gitignore @@ -0,0 +1 @@ +/tags diff --git a/doc/gopher.nvim.txt b/doc/gopher.nvim.txt new file mode 100644 index 0000000..7118e3c --- /dev/null +++ b/doc/gopher.nvim.txt @@ -0,0 +1,220 @@ +*gopher.nvim* + +============================================================================== + +gopher.nvim is a minimalistic plugin for Go development in Neovim written in Lua. +It's not an LSP tool, the main goal of this plugin is add go tooling support in Neovim. + +------------------------------------------------------------------------------ + *gopher.nvim-table-of-contents* +Table of Contents + Setup....................................................|gopher.nvim-setup| + Install dependencies..............................|gopher.nvim-install-deps| + Configuration...........................................|gopher.nvim-config| + Modifty struct tags................................|gopher.nvim-struct-tags| + Auto implementation of interface methods..................|gopher.nvim-impl| + Generating unit tests boilerplate......................|gopher.nvim-gotests| + Iferr....................................................|gopher.nvim-iferr| + Generate comments.....................................|gopher.nvim-comments| + Setup `nvim-dap` for Go......................................|gopher.nvim-dap| + +------------------------------------------------------------------------------ + *gopher.nvim-setup* + `gopher.setup` +Setup function. This method simply merges default configs with opts table. +You can read more about configuration at |gopher.nvim-config| +Calling this function is optional, if you ok with default settings. Look |gopher.nvim.config-defaults| + +Usage ~ +`require("gopher").setup {}` (replace `{}` with your `config` table) + +------------------------------------------------------------------------------ + *gopher.nvim-install-deps* + `gopher.install_deps` +Gopher.nvim implements most of its features using third-party tools. +To install these tools, you can run `:GoInstallDeps` command +or call `require("gopher").install_deps()` if you want ues lua api. + + +============================================================================== +------------------------------------------------------------------------------ + *gopher.nvim-config* +config it is the place where you can configure the plugin. +also this is optional is you're ok with default settings. +You can look at default options |gopher.nvim-config-defaults| + +------------------------------------------------------------------------------ + *gopher.nvim-config-defaults* + `default_config` +>lua + local default_config = { + --minidoc_replace_end + + -- user specified paths to binaries + ---@class gopher.ConfigCommand + commands = { + go = "go", + gomodifytags = "gomodifytags", + gotests = "gotests", + impl = "impl", + iferr = "iferr", + dlv = "dlv", + }, + ---@class gopher.ConfigGotests + gotests = { + -- gotests doesn't have template named "default" so this plugin uses "default" to set the default template + template = "default", + -- path to a directory containing custom test code templates + ---@type string|nil + template_dir = nil, + -- switch table tests from using slice to map (with test name for the key) + -- works only with gotests installed from develop branch + named = false, + }, + ---@class gopher.ConfigGoTag + gotag = { + ---@type gopher.ConfigGoTagTransform + transform = "snakecase", + }, + } +< +Class ~ +{gopher.Config} + +------------------------------------------------------------------------------ + *config.setup()* + `config.setup`({user_config}) +Parameters ~ +{user_config} `(optional)` gopher.Config + + +============================================================================== +------------------------------------------------------------------------------ + *gopher.nvim-struct-tags* +struct-tags is utilizing the `gomodifytags` tool to add or remove tags to struct fields. +Usage ~ +- put your coursor on the struct +- run `:GoTagAdd json` to add json tags to struct fields +- run `:GoTagRm json` to remove json tags to struct fields + +note: if you dont spesify the tag it will use `json` as default + +simple example: +>go + // before + type User struct { + // ^ put your cursor here + // run `:GoTagAdd yaml` + ID int + Name string + } + + // after + type User struct { + ID int `yaml:id` + Name string `yaml:name` + } +< + + +============================================================================== +------------------------------------------------------------------------------ + *gopher.nvim-impl* +impl is utilizing the `impl` tool to generate method stubs for interfaces. +Usage ~ + +1. put your coursor on the struct on which you want implement the interface + and run `:GoImpl io.Reader` + which will automatically choose the reciver for the methods and + implement the `io.Reader` interface +2. same as previous but with custom receiver, so put your coursor on the struct + run `:GoImpl w io.Writer` + where `w` is the receiver and `io.Writer` is the interface +3. specift receiver, struct, and interface + there's no need to put your coursor on the struct if you specify all arguments + `:GoImpl r RequestReader io.Reader` + where `r` is the receiver, `RequestReader` is the struct and `io.Reader` is the interface + +simple example: +>go + type BytesReader struct{} + // ^ put your cursor here + // run `:GoImpl b io.Reader` + + // this is what you will get + func (b *BytesReader) Read(p []byte) (n int, err error) { + panic("not implemented") // TODO: Implement + } +< + + +============================================================================== +------------------------------------------------------------------------------ + *gopher.nvim-gotests* +gotests is utilizing the `gotests` tool to generate unit tests boilerplate. +Usage ~ + +- generate unit test for spesisfic function/method + - to specift the function/method put your cursor on it + - run `:GoTestAdd` + +- generate unit tests for all functions/methods in current file + - run `:GoTestsAll` + +- generate unit tests only for exported(public) functions/methods + - run `:GoTestsExp` + +you can also specify the template to use for generating the tests. see |gopher.nvim-config| +more details about templates can be found at: https://github.com/cweill/gotests + + +------------------------------------------------------------------------------ + *gopher.nvim-gotests-named* + +if you prefare using named tests, you can enable it in the config. +but you would need to install `gotests@develop` because stable version doesn't support this feature. +you can do it with: +>lua + -- simply run go get in your shell: + go install github.com/cweill/gotests/...@develop + + -- if you want to install it within neovim, you can use one of this: + + vim.fn.jobstart("go install github.com/cweill/gotests/...@develop") + + -- or if you want to use mason: + require("mason-tool-installer").setup { + ensure_installed = { + { "gotests", version = "develop" }, + } + } +< + +if you choose to install `gotests` within neovim, i recommend adding it to your `build` section in your |lazy.nvim| + + +============================================================================== +------------------------------------------------------------------------------ + *gopher.nvim-iferr* +if you're using `iferr` tool, this module provides a way to automatically insert `if err != nil` check. +Usage ~ +execute `:GoIfErr` near any err variable to insert the check + + +============================================================================== +------------------------------------------------------------------------------ + *gopher.nvim-comments* +Usage ~ +Execute `:GoCmt` to generate a comment for the current function/method/struct/etc on this line. +This module provides a way to generate comments for Go code. + + +============================================================================== +------------------------------------------------------------------------------ + *gopher.nvim-dap* +This module sets up `nvim-dap` for Go. +Usage ~ +just call `require("gopher.dap").setup()`, and you're good to go. + + + vim:tw=78:ts=8:noet:ft=help:norl: \ No newline at end of file diff --git a/lua/gopher/comment.lua b/lua/gopher/comment.lua index 0a146fb..002894c 100644 --- a/lua/gopher/comment.lua +++ b/lua/gopher/comment.lua @@ -1,3 +1,8 @@ +---@toc_entry Generate comments +---@tag gopher.nvim-comments +---@usage Execute `:GoCmt` to generate a comment for the current function/method/struct/etc on this line. +---@text This module provides a way to generate comments for Go code. + local function generate(row, col) local ts_utils = require "gopher._utils.ts" local comment, ns = nil, nil diff --git a/lua/gopher/config.lua b/lua/gopher/config.lua index fca13a7..c0a0dcc 100644 --- a/lua/gopher/config.lua +++ b/lua/gopher/config.lua @@ -1,6 +1,17 @@ +---@toc_entry Configuration +---@tag gopher.nvim-config +---@text config it is the place where you can configure the plugin. +--- also this is optional is you're ok with default settings. +--- You can look at default options |gopher.nvim-config-defaults| + ---@type gopher.Config +---@private local config = {} +---@tag gopher.nvim-config.ConfigGoTagTransform +---@text Possible values for |gopher.Config|.gotag.transform: +--- +---@private ---@alias gopher.ConfigGoTagTransform ---| "snakecase" "GopherUser" -> "gopher_user" ---| "camelcase" "GopherUser" -> "gopherUser" @@ -9,8 +20,16 @@ local config = {} ---| "titlecase" "GopherUser" -> "Gopher User" ---| "keep" keeps the original field name +--minidoc_replace_start { + +---@tag gopher.nvim-config-defaults +---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section):gsub(">", ">lua") +--- ---@class gopher.Config local default_config = { + --minidoc_replace_end + + -- user specified paths to binaries ---@class gopher.ConfigCommand commands = { go = "go", @@ -29,7 +48,6 @@ local default_config = { template_dir = nil, -- switch table tests from using slice to map (with test name for the key) -- works only with gotests installed from develop branch - ---@type boolean named = false, }, ---@class gopher.ConfigGoTag @@ -38,8 +56,10 @@ local default_config = { transform = "snakecase", }, } +--minidoc_afterlines_end ---@type gopher.Config +---@private local _config = default_config ---@param user_config? gopher.Config diff --git a/lua/gopher/dap.lua b/lua/gopher/dap.lua index 551416c..6ff326a 100644 --- a/lua/gopher/dap.lua +++ b/lua/gopher/dap.lua @@ -1,3 +1,8 @@ +---@toc_entry Setup `nvim-dap` for Go +---@tag gopher.nvim-dap +---@text This module sets up `nvim-dap` for Go. +---@usage just call `require("gopher.dap").setup()`, and you're good to go. + local u = require "gopher._utils" local c = require "gopher.config" local dap = {} @@ -106,7 +111,7 @@ dap.configuration = { }, } ----setup `nvim-dap` for Go +-- sets ups nvim-dap for Go in one function call. function dap.setup() local d = u.sreq "dap" diff --git a/lua/gopher/gotests.lua b/lua/gopher/gotests.lua index 0ef52cc..3d96a05 100644 --- a/lua/gopher/gotests.lua +++ b/lua/gopher/gotests.lua @@ -1,3 +1,44 @@ +---@toc_entry Generating unit tests boilerplate +---@tag gopher.nvim-gotests +---@text gotests is utilizing the `gotests` tool to generate unit tests boilerplate. +---@usage +--- - generate unit test for spesisfic function/method +--- - to specift the function/method put your cursor on it +--- - run `:GoTestAdd` +--- +--- - generate unit tests for all functions/methods in current file +--- - run `:GoTestsAll` +--- +--- - generate unit tests only for exported(public) functions/methods +--- - run `:GoTestsExp` +--- +--- you can also specify the template to use for generating the tests. see |gopher.nvim-config| +--- more details about templates can be found at: https://github.com/cweill/gotests +--- + +---@tag gopher.nvim-gotests-named +---@text +--- if you prefare using named tests, you can enable it in the config. +--- but you would need to install `gotests@develop` because stable version doesn't support this feature. +--- you can do it with: +--- >lua +--- -- simply run go get in your shell: +--- go install github.com/cweill/gotests/...@develop +--- +--- -- if you want to install it within neovim, you can use one of this: +--- +--- vim.fn.jobstart("go install github.com/cweill/gotests/...@develop") +--- +--- -- or if you want to use mason: +--- require("mason-tool-installer").setup { +--- ensure_installed = { +--- { "gotests", version = "develop" }, +--- } +--- } +--- < +--- +--- if you choose to install `gotests` within neovim, i recommend adding it to your `build` section in your |lazy.nvim| + local c = require "gopher.config" local ts_utils = require "gopher._utils.ts" local r = require "gopher._utils.runner" @@ -5,6 +46,7 @@ local u = require "gopher._utils" local gotests = {} ---@param args table +---@private local function add_test(args) if c.gotests.named then table.insert(args, "-named") @@ -35,7 +77,7 @@ local function add_test(args) }) end ----generate unit test for one function +-- generate unit test for one function function gotests.func_test() local ns = ts_utils.get_func_method_node_at_pos(unpack(vim.api.nvim_win_get_cursor(0))) if ns == nil or ns.name == nil then @@ -46,12 +88,12 @@ function gotests.func_test() add_test { "-only", ns.name } end ----generate unit tests for all functions in current file +-- generate unit tests for all functions in current file function gotests.all_tests() add_test { "-all" } end ----generate unit tests for all exported functions +-- generate unit tests for all exported functions function gotests.all_exported_tests() add_test { "-exported" } end diff --git a/lua/gopher/iferr.lua b/lua/gopher/iferr.lua index 1eac0ce..56e9644 100644 --- a/lua/gopher/iferr.lua +++ b/lua/gopher/iferr.lua @@ -1,7 +1,12 @@ +---@toc_entry Iferr +---@tag gopher.nvim-iferr +---@text if you're using `iferr` tool, this module provides a way to automatically insert `if err != nil` check. +---@usage execute `:GoIfErr` near any err variable to insert the check + local c = require "gopher.config" local iferr = {} --- That's Lua of vimscript implementation of: github.com/koron/iferr +-- That's Lua implementation: github.com/koron/iferr function iferr.iferr() local boff = vim.fn.wordcount().cursor_bytes local pos = vim.fn.getcurpos()[2] diff --git a/lua/gopher/impl.lua b/lua/gopher/impl.lua index 155d6c2..f461376 100644 --- a/lua/gopher/impl.lua +++ b/lua/gopher/impl.lua @@ -1,3 +1,31 @@ +---@toc_entry Auto implementation of interface methods +---@tag gopher.nvim-impl +---@text impl is utilizing the `impl` tool to generate method stubs for interfaces. +---@usage +--- 1. put your coursor on the struct on which you want implement the interface +--- and run `:GoImpl io.Reader` +--- which will automatically choose the reciver for the methods and +--- implement the `io.Reader` interface +--- 2. same as previous but with custom receiver, so put your coursor on the struct +--- run `:GoImpl w io.Writer` +--- where `w` is the receiver and `io.Writer` is the interface +--- 3. specift receiver, struct, and interface +--- there's no need to put your coursor on the struct if you specify all arguments +--- `:GoImpl r RequestReader io.Reader` +--- where `r` is the receiver, `RequestReader` is the struct and `io.Reader` is the interface +--- +--- simple example: +--- >go +--- type BytesReader struct{} +--- // ^ put your cursor here +--- // run `:GoImpl b io.Reader` +--- +--- // this is what you will get +--- func (b *BytesReader) Read(p []byte) (n int, err error) { +--- panic("not implemented") // TODO: Implement +--- } +--- < + local c = require("gopher.config").commands local r = require "gopher._utils.runner" local ts_utils = require "gopher._utils.ts" @@ -5,6 +33,7 @@ local u = require "gopher._utils" local impl = {} ---@return string +---@private local function get_struct() local ns = ts_utils.get_struct_node_at_pos(unpack(vim.api.nvim_win_get_cursor(0))) if ns == nil then diff --git a/lua/gopher/init.lua b/lua/gopher/init.lua index fe86577..df0d174 100644 --- a/lua/gopher/init.lua +++ b/lua/gopher/init.lua @@ -1,10 +1,35 @@ +--- *gopher.nvim* +--- +--- ============================================================================== +--- +--- gopher.nvim is a minimalistic plugin for Go development in Neovim written in Lua. +--- It's not an LSP tool, the main goal of this plugin is add go tooling support in Neovim. + +--- Table of Contents +---@tag gopher.nvim-table-of-contents +---@toc + local tags = require "gopher.struct_tags" local tests = require "gopher.gotests" local gocmd = require("gopher._utils.runner.gocmd").run local gopher = {} +---@toc_entry Setup +---@tag gopher.nvim-setup +---@text Setup function. This method simply merges default configs with opts table. +--- You can read more about configuration at |gopher.nvim-config| +--- Calling this function is optional, if you ok with default settings. Look |gopher.nvim.config-defaults| +--- +---@usage `require("gopher").setup {}` (replace `{}` with your `config` table) gopher.setup = require("gopher.config").setup + +---@toc_entry Install dependencies +---@tag gopher.nvim-install-deps +---@text Gopher.nvim implements most of its features using third-party tools. +--- To install these tools, you can run `:GoInstallDeps` command +--- or call `require("gopher").install_deps()` if you want ues lua api. gopher.install_deps = require("gopher.installer").install_deps + gopher.impl = require("gopher.impl").impl gopher.iferr = require("gopher.iferr").iferr gopher.comment = require "gopher.comment" diff --git a/lua/gopher/struct_tags.lua b/lua/gopher/struct_tags.lua index afd4f87..4389b62 100644 --- a/lua/gopher/struct_tags.lua +++ b/lua/gopher/struct_tags.lua @@ -1,3 +1,29 @@ +---@toc_entry Modifty struct tags +---@tag gopher.nvim-struct-tags +---@text struct-tags is utilizing the `gomodifytags` tool to add or remove tags to struct fields. +---@usage - put your coursor on the struct +--- - run `:GoTagAdd json` to add json tags to struct fields +--- - run `:GoTagRm json` to remove json tags to struct fields +--- +--- note: if you dont spesify the tag it will use `json` as default +--- +--- simple example: +--- >go +--- // before +--- type User struct { +--- // ^ put your cursor here +--- // run `:GoTagAdd yaml` +--- ID int +--- Name string +--- } +--- +--- // after +--- type User struct { +--- ID int `yaml:id` +--- Name string `yaml:name` +--- } +--- < + local ts_utils = require "gopher._utils.ts" local r = require "gopher._utils.runner" local c = require "gopher.config" @@ -56,7 +82,7 @@ local function modify(...) or tagged["start"] == nil or tagged["start"] == 0 then - error("failed to set tags " .. vim.inspec(tagged)) + error("failed to set tags " .. vim.inspect(tagged)) end vim.api.nvim_buf_set_lines( @@ -69,8 +95,7 @@ local function modify(...) vim.cmd "write" end ----add tags to struct under cursor ----@param ... unknown +-- add tags to struct under cursor function struct_tags.add(...) local arg = { ... } if #arg == nil or arg == "" then @@ -85,8 +110,7 @@ function struct_tags.add(...) modify(unpack(cmd_args)) end ----remove tags to struct under cursor ----@param ... unknown +-- remove tags to struct under cursor function struct_tags.remove(...) local arg = { ... } if #arg == nil or arg == "" then diff --git a/scripts/docgen.lua b/scripts/docgen.lua new file mode 100644 index 0000000..f2deb8b --- /dev/null +++ b/scripts/docgen.lua @@ -0,0 +1,33 @@ +---@diagnostic disable: undefined-global +--# selene: allow(undefined_variable) + +local okay, minidoc = pcall(require, "mini.doc") +if not okay then + error "mini.doc not found, please install it. https://github.com/echasnovski/mini.doc" + return +end + +local files = { + "lua/gopher/init.lua", + "lua/gopher/config.lua", + "lua/gopher/struct_tags.lua", + "lua/gopher/impl.lua", + "lua/gopher/gotests.lua", + "lua/gopher/iferr.lua", + "lua/gopher/comment.lua", + "lua/gopher/dap.lua", +} + +minidoc.setup() + +local hooks = vim.deepcopy(minidoc.default_hooks) +hooks.write_pre = function(lines) + -- Remove first two lines with `======` and `------` delimiters to comply + -- with `:h local-additions` template + table.remove(lines, 1) + table.remove(lines, 1) + + return lines +end + +MiniDoc.generate(files, "doc/gopher.nvim.txt", { hooks = hooks }) diff --git a/spec/minimal_init.lua b/scripts/minimal_init.lua similarity index 93% rename from spec/minimal_init.lua rename to scripts/minimal_init.lua index 163efc5..49a606e 100644 --- a/spec/minimal_init.lua +++ b/scripts/minimal_init.lua @@ -26,6 +26,7 @@ vim.notify = print install_plug "nvim-lua/plenary.nvim" install_plug "nvim-treesitter/nvim-treesitter" +install_plug "echasnovski/mini.doc" -- used for docs generation vim.env.XDG_CONFIG_HOME = root ".tests/config" vim.env.XDG_DATA_HOME = root ".tests/data" From 65fa1486612ac4392f48e484ba0d6dbdac184256 Mon Sep 17 00:00:00 2001 From: Smirnov Oleksandr Date: Thu, 4 Apr 2024 17:31:43 +0300 Subject: [PATCH 22/24] refactor(health): keep in mind new way of health check (#63) --- .../_utils/{health.lua => health_util.lua} | 7 +++++++ lua/gopher/health.lua | 16 +++++++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) rename lua/gopher/_utils/{health.lua => health_util.lua} (75%) diff --git a/lua/gopher/_utils/health.lua b/lua/gopher/_utils/health_util.lua similarity index 75% rename from lua/gopher/_utils/health.lua rename to lua/gopher/_utils/health_util.lua index b651fe4..e1d44ee 100644 --- a/lua/gopher/_utils/health.lua +++ b/lua/gopher/_utils/health_util.lua @@ -23,4 +23,11 @@ function health.is_binary_found(bin) return false end +---@param ft string +---@return boolean +function health.is_treesitter_parser_available(ft) + local ok, parser = pcall(vim.treesitter.get_parser, 0, ft) + return ok and parser ~= nil +end + return health diff --git a/lua/gopher/health.lua b/lua/gopher/health.lua index a7a4d14..633a184 100644 --- a/lua/gopher/health.lua +++ b/lua/gopher/health.lua @@ -1,6 +1,6 @@ local health = {} local cmd = require("gopher.config").commands -local u = require "gopher._utils.health" +local u = require "gopher._utils.health_util" local deps = { plugin = { @@ -24,11 +24,12 @@ local deps = { }, { bin = cmd.dlv, msg = "required for debugging, (`nvim-dap`, `gopher.dap`)", optional = true }, }, + treesitter = { + { parser = "go", msg = "required for `gopher.nvim`", optional = false }, + }, } function health.check() - u.info "install go treesitter parser by `:TSInstall go` if you don't have it already" - u.start "required plugins" for _, plugin in ipairs(deps.plugin) do if u.is_lualib_found(plugin.lib) then @@ -55,6 +56,15 @@ function health.check() end end end + + u.start "required treesitter parsers" + for _, parser in ipairs(deps.treesitter) do + if u.is_treesitter_parser_available(parser.parser) then + u.ok(parser.parser .. " parser installed") + else + u.error(parser.parser .. " parser not found, " .. parser.msg) + end + end end return health From fbf6441f3d713b03fa3877a917f4a4dcef6d9362 Mon Sep 17 00:00:00 2001 From: Smirnov Oleksandr Date: Sat, 15 Jun 2024 12:18:26 +0300 Subject: [PATCH 23/24] feat: add logger (#64) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor(health): keep in mind new way of health check (#63) * feat(log): add logger module * refactor(utils): remove unused code * refactor(log, utils): get plugin name from config * refactor(logger): add some type annotations * refactor(utils): log notifications * feat: LOGGERâ„¢ * feat(config): TYPES * refactor(log): dont give a thing about var that is not even declared * feat(log): add easy way to open log * refactor(log): some types * update types * docs: regen * fix(log): make setting log level by config work * feat(iferr): write error to log file if occur * feat(gotests): add logger --- doc/gopher.nvim.txt | 14 +-- lua/gopher/_utils/init.lua | 19 ++--- lua/gopher/_utils/log.lua | 170 +++++++++++++++++++++++++++++++++++++ lua/gopher/comment.lua | 4 + lua/gopher/config.lua | 13 +++ lua/gopher/gotests.lua | 3 + lua/gopher/iferr.lua | 2 + lua/gopher/init.lua | 8 +- plugin/gopher.vim | 1 + spec/units/utils_spec.lua | 10 --- 10 files changed, 213 insertions(+), 31 deletions(-) create mode 100644 lua/gopher/_utils/log.lua diff --git a/doc/gopher.nvim.txt b/doc/gopher.nvim.txt index 7118e3c..d4a82d0 100644 --- a/doc/gopher.nvim.txt +++ b/doc/gopher.nvim.txt @@ -20,13 +20,15 @@ Table of Contents ------------------------------------------------------------------------------ *gopher.nvim-setup* - `gopher.setup` + `gopher.setup`({user_config}) Setup function. This method simply merges default configs with opts table. You can read more about configuration at |gopher.nvim-config| Calling this function is optional, if you ok with default settings. Look |gopher.nvim.config-defaults| Usage ~ `require("gopher").setup {}` (replace `{}` with your `config` table) +Parameters ~ +{user_config} gopher.Config ------------------------------------------------------------------------------ *gopher.nvim-install-deps* @@ -50,6 +52,10 @@ You can look at default options |gopher.nvim-config-defaults| local default_config = { --minidoc_replace_end + -- log level, you might consider using DEBUG or TRACE for degugging the plugin + ---@type number + log_level = vim.log.levels.INFO, + -- user specified paths to binaries ---@class gopher.ConfigCommand commands = { @@ -81,12 +87,6 @@ You can look at default options |gopher.nvim-config-defaults| Class ~ {gopher.Config} ------------------------------------------------------------------------------- - *config.setup()* - `config.setup`({user_config}) -Parameters ~ -{user_config} `(optional)` gopher.Config - ============================================================================== ------------------------------------------------------------------------------ diff --git a/lua/gopher/_utils/init.lua b/lua/gopher/_utils/init.lua index 136717d..a3b567c 100644 --- a/lua/gopher/_utils/init.lua +++ b/lua/gopher/_utils/init.lua @@ -1,23 +1,15 @@ +local c = require "gopher.config" +local log = require "gopher._utils.log" local utils = {} -local TITLE = "gopher.nvim" - ----@param t table ----@return boolean -function utils.is_tbl_empty(t) - if t == nil then - return true - end - return next(t) == nil -end - ---@param msg string ---@param lvl number function utils.deferred_notify(msg, lvl) vim.defer_fn(function() vim.notify(msg, lvl, { - title = TITLE, + title = c.___plugin_name, }) + log.debug(msg) end, 0) end @@ -26,8 +18,9 @@ end function utils.notify(msg, lvl) lvl = lvl or vim.log.levels.INFO vim.notify(msg, lvl, { - title = TITLE, + title = c.___plugin_name, }) + log.debug(msg) end -- safe require diff --git a/lua/gopher/_utils/log.lua b/lua/gopher/_utils/log.lua new file mode 100644 index 0000000..c7dccd7 --- /dev/null +++ b/lua/gopher/_utils/log.lua @@ -0,0 +1,170 @@ +-- thanks https://github.com/tjdevries/vlog.nvim +-- and https://github.com/williamboman/mason.nvim +-- for the code i have stolen(or have inspected by idk) +local c = require "gopher.config" + +---@class Gopher.Logger +---@field get_outfile fun():string +---@field trace fun(...) +---@field fmt_trace fun(...) +---@field debug fun(...) +---@field fmt_debug fun(...) +---@field info fun(...) +---@field fmt_info fun(...) +---@field warn fun(...) +---@field fmt_warn fun(...) +---@field error fun(...) +---@field fmt_error fun(...) + +local config = { + -- Name of the plugin. Prepended to log messages + name = c.___plugin_name, + + -- Should print the output to neovim while running + -- values: 'sync','async',false + use_console = vim.env.GOPHER_VERBOSE_LOGS == "1", + + -- Should highlighting be used in console (using echohl) + highlights = true, + + -- Should write to a file + use_file = true, + + -- Level configuration + modes = { + { name = "trace", hl = "Comment", level = vim.log.levels.TRACE }, + { name = "debug", hl = "Comment", level = vim.log.levels.DEBUG }, + { name = "info", hl = "None", level = vim.log.levels.INFO }, + { name = "warn", hl = "WarningMsg", level = vim.log.levels.WARN }, + { name = "error", hl = "ErrorMsg", level = vim.log.levels.ERROR }, + }, + + -- Can limit the number of decimals displayed for floats + float_precision = 0.01, +} + +---@type Gopher.Logger +---@diagnostic disable-next-line: missing-fields +local log = {} + +---@return string +function log.get_outfile() + return table.concat { + (vim.fn.has "nvim-0.8.0" == 1) and vim.fn.stdpath "log" or vim.fn.stdpath "cache", + ("/%s.log"):format(config.name), + } +end + +-- selene: allow(incorrect_standard_library_use) +local unpack = unpack or table.unpack + +do + local round = function(x, increment) + increment = increment or 1 + x = x / increment + return (x > 0 and math.floor(x + 0.5) or math.ceil(x - 0.5)) * increment + end + + local tbl_has_tostring = function(tbl) + local mt = getmetatable(tbl) + return mt and mt.__tostring ~= nil + end + + local make_string = function(...) + local t = {} + for i = 1, select("#", ...) do + local x = select(i, ...) + + if type(x) == "number" and config.float_precision then + x = tostring(round(x, config.float_precision)) + elseif type(x) == "table" and not tbl_has_tostring(x) then + x = vim.inspect(x) + else + x = tostring(x) + end + + t[#t + 1] = x + end + return table.concat(t, " ") + end + + local log_at_level = function(level_config, message_maker, ...) + -- Return early if we're below the current_log_level + -- + -- the log level source get from config directly because otherwise it doesnt work + if level_config.level < c.log_level then + return + end + local nameupper = level_config.name:upper() + + local msg = message_maker(...) + local info = debug.getinfo(2, "Sl") + local lineinfo = info.short_src .. ":" .. info.currentline + + -- Output to console + if config.use_console then + local log_to_console = function() + local console_string = + string.format("[%-6s%s] %s: %s", nameupper, os.date "%H:%M:%S", lineinfo, msg) + + if config.highlights and level_config.hl then + vim.cmd(string.format("echohl %s", level_config.hl)) + end + + local split_console = vim.split(console_string, "\n") + for _, v in ipairs(split_console) do + local formatted_msg = string.format("[%s] %s", config.name, vim.fn.escape(v, [["\]])) + + ---@diagnostic disable-next-line: param-type-mismatch + local ok = pcall(vim.cmd, string.format([[echom "%s"]], formatted_msg)) + if not ok then + vim.api.nvim_out_write(msg .. "\n") + end + end + + if config.highlights and level_config.hl then + vim.cmd "echohl NONE" + end + end + if config.use_console == "sync" and not vim.in_fast_event() then + log_to_console() + else + vim.schedule(log_to_console) + end + end + + -- Output to log file + if config.use_file then + local fp = assert(io.open(log.get_outfile(), "a")) + local str = string.format("[%-6s%s] %s: %s\n", nameupper, os.date(), lineinfo, msg) + fp:write(str) + fp:close() + end + end + + for _, x in ipairs(config.modes) do + -- log.info("these", "are", "separated") + log[x.name] = function(...) ---@diagnostic disable-line: assign-type-mismatch + return log_at_level(x, make_string, ...) + end + + -- log.fmt_info("These are %s strings", "formatted") + log[("fmt_%s"):format(x.name)] = function(...) ---@diagnostic disable-line: assign-type-mismatch + return log_at_level(x, function(...) + local passed = { ... } + local fmt = table.remove(passed, 1) + local inspected = {} + for _, v in ipairs(passed) do + if type(v) == "table" and tbl_has_tostring(v) then + table.insert(inspected, v) + else + table.insert(inspected, vim.inspect(v)) + end + end + return string.format(fmt, unpack(inspected)) + end, ...) + end + end +end + +return log diff --git a/lua/gopher/comment.lua b/lua/gopher/comment.lua index 002894c..8754405 100644 --- a/lua/gopher/comment.lua +++ b/lua/gopher/comment.lua @@ -3,6 +3,8 @@ ---@usage Execute `:GoCmt` to generate a comment for the current function/method/struct/etc on this line. ---@text This module provides a way to generate comments for Go code. +local log = require "gopher._utils.log" + local function generate(row, col) local ts_utils = require "gopher._utils.ts" local comment, ns = nil, nil @@ -38,6 +40,8 @@ return function() local row, col = unpack(vim.api.nvim_win_get_cursor(0)) local comment, ns = generate(row + 1, col + 1) + log.debug("generated comment: " .. comment) + vim.api.nvim_win_set_cursor(0, { ns.dim.s.r, ns.dim.s.c, diff --git a/lua/gopher/config.lua b/lua/gopher/config.lua index c0a0dcc..9c20843 100644 --- a/lua/gopher/config.lua +++ b/lua/gopher/config.lua @@ -29,6 +29,10 @@ local config = {} local default_config = { --minidoc_replace_end + -- log level, you might consider using DEBUG or TRACE for degugging the plugin + ---@type number + log_level = vim.log.levels.INFO, + -- user specified paths to binaries ---@class gopher.ConfigCommand commands = { @@ -62,7 +66,16 @@ local default_config = { ---@private local _config = default_config +-- I am kinda secret so don't tell anyone about me +-- even dont use me +-- +-- if you don't belive me that i am secret see +-- the line below it says @private +---@private +_config.___plugin_name = "gopher.nvim" ---@diagnostic disable-line: inject-field + ---@param user_config? gopher.Config +---@private function config.setup(user_config) _config = vim.tbl_deep_extend("force", default_config, user_config or {}) end diff --git a/lua/gopher/gotests.lua b/lua/gopher/gotests.lua index 3d96a05..da4753d 100644 --- a/lua/gopher/gotests.lua +++ b/lua/gopher/gotests.lua @@ -43,6 +43,7 @@ local c = require "gopher.config" local ts_utils = require "gopher._utils.ts" local r = require "gopher._utils.runner" local u = require "gopher._utils" +local log = require "gopher._utils.log" local gotests = {} ---@param args table @@ -65,6 +66,8 @@ local function add_test(args) table.insert(args, "-w") table.insert(args, vim.fn.expand "%") + log.debug("generating tests with args: ", args) + return r.sync(c.commands.gotests, { args = args, on_exit = function(data, status) diff --git a/lua/gopher/iferr.lua b/lua/gopher/iferr.lua index 56e9644..a1cdf9f 100644 --- a/lua/gopher/iferr.lua +++ b/lua/gopher/iferr.lua @@ -4,6 +4,7 @@ ---@usage execute `:GoIfErr` near any err variable to insert the check local c = require "gopher.config" +local log = require "gopher._utils.log" local iferr = {} -- That's Lua implementation: github.com/koron/iferr @@ -14,6 +15,7 @@ function iferr.iferr() local data = vim.fn.systemlist((c.commands.iferr .. " -pos " .. boff), vim.fn.bufnr "%") if vim.v.shell_error ~= 0 then error("iferr failed: " .. data) + log.error("failed. output: " .. data) end vim.fn.append(pos, data) diff --git a/lua/gopher/init.lua b/lua/gopher/init.lua index df0d174..2aa138e 100644 --- a/lua/gopher/init.lua +++ b/lua/gopher/init.lua @@ -9,6 +9,7 @@ ---@tag gopher.nvim-table-of-contents ---@toc +local log = require "gopher._utils.log" local tags = require "gopher.struct_tags" local tests = require "gopher.gotests" local gocmd = require("gopher._utils.runner.gocmd").run @@ -21,7 +22,12 @@ local gopher = {} --- Calling this function is optional, if you ok with default settings. Look |gopher.nvim.config-defaults| --- ---@usage `require("gopher").setup {}` (replace `{}` with your `config` table) -gopher.setup = require("gopher.config").setup +---@param user_config gopher.Config +gopher.setup = function(user_config) + log.debug "setting up config" + require("gopher.config").setup(user_config) + log.debug(vim.inspect(user_config)) +end ---@toc_entry Install dependencies ---@tag gopher.nvim-install-deps diff --git a/plugin/gopher.vim b/plugin/gopher.vim index 997ec94..a219a1c 100644 --- a/plugin/gopher.vim +++ b/plugin/gopher.vim @@ -11,3 +11,4 @@ command! -nargs=* GoGenerate :lua require"gopher".generate() command! GoCmt :lua require"gopher".comment() command! GoIfErr :lua require"gopher".iferr() command! GoInstallDeps :lua require"gopher".install_deps() +command! GopherLog :lua vim.cmd("tabnew " .. require("gopher._utils.log").get_outfile()) diff --git a/spec/units/utils_spec.lua b/spec/units/utils_spec.lua index dcf94f2..ea2f30c 100644 --- a/spec/units/utils_spec.lua +++ b/spec/units/utils_spec.lua @@ -1,16 +1,6 @@ describe("gopher._utils", function() local u = require "gopher._utils" - describe(".is_tbl_empty()", function() - it("it is empty", function() - assert.are.same(true, u.is_tbl_empty {}) - end) - - it("it is not empty", function() - assert.are.same(false, u.is_tbl_empty { first = "1", second = 2 }) - end) - end) - describe(".sreq()", function() it("can require existing module", function() assert.are.same(require "gopher", u.sreq "gopher") From af1d5d166f72f42ba5a7c8c37dc500aebc79520f Mon Sep 17 00:00:00 2001 From: Smirnov Oleksandr Date: Sat, 15 Jun 2024 12:37:15 +0300 Subject: [PATCH 24/24] add deprecation message (#67) --- README.md | 2 ++ lua/gopher/dap.lua | 11 +++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f105a58..d256e5f 100644 --- a/README.md +++ b/README.md @@ -220,6 +220,8 @@ require("gopher").setup { Setup nvim-dap for go in one line + THIS FEATURE WILL BE REMOVED IN `0.1.6` + note [nvim-dap](https://github.com/mfussenegger/nvim-dap) has to be installed ```lua diff --git a/lua/gopher/dap.lua b/lua/gopher/dap.lua index 6ff326a..9930318 100644 --- a/lua/gopher/dap.lua +++ b/lua/gopher/dap.lua @@ -3,7 +3,6 @@ ---@text This module sets up `nvim-dap` for Go. ---@usage just call `require("gopher.dap").setup()`, and you're good to go. -local u = require "gopher._utils" local c = require "gopher.config" local dap = {} @@ -113,7 +112,15 @@ dap.configuration = { -- sets ups nvim-dap for Go in one function call. function dap.setup() - local d = u.sreq "dap" + vim.deprecate( + "gopher.dap", + "you might consider setting up `nvim-dap` manually, or using another plugin(https://github.com/leoluz/nvim-dap-go)", + "v0.1.6", + "gopher" + ) + + local ok, d = pcall(require, "dap") + assert(ok, "gopher.nvim dependency error: dap not installed") d.adapters.go = dap.adapter d.configurations.go = dap.configuration