Here is the plan: A floating input shows up, you a enter a command and you're done. You can use <Tab>
completion like the regular cmdline
, and can also navigate the command history with <Up>
and <Down>
arrows. That's it.
My hope is that someone else with more knowledge sees this and inspires them to make a Telescope plugin with the same features.
Make sure you have Neovim v0.5.1 or greater.
Use your favorite plugin manager. For example.
With vim-plug
Plug 'MunifTanjim/nui.nvim'
Plug 'VonHeikemen/fine-cmdline.nvim'
With packer
.
use {
'VonHeikemen/fine-cmdline.nvim',
requires = {
{'MunifTanjim/nui.nvim'}
}
}
You just need to require this plugin and call .open()
... in a keybinding.
With lua.
vim.api.nvim_set_keymap(
'n',
'<C-p>',
':lua require("fine-cmdline").open()<CR>',
{noremap = true}
)
Or use vimscript.
nnoremap <C-p> :lua require('fine-cmdline').open()<CR>
If you want to change anything from the ui
or add a "hook" you can use .setup()
.
This are the defaults.
require('fine-cmdline').setup({
popup = {
position = {
row = '10%',
col = '50%',
},
size = {
width = '60%',
height = 1
},
border = {
style = 'rounded',
highlight = 'FloatBorder',
},
win_options = {
winhighlight = 'Normal:Normal',
},
},
hooks = {
before_mount = function(input)
-- code
end,
after_mount = function(input)
-- code
end,
set_keymaps = function(imap, feedkeys)
-- code
end
}
})
-
popup
is passed directly tonui.popup
. You can check the valid keys in their documentation: popup.options -
hooks
must be functions. They will be executed during the "lifecycle" of the input.
before_mount
and after_mount
recieve the instance of the input, so you can do anything with it.
set_keymaps
. Why is this even in a "hook"? Funny story, you can only map keys after the input is mounted. And there are other not so funny quirks. So I thought I could make things easier for you.
With set_keymaps
you get two parameters. imap
makes non-recursive mappings in insert mode. feedkeys
types keys for you (because of reasons).
Let's say you want to create a shortcut (Alt + s
) for a simple search and replace.
set_keymaps = function(imap, feedkeys)
imap('<M-s>', '%s///gc<Left><Left><Left><Left>')
end
If you need something more complex you can use a function.
set_keymaps = function(imap, feedkeys)
imap('<M-s>', function()
if vim.fn.pumvisible() == 0 then
feedkeys('%s///gc<Left><Left><Left><Left>')
end
end)
end
There are a few utility functions you could use, they are available under .fn
.
local fn = require('fine-cmdline').fn
-
fn.close
: If completion menu is visible, hide it. Else, unmounts the input. -
fn.next_item
: Go to the next item in the completion list. -
fn.previous_item
: Go to the previous item in the completion list. -
fn.complete_or_next_item
: Shows the completion menu if is not visible. Else, navigates to the next item in the completion list. -
fn.up_history
: Replaces the text in the input with the previous entry in the command history. -
fn.down_history
: Replaces the text in the input with the next entry in the command history.
If you wanted to navigate command history with Alt + k
and Alt + j
.
set_keymaps = function(imap, feedkeys)
local fn = require('fine-cmdline').fn
imap('<M-k>', fn.up_history)
imap('<M-j>', fn.down_history)
end
This is not a special mode. It's just a normal buffer, incremental search will not work here.
How nice of you. Keep in mind I want to keep this plugin small. Scope creep is the enemy. This thing already does everything I want.
Bug fixes are welcome. Suggestions to improve defaults. Maybe some tweaks to the lua public api.
If you want to improve the ui it will be better if you contribute to nui.nvim.
If you find this tool useful and want to support my efforts, buy me a coffee ☕.