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

Beta-testing 'mini.clue' #430

Closed
echasnovski opened this issue Aug 1, 2023 · 131 comments
Closed

Beta-testing 'mini.clue' #430

echasnovski opened this issue Aug 1, 2023 · 131 comments

Comments

@echasnovski
Copy link
Owner

Please leave your feedback about new mini.clue module here. Feel free to either add new comment or positively upvote existing one.

Some things I am interested to find out (obviously, besides bugs):

  • Are configuration and function names intuitive enough?
  • Are default values of settings convenient for you?
  • Is documentation and examples clear enough?

Thanks!

@echasnovski echasnovski pinned this issue Aug 1, 2023
@Aneeqasif
Copy link

i am getting error after install

.config/lvim/lua/plugins.lua:725: module 'mini.clue' not found:\n\tno field package.preload['
mini.clue']\n\tno file './mini/clue.lua'\n\tno file '/build/neovim/src/neovim-0.9.1/.deps/usr/share/luajit-2.1.0-beta3/mini/clue.lua'\n\tno file '/usr/l
ocal/share/lua/5.1/mini/clue.lua'\n\tno file '/usr/local/share/lua/5.1/mini/clue/init.lua'\n\tno file '/build/neovim/src/neovim-0.9.1/.deps/usr/share/lu
a/5.1/mini/clue.lua'\n\tno file '/build/neovim/src/neovim-0.9.1/.deps/usr/share/lua/5.1/mini/clue/init.lua'\n\tno file './mini/clue.so'\n\tno file '/usr
/local/lib/lua/5.1/mini/clue.so'\n\tno file '/build/neovim/src/neovim-0.9.1/.deps/usr/lib/lua/5.1/mini/clue.so'\n\tno file '/usr/local/lib/lua/5.1/loada
ll.so'\n\tno file './mini.so'\n\tno file '/usr/local/lib/lua/5.1/mini.so'\n\tno file '/build/neovim/src/neovim-0.9.1/.deps/usr/lib/lua/5.1/mini.so'\n\tn
o file '/usr/local/lib/lua/5.1/loadall.so'" file="[C]", line=-1

lazy config

{'echasnovski/mini.clue',
    version = false,
    enabled=false,
    lazy=false,
    config = require('mini.clue').setup{
      triggers = {
        -- Leader triggers
        { mode = 'n', keys = '<Leader>' },
        { mode = 'x', keys = '<Leader>' },

        -- Built-in completion
        { mode = 'i', keys = '<C-x>' },

        -- `g` key
        { mode = 'n', keys = 'g' },
        { mode = 'x', keys = 'g' },

        -- Marks
        { mode = 'n', keys = "'" },
        { mode = 'n', keys = '`' },
        { mode = 'x', keys = "'" },
        { mode = 'x', keys = '`' },

        -- Registers
        { mode = 'n', keys = '"' },
        { mode = 'x', keys = '"' },
        { mode = 'i', keys = '<C-r>' },
        { mode = 'c', keys = '<C-r>' },

        -- Window commands
        { mode = 'n', keys = '<C-w>' },

        -- `z` key
        { mode = 'n', keys = 'z' },
        { mode = 'x', keys = 'z' },
      },

      clues = {
        -- Enhance this by adding descriptions for <Leader> mapping groups
        miniclue.gen_clues.builtin_completion(),
        miniclue.gen_clues.g(),
        miniclue.gen_clues.marks(),
        miniclue.gen_clues.registers(),
        miniclue.gen_clues.windows(),
        miniclue.gen_clues.z(),
      },
    },
  },

@echasnovski
Copy link
Owner Author

i am getting error after install

You are calling require() for the module before making it "visible" for Neovim. Try making config a function. Something like this:

{'echasnovski/mini.clue',
    version = false,
    enabled=true,
    lazy=false,
    config = function()
      local miniclue = require('mini.clue')
      miniclue.setup(
      -- Your config table
      )
    end,
  },

@haoming-li-ling
Copy link

haoming-li-ling commented Aug 1, 2023

The gcc keymap of Comment.nvim will not work unless it is triggered through mini.clue's menu at least once. Why is this happening?

@echasnovski
Copy link
Owner Author

The gcc keymap of Comment.nvim will not work unless it is triggered through mini.clue's menu at least once. Why is this happening?

I am not sure what you mean. As far as I can tell, gcc in 'Comment.nvim' is a separate mappings, same as in 'mini.comment' (which does work right away, as even visible in demo).

I've just tried commenting with 'Comment.nvim' and g as Normal mode trigger and it works as if without 'mini.clue'. So can not reproduce.

@farias-hecdin
Copy link

farias-hecdin commented Aug 1, 2023

Hi, @echasnovski. 👋
Would it be possible to truncate the description of the keybinding. I.e., show three dots (...) if the number of characters of the description is greater than the size of the window?

PD: Congratulations! Your plugin is just simply amazing.

@echasnovski
Copy link
Owner Author

echasnovski commented Aug 1, 2023

Hi, @echasnovski. wave Would it be possible to truncate the description of the keybinding. I.e., show three dots (...) if the number of characters of the description is greater than the size of the window?

PD: Congratulations! Your plugin is just simply amazing.

Thanks!

That is a great suggestion! I don't know why I didn't think about it myself. I'll look into it.

Edit: @farias-hecdin, done. This should be present on latest main. Thanks again for the idea!

@farias-hecdin
Copy link

Thanks!

That is a great suggestion! I don't know why I didn't think about it myself. I'll look into it.

Edit: @farias-hecdin, done. This should be present on latest main. Thanks again for the idea!

Wow, thanks @echasnovski. It looks great.

@MariaSolOs
Copy link
Contributor

@echasnovski I'm having some trouble understanding the difference between clues and triggers. I promise that I've read the specs, but coming from which-key I'm finding the distinction confusing :/

@haoming-li-ling
Copy link

The gcc keymap of Comment.nvim will not work unless it is triggered through mini.clue's menu at least once. Why is this happening?

I am not sure what you mean. As far as I can tell, gcc in 'Comment.nvim' is a separate mappings, same as in 'mini.comment' (which does work right away, as even visible in demo).

I've just tried commenting with 'Comment.nvim' and g as Normal mode trigger and it works as if without 'mini.clue'. So can not reproduce.

So if I press gcc quickly enough so that mini.clue's menu does not show up at all, nothing happens (the current line is not commented). If I press gcc more slowly so that mini.clue's menu is visible in the process, the current line is commented. And after once triggering gcc this latter way, it will work afterwards regardless of how quickly I press the gcc keys; the current line is commented whether the mini.clue is visible or not.

So it looks like the gcc mapping is inactive (though recognized by mini.clue itself) unless triggered once through mini.clue.

@MariaSolOs
Copy link
Contributor

@echasnovski what are your thoughts on creating a more comprehensive default setup? I understand (and love!) the simplicity of the mini plugins, but I feel like 99% of users will end up copy-pasting this non-trivial config, which could potentially be made into a simple preset.

@leaxoy
Copy link

leaxoy commented Aug 2, 2023

Is there a way to place popup window in the center of editor? Placed in the four corners on a big screen would be a distraction.

@farzadmf
Copy link

farzadmf commented Aug 2, 2023

Is there a way to place popup window in the center of editor? Placed in the four corners on a big screen would be a distraction.

+1 on this, I saw on Reddit, someone mentioned that they've done it, but, from the config, I only see anchors pointing to the 4 corners

@hbiel
Copy link

hbiel commented Aug 2, 2023

Hi @echasnovski!

Thank you for another great plugin. It looks very intriguing!

One question: Is it possible to have conditional clues? I want to show some clues only on specific buffers, for example only show the lsp group when an lsp is connected.

@echasnovski
Copy link
Owner Author

@MariaSolOs

@echasnovski I'm having some trouble understanding the difference between clues and triggers. I promise that I've read the specs, but coming from which-key I'm finding the distinction confusing :/

Here is the quick example:

require('mini.clue').setup({
  -- Information about when to start the special key query process.
  -- Starts the timer for clue window.
  triggers = {
    { mode = 'n', keys = '<Leader>' },
  },

  -- Information about key combinations: `desc` will be shown in clue window
  -- while `postkeys` may define "submodes".
  clues = {
    { mode = 'n', keys = '<Leader>a', desc = 'Leader a' },
    { mode = 'n', keys = '<Leader>b', desc = 'Leader b' },
  },
})

When you press <Leader> in Normal mode, it triggers the special key query process which takes over the standard procedure of typing the mapping. It looks at all available key combinations (from mappings and config.clues) to see if there are any that start with <Leader> in the Normal mode. In this case it waits for the next key, because there are more than 1 such key combinations. Here "clues" are essentially "information about key combinations".

@echasnovski what are your thoughts on creating a more comprehensive default setup? I understand (and love!) the simplicity of the mini plugins, but I feel like 99% of users will end up copy-pasting this non-trivial config, which could potentially be made into a simple preset.

At the moment I believe that 'mini.clue' config should be as explicit as possible in terms of triggers because it might lead to confusion an unexpected behavior.

@echasnovski
Copy link
Owner Author

echasnovski commented Aug 2, 2023

So if I press gcc quickly enough so that mini.clue's menu does not show up at all, nothing happens (the current line is not commented). If I press gcc more slowly so that mini.clue's menu is visible in the process, the current line is commented. And after once triggering gcc this latter way, it will work afterwards regardless of how quickly I press the gcc keys; the current line is commented whether the mini.clue is visible or not.

So it looks like the gcc mapping is inactive (though recognized by mini.clue itself) unless triggered once through mini.clue.

@haoming-li-ling, I can not reproduce this behavior.

Couple of questions:

  • Do you, by any chance, lazy load 'Comment.nvim' on certain keys? Like "lazy load it after pressing gc"? It might shed some light, but still won't fully explain the behavior you experience.
  • What other mappings do you have starting with gc? You can execute the following command, copy lines from the start of the current buffer, and paste it here:
lua vim.fn.append(0, vim.split(vim.api.nvim_exec2('nmap gc', { output = true }).output, '\n'))

@echasnovski
Copy link
Owner Author

@leaxoy, @farzadmf, it is possible to a certain degree by utilizing config.window.config which defines the properties of floating window (as opts in vim.api.nvim_open_win()).

Here is the most reasonable way to do it I can think of right now:

local make_win_config = function()
  local width = 40
  -- Stick to the top side at center
  return {
    anchor = 'NW',
    width = width,
    -- Height is computed automatically
    row = 'auto',
    col = math.max(math.floor(0.5 * (vim.o.columns - width)), 0),
  }
end

require('mini.clue').setup({
  window = { config = make_win_config() },
  -- The rest of config, including `clues` and `triggers`
})

-- Make sure that the window config is updated when Neovim is resized
vim.api.nvim_create_autocmd('VimResized', {
  group = vim.api.nvim_create_augroup('clue-resize', { clear = true }),
  callback = function() MiniClue.config.window.config = make_win_config() end,
})

Placed in the four corners on a big screen would be a distraction.

The reasoning for placing it in one of the four corners was precisely for it to not be a distraction. I think the user is already distracted if they want to look at clues, so positioning should be done for the user which doesn't want to look at clues and just taking the time to type whole mapping. The bottom right corner seemed like the best place for this.

@echasnovski
Copy link
Owner Author

Hi @echasnovski!

👋

Thank you for another great plugin. It looks very intriguing!

One question: Is it possible to have conditional clues? I want to show some clues only on specific buffers, for example only show the lsp group when an lsp is connected.

@hbiel, you have at least two options here:

  • Use buffer-local variable vim.b.miniclue_config. For example, you can have it defined when LSP is attached (in on_attach()). So add something like this:
-- Use `vim.b[buf_id].miniclue_config` if you have explicit buffer id
vim.b.miniclue_config = {
  clues = {
    { mode = 'n', keys = '<Leader>y', desc = 'My buffer-local clue' },
    -- And so on ...
  },
}
  • Use callable (a.k.a. function) clue, as config.clues allows this specifically for this reason. So you can have something like this:
local conditional_clues = function()
  -- Your logic goes here

  -- Should return an array of clues
  return {
    { mode = 'n', keys = '<Leader>x', desc = 'My callable clue' },
    -- And so on ...
  }
end

require('mini.clue').setup({
  clues = {
    conditional_clues,
    -- Your other clues go here
  },
})

Although a bit more complicated, I'd prefer the first approach with buffer-local variable because callable clues will be evaluated after every trigger (even if it doesn't match the conditional clues).

@jhermelink
Copy link

Hi @echasnovski, looks good so far! Thank you!

Is it possible to show register contents (after ") and marks in use (after ' and `) like which-key does?

@michaeladler
Copy link

michaeladler commented Aug 2, 2023

@echasnovski This plugin is excellent; thank you. Replacing 'which-key' was simple, but I am struggling to replace some Hydras. Specifically, I'm missing hooks (functions) that execute when a sub-mode is activated. For instance, Hydra Git employs on_enter to activate Git signs, which highlight the changed lines. Is this functionality already available with mini.clue? If not, it would be a fantastic addition.

@echasnovski
Copy link
Owner Author

Hi @echasnovski, looks good so far! Thank you!

Is it possible to show register contents (after ") and marks in use (after ' and `) like which-key does?

@jhermelink, for registers try using miniclue.gen_clues.registers({ show_contents = true }) (see its help). It shows all possible registers, which is plenty. To show only non-empty registers, it can return callable which is not great because it will be executed on every trigger. Possible to do manually, though, and not that complicated: here is a helper function (basically, call vim.fn.getreg() and check if it is non-empty).

There is no such functionality for marks as I genuinely don't find it useful to have line number shown (not much useful information). Again, can be done manually, though.

@echasnovski
Copy link
Owner Author

@echasnovski This plugin is excellent; thank you. Replacing 'which-key' was simple, but I am struggling to replace some Hydras. Specifically, I'm missing hooks (functions) that execute when a sub-mode is activated. For instance, Hydra Git employs on_enter to activate Git signs, which highlight the changed lines. Is this functionality already available with mini.clue? If not, it would be a fantastic addition.

The only way to emulate submode is by creating all mappings yourself and adding postkeys to their clues. It is not (currently) possible to have any hooks, mostly because it doesn't quite align with the design of showing clues and directly executing mappings. At the moment I think that having separate hooks is quite complex while leaving it to the user to include in their mappings is more straightforward.

Having an on_exit hook is more complicated because exiting key query process doesn't depend on the current clue...

I'll think about it, but there is no high hopes right now.

@leaxoy
Copy link

leaxoy commented Aug 2, 2023

Another question, does triggers support desc field.

@echasnovski
Copy link
Owner Author

Another question, does triggers support desc field.

No, because they are implemented as regular mappings and have their description auto generated.

Do you have any particular use case in mind for triggers to have description field?

@gj86
Copy link

gj86 commented Aug 2, 2023

Mini.Clue window doesn't show in special buffers Neo-tree, Aerial etc. Is this intentional? Since which-key does work in this special buffers I expected Mini.clue will too.

Example use case: Use of localleader mappings for specific buffers or Main leader mappings or C-w mappings etc.

Edit: Forgive my mistake. Many thanks for very useful plugins. I use several of them daily.

@echasnovski
Copy link
Owner Author

Mini.Clue window doesn't show in special buffers Neo-tree, Aerial etc. Is this intentional? Since which-key does work in this special buffers I expected Mini.clue will too.

Example use case: Use of localleader mappings for specific buffers or Main leader mappings or C-w mappings etc.

Edit: Forgive my mistake. Many thanks for very useful plugins. I use several of them daily.

Right now 'mini.clue' creates triggers only for listed buffers. Some "special" buffers might not be listed, so that is what you are experiencing.

The idea is that there is MiniClue.enable_buf_triggers() if user wants to also enable them in non-listed buffers.

@MariaSolOs
Copy link
Contributor

@MariaSolOs

@echasnovski I'm having some trouble understanding the difference between clues and triggers. I promise that I've read the specs, but coming from which-key I'm finding the distinction confusing :/

Here is the quick example:

require('mini.clue').setup({

  -- Information about when to start the special key query process.

  -- Starts the timer for clue window.

  triggers = {

    { mode = 'n', keys = '<Leader>' },

  },



  -- Information about key combinations: `desc` will be shown in clue window

  -- while `postkeys` may define "submodes".

  clues = {

    { mode = 'n', keys = '<Leader>a', desc = 'Leader a' },

    { mode = 'n', keys = '<Leader>b', desc = 'Leader b' },

  },

})

When you press <Leader> in Normal mode, it triggers the special key query process which takes over the standard procedure of typing the mapping. It looks at all available key combinations (from mappings and config.clues) to see if there are any that start with <Leader> in the Normal mode. In this case it waits for the next key, because there are more than 1 such key combinations. Here "clues" are essentially "information about key combinations".

@echasnovski what are your thoughts on creating a more comprehensive default setup? I understand (and love!) the simplicity of the mini plugins, but I feel like 99% of users will end up copy-pasting this non-trivial config, which could potentially be made into a simple preset.

At the moment I believe that 'mini.clue' config should be as explicit as possible in terms of triggers because it might lead to confusion an unexpected behavior.

Thank you for the careful reply ♥️

@gj86
Copy link

gj86 commented Aug 2, 2023

Mini.Clue window doesn't show in special buffers Neo-tree, Aerial etc. Is this intentional? Since which-key does work in this special buffers I expected Mini.clue will too.
Example use case: Use of localleader mappings for specific buffers or Main leader mappings or C-w mappings etc.
Edit: Forgive my mistake. Many thanks for very useful plugins. I use several of them daily.

Right now 'mini.clue' creates triggers only for listed buffers. Some "special" buffers might not be listed, so that is what you are experiencing.

The idea is that there is MiniClue.enable_buf_triggers() if user wants to also enable them in non-listed buffers.

Thanks for the reply and explaining the concept.

I have a question about clue = {} config. For example I have this in the Mini.clue config option.

clues = { 
    { mode = 'n', keys = 'zb', desc = 'Bottom this line' },
    { mode = 'n', keys = 'zt', desc = 'Top this line' },
    { mode = 'n', keys = 'z%', desc = 'Go to inside [count]th nearest block' },
    { mode = 'n', keys = 'g%', desc = 'Cycle Next/Prev match' }

}

for vim-smoothie and vim-matchup plugin. But Mini.clue seems to ignore this and doesn't show any desc for this keys. For reference this plugins doesn't set any desc property for the keymaps.

I understand the clues config option provides information about the keymaps to Mini.clue. But why Mini.clue not using this.

@echasnovski
Copy link
Owner Author

I have a question about clue = {} config. For example I have this in the Mini.clue config option.

clues = { 
    { mode = 'n', keys = 'zb', desc = 'Bottom this line' },
    { mode = 'n', keys = 'zt', desc = 'Top this line' },
    { mode = 'n', keys = 'z%', desc = 'Go to inside [count]th nearest block' },
    { mode = 'n', keys = 'g%', desc = 'Cycle Next/Prev match' }

}

for vim-smoothie and vim-matchup plugin. But Mini.clue seems to ignore this and doesn't show any desc for this keys. For reference this plugins doesn't set any desc property for the keymaps.

I understand the clues config option provides information about the keymaps to Mini.clue. But why Mini.clue not using this.

It is a result of a relatively hard choice about what should have precedence: description from existing mapping or from config.clues entry. Initially I thought that config.clues should have higher precedence to allow user to "patch" mappings without descriptions. But that might lead to a hard to debug behavior: clue shows one thing, but different actual action is done.

For example, there is built-in ga mapping for which there is an entry in gen_clues.g() ("Print ascii value"). But it then can't be used along with the 'mini.align' because it will override its description ("Align").

That is why I decided that clue window will always show the description from the source that will actually be executed. In your example - mapping without description.

This was also motivated by the fact that user can add description to already created mapping. Using function like this:

_G.add_mapping_desc = function(mode, lhs, desc)
  local map_data = vim.fn.maparg(lhs, mode, false, true)
  map_data.desc = desc
  vim.fn.mapset(mode, false, map_data)
end

And then doing something like _G.add_mapping_desc('n', 'g%', 'Cycle Next/Prev match').

To be honest, I forgot about adding all of this to the documentation. I think I'll add this function directly to 'mini.clue' with motivation and instructions on how to use it. But not until tomorrow.

@echasnovski
Copy link
Owner Author

These are the limitations you were mentioning or just a matter of missing clues?

The first one is the matter of missing clues. I believe that you test 'folke/which-key.nvim' with LazyVim? Because it explicitly adds items for 'mini.ai'. It comes from how 'mini.ai' implements its textobjects: it creates only mappings for a/i (possibly along with an/in/al/il) and then handles next key on its own.
Blank lines for present mappings is the matter of missing description field. See this part of help.

The second one (after single d) is a bit more complicated. Because it waits for the next key to finish Normal mode mapping (as you seem to have ds one). What you show is (probably) description for Operator-pending mappings. Such automatic switch is currently not really possible right now (see this comment with its answer and #442). And to be honest, I don't think it will ever be possible.

  • key aliases to save space (e.g. showing ^w instead of <C-w> to save some precious width), and

Probably not, as <C-*> is a more canonical way of displaying such keys, as it is taken directly from Neovim's keytrans() function.

  • some kind of a scrollbar indicator to know that there are some additional clues hidden.

I tried to think about indicating that some clues are not shown, but didn't come up with something both concise to implement and useful for users.

Currently suggested approach is to use default automatic height and assume that there more lines if clue window takes maximum height (from tabline to statusline). If it is shorter than that, then there are no more clues.

@thenbe
Copy link

thenbe commented Sep 1, 2023

The first one is the matter of missing clues. I believe that you test 'folke/which-key.nvim' with LazyVim? Because it explicitly adds items for 'mini.ai'.

@simonmandlik This was a quick attempt at replicating how LazyVim registers textobjects explicitly. It can probably be implemented in a better way.

image

	{
		"echasnovski/mini.clue",
		opts = function(_, opts)
			---@type table<string, string|table>
			local i = {
				[" "] = "Whitespace",
				['"'] = 'Balanced "',
				["'"] = "Balanced '",
				["`"] = "Balanced `",
				["("] = "Balanced (",
				[")"] = "Balanced ) including white-space",
				[">"] = "Balanced > including white-space",
				["<lt>"] = "Balanced <",
				["]"] = "Balanced ] including white-space",
				["["] = "Balanced [",
				["}"] = "Balanced } including white-space",
				["{"] = "Balanced {",
				["?"] = "User Prompt",
				_ = "Underscore",
				a = "Argument",
				b = "Balanced ), ], }",
				c = "Class",
				f = "Function",
				o = "Block, conditional, loop",
				q = "Quote `, \", '",
				t = "Tag",
			}
			local a = vim.deepcopy(i)
			for k, v in pairs(a) do
				a[k] = v:gsub(" including.*", "")
			end

			-- Example of desired clues output:
			-- { mode = "o", keys = "if", desc = "Inside Function" },
			-- { mode = "o", keys = "af", desc = "Around Function" },
			-- { mode = "o", keys = "inf", desc = "Inside next Function" },
			-- { mode = "o", keys = "ilf", desc = "Inside last Function" },
			-- { mode = "o", keys = "anf", desc = "Around next Function" },
			-- { mode = "o", keys = "alf", desc = "Around last Function" },

			local clues = {}
			for key, name in pairs(i) do
				table.insert(clues, { mode = "o", keys = "i" .. key, desc = "Inside " .. name })
			end
			for key, name in pairs(a) do
				table.insert(clues, { mode = "o", keys = "a" .. key, desc = "Around " .. name })
			end

			for key1, name1 in pairs({ n = "Next", l = "Last" }) do
				for key2, name2 in pairs(i) do
					-- stylua: ignore
					table.insert(clues, { mode = "o", keys = "i" .. key1 .. key2, desc = "Inside " .. name1 .. " " .. name2 })
				end
				for key2, name2 in pairs(a) do
					-- stylua: ignore
					table.insert(clues, { mode = "o", keys = "a" .. key1 .. key2, desc = "Around " .. name1 .. " " .. name2 })
				end
			end

			local triggers = {
				{ mode = "o", keys = "i", desc = "inside" },
				{ mode = "o", keys = "a", desc = "around" },
			}
			for _, trigger in ipairs(triggers) do
				table.insert(opts.triggers, trigger)
			end
			for _, clue in ipairs(clues) do
				table.insert(opts.clues, clue)
			end
		end,
	},

@simonmandlik
Copy link

The first one is the matter of missing clues. I believe that you test 'folke/which-key.nvim' with LazyVim?

No no, I'm not using LazyVim. Sorry, I made it confusing by showing everything my full config. I have narrowed it down to a simpler setup:

local root = vim.fn.fnamemodify("./.repro", ":p")
for _, name in ipairs({ "config", "data", "state", "cache" }) do
    vim.env[("XDG_%s_HOME"):format(name:upper())] = root .. "/" .. name
end
local lazypath = root .. "/plugins/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
    vim.fn.system({ "git", "clone", "--filter=blob:none", "https://github.com/folke/lazy.nvim.git", lazypath, })
end
vim.opt.runtimepath:prepend(lazypath)

local plugins = {
    {
        "echasnovski/mini.clue",
        version = "*",
        config = function()
            local miniclue = require('mini.clue')
            miniclue.setup({
                triggers = {
                    { mode = "o", keys = "a" },
                    { mode = "o", keys = "i" },
                    { mode = "n", keys = "y" },
                    { mode = "n", keys = "d" },

                    { mode = 'n', keys = 'g' },
                    { mode = 'x', keys = 'g' },

                    { mode = 'n', keys = '<C-w>' },
                },

                clues = {
                    miniclue.gen_clues.builtin_completion(),
                    miniclue.gen_clues.g(),
                    miniclue.gen_clues.marks(),
                    miniclue.gen_clues.registers(),
                    miniclue.gen_clues.windows(),
                    miniclue.gen_clues.z(),
                },
            })
        end
    },
}

require("lazy").setup(plugins, {
    root = root .. "/plugins",
})

vim.o.termguicolors = true

vim.cmd("colorscheme evening")

The core of my question was about builtins. With the config above get no clues for d, di, or da. So even for builtins like d$, dd, and diw. I tested with something like

            clues = {
                { mode = "o", keys = "iw", desc = "test1" },
                { mode = "n", keys = "d$", desc = "test2" },
           }

and they show. Could these clues be collected and provided e.g. as miniclue.gen_clues.builtin_delete as it is done for z, g, etc, or are you against?

@simonmandlik
Copy link

simonmandlik commented Sep 2, 2023

Probably not, as <C-*> is a more canonical way of displaying such keys, as it is taken directly from Neovim's keytrans() function.

That probably wasn't the best example, still neovim shows e.g. ^w in the status line. I would also like to show <Tab>, <Space> and others as a single character to save space. But I understand why this it is not interesting for you.

@MariaSolOs
Copy link
Contributor

@echasnovski I just found an issue using this plugin with nvim-treesitter-context. Notice how when the menu opens, the context disappears:

Screen.Recording.2023-09-02.at.3.36.11.PM.mov

@thenbe
Copy link

thenbe commented Sep 3, 2023

Notice how when the menu opens, the context disappears

The cursor itself also disappears. If you use a submode with jumps (eg. with Mini.bracketed), you need to enable set cursorline, otherwise you can't tell which row your cursor is on.

@echasnovski
Copy link
Owner Author

The core of my question was about builtins. With the config above get no clues for d, di, or da. So even for builtins like d$, dd, and diw. I tested with something like

            clues = {
                { mode = "o", keys = "iw", desc = "test1" },
                { mode = "n", keys = "d$", desc = "test2" },
           }

and they show. Could these clues be collected and provided e.g. as miniclue.gen_clues.builtin_delete as it is done for z, g, etc, or are you against?

@simonmandlik, I don't think so. I'd rather err on the side of caution and not provide built-in clues for Operator-pending mode which 'mini.clue' can't support 100%.

@echasnovski
Copy link
Owner Author

echasnovski commented Sep 3, 2023

@echasnovski I just found an issue using this plugin with nvim-treesitter-context. Notice how when the menu opens, the context disappears:

@MariaSolOs, I think this is how 'nvim-treesitter-context' works. Some of its autocommands closes context when there is a floating window opened. I can reproduce same behavior when floating window from 'mini.completion' is opened.


Notice how when the menu opens, the context disappears

The cursor itself also disappears. If you use a submode with jumps (eg. with Mini.bracketed), you need to enable set cursorline, otherwise you can't tell which row your cursor is on.

It does in the demo, but I can not reproduce this (on Neovim 0.9.1). Disappearing cursor (or rather "moving to command line" cursor) when getcharstr() is active indeed was the case, but the behavior changed quite some time ago.

@thenbe
Copy link

thenbe commented Sep 3, 2023

I was on v0.10.0-dev-6462ee1, so I tried with v0.9.1 but that did not fix the invisibile cursor for me. Since you mentioned something about the command line, I went ahead and tried disabling noice.nvim. This made the cursor behave much better, and nvim-treesitter-context is not hidden anymore.

One issue that is still wonky is the following jump. When I trigger it, the cursor jumps to the command line on ~every other trigger.

{
  "lewis6991/gitsigns.nvim",
  keys = {
    { "]e", function() require("gitsigns").next_hunk() end, desc = "Hunk backward" },
    { "[e", function() require("gitsigns").prev_hunk() end, desc = "Hunk forward" },
  }
}

The following change improved things, the cursor no longer jumps to the command line.

{
  "lewis6991/gitsigns.nvim",
  keys = {
-   { "]e", function() require("gitsigns").next_hunk() end, desc = "Hunk backward" },
+   { "]e", function() require("gitsigns").next_hunk({ navigation_message = false }) end, desc = "Hunk backward" },
-   { "[e", function() require("gitsigns").prev_hunk() end, desc = "Hunk forward" },
+   { "[e", function() require("gitsigns").prev_hunk({ navigation_message = false }) end, desc = "Hunk forward" },
  }
}

The cursor still sometimes "overshoots" the hunk, but as soon as you exit the submode, the cursor will jump up to the correct position. I thought it maybe had something to do with scrolloff, but I don't think scrolloff is related.

tldr; submode is difficult to use alongside noice.nvim (as of time of writing)

@MariaSolOs
Copy link
Contributor

@MariaSolOs, I think this is how 'nvim-treesitter-context' works. Some of its autocommands closes context when there is a floating window opened. I can reproduce same behavior when floating window from 'mini.completion' is opened.

Interesting. I don't have that behaviour with which-key nor the completion menu from nvim-cmp.

@echasnovski
Copy link
Owner Author

Interesting. I don't have that behaviour with which-key nor the completion menu from nvim-cmp.

Well, then the way we create floating window might differ. Or something else. But the fact that I see this not only with 'mini.clue' does point to some different (more systemic) reason.

@MariaSolOs
Copy link
Contributor

MariaSolOs commented Sep 3, 2023

Well, then the way we create floating window might differ. Or something else. But the fact that I see this not only with 'mini.clue' does point to some different (more systemic) reason.

Well I found the explanation. Both which-key and nvim-cmp use noautocmd in their window options: https://github.com/folke/which-key.nvim/blob/7ccf476ebe0445a741b64e36c78a682c1c6118b7/lua/which-key/view.lua#L70, https://github.com/hrsh7th/nvim-cmp/blob/5dce1b778b85c717f6614e3f4da45e9f19f54435/lua/cmp/utils/window.lua#L124

@echasnovski
Copy link
Owner Author

Well, then the way we create floating window might differ. Or something else. But the fact that I see this not only with 'mini.clue' does point to some different (more systemic) reason.

Well I found the explanation. Both which-key and nvim-cmp use noautocmd in their window options: https://github.com/folke/which-key.nvim/blob/7ccf476ebe0445a741b64e36c78a682c1c6118b7/lua/which-key/view.lua#L70, https://github.com/hrsh7th/nvim-cmp/blob/5dce1b778b85c717f6614e3f4da45e9f19f54435/lua/cmp/utils/window.lua#L124

Interesting. Yes, that might be it.
I'll into implications of adding it later.

@MariaSolOs
Copy link
Contributor

MariaSolOs commented Sep 3, 2023

Interesting. Yes, that might be it.
I'll into implications of adding it later.

@echasnovski I don't think you actually need to do anything here, since we can just add noautocmd to opts.window.config :) I just tried it and it works.

EDIT 1: Never mind, that's not a good solution since now the window isn't properly resized when typing the next character of a key sequence...

EDIT 2: Adding win_config.noautocmd = true below line 1523 in this code does seem to fix the issue.

mini.nvim/lua/mini/clue.lua

Lines 1521 to 1526 in 3a3e19d

-- Create-update window showing buffer
local win_config = H.window_get_config()
if not H.is_valid_win(win_id) then
win_id = H.window_open(win_config)
H.state.win_id = win_id
else

I have a branch with the modification, but it seems like I don't have the permissions to open a PR...

@MariaSolOs
Copy link
Contributor

@echasnovski what are your thoughts about adding a setting for hiding mappings with no descriptions?

@echasnovski
Copy link
Owner Author

@echasnovski what are your thoughts about adding a setting for hiding mappings with no descriptions?

Extremely against. Not only this is an extra setting, but also clues without description do provide information that there is some actual mapping without description. 'mini.clue' is designed around the idea of showing what is actually defined.

@MariaSolOs
Copy link
Contributor

@echasnovski what are your thoughts about adding a setting for hiding mappings with no descriptions?

Extremely against. Not only this is an extra setting, but also clues without description do provide information that there is some actual mapping without description. 'mini.clue' is designed around the idea of showing what is actually defined.

That’s fair. In my defence I wanted this because of some builtin mappings from matchit, I’m a civilized person and do use descriptions for all my keymaps :D

@echasnovski
Copy link
Owner Author

That’s fair. In my defence I wanted this because of some builtin mappings from matchit, I’m a civilized person and do use descriptions for all my keymaps :D

Sure. That is why there is an exported set_mapping_desc() to patch situations like this.

@echasnovski
Copy link
Owner Author

With the release of 0.10.0, 'mini.clue' is now out of beta-testing. Huge thanks to everyone for constructive feedback and participation!

@echasnovski
Copy link
Owner Author

Is there a way to have a dynamic but bounded width? I would like to set window.config.width = 'auto' but set a maximum width.

@MariaSolOs, this is now possible on latest main with callable config.window.config. With something like this:

local win_config = function(buf_id)
  local max_width = 0
  for _, l in ipairs(vim.api.nvim_buf_get_lines(buf_id, 0, -1, false)) do
    max_width = math.max(max_width, vim.fn.strchars(l))
  end
  -- Choose your own maximum width instead of 20
  return { width = math.min(max_width, 20), border = 'double' }
end

require('mini.clue').setup({
  -- Place for your triggers and clues

  window = { config = win_config },
})

@MariaSolOs
Copy link
Contributor

this is now possible on latest main with callable config.window.config.

@echasnovski Nice! Thank you for following up. Out of curiosity, which was the neovim change that provided this functionality?

@echasnovski
Copy link
Owner Author

Out of curiosity, which was the neovim change that provided this functionality?

You might have been contributing to Neovim too much (just joking, no such limit exists) :).

It was meant as 'mini.nvim' main branch :)

@MariaSolOs
Copy link
Contributor

@echasnovski lol yeah, I had just reviewing echasnovski/mini.clue@97b881f. Thank you for the feature <3

@llllvvuu
Copy link

llllvvuu commented Nov 4, 2023

@echasnovski This plugin is excellent; thank you. Replacing 'which-key' was simple, but I am struggling to replace some Hydras. Specifically, I'm missing hooks (functions) that execute when a sub-mode is activated. For instance, Hydra Git employs on_enter to activate Git signs, which highlight the changed lines. Is this functionality already available with mini.clue? If not, it would be a fantastic addition.

The way I do this currently is to:

  • map <leader>g to execute entry hooks and execute <leader><C-g>
  • put all submode commands under <leader><C-g> prefix
  • map <leader><C-g>q to exit submode and execute exit hooks

Not sure anything "cleaner" can be done without lower-level APIs from Nvim (unlikely?)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests