-
Notifications
You must be signed in to change notification settings - Fork 69
Expand file tree
/
Copy pathinline_input.lua
More file actions
134 lines (118 loc) · 3.46 KB
/
Copy pathinline_input.lua
File metadata and controls
134 lines (118 loc) · 3.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
local M = {}
---@type string|nil
local saved_text = nil
---@class InlineInputOpts
---@field win integer -- window to anchor against
---@field row integer -- 0-indexed row in that window's buffer
---@field col integer -- 0-indexed col in that window's buffer
---@field min_width? integer
---@field max_width? integer
---@field title? string -- window border title
---@field on_submit fun(text: string)
---@field on_cancel fun()
---Open a floating, prompt-buffer-backed text input anchored at a specific
---(row, col) inside an existing window's buffer, so it visually appears
---"inline" at that position rather than as a separate cmdline prompt.
---@param opts InlineInputOpts
---@return { close: fun(), win: integer, buf: integer }
function M.open(opts)
local min_width = opts.min_width or 50
local max_width = opts.max_width or 75
local buf = vim.api.nvim_create_buf(false, true)
vim.bo[buf].buftype = 'prompt'
vim.bo[buf].bufhidden = 'wipe'
vim.fn.prompt_setprompt(buf, '')
if saved_text and saved_text ~= '' then
vim.api.nvim_buf_set_lines(buf, 0, 1, false, { saved_text })
saved_text = nil
end
local win = vim.api.nvim_open_win(buf, true, {
relative = 'win',
win = opts.win,
bufpos = { opts.row, opts.col },
width = min_width,
height = 1,
style = 'minimal',
border = 'rounded',
title = opts.title and (' ' .. opts.title .. ' ') or nil,
title_pos = 'left',
zindex = 60,
})
local closed = false
local function close()
if closed then
return
end
closed = true
if vim.api.nvim_win_is_valid(win) then
vim.api.nvim_win_close(win, true)
end
if vim.api.nvim_win_is_valid(opts.win) then
vim.api.nvim_set_current_win(opts.win)
end
end
vim.fn.prompt_setcallback(buf, function(text)
close()
if text ~= '' then
saved_text = nil
opts.on_submit(text)
else
opts.on_cancel()
end
end)
vim.keymap.set('i', '<C-c>', function()
saved_text = nil
close()
opts.on_cancel()
end, { buffer = buf, silent = true, nowait = true })
vim.keymap.set('n', '<Esc>', function()
saved_text = nil
close()
opts.on_cancel()
end, { buffer = buf, silent = true, nowait = true })
vim.api.nvim_create_autocmd('TextChangedI', {
buffer = buf,
callback = function()
if not vim.api.nvim_win_is_valid(win) then
return
end
local line = vim.api.nvim_buf_get_lines(buf, 0, 1, false)[1] or ''
local width = math.min(max_width, math.max(min_width, vim.fn.strdisplaywidth(line) + 2))
vim.api.nvim_win_set_config(win, { width = width })
end,
})
vim.api.nvim_create_autocmd('WinClosed', {
pattern = tostring(win),
callback = function()
if closed then
return
end
closed = true
if vim.api.nvim_win_is_valid(opts.win) then
vim.api.nvim_set_current_win(opts.win)
end
opts.on_cancel()
end,
})
vim.api.nvim_create_autocmd('WinLeave', {
buffer = buf,
callback = function()
if not closed then
local line = vim.api.nvim_buf_get_lines(buf, 0, 1, false)[1] or ''
if line ~= '' then
saved_text = line
end
close()
opts.on_cancel()
end
end,
})
vim.schedule(function()
if vim.api.nvim_win_is_valid(win) then
vim.api.nvim_set_current_win(win)
vim.cmd.startinsert()
end
end)
return { close = close, win = win, buf = buf }
end
return M