feat: initial commit

Release-As: 0.1.0
This commit is contained in:
2026-04-04 23:58:45 +03:00
commit 7df3775ae7
30 changed files with 2118 additions and 0 deletions

237
README.md Normal file
View File

@@ -0,0 +1,237 @@
# 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.
## Features
- Bordered floating window with optional title
- Keyboard-navigable: `<Tab>` / `<S-Tab>` to move between inputs
- Input types: `text`, `multiline`, `select`
- Select dropdowns open with `<CR>`; arrows navigate; `<CR>` confirms
- Submit with `<C-s>` — results delivered as a `{ [name] = value }` table
- Cancel with `<Esc>`
- 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
- Auto-generated help doc (`:h input-form`)
- Tested with `mini.test`
## Installation
### lazy.nvim
```lua
{
"chenasraf/input-form.nvim",
config = function()
require("input-form").setup()
end,
}
```
### packer.nvim
```lua
use({
"chenasraf/input-form.nvim",
config = function()
require("input-form").setup()
end,
})
```
### vim-plug
```vim
Plug 'chenasraf/input-form.nvim'
lua require('input-form').setup()
```
## Usage
```lua
local f = require("input-form")
local form = f.create_form({
inputs = {
{ name = "id", label = "Enter ID", type = "text", default = "sample ID" },
{
name = "choice",
label = "Select an option",
type = "select",
options = {
{ id = "opt1", label = "Option 1" },
{ id = "opt2", label = "Option 2" },
},
},
{ name = "body", label = "Enter multiline text", type = "multiline" },
},
on_submit = function(results)
vim.print(results) -- { id = "...", choice = "opt1", body = "..." }
end,
on_cancel = function()
vim.notify("cancelled")
end,
})
-- Create once, show on demand:
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:
```lua
vim.keymap.set("n", "<leader>xf", function()
form:show()
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. |
| `form:submit()`| Gather values, close, and invoke `on_submit(results)`. |
| `form:cancel()`| Close and invoke `on_cancel()` if provided. |
| `form:results()`| Return `{ [name] = value }` without closing. |
### Input spec reference
All inputs share `name` (string, required — the key in the result table) and
`label` (string, shown above the field).
#### `text`
```lua
{ name = "id", label = "Enter ID", type = "text", default = "sample ID" }
```
#### `multiline`
```lua
{ name = "body", label = "Notes", type = "multiline", default = "", height = 5 }
```
- `height` (optional) — number of rows for the input; falls back to
`config.multiline.height`.
#### `select`
```lua
{
name = "choice",
label = "Pick one",
type = "select",
default = "opt1", -- optional; defaults to first option's id
options = {
{ id = "opt1", label = "Option 1" },
{ id = "opt2", label = "Option 2" },
},
}
```
`value()` returns the selected `id` (not the label).
## Configuration
Defaults:
```lua
require("input-form").setup({
window = {
border = "rounded", -- any nvim_open_win border
width = 60, -- number of columns; <= 1 treated as ratio
title = " Form ",
title_pos = "center",
winblend = 0,
padding = 0, -- cells between the outer border and inputs (all sides)
gap = 0, -- blank rows between adjacent inputs
},
keymaps = {
next = "<Tab>",
prev = "<S-Tab>",
submit = "<C-s>",
cancel = "<Esc>",
open_select = "<CR>",
},
select = {
max_height = 10,
},
multiline = {
height = 5,
},
})
```
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:
```
:h input-form
```
## 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:
```lua
-- In your plugin's code:
local ok, input_form = pcall(require, 'input-form')
if not ok then
vim.notify('my-plugin: input-form.nvim is required', vim.log.levels.ERROR)
return
end
input_form.create_form({
inputs = { ... },
on_submit = function(results) ... end,
}):show()
```
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.
- **Declaring the dep.** With lazy.nvim, add it to your `dependencies`:
```lua
{
'your-name/your-plugin.nvim',
dependencies = { 'chenasraf/input-form.nvim' },
}
```
## Contributing & development
```
make deps # install mini.nvim into deps/
make test # run the test suite (mini.test)
make documentation # regenerate doc/input-form.txt (mini.doc)
make lint # stylua check
```
## License
MIT — see [LICENSE](./LICENSE).