Skip to content

Commit

Permalink
Allow commands to be input from a floating window
Browse files Browse the repository at this point in the history
This adds a new `command_floating_window` option. When set to true, gp
will use a floating window + scratch buffer to read the command. The
map to accept the input is the same as the one to send a message in the
chat window (ctrl+g, ctrl+g by default).
  • Loading branch information
tarruda committed Dec 20, 2024
1 parent 2372d53 commit 3dd1809
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 4 deletions.
2 changes: 2 additions & 0 deletions lua/gp/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,8 @@ local config = {
-- auto select command response (easier chaining of commands)
-- if false it also frees up the buffer cursor for further editing elsewhere
command_auto_select_response = true,
-- if enabled, will use a floating window + scratch buffer for reading user command
command_floating_window = false,

-- templates
template_selection = "I have the following from {{filename}}:"
Expand Down
67 changes: 67 additions & 0 deletions lua/gp/helper.lua
Original file line number Diff line number Diff line change
Expand Up @@ -293,4 +293,71 @@ _H.create_user_command = function(cmd_name, cmd_func, completion, desc)
})
end

_H.floating_input = function(opts, cb)
if not opts.accept_shortcut or not opts.accept_modes then
error('accept_shortcut and accept_modes must be provided for floating_input()')
end

-- Create a scratch buffer
local buf = vim.api.nvim_create_buf(false, true)

-- Set buffer options
vim.api.nvim_buf_set_option(buf, 'bufhidden', 'wipe')
vim.api.nvim_buf_set_option(buf, 'buftype', 'nofile')

-- Calculate window size and position
local width = opts.width or math.floor(vim.api.nvim_win_get_width(0) / 2)
local height = opts.height or math.floor(vim.api.nvim_win_get_height(0) / 2)
local win_opts = {
relative = 'editor',
width = width,
height = height,
col = math.floor((vim.o.columns - width) / 2),
row = math.floor((vim.o.lines - height) / 2),
style = 'minimal',
border = 'rounded'
}

-- Create window
local win = vim.api.nvim_open_win(buf, true, win_opts)

-- Add title if prompt is provided
if opts.prompt then
vim.api.nvim_win_set_option(win, 'winhl', 'Normal:Normal')
vim.api.nvim_buf_set_lines(buf, 0, -1, false, {opts.prompt, ""})
vim.api.nvim_win_set_cursor(win, {2, 0})
end

-- Set default content if provided
if opts.default and opts.default ~= "" then
vim.api.nvim_buf_set_lines(buf, -1, -1, false, {opts.default})
end

-- Set up the key mapping to accept the input
vim.keymap.set(opts.accept_modes, opts.accept_shortcut, function()
-- Get buffer content
local lines = vim.api.nvim_buf_get_lines(buf, 0, -1, false)

-- Remove prompt and empty line if they exist
if opts.prompt and lines[1] == opts.prompt then
table.remove(lines, 1) -- Remove prompt line
if lines[1] == "" then
table.remove(lines, 1) -- Remove empty line after prompt
end
end

local content = table.concat(lines, '\n')

-- Close the window
vim.api.nvim_win_close(win, true)

-- Invoke the callback with the content
cb(content)
end, { buffer = buf, nowait = true })

vim.schedule(function()
vim.api.nvim_command("startinsert")
end)
end

return _H
18 changes: 14 additions & 4 deletions lua/gp/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1485,7 +1485,6 @@ end
--------------------------------------------------------------------------------
-- Prompt logic
--------------------------------------------------------------------------------

M.cmd.Agent = function(params)
local agent_name = string.gsub(params.args, "^%s*(.-)%s*$", "%1")
if agent_name == "" then
Expand Down Expand Up @@ -1952,13 +1951,24 @@ M.Prompt = function(params, target, agent, template, prompt, whisper, callback)
return
end

-- if prompt is provided, ask the user to enter the command
vim.ui.input({ prompt = prompt, default = whisper }, function(input)
local function input_callback(input)
if not input or input == "" then
return
end
cb(input)
end)
end

-- if prompt is provided, ask the user to enter the command
if M.config.command_floating_window then
M.helpers.floating_input({
prompt = prompt,
default = whisper,
accept_shortcut = M.config.chat_shortcut_respond.shortcut,
accept_modes = M.config.chat_shortcut_respond.modes
}, input_callback)
else
vim.ui.input({ prompt = prompt, default = whisper }, input_callback)
end
end)
end

Expand Down

0 comments on commit 3dd1809

Please sign in to comment.