diff --git a/doc/python.txt b/doc/python.txt index 15c4545..b3f46c1 100644 --- a/doc/python.txt +++ b/doc/python.txt @@ -295,8 +295,8 @@ Parameters ~ Class ~ {PythonStateVEnv} Fields ~ -{python_interpreter} `(string | nil)` -{venv_path} `(string | nil)` +{python_interpreter} `(string)` +{venv_path} `(string)` {install_method} `(string)` {install_file} `(string)` {source} `(string)` @@ -320,14 +320,14 @@ Fields ~ {dap} `(table)` ------------------------------------------------------------------------------ - *PythonState.State()* - `PythonState.State`() + *PythonStateM.State()* + `PythonStateM.State`() Return ~ `(PythonState)` ------------------------------------------------------------------------------ - *PythonState.save()* - `PythonState.save`({new_state}) + *PythonStateM.save()* + `PythonStateM.save`({new_state}) Parameters ~ {new_state} `(PythonState)` diff --git a/doc/tags b/doc/tags index 1c8c77a..199f643 100644 --- a/doc/tags +++ b/doc/tags @@ -8,9 +8,9 @@ PythonConfig.setup() python.txt /*PythonConfig.setup()* PythonDap.prepare_debugpy() python.txt /*PythonDap.prepare_debugpy()* PythonLSPCommands.pyright_change_type_checking() python.txt /*PythonLSPCommands.pyright_change_type_checking()* PythonState python.txt /*PythonState* -PythonState.State() python.txt /*PythonState.State()* -PythonState.save() python.txt /*PythonState.save()* PythonStateDap python.txt /*PythonStateDap* +PythonStateM.State() python.txt /*PythonStateM.State()* +PythonStateM.save() python.txt /*PythonStateM.save()* PythonStateVEnv python.txt /*PythonStateVEnv* PythonTreeSitterCommands.ts_wrap_at_cursor() python.txt /*PythonTreeSitterCommands.ts_wrap_at_cursor()* PythonUI.activate_system_call_ui() python.txt /*PythonUI.activate_system_call_ui()* diff --git a/lua/python/commands.lua b/lua/python/commands.lua index 66700b8..63aa580 100644 --- a/lua/python/commands.lua +++ b/lua/python/commands.lua @@ -199,7 +199,12 @@ local subcommand_tbl = { end if command == "wrap_cursor" then - ts_cmd.ts_wrap_at_cursor(args[#args]) + -- Account for if the last argument is the command or an actual arg + local wrap_arg = args[#args] + if wrap_arg == "wrap_cursor" then + wrap_arg = "" + end + ts_cmd.ts_wrap_at_cursor(wrap_arg) return end end, @@ -289,7 +294,7 @@ function PythonCommands.load_commands() -- NOTE: the options will vary, based on your use case. vim.api.nvim_create_user_command("Python", python_cmd, { nargs = "+", - desc = "My awesome command with subcommand completions", + desc = "Python.nvim commands", complete = function(arg_lead, cmdline, _) -- Get the subcommand. local subcmd_key, subcmd_arg_lead = cmdline:match("^['<,'>]*Python[!]*%s(%S+)%s(.*)$") @@ -310,6 +315,7 @@ function PythonCommands.load_commands() end end, bang = true, -- If you want to support ! modifiers + range = true, -- Support some visual command }) end diff --git a/scripts/minimal_init.lua b/scripts/minimal_init.lua index 7045eeb..9f7de55 100644 --- a/scripts/minimal_init.lua +++ b/scripts/minimal_init.lua @@ -1,28 +1,67 @@ -- Add current directory to 'runtimepath' to be able to use 'lua' files vim.cmd([[let &rtp.=','.getcwd()]]) --- Set up 'mini.test' only when calling headless Neovim (like with `make test`) -if #vim.api.nvim_list_uis() == 0 then - -- Add 'mini.nvim' to 'runtimepath' to be able to use 'mini.test' - -- Assumed that 'mini.nvim' is stored in 'deps/mini.nvim' - -- - local runtime_dependencies = { - "deps/mini.nvim", - "deps/nvim-treesitter", - "deps/neotest", - "deps/neotest-python", - "deps/nvim-dap", - "deps/nvim-dap-python", - "deps/nvim-lspconfig", - "deps/LuaSnip", - } - local runtime_path = vim.fn.join(runtime_dependencies, ",") - vim.cmd("set rtp+=" .. runtime_path) +local runtime_dependencies = { + "deps/mini.nvim", + "deps/nvim-treesitter", + "deps/neotest", + "deps/neotest-python", + "deps/nvim-dap", + "deps/nvim-dap-python", + "deps/nvim-lspconfig", + "deps/LuaSnip", +} +local runtime_path = vim.fn.join(runtime_dependencies, ",") +vim.cmd("set rtp+=" .. runtime_path) - -- Set up 'mini.test' - require("luasnip.extras.fmt") - require("luasnip.nodes.absolute_indexer") - require("nvim-treesitter.locals") - require("mini.test").setup() - require("mini.doc").setup() +-- Set up 'mini.test' +require("luasnip.extras.fmt") +require("luasnip.nodes.absolute_indexer") +require("nvim-treesitter.locals") +require("nvim-treesitter").setup() +require("mini.test").setup() +require("mini.doc").setup() +local ts_configs = require("nvim-treesitter.configs").setup({ + modules = { + "highlight", + }, + sync_install = false, + auto_install = true, + ignore_install = {}, + ensure_installed = {}, + highlight = { + enable = true, + }, +}) + +-- Clean path for use in a prefix comparison +---@param input string +---@return string +local function clean_path(input) + local pth = vim.fn.fnamemodify(input, ":p") + if vim.fn.has("win32") == 1 then + pth = pth:gsub("/", "\\") + end + return pth +end + +local function ts_is_installed(lang) + local matched_parsers = vim.api.nvim_get_runtime_file("parser/" .. lang .. ".so", true) or {} + local configs = require("nvim-treesitter.configs") + local install_dir = configs.get_parser_install_dir() + if not install_dir then + return false + end + install_dir = clean_path(install_dir) + for _, path in ipairs(matched_parsers) do + local abspath = clean_path(path) + if vim.startswith(abspath, install_dir) then + return true + end + end + return false +end + +if not ts_is_installed("python") then + vim.cmd("TSInstallSync python") end diff --git a/tests/test_text_actions.lua b/tests/test_text_actions.lua new file mode 100644 index 0000000..ae125ad --- /dev/null +++ b/tests/test_text_actions.lua @@ -0,0 +1,43 @@ +-- Define helper aliases +local new_set = MiniTest.new_set +local expect, eq = MiniTest.expect, MiniTest.expect.equality + +-- Create (but not start) child Neovim object +local child = MiniTest.new_child_neovim() + +-- Define main test set of this file +local T = new_set({ + -- Register hooks + hooks = { + -- This will be executed before every (even nested) case + pre_case = function() + -- Restart child process with custom 'init.lua' script + child.restart({ "-u", "scripts/minimal_init.lua" }) + -- Load tested plugin + child.lua([[require('python').setup()]]) + end, + -- This will be executed one after all tests from this set are finished + post_once = child.stop, + }, +}) + +local get_lines = function() + return child.api.nvim_buf_get_lines(0, 0, -1, true) +end + +T["text_actions"] = MiniTest.new_set({ + hooks = { + pre_case = function() + child.cmd("e _not_existing_new_buffer.py") + end, + }, +}) + +T["text_actions"]["insert_f_string"] = function() + child.type_keys("i", [[print("{foo}")]], "") + + eq(get_lines(), { [[print(f"{foo}")]] }) +end + +-- Return test set which will be collected and execute inside `MiniTest.run()` +return T diff --git a/tests/test_treesitter.lua b/tests/test_treesitter.lua new file mode 100644 index 0000000..bc456f9 --- /dev/null +++ b/tests/test_treesitter.lua @@ -0,0 +1,67 @@ +-- Define helper aliases +local new_set = MiniTest.new_set +local expect, eq = MiniTest.expect, MiniTest.expect.equality + +-- Create (but not start) child Neovim object +local child = MiniTest.new_child_neovim() + +-- Define main test set of this file +local T = new_set({ + -- Register hooks + hooks = { + -- This will be executed before every (even nested) case + pre_case = function() + -- Restart child process with custom 'init.lua' script + child.restart({ "-u", "scripts/minimal_init.lua" }) + -- Load tested plugin + child.lua([[require('python').setup()]]) + end, + -- This will be executed one after all tests from this set are finished + post_once = child.stop, + }, +}) + +local get_lines = function() + return child.api.nvim_buf_get_lines(0, 0, -1, true) +end + +T["wrap_cursor"] = MiniTest.new_set({ + hooks = { + pre_case = function() + child.cmd("e _not_existing_new_buffer.py") + child.type_keys("cc", [["TEST"]], "", "0") + end, + }, +}) + +T["wrap_cursor"]["normal"] = function() + child.cmd("Python treesitter wrap_cursor test(%s)") + eq(get_lines(), { [[test("TEST")]] }) +end + +T["wrap_cursor"]["visual"] = function() + child.type_keys("l", "v", "$") + child.type_keys([[:Python treesitter wrap_cursor test(%s)]]) + eq(get_lines(), { [["test(TEST")]] }) +end + +T["wrap_cursor"]["visual_with_selection"] = function() + child.type_keys("l", "v", "$") + child.type_keys([[:Python treesitter wrap_cursor1]]) + eq(get_lines(), { [["print(TEST")]] }) +end + +T["wrap_cursor"]["with_selection"] = function() + child.type_keys([[:Python treesitter wrap_cursor1]]) + eq(get_lines(), { [[print("TEST")]] }) +end + +T["enumerate"] = function() + child.cmd("e _not_existing_new_buffer.py") + child.type_keys("cc", "for i in [1, 2, 3]:", "", "0") + child.type_keys([[:Python treesitter toggle_enumerate]]) + eq(get_lines(), { "for idx, i in enumerate([1, 2, 3]):" }) +end + +-- Return test set which will be collected and execute inside `MiniTest.run()` +return T