feat: keymaps window instead of help line

This commit is contained in:
2026-04-06 01:18:25 +03:00
parent 0424bdf633
commit 1363f6bdcc
5 changed files with 369 additions and 108 deletions

182
README.md
View File

@@ -1,9 +1,8 @@
# input-form.nvim
A small Neovim plugin for building bordered, keyboard-navigable **forms** in a
floating window. Create a single window containing multiple typed inputs
(single-line text, multiline text, select dropdowns), collect results via an
`on_submit` callback.
A small Neovim plugin for building bordered, keyboard-navigable **forms** in a floating window.
Create a single window containing multiple typed inputs (single-line text, multiline text, select
dropdowns, checkboxes), collect results via an `on_submit` callback.
![input form example](/input-form.gif)
@@ -11,13 +10,17 @@ floating window. Create a single window containing multiple typed inputs
- Bordered floating window with optional title
- Keyboard-navigable: `<Tab>` / `<S-Tab>` to move between inputs
- Input types: `text`, `multiline`, `select`, `checkbox`
- Input types: `text`, `multiline`, `select`, `checkbox`, plus `spacer` (visual-only gap between
fields)
- Select dropdowns open with `<CR>`; arrows navigate; `<CR>` confirms
- Checkbox toggles with `<Space>` or `<CR>`
- Submit with `<C-s>` — results delivered as a `{ [name] = value }` table
- Cancel with `<Esc>`
- Cancel with `<Esc>` or `q`
- Built-in toggleable help popup (`?`) listing every active keymap — updates automatically when you
remap keys
- Lazy: `create_form` builds the form; `:show()` renders it when you want
- `:hide()` / `:show()` re-open a form while preserving in-progress values
- Fully configurable keymaps, border, width, title
- Fully configurable keymaps (strings or lists), border, width, title
- Auto-generated help doc (`:h input-form`)
- Tested with `mini.test`
@@ -83,9 +86,8 @@ local form = f.create_form({
form:show()
```
`create_form` returns a form object. Nothing is rendered until you call
`form:show()`. This lets you construct the form in one place and open it from a
keymap, autocommand, or anywhere else:
`create_form` returns a form object. Nothing is rendered until you call `form:show()`. This lets you
construct the form in one place and open it from a keymap, autocommand, or anywhere else:
```lua
vim.keymap.set("n", "<leader>xf", function()
@@ -96,7 +98,7 @@ end)
### Form methods
| Method | Description |
| -------------- | ---------------------------------------------------------------- |
| ---------------- | ---------------------------------------------------------------------- |
| `form:show()` | Open the form. No-op if already visible. |
| `form:hide()` | Close windows but keep values so `:show()` resumes where you left off. |
| `form:close()` | Permanently tear down the form. |
@@ -106,8 +108,8 @@ end)
### Input spec reference
All inputs share `name` (string, required — the key in the result table) and
`label` (string, shown above the field).
Most inputs share `name` (string, required — the key in the result table) and `label` (string, shown
above the field). `spacer` is the only exception: it's visual-only and needs no `name`.
#### `text`
@@ -121,8 +123,7 @@ All inputs share `name` (string, required — the key in the result table) and
{ name = "body", label = "Notes", type = "multiline", default = "", height = 5 }
```
- `height` (optional) — number of rows for the input; falls back to
`config.multiline.height`.
- `height` (optional) — number of rows for the input; falls back to `config.multiline.height`.
#### `select`
@@ -147,9 +148,8 @@ All inputs share `name` (string, required — the key in the result table) and
{ name = "agree", label = "I agree", type = "checkbox", default = false }
```
Unlike text/multiline/select, checkboxes render **inline** — no border, no
separate label row. The glyph sits immediately next to the label, and any
validation error is appended on the same line:
Unlike text/multiline/select, checkboxes render **inline** — no border, no separate label row. The
glyph sits immediately next to the label, and any validation error is appended on the same line:
```
☐ I agree (must be checked)
@@ -157,13 +157,34 @@ validation error is appended on the same line:
- `default` (optional) — boolean (defaults to `false`).
- `value()` returns a boolean.
- Toggled with the configured `keymaps.toggle` key (default `<Space>`) or
the `keymaps.open_select` key (default `<CR>`) — both work so users get
a consistent "interact with this field" key.
- Glyphs come from `style.checkbox.{checked, unchecked}` (defaults
`"☑"` / `"☐"`).
- Pair with `validators.checked()` to require the box to be ticked (see
[Validation](#validation)).
- Toggled with the configured `keymaps.toggle` key (default `<Space>`) or the `keymaps.open_select`
key (default `<CR>`) — both work so users get a consistent "interact with this field" key.
- Glyphs come from `style.checkbox.{checked, unchecked}` (defaults `"☑"` / `"☐"`).
- A blank row is rendered above and below each checkbox to visually separate it from adjacent
bordered inputs. Tune via `style.checkbox.padding` (default `1`, set to `0` to pack tight).
- Pair with `validators.checked()` to require the box to be ticked (see [Validation](#validation)).
#### `spacer`
```lua
{ type = "spacer" } -- 1 blank row
{ type = "spacer", height = 2 } -- 2 blank rows
```
A visual-only faux input that reserves blank rows in the layout. It has no window, no focus, no
validator, and never appears in `results()`. Use it to group related inputs visually:
```lua
inputs = {
{ name = "first", label = "First name", type = "text" },
{ name = "last", label = "Last name", type = "text" },
{ type = "spacer" },
{ name = "email", label = "Email", type = "text" },
}
```
- `height` (optional) — number of blank rows (default `1`).
- `<Tab>` / `<S-Tab>` skip over spacers automatically.
## Validation
@@ -173,16 +194,15 @@ Each input spec accepts an optional `validator` function:
validator = fun(value: any): string|nil
```
Return a non-empty error message string to mark the input invalid, or `nil` /
`""` when valid. The error message is shown in the input's bottom border
(red), and the border + label turn red too. Validation runs:
Return a non-empty error message string to mark the input invalid, or `nil` / `""` when valid. The
error message is shown in the input's bottom border (red), and the border + label turn red too.
Validation runs:
- **On blur** — the first time the user leaves the field it is marked
"touched" and the validator runs. Nothing is shown before that.
- **On blur** — the first time the user leaves the field it is marked "touched" and the validator
runs. Nothing is shown before that.
- **On change** — once touched, each buffer change re-runs the validator.
- **On submit** — `form:submit()` force-validates every input (touched or
not). If any input has an error, submission is blocked, all errors are
rendered, and focus moves to the first invalid input.
- **On submit** — `form:submit()` force-validates every input (touched or not). If any input has an
error, submission is blocked, all errors are rendered, and focus moves to the first invalid input.
### Built-in validators
@@ -234,8 +254,8 @@ f.create_form({
}):show()
```
Custom validators are just functions — no need to use the builder helpers if
you'd rather write one inline:
Custom validators are just functions — no need to use the builder helpers if you'd rather write one
inline:
```lua
validator = function(value)
@@ -245,7 +265,7 @@ validator = function(value)
end
```
### Checkbox glyphs
### Checkbox glyphs and padding
Override the characters rendered by `checkbox` inputs via `style.checkbox`:
@@ -255,18 +275,30 @@ require("input-form").setup({
checkbox = {
checked = "☑", -- default
unchecked = "☐", -- default
padding = 1, -- default: blank rows above/below each checkbox
},
},
})
```
Alternatives that render well in most fonts: `[x]` / `[ ]`, `✔` / `·`,
`●` / `○`.
Alternatives that render well in most fonts: `[x]` / `[ ]`, `✔` / `·`, `●` / `○`. Set `padding = 0`
to pack checkboxes flush against adjacent bordered inputs.
### Help popup
The form's bottom border shows a compact `? help` hint on the right. Press `?` (configurable via
`keymaps.help`) to toggle a floating popup below the form that lists **every active keymap** — it
reads from `config.keymaps` at render time, so if you remap `submit` to `<C-Enter>` the popup
reflects that automatically. The popup matches the form's width, wraps long descriptions, and flips
above the form if it would overflow the editor bottom. It only lists keys relevant to the current
form (e.g. `toggle checkbox` only appears when a checkbox is present).
Set `keymaps.help = false` to disable both the popup and the footer hint.
### Select chevrons
The glyphs shown on the right side of `select` inputs to indicate the
dropdown state are configurable under `style.chevron`:
The glyphs shown on the right side of `select` inputs to indicate the dropdown state are
configurable under `style.chevron`:
```lua
require("input-form").setup({
@@ -279,22 +311,19 @@ require("input-form").setup({
})
```
Use whatever you like — e.g. ASCII fallbacks for terminals without good
Unicode support:
Use whatever you like — e.g. ASCII fallbacks for terminals without good Unicode support:
```lua
style = { chevron = { closed = " v", open = " ^" } }
```
A leading space is recommended so the glyph doesn't sit flush against the
label.
A leading space is recommended so the glyph doesn't sit flush against the label.
### Highlight groups
All highlight groups the plugin uses are listed under `style.highlights` in
the config and can be overridden via `setup()`. Each entry is passed directly
to `vim.api.nvim_set_hl(0, name, spec)`, so anything `nvim_set_hl` accepts
works (`fg`, `bg`, `link`, `bold`, `italic`, `default`, etc.).
All highlight groups the plugin uses are listed under `style.highlights` in the config and can be
overridden via `setup()`. Each entry is passed directly to `vim.api.nvim_set_hl(0, name, spec)`, so
anything `nvim_set_hl` accepts works (`fg`, `bg`, `link`, `bold`, `italic`, `default`, etc.).
```lua
require("input-form").setup({
@@ -320,7 +349,7 @@ Available groups:
| `InputFormNormal` | Parent form window background |
| `InputFormBorder` | Parent form border |
| `InputFormTitle` | Parent form title |
| `InputFormHelp` | Footer help line (key hints) |
| `InputFormHelp` | Footer `? help` hint on the form border |
| `InputFormField` | Individual input field background |
| `InputFormFieldBorder` | Individual input field border |
| `InputFormFieldTitle` | Individual input field label (on top border) |
@@ -330,11 +359,10 @@ Available groups:
| `InputFormDropdown` | Select dropdown background |
| `InputFormDropdownActive` | Highlighted dropdown row |
User overrides fully **replace** the default spec per group (they are not
deep-merged at the field level), so you don't need to re-specify
`default = true`. Highlights are re-applied on every `form:show()`, so a
`setup({ style = { highlights = ... } })` call that happens after the first
form has been rendered still takes effect on the next open.
User overrides fully **replace** the default spec per group (they are not deep-merged at the field
level), so you don't need to re-specify `default = true`. Highlights are re-applied on every
`form:show()`, so a `setup({ style = { highlights = ... } })` call that happens after the first form
has been rendered still takes effect on the next open.
## Configuration
@@ -352,12 +380,15 @@ require("input-form").setup({
gap = 0, -- blank rows between adjacent inputs
},
keymaps = {
-- Every keymap accepts either a single key string or a list of keys.
-- Set any value to `false` to disable.
next = "<Tab>",
prev = "<S-Tab>",
submit = "<C-s>",
cancel = "<Esc>",
cancel = { "<Esc>", "q" }, -- list form: both keys cancel the form
open_select = "<CR>",
toggle = "<Space>",
help = "?", -- toggle the help popup (set `false` to hide)
},
select = {
max_height = 10,
@@ -365,6 +396,14 @@ require("input-form").setup({
multiline = {
height = 5,
},
style = {
checkbox = {
checked = "☑",
unchecked = "☐",
padding = 1, -- blank rows above/below each checkbox
},
-- ...chevron, highlights, etc. — see sections above.
},
})
```
@@ -372,8 +411,8 @@ Per-form overrides: pass `title` and/or `width` in the `create_form` spec.
## Help
Help tags are registered automatically on the first `require('input-form')`,
so `setup()` is not required for them either:
Help tags are registered automatically on the first `require('input-form')`, so `setup()` is not
required for them either:
```
:h input-form
@@ -381,8 +420,8 @@ so `setup()` is not required for them either:
## For plugin developers — using input-form.nvim as a dependency
You can depend on `input-form.nvim` from another plugin without forcing your
users to call `setup()`. The module is safe to use immediately after require:
You can depend on `input-form.nvim` from another plugin without forcing your users to call
`setup()`. The module is safe to use immediately after require:
```lua
-- In your plugin's code:
@@ -400,19 +439,18 @@ input_form.create_form({
Key points:
- **No `setup()` required.** Defaults are loaded at module-load time and
`create_form` / `form:show()` work on a bare `require('input-form')`. End
users of your plugin don't need to know input-form.nvim exists.
- **Per-form overrides.** Pass `title`, `width`, `on_cancel`, etc. directly in
the `create_form` spec — no need to mutate global config for one-off tweaks.
- **Baseline config.** If your plugin wants a different baseline (say, a
non-default border style for all forms it opens), call
`require('input-form').setup({ ... })` once during your plugin's own
initialization. This is idempotent and safe to call even if the end user
has already called setup — later calls deep-merge over earlier ones.
- **Respect the user.** Prefer per-form overrides over global `setup()` when
possible so you don't stomp on a user who has configured input-form.nvim
for their own keymaps or other plugins that use it.
- **No `setup()` required.** Defaults are loaded at module-load time and `create_form` /
`form:show()` work on a bare `require('input-form')`. End users of your plugin don't need to know
input-form.nvim exists.
- **Per-form overrides.** Pass `title`, `width`, `on_cancel`, etc. directly in the `create_form`
spec — no need to mutate global config for one-off tweaks.
- **Baseline config.** If your plugin wants a different baseline (say, a non-default border style
for all forms it opens), call `require('input-form').setup({ ... })` once during your plugin's own
initialization. This is idempotent and safe to call even if the end user has already called setup
— later calls deep-merge over earlier ones.
- **Respect the user.** Prefer per-form overrides over global `setup()` when possible so you don't
stomp on a user who has configured input-form.nvim for their own keymaps or other plugins that use
it.
- **Declaring the dep.** With lazy.nvim, add it to your `dependencies`:
```lua
{

View File

@@ -113,12 +113,16 @@ Default configuration for |input-form|.
prev = "<S-Tab>",
--- Submit the form and invoke `on_submit(results)`.
submit = "<C-s>",
--- Cancel the form and invoke `on_cancel()` if provided.
cancel = "<Esc>",
--- Cancel the form and invoke `on_cancel()` if provided. Accepts a
--- single key string or a list of keys — all listed keys trigger cancel.
cancel = { "<Esc>", "q" },
--- Open the dropdown when focused on a `select` input.
open_select = "<CR>",
--- Toggle the value of a `checkbox` input.
toggle = "<Space>",
--- Toggle a help popup listing every active keymap. The popup opens
--- directly below the form window and closes on the same key.
help = "?",
},
--- Options for `select` inputs.
select = {

View File

@@ -37,12 +37,16 @@ M.defaults = {
prev = "<S-Tab>",
--- Submit the form and invoke `on_submit(results)`.
submit = "<C-s>",
--- Cancel the form and invoke `on_cancel()` if provided.
cancel = "<Esc>",
--- Cancel the form and invoke `on_cancel()` if provided. Accepts a
--- single key string or a list of keys — all listed keys trigger cancel.
cancel = { "<Esc>", "q" },
--- Open the dropdown when focused on a `select` input.
open_select = "<CR>",
--- Toggle the value of a `checkbox` input.
toggle = "<Space>",
--- Toggle a help popup listing every active keymap. The popup opens
--- directly below the form window and closes on the same key.
help = "?",
},
--- Options for `select` inputs.
select = {

View File

@@ -50,12 +50,12 @@ function M:_compute_layout()
-- `width` is the parent's OUTER width (i.e. visible width including border).
local outer_width = utils.resolve_width(self._width or opts.window.width)
-- Grow the window to fit the footer help line if the user's configured
-- width is too narrow. The footer string is " <help> " so we need at least
-- #help + 2 (leading/trailing space) + 2 (corners) cells of outer width.
local help = self:_help_line()
if help and help ~= "" then
local needed = vim.fn.strdisplaywidth(help) + 4
-- Grow the window to fit the footer hint if the user's configured width
-- is too narrow. The footer string is " <hint> " so we need at least
-- #hint + 2 (leading/trailing space) + 2 (corners) cells of outer width.
local hint = self:_help_hint()
if hint and hint ~= "" then
local needed = vim.fn.strdisplaywidth(hint) + 4
if outer_width < needed then
outer_width = needed
end
@@ -184,10 +184,10 @@ function M:show()
win_opts.title_pos = config.options.window.title_pos
end
if vim.fn.has("nvim-0.10") == 1 then
local footer = self:_help_line()
local footer = self:_help_hint()
if footer and footer ~= "" then
win_opts.footer = " " .. footer .. " "
win_opts.footer_pos = "center"
win_opts.footer_pos = "right"
end
end
self._parent_win = vim.api.nvim_open_win(self._parent_buf, false, win_opts)
@@ -268,6 +268,7 @@ function M:hide()
if not self._visible then
return
end
self:_close_help()
for _, input in ipairs(self._inputs) do
input:unmount()
end
@@ -475,23 +476,57 @@ function M:_render_validation(input)
end
end
--- Build a help-line string describing the active keymaps.
function M:_help_line()
local km = config.options.keymaps
--- Format a keymap value (string or list of strings) for display. Returns
--- `nil` if the value is effectively empty / disabled.
local function format_keys(val)
if not val or val == false or val == "" then
return nil
end
if type(val) == "table" then
local parts = {}
for _, k in ipairs(val) do
if k and k ~= false and k ~= "" then
table.insert(parts, k)
end
end
if #parts == 0 then
return nil
end
return table.concat(parts, " / ")
end
return tostring(val)
end
--- Short footer hint shown on the form's bottom border (e.g. `"? help"`).
--- Returns `nil` if the help keymap is disabled.
function M:_help_hint()
local key = format_keys(config.options.keymaps.help)
if not key then
return nil
end
return key .. " help"
end
--- Collect `{ keys, description }` pairs for every active keymap, filtered
--- to what this form actually uses. Consumed by the help popup.
function M:_help_entries()
local km = config.options.keymaps
local entries = {}
local function add(keys, desc)
if keys and keys ~= false and keys ~= "" then
table.insert(parts, keys .. " " .. desc)
local display = format_keys(keys)
if display then
table.insert(entries, { display, desc })
end
end
local nxt, prv = format_keys(km.next), format_keys(km.prev)
local nav
if km.next and km.prev then
nav = km.next .. "/" .. km.prev
if nxt and prv then
nav = nxt .. " / " .. prv
else
nav = km.next or km.prev
nav = nxt or prv
end
if nav then
table.insert(parts, nav .. " navigate")
table.insert(entries, { nav, "navigate fields" })
end
-- Only advertise type-specific keys if the form actually has such an input.
local has_select, has_checkbox = false, false
@@ -503,14 +538,180 @@ function M:_help_line()
end
end
if has_select then
add(km.open_select, "open")
add(km.open_select, "open dropdown")
end
if has_checkbox then
add(km.toggle, "toggle")
add(km.toggle, "toggle checkbox")
end
add(km.submit, "submit form")
add(km.cancel, "cancel form")
add(km.help, "toggle this help")
return entries
end
--- Build the wrapped lines of the help popup given a maximum width (the
--- popup's content width). Each keymap occupies its own row formatted as
--- `"<keys> <description>"` with keys right-padded to a common column so
--- descriptions line up. If an entry exceeds `max_w` the description wraps
--- onto a hanging indent.
function M:_help_lines(max_w)
local entries = self:_help_entries()
if #entries == 0 then
return {}
end
-- Cap the key column so a single oversized key doesn't eat the whole row.
local max_key_w = 0
for _, e in ipairs(entries) do
local w = vim.fn.strdisplaywidth(e[1])
if w > max_key_w then
max_key_w = w
end
end
max_key_w = math.min(max_key_w, math.max(4, math.floor(max_w / 2)))
local gap = " "
local gap_w = vim.fn.strdisplaywidth(gap)
local indent = string.rep(" ", max_key_w + gap_w)
local lines = {}
for _, e in ipairs(entries) do
local keys, desc = e[1], e[2]
local key_w = vim.fn.strdisplaywidth(keys)
local pad = string.rep(" ", math.max(0, max_key_w - key_w))
local prefix = keys .. pad .. gap
-- Wrap the description into the remaining width. `avail` is the
-- width available for description text (max_w minus key column).
local avail = math.max(1, max_w - vim.fn.strdisplaywidth(prefix))
local chunks = M._wrap_text(desc, avail)
table.insert(lines, prefix .. (chunks[1] or ""))
for i = 2, #chunks do
table.insert(lines, indent .. chunks[i])
end
end
return lines
end
--- Word-wrap `text` to rows no wider than `width` display cells. Falls back
--- to a hard character cut for a single token longer than `width`.
function M._wrap_text(text, width)
if width <= 0 then
return { text }
end
if vim.fn.strdisplaywidth(text) <= width then
return { text }
end
local out = {}
local line = ""
for word in string.gmatch(text, "%S+") do
if line == "" then
line = word
else
local candidate = line .. " " .. word
if vim.fn.strdisplaywidth(candidate) <= width then
line = candidate
else
table.insert(out, line)
line = word
end
end
-- Single word wider than width: hard-cut on character boundaries.
while vim.fn.strdisplaywidth(line) > width do
local cut = vim.fn.strcharpart(line, 0, width)
table.insert(out, cut)
line = vim.fn.strcharpart(line, vim.fn.strchars(cut))
end
end
if line ~= "" then
table.insert(out, line)
end
return out
end
--- Open the help popup directly below the form window. No-op if already
--- open or if the form is not visible.
function M:_open_help()
if not self._visible or not self._layout then
return
end
if self._help_win and vim.api.nvim_win_is_valid(self._help_win) then
return
end
local layout = self._layout
-- Match the parent's outer width so borders align vertically.
local content_w = layout.parent_inner_w
local lines = self:_help_lines(content_w)
if #lines == 0 then
return
end
local buf = vim.api.nvim_create_buf(false, true)
vim.bo[buf].buftype = "nofile"
vim.bo[buf].bufhidden = "wipe"
vim.bo[buf].swapfile = false
utils.mark_form_buffer(buf)
vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines)
vim.bo[buf].modifiable = false
-- Parent's outer bottom-border row = parent_row + parent_inner_h + 1
-- (parent_row is the border origin). The help popup's top border sits
-- one row below that.
local help_row = layout.parent_row + layout.parent_inner_h + 2
local help_col = layout.parent_col
-- If the popup would overflow the editor below the form, flip it above.
local outer_h = #lines + 2
local max_row = vim.o.lines - outer_h - 2
if help_row > max_row then
local above = layout.parent_row - outer_h
if above >= 0 then
help_row = above
else
help_row = math.max(0, max_row)
end
end
local win = vim.api.nvim_open_win(buf, false, {
relative = "editor",
row = help_row,
col = help_col,
width = content_w,
height = #lines,
style = "minimal",
border = config.options.window.border,
focusable = false,
zindex = 60,
title = " Help ",
title_pos = "left",
})
vim.wo[win].winblend = config.options.window.winblend
vim.wo[win].winhl = table.concat({
"NormalFloat:InputFormNormal",
"FloatBorder:InputFormBorder",
"FloatTitle:InputFormTitle",
}, ",")
self._help_win = win
self._help_buf = buf
end
--- Close the help popup. No-op if not open.
function M:_close_help()
if self._help_win and vim.api.nvim_win_is_valid(self._help_win) then
pcall(vim.api.nvim_win_close, self._help_win, true)
end
if self._help_buf and vim.api.nvim_buf_is_valid(self._help_buf) then
pcall(vim.api.nvim_buf_delete, self._help_buf, { force = true })
end
self._help_win = nil
self._help_buf = nil
end
--- Toggle the help popup.
function M:toggle_help()
if self._help_win and vim.api.nvim_win_is_valid(self._help_win) then
self:_close_help()
else
self:_open_help()
end
add(km.submit, "submit")
add(km.cancel, "cancel")
return table.concat(parts, " ")
end
--- Advance from `start` by `step` (+1 or -1), wrapping, until a focusable
@@ -559,9 +760,17 @@ function M:_install_keymaps(input)
if not buf then
return
end
-- `lhs` may be a single key string or a list of keys. All listed keys
-- are bound to the same callback.
local function map(mode, lhs, fn)
if lhs and lhs ~= false then
vim.keymap.set(mode, lhs, fn, { buffer = buf, nowait = true, silent = true })
if not lhs or lhs == false or lhs == "" then
return
end
local keys = type(lhs) == "table" and lhs or { lhs }
for _, k in ipairs(keys) do
if k and k ~= false and k ~= "" then
vim.keymap.set(mode, k, fn, { buffer = buf, nowait = true, silent = true })
end
end
end
@@ -584,6 +793,12 @@ function M:_install_keymaps(input)
self:cancel()
end)
-- Help popup toggle (normal mode only so `?` stays usable inside text/
-- multiline inputs during insert).
map("n", km.help, function()
self:toggle_help()
end)
if input.type == "select" then
map("n", km.open_select, function()
input:open_dropdown()

View File

@@ -30,7 +30,7 @@ T["setup()"]["exposes defaults"] = function()
eq_config(child, "keymaps.next", "<Tab>")
eq_config(child, "keymaps.prev", "<S-Tab>")
eq_config(child, "keymaps.submit", "<C-s>")
eq_config(child, "keymaps.cancel", "<Esc>")
eq_config(child, "keymaps.cancel", { "<Esc>", "q" })
eq_config(child, "keymaps.open_select", "<CR>")
eq_config(child, "select.max_height", 10)
eq_config(child, "multiline.height", 5)