Meh I'll figure out submodules later

This commit is contained in:
mustard 2025-09-16 01:01:02 +02:00
parent 4ca9d44a90
commit 8cb281f436
352 changed files with 66107 additions and 0 deletions

View file

@ -0,0 +1,114 @@
# Input
Input is an abstraction layer on top of Popup.
It uses prompt buffer (check `:h prompt-buffer`) for its popup window.
```lua
local Input = require("nui.input")
local event = require("nui.utils.autocmd").event
local popup_options = {
relative = "cursor",
position = {
row = 1,
col = 0,
},
size = 20,
border = {
style = "rounded",
text = {
top = "[Input]",
top_align = "left",
},
},
win_options = {
winhighlight = "Normal:Normal",
},
}
local input = Input(popup_options, {
prompt = "> ",
default_value = "42",
on_close = function()
print("Input closed!")
end,
on_submit = function(value)
print("Value submitted: ", value)
end,
on_change = function(value)
print("Value changed: ", value)
end,
})
```
If you provide the `on_change` function, it'll be run everytime value changes.
Pressing `<CR>` runs the `on_submit` callback function and closes the window.
Pressing `<C-c>` runs the `on_close` callback function and closes the window.
Of course, you can override the default keymaps and add more. For example:
```lua
-- unmount input by pressing `<Esc>` in normal mode
input:map("n", "<Esc>", function()
input:unmount()
end, { noremap = true })
```
You can manipulate the associated buffer and window using the
`input.bufnr` and `input.winid` properties.
**NOTE**: the first argument accepts options for `nui.popup` component.
## Options
### `prompt`
**Type:** `string` or `NuiText`
Prefix in the input.
### `default_value`
**Type:** `string`
Default value placed in the input on mount
### `on_close`
**Type:** `function`
_Signature:_ `on_close() -> nil`
Callback function, called when input is closed.
### `on_submit`
**Type:** `function`
_Signature:_ `on_submit(value: string) -> nil`
Callback function, called when input value is submitted.
### `on_change`
**Type:** `function`
_Signature:_ `on_change(value: string) -> nil`
Callback function, called when input value is changed.
### `disable_cursor_position_patch`
By default, `nui.input` will try to make sure the cursor on parent window is not
moved after input is submitted/closed. If you want to disable this behavior
for some reason, you can set `disable_cursor_position_patch` to `true`.
## Methods
Methods from `nui.popup` are also available for `nui.input`.
## Wiki Page
You can find additional documentation/examples/guides/tips-n-tricks in [nui.input wiki page](https://github.com/MunifTanjim/nui.nvim/wiki/nui.input).

View file

@ -0,0 +1,174 @@
local Popup = require("nui.popup")
local Text = require("nui.text")
local defaults = require("nui.utils").defaults
local is_type = require("nui.utils").is_type
local event = require("nui.utils.autocmd").event
-- exiting insert mode places cursor one character backward,
-- so patch the cursor position to one character forward
-- when unmounting input.
---@param target_cursor number[]
---@param force? boolean
local function patch_cursor_position(target_cursor, force)
local cursor = vim.api.nvim_win_get_cursor(0)
if target_cursor[2] == cursor[2] and force then
-- didn't exit insert mode yet, but it's gonna
vim.api.nvim_win_set_cursor(0, { cursor[1], cursor[2] + 1 })
elseif target_cursor[2] - 1 == cursor[2] then
-- already exited insert mode
vim.api.nvim_win_set_cursor(0, { cursor[1], cursor[2] + 1 })
end
end
---@class nui_input_options
---@field prompt? string|NuiText
---@field default_value? string
---@field on_change? fun(value: string): nil
---@field on_close? fun(): nil
---@field on_submit? fun(value: string): nil
---@class nui_input_internal: nui_popup_internal
---@field default_value string
---@field prompt NuiText
---@field disable_cursor_position_patch boolean
---@field on_change? fun(value: string): nil
---@field on_close fun(): nil
---@field on_submit fun(value: string): nil
---@field pending_submit_value? string
---@class NuiInput: NuiPopup
---@field private _ nui_input_internal
local Input = Popup:extend("NuiInput")
---@param popup_options nui_popup_options
---@param options nui_input_options
function Input:init(popup_options, options)
popup_options.enter = false
popup_options.buf_options = defaults(popup_options.buf_options, {})
popup_options.buf_options.buftype = "prompt"
if not is_type("table", popup_options.size) then
popup_options.size = {
width = popup_options.size,
}
end
popup_options.size.height = 1
Input.super.init(self, popup_options)
self._.default_value = defaults(options.default_value, "")
self._.prompt = Text(defaults(options.prompt, ""))
self._.disable_cursor_position_patch = defaults(options.disable_cursor_position_patch, false)
self.input_props = {}
self._.on_change = options.on_change
self._.on_close = options.on_close or function() end
self._.on_submit = options.on_submit or function() end
end
function Input:mount()
local props = self.input_props
if self._.mounted then
return
end
vim.fn.prompt_setprompt(self.bufnr, self._.prompt:content())
vim.api.nvim_buf_set_lines(self.bufnr, 0, -1, false, { self._.prompt:content() .. self._.default_value })
self:on(event.BufWinEnter, function()
vim.schedule(function()
if self._.prompt:length() > 0 then
self._.prompt:highlight(self.bufnr, self.ns_id, 1, 0)
end
vim.api.nvim_set_current_win(self.winid)
end)
vim.api.nvim_command("startinsert!")
end, { once = false })
Input.super.mount(self)
if self._.on_change then
---@deprecated
props.on_change = function()
local value_with_prompt = vim.api.nvim_buf_get_lines(self.bufnr, 0, 1, false)[1]
local value = string.sub(value_with_prompt, self._.prompt:length() + 1)
self._.on_change(value)
end
vim.api.nvim_buf_attach(self.bufnr, false, {
on_lines = props.on_change,
})
end
---@deprecated
props.on_submit = function(value)
self._.pending_submit_value = value
self:unmount()
end
vim.fn.prompt_setcallback(self.bufnr, props.on_submit)
-- @deprecated
--- Use `input:unmount`
---@deprecated
props.on_close = function()
self:unmount()
end
vim.fn.prompt_setinterrupt(self.bufnr, props.on_close)
end
function Input:unmount()
if not self._.mounted then
return
end
local container_winid = self._.container_info.winid
local target_cursor = vim.api.nvim_win_is_valid(container_winid) and vim.api.nvim_win_get_cursor(container_winid)
or nil
local prompt_mode = vim.fn.mode()
Input.super.unmount(self)
if self._.loading then
return
end
self._.loading = true
local pending_submit_value = self._.pending_submit_value
vim.schedule(function()
-- NOTE: on prompt-buffer normal mode <CR> causes neovim to enter insert mode.
-- ref: https://github.com/neovim/neovim/blob/d8f5f4d09078/src/nvim/normal.c#L5327-L5333
if (pending_submit_value and prompt_mode == "n") or prompt_mode == "i" then
vim.api.nvim_command("stopinsert")
end
if not self._.disable_cursor_position_patch and target_cursor ~= nil then
patch_cursor_position(target_cursor, pending_submit_value and prompt_mode == "n")
end
if pending_submit_value then
self._.pending_submit_value = nil
self._.on_submit(pending_submit_value)
else
self._.on_close()
end
self._.loading = false
end)
end
---@alias NuiInput.constructor fun(popup_options: nui_popup_options, options: nui_input_options): NuiInput
---@type NuiInput|NuiInput.constructor
local NuiInput = Input
return NuiInput