repositories / dotfiles
dotfiles
bugabingas dorkfiles
owned by admin
neovim/lua/bugabinga/cmdline/render.lua
Rawlocal format = require 'bugabinga.cmdline.format'
local position = require 'bugabinga.cmdline.position'
local cursor = require 'bugabinga.cmdline.cursor'
local highlight = require 'bugabinga.cmdline.highlight'
local ns = vim.api.nvim_create_namespace 'bugabinga.cmdline'
local hl_ns = vim.api.nvim_create_namespace 'bugabinga.cmdline.hl'
local prompt_ns = vim.api.nvim_create_namespace 'bugabinga.cmdline.prompt'
local state = {
buffer = -1,
window = -1,
current_fmt = nil,
text = '',
firstc = '',
prompt = '',
}
local function get_buf()
if vim.api.nvim_buf_is_valid( state.buffer ) then
return state.buffer
end
state.buffer = vim.api.nvim_create_buf( false, true )
vim.bo[state.buffer].buflisted = false
vim.bo[state.buffer].filetype = 'bugabinga_cmdline'
return state.buffer
end
local function get_win( buf, width, fmt )
if vim.api.nvim_win_is_valid( state.window ) then
return state.window
end
local screen_pos = position.at_cursor( width or vim.o.columns )
state.window = vim.api.nvim_open_win( buf, false, {
relative = 'editor',
width = width or vim.o.columns,
height = 1,
row = screen_pos.row,
col = 0,
style = 'minimal',
border = vim.g.border_style,
focusable = false,
zindex = 50,
} )
vim.wo[state.window].cursorline = false
vim.wo[state.window].winbar = ''
vim.wo[state.window].foldenable = false
vim.wo[state.window].winhighlight = format.winhighlight( fmt.type, 'NormalFloat' )
return state.window
end
local function apply_icon( buf, fmt )
vim.api.nvim_buf_clear_namespace( buf, ns, 0, -1 )
local icon_hl = format.icon_highlight( fmt.type )
vim.api.nvim_buf_set_extmark( buf, ns, 0, 0, {
virt_text = { { fmt.icon, icon_hl } },
virt_text_pos = 'overlay',
} )
end
local function show( cmdline_state )
local text = cmdline_state:text()
local firstc = cmdline_state.firstc
local prompt = cmdline_state.prompt
state.text = text
state.firstc = firstc
state.prompt = prompt
local fmt = format.detect( firstc, text, prompt )
local fmt_changed = not state.current_fmt or fmt.type ~= state.current_fmt.type
state.current_fmt = fmt
local display_text = ' ' .. text .. ' '
local width = vim.o.columns
local buf = get_buf()
local win = get_win( buf, width, fmt )
local is_new = not position.get_cmdline_anchor()
if is_new then
local screen_pos = position.at_cursor( width )
vim.api.nvim_win_set_config( win, {
relative = 'editor',
width = width,
height = 1,
row = screen_pos.row,
col = 0,
} )
local anchor = {
screenpos = { row = screen_pos.row, col = 0 },
cursor = 0,
buf = buf,
win = win,
bufpos = { row = 0, col = 0 },
}
position.set_cmdline_anchor( anchor )
vim.g.ui_cmdline_pos = { anchor.screenpos.row, anchor.screenpos.col }
end
if fmt_changed then
vim.wo[win].winhighlight = format.winhighlight( fmt.type, 'NormalFloat' )
end
vim.api.nvim_buf_set_lines( buf, 0, -1, false, { display_text } )
apply_icon( buf, fmt )
highlight.apply( buf, hl_ns, text, fmt.lang, 0, 2 )
if fmt.type == 'input' and prompt and prompt ~= '' then
vim.api.nvim_buf_clear_namespace( buf, prompt_ns, 0, -1 )
local max_prompt_width = math.floor( vim.o.columns * format.PROMPT_MAX_RATIO )
local prompt_is_single_line = not prompt:match '\n'
local prompt_fits = vim.fn.strdisplaywidth( prompt ) <= max_prompt_width
if prompt_is_single_line and prompt_fits then
local title_text = ' ' .. prompt .. ' '
vim.api.nvim_win_set_config( win, {
border = vim.g.border_style,
title = { { title_text, 'CmdlineBorderInput' } },
title_pos = 'left',
} )
else
local prompt_chunks = format.prompt_lines( prompt, max_prompt_width )
local virt_line_tuples = {}
for _, chunk in ipairs( prompt_chunks ) do
vim.notify( 'adding prompt chunk', chunk )
table.insert( virt_line_tuples, { { chunk, 'NormalFloat' } } )
end
vim.api.nvim_buf_set_extmark( buf, prompt_ns, 0, 0, {
virt_lines = virt_line_tuples,
virt_lines_above = true,
} )
vim.api.nvim_win_set_config( win, {
border = vim.g.border_style,
title = { { ' ', 'Normal' } },
title_pos = 'left',
height = #prompt_chunks + 1,
} )
end
end
local cursor_byte = cmdline_state:cursor_byte()
local cursor_col = 2 + cursor_byte
local anchor = position.get_cmdline_anchor()
if anchor then
anchor.cursor = cursor_col
anchor.bufpos.col = cursor_col
position.set_cmdline_anchor( anchor )
end
cursor.fix( win, cursor_col )
end
local function hide()
if vim.api.nvim_win_is_valid( state.window ) then
vim.api.nvim_buf_clear_namespace( state.buffer, prompt_ns, 0, -1 )
vim.api.nvim_win_hide( state.window )
end
state.window = -1
state.current_fmt = nil
state.text = ''
state.firstc = ''
state.prompt = ''
position.set_cmdline_anchor( nil )
vim.g.ui_cmdline_pos = nil
end
local function update_cursor( cmdline_state )
if not vim.api.nvim_win_is_valid( state.window ) then
return
end
local cursor_byte = cmdline_state:cursor_byte()
local cursor_col = 2 + cursor_byte
local anchor = position.get_cmdline_anchor()
if anchor then
anchor.cursor = cursor_col
position.set_cmdline_anchor( anchor )
end
cursor.fix( state.window, cursor_col )
end
local function get_format_type()
return state.current_fmt and state.current_fmt.type or 'cmdline'
end
local function get_text()
return state.text
end
return {
show = show,
hide = hide,
update_cursor = update_cursor,
get_format_type = get_format_type,
get_text = get_text,
}