aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/lua/vim/_extregs.lua4
-rw-r--r--src/nvim/cmdexpand.c14
-rw-r--r--src/nvim/cmdexpand_defs.h1
-rw-r--r--src/nvim/extreg.c33
-rw-r--r--src/nvim/extreg.h1
-rw-r--r--src/nvim/lua/executor.c4
-rw-r--r--test/functional/editor/extreg_spec.lua89
7 files changed, 145 insertions, 1 deletions
diff --git a/runtime/lua/vim/_extregs.lua b/runtime/lua/vim/_extregs.lua
index c03e8fda23..be4f3e30af 100644
--- a/runtime/lua/vim/_extregs.lua
+++ b/runtime/lua/vim/_extregs.lua
@@ -3,6 +3,10 @@
local M = {}
+function M.complete()
+ return vim._C._extregs.get_provider_names()
+end
+
--- Register a new extregister provider
---@param name string Provider name
---@param text_yanked_cb? fun(content:table) Callback for yank operations
diff --git a/src/nvim/cmdexpand.c b/src/nvim/cmdexpand.c
index 040a18f889..50f795c590 100644
--- a/src/nvim/cmdexpand.c
+++ b/src/nvim/cmdexpand.c
@@ -1508,6 +1508,14 @@ void set_expand_context(expand_T *xp)
return;
}
+ if (ccline->cmdfirstc == '~') {
+ xp->xp_context = EXPAND_EXTREGS;
+ xp->xp_pattern = ccline->cmdbuff;
+ xp->xp_line = ccline->cmdbuff;
+ xp->xp_col = ccline->cmdpos;
+ return;
+ }
+
// Only handle ':', '>', or '=' command-lines, or expression input
if (ccline->cmdfirstc != ':'
&& ccline->cmdfirstc != '>' && ccline->cmdfirstc != '='
@@ -2970,6 +2978,11 @@ static char *get_arg1_from_lua(char *lua, expand_T *xp, int idx)
return NULL;
}
+static char* get_extreg_arg(expand_T *xp, int idx) {
+ char* ret = get_arg1_from_lua("return vim._extregs.get_provider_names(...)", xp, idx);
+ return ret;
+}
+
/// Completion for the |:marks| command. Given to ExpandGeneric().
/// @param[in] xp Expandy thing 🤷
/// @param[in] idx Index of the item.
@@ -3057,6 +3070,7 @@ static int ExpandOther(char *pat, expand_T *xp, regmatch_T *rmp, char ***matches
{ EXPAND_LSP, get_lsp_arg, true, false },
{ EXPAND_PACKDEL, get_packdel_arg, true, false },
{ EXPAND_PACKUPDATE, get_packupdate_arg, true, false },
+ { EXPAND_EXTREGS, get_extreg_arg, true, false },
};
int ret = FAIL;
diff --git a/src/nvim/cmdexpand_defs.h b/src/nvim/cmdexpand_defs.h
index 9fee7fd06f..5afc2f77e2 100644
--- a/src/nvim/cmdexpand_defs.h
+++ b/src/nvim/cmdexpand_defs.h
@@ -134,6 +134,7 @@ enum {
EXPAND_PACKDEL,
EXPAND_PACKUPDATE,
EXPAND_MARKS,
+ EXPAND_EXTREGS,
};
/// Type used by ExpandGeneric()
diff --git a/src/nvim/extreg.c b/src/nvim/extreg.c
index b416ac8111..455a8e24e5 100644
--- a/src/nvim/extreg.c
+++ b/src/nvim/extreg.c
@@ -855,3 +855,36 @@ int nlua_extregs_get_provider(lua_State *lstate)
lua_pushlightuserdata(lstate, (void *)prov);
return 1;
}
+
+/// Lua: vim._extregs.get_provider_names()
+/// Returns a table of all registered extreg provider names
+int nlua_extregs_get_provider_names(lua_State *lstate)
+{
+ hash_lock(&extreg_providers);
+
+ // First, count the registered providers
+ size_t count = 0;
+ HASHTAB_ITER(&extreg_providers, hi, {
+ extreg_provider_t *prov = HASH_ITEM_TO_EXTREG_PROVIDER(hi);
+ if (prov->registered) {
+ count++;
+ }
+ });
+
+ // Create table with pre-allocated size
+ lua_createtable(lstate, (int)count, 0);
+
+ // Now fill the table
+ size_t idx = 1;
+ HASHTAB_ITER(&extreg_providers, hi, {
+ extreg_provider_t *prov = HASH_ITEM_TO_EXTREG_PROVIDER(hi);
+ if (prov->registered && idx <= count) {
+ lua_pushstring(lstate, prov->name);
+ lua_rawseti(lstate, -2, (int)idx++);
+ }
+ });
+
+ hash_unlock(&extreg_providers);
+
+ return 1; // return the table
+}
diff --git a/src/nvim/extreg.h b/src/nvim/extreg.h
index 5dc8fec367..4137d17e8b 100644
--- a/src/nvim/extreg.h
+++ b/src/nvim/extreg.h
@@ -70,3 +70,4 @@ extern int nlua_extregs_unbind(lua_State *lstate);
extern int nlua_extregs_is_alias(lua_State *lstate);
extern int nlua_extregs_get_provider_name_for_alias(lua_State *lstate);
extern int nlua_extregs_get_provider(lua_State *lstate);
+extern int nlua_extregs_get_provider_names(lua_State *lstate);
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index aa159ef94d..204c5d53a8 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -760,7 +760,7 @@ static void nlua_common_vim_init(lua_State *lstate, bool is_thread)
lua_setfield(lstate, -2, "_empty_dict_mt");
// vim._extregs
- lua_createtable(lstate, 0, 8);
+ lua_createtable(lstate, 0, 9);
lua_pushcfunction(lstate, &nlua_extregs_register);
lua_setfield(lstate, -2, "register");
lua_pushcfunction(lstate, &nlua_extregs_unregister);
@@ -775,6 +775,8 @@ static void nlua_common_vim_init(lua_State *lstate, bool is_thread)
lua_setfield(lstate, -2, "get_provider_name_for_alias");
lua_pushcfunction(lstate, &nlua_extregs_get_provider);
lua_setfield(lstate, -2, "get_provider");
+ lua_pushcfunction(lstate, &nlua_extregs_get_provider_names);
+ lua_setfield(lstate, -2, "get_provider_names");
lua_setfield(lstate, -2, "_extregs");
// vim.uv
diff --git a/test/functional/editor/extreg_spec.lua b/test/functional/editor/extreg_spec.lua
index 44f2b618f8..b9637288f9 100644
--- a/test/functional/editor/extreg_spec.lua
+++ b/test/functional/editor/extreg_spec.lua
@@ -889,4 +889,93 @@ describe('extregs', function()
feed(':%yank ~empty.reg<CR>')
eq('5 lines yanked into "~empty.reg', exec_lua([[ return vim.v.statusmsg ]]))
end)
+
+ it('get_provider_names returns registered provider names', function()
+ exec_lua([[
+ vim._extregs.register('alpha',
+ function(_)
+ return true
+ end,
+ function()
+ return { lines = {'alpha'}, size = 1, type = 'v' }
+ end
+ )
+ vim._extregs.register('beta',
+ function(_)
+ return true
+ end,
+ function()
+ return { lines = {'beta'}, size = 1, type = 'v' }
+ end
+ )
+ vim._extregs.register('gamma',
+ function(_)
+ return true
+ end,
+ function()
+ return { lines = {'gamma'}, size = 1, type = 'v' }
+ end
+ )
+ ]])
+
+ local names = exec_lua([[ return vim._extregs.get_provider_names() ]])
+
+ eq('table', type(names))
+ -- 'test' provider exists from before_each, so we expect 6 providers total
+ eq(6, #names)
+
+ -- Check that all expected providers are present
+ local provider_map = {}
+ for i, name in ipairs(names) do
+ provider_map[name] = true
+ end
+ eq(true, provider_map.test) -- from before_each
+ eq(true, provider_map['let.test']) -- from before_each
+ eq(true, provider_map.alpha)
+ eq(true, provider_map.beta)
+ eq(true, provider_map.gamma)
+
+ -- Cleanup
+ exec_lua([[
+ vim._extregs.unregister('alpha')
+ vim._extregs.unregister('beta')
+ vim._extregs.unregister('gamma')
+ ]])
+ end)
+
+ it('get_provider_names handles empty and unregistered providers', function()
+ -- Unregister providers from before_each
+ exec_lua([[
+ vim._extregs.unregister('test')
+ vim._extregs.unregister('let.test')
+ vim._extregs.unregister('macro.replay')
+ ]])
+
+ -- Test with no providers
+ local names = exec_lua([[ return vim._extregs.get_provider_names() ]])
+ eq('table', type(names))
+ eq(0, #names)
+
+ -- Register one provider but then unregister it
+ exec_lua([[
+ vim._extregs.register('temp',
+ function(_)
+ return true
+ end,
+ function()
+ return { lines = {'temp'}, size = 1, type = 'v' }
+ end
+ )
+ ]])
+
+ names = exec_lua([[ return vim._extregs.get_provider_names() ]])
+ eq(1, #names)
+ eq('temp', names[1])
+
+ -- Unregister the provider
+ exec_lua([[ vim._extregs.unregister('temp') ]])
+
+ names = exec_lua([[ return vim._extregs.get_provider_names() ]])
+ eq(0, #names)
+ end)
end)