-
Notifications
You must be signed in to change notification settings - Fork 32
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(input): opening input while existing input is open
- Loading branch information
Showing
2 changed files
with
112 additions
and
88 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,97 +1,121 @@ | ||
local global_config = require("dressing.config") | ||
local util = require("dressing.util") | ||
local M = {} | ||
|
||
local function clear_callbacks() | ||
_G.dressing_prompt_confirm = function() end | ||
_G.dressing_prompt_hl = function() end | ||
end | ||
|
||
clear_callbacks() | ||
local context = { | ||
opts = nil, | ||
on_confirm = nil, | ||
winid = nil, | ||
} | ||
|
||
return function(opts, on_confirm) | ||
vim.validate({ | ||
on_confirm = { on_confirm, "function", false }, | ||
}) | ||
M.confirm = function(text) | ||
if not context.on_confirm then | ||
return | ||
end | ||
local ctx = context | ||
context = {} | ||
vim.api.nvim_win_close(ctx.winid, true) | ||
vim.cmd("stopinsert") | ||
-- stopinsert will move the cursor back 1. We need to move it forward 1 to | ||
-- put it in the place you were when you opened the modal. | ||
local cursor = vim.api.nvim_win_get_cursor(0) | ||
cursor[2] = cursor[2] + 1 | ||
vim.api.nvim_win_set_cursor(0, cursor) | ||
vim.schedule_wrap(ctx.on_confirm)(text) | ||
end | ||
|
||
opts = opts or {} | ||
if type(opts) ~= "table" then | ||
opts = { prompt = tostring(opts) } | ||
M.highlight = function() | ||
if not context.opts or not context.opts.highlight then | ||
return | ||
end | ||
local config = global_config.get_mod_config("input", opts) | ||
local bufnr = vim.api.nvim_win_get_buf(context.winid) | ||
local opts = context.opts | ||
local text = vim.api.nvim_buf_get_lines(bufnr, 0, 1, true)[1] | ||
local ns = vim.api.nvim_create_namespace("DressingHl") | ||
local highlights | ||
if type(opts.highlight) == "function" then | ||
highlights = opts.highlight(text) | ||
else | ||
highlights = vim.fn[opts.highlight](text) | ||
end | ||
vim.api.nvim_buf_clear_namespace(bufnr, ns, 0, -1) | ||
for _, highlight in ipairs(highlights) do | ||
local start = highlight[1] | ||
local stop = highlight[2] | ||
local group = highlight[3] | ||
vim.api.nvim_buf_add_highlight(bufnr, ns, group, 0, start, stop) | ||
end | ||
end | ||
|
||
local start_in_insert = vim.api.nvim_get_mode().mode == "i" | ||
local bufnr = vim.api.nvim_create_buf(false, true) | ||
local prompt = opts.prompt or config.default_prompt | ||
local width = util.calculate_width(config.prefer_width + vim.api.nvim_strwidth(prompt), config) | ||
local winopt = { | ||
relative = config.relative, | ||
anchor = config.anchor, | ||
row = config.row, | ||
col = config.col, | ||
border = config.border, | ||
width = width, | ||
height = 1, | ||
zindex = 150, | ||
style = "minimal", | ||
} | ||
local winnr = vim.api.nvim_open_win(bufnr, true, winopt) | ||
vim.api.nvim_buf_set_option(bufnr, "buftype", "prompt") | ||
vim.api.nvim_buf_set_option(bufnr, "swapfile", false) | ||
vim.api.nvim_buf_set_option(bufnr, "bufhidden", "wipe") | ||
local keyopts = { silent = true, noremap = true } | ||
vim.api.nvim_buf_set_keymap( | ||
bufnr, | ||
"i", | ||
"<Esc>", | ||
"<cmd>lua dressing_prompt_confirm()<CR>", | ||
keyopts | ||
) | ||
vim.fn.prompt_setprompt(bufnr, prompt) | ||
-- Would prefer to use v:lua directly here, but it doesn't work :( | ||
vim.fn.prompt_setcallback(bufnr, "dressing#prompt_confirm") | ||
vim.fn.prompt_setinterrupt(bufnr, "dressing#prompt_cancel") | ||
_G.dressing_prompt_confirm = function(text) | ||
clear_callbacks() | ||
vim.api.nvim_win_close(winnr, true) | ||
if not start_in_insert then | ||
vim.cmd("stopinsert") | ||
-- stopinsert will move the cursor back 1. We need to move it forward 1 to | ||
-- put it in the place you were when you opened the modal. | ||
local cursor = vim.api.nvim_win_get_cursor(0) | ||
cursor[2] = cursor[2] + 1 | ||
vim.api.nvim_win_set_cursor(0, cursor) | ||
setmetatable(M, { | ||
__call = function(_, opts, on_confirm) | ||
vim.validate({ | ||
on_confirm = { on_confirm, "function", false }, | ||
}) | ||
opts = opts or {} | ||
if type(opts) ~= "table" then | ||
opts = { prompt = tostring(opts) } | ||
end | ||
vim.schedule_wrap(on_confirm)(text) | ||
end | ||
if opts.highlight then | ||
_G.dressing_prompt_hl = function() | ||
local text = vim.api.nvim_buf_get_lines(bufnr, 0, 1, true)[1] | ||
local ns = vim.api.nvim_create_namespace("DressingHl") | ||
local highlights | ||
if type(opts.highlight) == "function" then | ||
highlights = opts.highlight(text) | ||
else | ||
highlights = vim.fn[opts.highlight](text) | ||
end | ||
vim.api.nvim_buf_clear_namespace(bufnr, ns, 0, -1) | ||
for _, highlight in ipairs(highlights) do | ||
local start = highlight[1] | ||
local stop = highlight[2] | ||
local group = highlight[3] | ||
vim.api.nvim_buf_add_highlight(bufnr, ns, group, 0, start, stop) | ||
end | ||
local config = global_config.get_mod_config("input", opts) | ||
|
||
local bufnr = vim.api.nvim_create_buf(false, true) | ||
local prompt = opts.prompt or config.default_prompt | ||
local width = util.calculate_width(config.prefer_width + vim.api.nvim_strwidth(prompt), config) | ||
local winopt = { | ||
relative = config.relative, | ||
anchor = config.anchor, | ||
row = config.row, | ||
col = config.col, | ||
border = config.border, | ||
width = width, | ||
height = 1, | ||
zindex = 150, | ||
style = "minimal", | ||
} | ||
local winnr | ||
if context.winid and vim.api.nvim_win_is_valid(context.winid) then | ||
winnr = context.winid | ||
vim.schedule(context.on_confirm) | ||
vim.api.nvim_win_set_width(winnr, width) | ||
bufnr = vim.api.nvim_win_get_buf(winnr) | ||
else | ||
winnr = vim.api.nvim_open_win(bufnr, true, winopt) | ||
end | ||
context = { | ||
winid = winnr, | ||
on_confirm = on_confirm, | ||
opts = opts, | ||
} | ||
vim.api.nvim_buf_set_option(bufnr, "buftype", "prompt") | ||
vim.api.nvim_buf_set_option(bufnr, "swapfile", false) | ||
vim.api.nvim_buf_set_option(bufnr, "bufhidden", "wipe") | ||
local keyopts = { silent = true, noremap = true } | ||
vim.api.nvim_buf_set_keymap( | ||
bufnr, | ||
"i", | ||
"<Esc>", | ||
"<cmd>lua require('dressing.input').confirm()<CR>", | ||
keyopts | ||
) | ||
vim.fn.prompt_setprompt(bufnr, prompt) | ||
-- Would prefer to use v:lua directly here, but it doesn't work :( | ||
vim.fn.prompt_setcallback(bufnr, "dressing#prompt_confirm") | ||
vim.fn.prompt_setinterrupt(bufnr, "dressing#prompt_cancel") | ||
if opts.highlight then | ||
vim.cmd([[ | ||
autocmd TextChanged <buffer> lua require('dressing.input').highlight() | ||
autocmd TextChangedI <buffer> lua require('dressing.input').highlight() | ||
]]) | ||
end | ||
vim.cmd([[ | ||
autocmd TextChanged <buffer> lua dressing_prompt_hl() | ||
autocmd TextChangedI <buffer> lua dressing_prompt_hl() | ||
autocmd BufLeave <buffer> ++nested ++once lua require('dressing.input').confirm() | ||
]]) | ||
end | ||
vim.cmd([[ | ||
autocmd BufLeave <buffer> ++nested ++once lua dressing_prompt_confirm() | ||
]]) | ||
vim.cmd("startinsert!") | ||
if opts.default then | ||
vim.api.nvim_feedkeys(opts.default, "n", false) | ||
end | ||
_G.dressing_prompt_hl() | ||
end | ||
vim.cmd("startinsert!") | ||
if opts.default then | ||
vim.api.nvim_feedkeys(opts.default, "n", false) | ||
end | ||
M.highlight() | ||
end, | ||
}) | ||
|
||
return M |