Signal
Signal follows the reactive programming paradigm. It allows the creation of signal values, which are objects that emit values over time, and provides methods for observing and manipulating them.
Signal values are similar to variables in that they store data. However, unlike variables, signal values can change over time. Signal values are triggered by mutating them, and when they are triggered, they emit a new value. These values can be transformed and combined using operators. Operators allow for the creation of more complex data flows. By chaining together operators, it is possible to handle a wide range of use cases. Signal values can eventually be observed to call side effect functions.
Usage Example
Let's start by defining a signal. The signal has two properties: is_checked (initially false) and text (empty string), which we'll use later.
local n = require("nui-components")
local renderer = n.create_renderer({
width = 60,
height = 12,
})
local signal = n.create_signal({
is_checked = false,
text = "",
})
local body = function()
return n.rows()
end
renderer:render(body)Now, let's use n.checkbox to create a row with a checkbox component. This checkbox will allow us to display a text input component. The checkbox has the following properties: autofocus (set to true), label, value (bound to the is_checked property of the signal). When you press the checkbox (using <CR> or <Space>), we update the is_checked property of the signal.
local n = require("nui-components")
local renderer = n.create_renderer({
width = 60,
height = 12,
})
local signal = n.create_signal({
is_checked = false,
text = "",
})
local body = function()
return n.rows(
n.checkbox({
autofocus = true,
label = "Display text_input component",
value = signal.is_checked,
on_change = function(is_checked)
signal.is_checked = is_checked
end,
})
)
end
renderer:render(body)Let's create another row. This time, we'll have two nested rows. Both rows will be hidden when the is_checked property of the signal is false. The first row contains a text input component with the following properties: flex (set to 1), value (bound to the text property of the signal). When the user types something, we update the text property of the signal.
local n = require("nui-components")
local renderer = n.create_renderer({
width = 60,
height = 12,
})
local signal = n.create_signal({
is_checked = false,
text = "",
})
local body = function()
return n.rows(
n.checkbox({
autofocus = true,
label = "Display text_input component",
value = signal.is_checked,
on_change = function(is_checked)
signal.is_checked = is_checked
end,
}),
n.rows(
{
flex = 1,
hidden = signal.is_checked:negate(),
},
n.text_input({
flex = 1,
value = signal.text,
on_change = function(value)
signal.text = value
end,
})
)
)
end
renderer:render(body)Next, let's use n.columns to create the second row with two columns. The first column fills all available horizontal space. The second column contains a button component. When you press the button, we clear the text input.
local n = require("nui-components")
local renderer = n.create_renderer({
width = 60,
height = 12,
})
local signal = n.create_signal({
is_checked = false,
text = "",
})
local body = function()
return n.rows(
n.checkbox({
autofocus = true,
label = "Display text_input component",
value = signal.is_checked,
on_change = function(is_checked)
signal.is_checked = is_checked
end,
}),
n.rows(
{
flex = 1,
hidden = signal.is_checked:negate(),
},
n.text_input({
flex = 1,
value = signal.text,
on_change = function(value)
signal.text = value
end,
}),
n.columns(
{ flex = 0 },
n.gap({ flex = 1 }),
n.button({
label = "Clear",
on_press = function()
signal.text = ""
end,
})
)
)
)
end
renderer:render(body)And here's the final result:

Methods
observe
The
observemethod allows you to keep track of changes that occur in a signal. You can also specify a debounce delay. To prevent any memory leaks, it's important to remember to call theunsubscribemethod when you no longer need to observe the changes.
:observe(next_fn, debounce_ms?)next_fn | fun(previous_state: table, current_state: table): nil |
debounce_ms? | number |
Subscriptionget_value
Returns the current value of the
Signalobject.
:get_value()tableMethods / Operators (Signal Value)
get_value
Returns the current value of the corresponding key from the
Signalobject.
:get_value()Tget_observer_value
Returns the current value returned by the observer subscription.
:get_observer_value()Tget_observable
Returns an observable that emits the values of the corresponding key in the
Signalobject over time.
:get_observable()Observablemap
Applies a mapping function to each value emitted by the observable.
:map(map_fn)map_fn | fun(value: T): R |
SignalValuenegate
Negates the emitted value using a mapping function.
:negate()SignalValuedebounce
Delays an operation until a specified time has passed without further input.
:debounce(ms)ms | number |
SignalValuetap
Executes a function with each value emitted by the observable.
:tap(tap_fn)tap_fn | fun(value: T): nil |
SignalValuefilter
Filters the values emitted by the observable using a predicate function.
:filter(pred_fn)pred_fn | fun(value: T): boolean |
SignalValueskip
Skips the first
nvalues emitted by the observable.
:skip(n)n | number |
SignalValuecombine_latest
Combines the latest values from multiple SignalValue objects (using the provided arguments as keys).
:combine_latest(..., combinator_fn)... | SignalValue[] |
combinator_fn | fun(...): T |
SignalValuescan
Applies a scan function to each value emitted by the observable and accumulates the result into an internal variable, returning the final value.
:scan(scan_fn, initial_value)scan_fn | fun(acc: T, value: R): T |
initial_value | T |
SignalValuestart_with
Emits a default value immediately and synchronously after subscribing.
:start_with(default_value)default_value | T |
SignalValueobserve
Subscribes an observer function to the observable. The observer function is called every time a new value is emitted by the observable.
:observe(on_next)on_next | fun(value: T): nil |
unsubscribe
Unsubscribes the observer subscription from the observable, cancelling any further updates.
:unsubscribe()dup
Returns a new SignalValue object with a reference to the same underlying subject and key.
:dup()SignalValue