require "rooibos"
module CustomShellInput
InputBuffer = Data.define(:text, :canceled, :submitted)
Init = -> do
InputBuffer.new(text: "", canceled: false, submitted: false)
end
View = -> (model, tui) do
content = if model.text.empty?
tui.paragraph(text: tui.text_span(content: "Type a command...", style: { fg: :dark_gray }))
else
tui.paragraph(text: model.text)
end
tui.layout(
direction: :vertical,
constraints: [
tui.constraint_length(1),
tui.constraint_length(3),
tui.constraint_min(0),
],
children: [
nil,
tui.center(
width_percent: 80,
child: tui.overlay(
layers: [
tui.clear,
tui.block(
title: "Run Command",
titles: [
{ content: "ESC: Cancel", position: :bottom, alignment: :left },
{ content: "ENTER: Run", position: :bottom, alignment: :right },
],
borders: [:all],
children: [content]
),
]
)
),
nil,
]
)
end
Update = -> (message, model) do
case message
in _ if message.respond_to?(:esc?) && message.esc?
[model.with(canceled: true), nil]
in _ if message.respond_to?(:enter?) && message.enter?
return [model.with(canceled: true), nil] if model.text.strip.empty?
[model.with(submitted: true), nil]
in _ if message.respond_to?(:backspace?) && message.backspace?
[model.with(text: model.text.chop.freeze), nil]
in RatatuiRuby::Event::Paste
normalized = message.content.gsub(/\\\r?\n/, "").gsub(/[\r\n]/, " ")
[model.with(text: "#{model.text}#{normalized}".freeze), nil]
in RatatuiRuby::Event::Key if message.text? && message.code.length == 1
[model.with(text: "#{model.text}#{message.code}".freeze), nil]
else
[model, nil]
end
end
end