Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

What's the best way to expose the mode keymaps table to my consumers? #35

Closed
mawkler opened this issue Mar 22, 2024 · 4 comments
Closed
Assignees
Labels
question Further information is requested

Comments

@mawkler
Copy link

mawkler commented Mar 22, 2024

Hi again! I'm trying to expose the keymaps table to the consumers of my plugin. Here's a simplified example:

local options = {
local libmodal = require('libmodal')

local M = {}

local options = {
  mode_keymaps = {
    n = function() vim.notify('foo') end,
    u = vim.cmd.undo, -- THIS DOESN'T CURRENTLY WORK
  }
}

vim.keymap.set('n', 'M', function()
  require('libmodal').mode.enter('Mode 1', mode_keymaps)
end)

function M.setup(opts)
  options = vim.tbl_deep_extend('force', options, opts or {})
end

The problem is the line u = vim.cmd.undo. Since libmodal passes the current mode as an agrument, that argument gets passed to vim.cmd.undo, causing the following error:

...ocal/share/nvim/lazy/nvim-libmodal/lua/libmodal/Mode.lua:125: invalid key: input

I could solve this by requiring my users to wrap each callback in a function like this:

u = function() vim.cmd.undo() end

But it feels like an ugly solution. I would prefer if I could abstract away libmodal. So I tried creating a function that iterates over all the mappings and wraps them with a function:

local function clean_mappings(mappings)
  local new_mappings = {}
  for keymap, fn in pairs(mappings) do
    new_mappings[keymap] = function() fn() end
  end

  return new_mappings
end

This solves the agove problem. However, I also want to use a mapping to switch mode with libmodal.mode.switch. That means that the Mode type argument passed to switches returned function gets lost.

Do you have any suggestions as to how I could solve this? Or is there any way for libmodal to determine whether it should or shouldn't pass an argument to the callback when calling it?

@Iron-E
Copy link
Owner

Iron-E commented Mar 22, 2024

You might be able to use something like this:

--- Checks if `fn` is a callback, or a "mode callback" (meaning it uses `self`)
--- @param fn function
--- @return boolean
local function is_mode_callback(fn)
	local info = debug.getinfo(fn, 'Su')
	return
		info.nparams == 1 -- takes one parameter
		and info.what == 'Lua' -- is a lua function
		and not info.source:find '^@vim' -- is not a builtin
end

Unfortunately, this kind of thing seems prevalent when it comes to callbacks. For example:

-- Template from `:h nvim_create_autocmd`
vim.api.nvim_create_autocmd({"BufEnter", "BufWinEnter"}, {
  pattern = {"*.c", "*.h"},
  callback = vim.cmd.undo, -- ← this also doesn't work
})

I could provide a helper, e.g.

function libmodal.mode.fn(f, ...)
	local args = { ... }
	return function()
		f(unpack(args))
	end
end

And then the example becomes:

local fn = libmodal.mode.fn
local options = {
  mode_keymaps = {
    n = function() vim.notify('foo') end,
    u = fn(vim.cmd.undo), 
    e = fn(vim.cmd.edit, 'foo'), -- you can also pass args
  }
}

@Iron-E Iron-E added the question Further information is requested label Mar 22, 2024
@Iron-E Iron-E self-assigned this Mar 22, 2024
@mawkler
Copy link
Author

mawkler commented Mar 22, 2024

Ok thank you for your response. I guess that I could expose my own fn and tell users to use that 🙂

@Iron-E
Copy link
Owner

Iron-E commented Mar 22, 2024

I've merged #36 which adds libmodal.mode.map, a namespace including fn (the utility we discussed) and also switch (the utility implemented previously, just soft-moved to create emphasis that it can only be used as a mapping).

@Iron-E
Copy link
Owner

Iron-E commented Mar 22, 2024

I'll close this for now, but if anything else comes up let me know :)

@Iron-E Iron-E closed this as completed Mar 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants