All checks were successful
NeoVim tests / code-quality (push) Successful in 1m21s
118 lines
3.6 KiB
Lua
118 lines
3.6 KiB
Lua
-- form.lua:
|
|
--
|
|
-- This is a runnable example of a form. Open this file in Neovim, and execute
|
|
-- `:luafile %` to run it. It will create a new buffer to the side, and render
|
|
-- an interactive form. Edit the "inputs" between the `[...]` brackets, and
|
|
-- watch the buffer react immediately to your changes.
|
|
--
|
|
|
|
local Renderer = require('u.renderer').Renderer
|
|
local h = require('u.renderer').h
|
|
local tracker = require 'u.tracker'
|
|
|
|
-- Create a new, temporary, buffer to the side:
|
|
vim.cmd.vnew()
|
|
vim.bo.buftype = 'nofile'
|
|
vim.bo.bufhidden = 'wipe'
|
|
vim.bo.buflisted = false
|
|
local renderer = Renderer.new()
|
|
|
|
-- Create two signals:
|
|
local s_name = tracker.create_signal 'whoever-you-are'
|
|
local s_age = tracker.create_signal 'ideally-a-number'
|
|
|
|
-- We can create derived information from the signals above. Say we want to do
|
|
-- some validation on the input for `age`: we can do that with a memo:
|
|
local s_age_info = tracker.create_memo(function()
|
|
local age_raw = s_age:get()
|
|
local age_digits = age_raw:match '^%s*(%d+)%s*$'
|
|
local age_n = age_digits and tonumber(age_digits) or nil
|
|
return {
|
|
type = age_n and 'number' or 'string',
|
|
raw = age_raw,
|
|
n = age_n,
|
|
n1 = age_n and age_n + 1 or nil,
|
|
}
|
|
end)
|
|
|
|
-- This is the render effect that depends on the signals created above. This
|
|
-- will re-run every time one of the signals changes.
|
|
tracker.create_effect(function()
|
|
local name = s_name:get()
|
|
local age = s_age:get()
|
|
local age_info = s_age_info:get()
|
|
|
|
-- Each time the signals change, we re-render the buffer:
|
|
renderer:render {
|
|
h.Type({}, '# Form Example'),
|
|
'\n\n',
|
|
|
|
-- We can also listen for when specific locations in the buffer change, on
|
|
-- a tag-by-tag basis. This gives us two-way data-binding between the
|
|
-- buffer and the signals.
|
|
{
|
|
'Name: ',
|
|
h.Structure({
|
|
on_change = function(text) s_name:set(text) end,
|
|
}, name),
|
|
},
|
|
{
|
|
'\nAge: ',
|
|
h.Structure({
|
|
on_change = function(text) s_age:set(text) end,
|
|
}, age),
|
|
},
|
|
|
|
'\n\n',
|
|
|
|
-- Show the values of the signals here, too, so that we can see the
|
|
-- reactivity in action. If you change the values in the tags above, you
|
|
-- can see the changes reflected here immediately.
|
|
{ 'Hello, "', name, '"!' },
|
|
|
|
--
|
|
-- A more complex example: we can do much more complex rendering, based on
|
|
-- the state. For example, if you type different values into the `age`
|
|
-- field, you can see not only the displayed information change, but also
|
|
-- the color of the highlights in this section will adapt to the type of
|
|
-- information that has been detected.
|
|
--
|
|
-- If string input is detected, values below are shown in the
|
|
-- `String`/`ErrorMsg` highlight groups.
|
|
--
|
|
-- If number input is detected, values below are shown in the `Number`
|
|
-- highlight group.
|
|
--
|
|
-- If a valid number is entered, then this section also displays how old
|
|
-- you willl be next year (`n + 1`).
|
|
--
|
|
|
|
'\n\n',
|
|
h.Type({}, '## Computed Information (derived from `age`)'),
|
|
'\n\n',
|
|
{
|
|
'Type: ',
|
|
h('text', {
|
|
hl = age_info.type == 'number' and 'Number' or 'String',
|
|
}, age_info.type),
|
|
},
|
|
{ '\nRaw input: ', h.String({}, '"' .. age_info.raw .. '"') },
|
|
{
|
|
'\nCurrent age: ',
|
|
age_info.n
|
|
-- Show the age:
|
|
and h.Number({}, tostring(age_info.n))
|
|
-- Show an error-placeholder if the age is invalid:
|
|
or h.ErrorMsg({}, '(?)'),
|
|
},
|
|
|
|
-- This part is shown conditionally, i.e., only if the age next year can be
|
|
-- computed:
|
|
age_info.n1
|
|
and {
|
|
'\nAge next year: ',
|
|
h.Number({}, tostring(age_info.n1)),
|
|
},
|
|
}
|
|
end)
|