repositories / dotfiles
dotfiles
bugabingas dorkfiles
owned by admin
neovim/lua/bugabinga/pivi/guide.lua
Rawlocal transcript = require 'bugabinga.pivi.transcript'
local glyph = require 'std.icon'
local MODES = { 'n', 'i', 'x', }
--- What every published intent is for, by its name.
local intents = function( bufnr )
local known = {}
for _, mode in ipairs( MODES ) do
for _, mapping in ipairs( vim.api.nvim_buf_get_keymap( bufnr, mode ) ) do
local plug = mapping.lhs:match '^<Plug>%((pivi%-[%w%-]+)%)$'
if plug then known[plug] = ( mapping.desc or plug ):gsub( '^pivi ', '' ) end
end
end
return known
end
--- What the keys of a pivi buffer are for.
--- pivi chooses no keys, so the guide reports the ones the configuration bound
--- to pivi's intents. It describes what is actually reachable rather than what
--- anyone intended, and cannot drift from either.
local describe = function( bufnr )
local known = intents( bufnr )
local found = {}
local seen = {}
local collect = function( mappings )
for _, mapping in ipairs( mappings ) do
if not mapping.lhs:find( '<Plug>', 1, true ) then
local target = ( mapping.rhs or '' ):match '<Plug>%((pivi%-[%w%-]+)%)'
local what = target and known[target] or nil
-- A key pivi binds itself, such as slash-command entry, is described
-- by its own mapping rather than by an intent.
if not what and ( mapping.desc or '' ):find( 'pivi', 1, true ) then
what = mapping.desc:gsub( '^pivi ', '' )
end
if what and not seen[mapping.lhs] then
seen[mapping.lhs] = true
table.insert( found, { keys = mapping.lhs, what = what, } )
end
end
end
end
for _, mode in ipairs( MODES ) do
collect( vim.api.nvim_buf_get_keymap( bufnr, mode ) )
collect( vim.api.nvim_get_keymap( mode ) )
end
table.sort( found, function( left, right ) return left.keys < right.keys end )
return found
end
local commands = function()
local ok, command = pcall( require, 'bugabinga.pivi.command' )
if not ok then return {} end
return command.names()
end
local lines = function( bufnr )
local written = { '# ' .. glyph.help .. ' pivi', '', }
local keys = describe( bufnr )
if #keys > 0 then
table.insert( written, '## ' .. glyph.keyword .. ' keys here' )
table.insert( written, '' )
for _, mapping in ipairs( keys ) do
table.insert( written, ( '- `%s` %s' ):format( mapping.keys, mapping.what ) )
end
table.insert( written, '' )
end
local names = commands()
if #names > 0 then
table.insert( written, '## ' .. glyph.command .. ' commands' )
table.insert( written, '' )
for _, name in ipairs( names ) do
table.insert( written, '- `:Pi ' .. name .. '`' )
end
table.insert( written, '' )
table.insert( written, 'Bare `:Pi` opens the prompt.' )
table.insert( written, '' )
end
if vim.bo[bufnr].filetype == 'pivi-input' then
table.insert( written, '## ' .. glyph.insert .. ' while writing' )
table.insert( written, '' )
table.insert( written, 'The prompt opens in insert mode, so keys behind a leader need `<Esc>` first.' )
table.insert( written, 'Set `vim.g.pivi_start_insert = false` to open in normal mode instead.' )
table.insert( written, '' )
end
table.insert( written, '## ' .. glyph.list .. ' ordinary neovim' )
table.insert( written, '' )
table.insert( written, '- `za` `zo` `zc` collapse or expand the entry under the cursor' )
table.insert( written, '- `zR` / `zM` expand or collapse every entry' )
table.insert( written, '- `]c` / `[c` move between changes inside a comparison' )
table.insert( written, '' )
table.insert( written, 'Entries are real folds, so no key here replaces one you already know.' )
return written
end
--- Shows the guide without leaving the buffer it describes.
--- @return number? bufnr
--- @return number? winid
local show = function( bufnr )
bufnr = bufnr or vim.api.nvim_get_current_buf()
if not vim.api.nvim_buf_is_valid( bufnr ) then return nil end
local ok, float, window = pcall( vim.lsp.util.open_floating_preview, lines( bufnr ), 'markdown', {
border = 'rounded',
focus = false,
focusable = true,
max_width = 80,
max_height = 30,
title = ' pivi ',
} )
if not ok then return nil end
if float and vim.api.nvim_buf_is_valid( float ) then
pcall( vim.api.nvim_buf_set_name, float, 'pivi://guide' )
end
return float, window
end
local bind = function( bufnr )
vim.keymap.set( 'n', '<Plug>(pivi-guide)', function() show( bufnr ) end,
{ buffer = bufnr, desc = 'pivi show this guide', } )
end
transcript.on_buffer( bind )
return {
describe = describe,
lines = lines,
show = show,
bind = bind,
}