text_panel.lua
#!/usr/bin/env lua
local TextPanel = require("src.terminal.ui.panel.text")
local Screen = require("src.terminal.ui.panel.screen")
local Bar = require("src.terminal.ui.panel.bar")
local terminal = require("terminal")
local sample_text = {
"Welcome to the TextPanel example!",
"",
"This panel displays scrollable text content with the following features:",
"",
"• Text truncation for lines that are too long",
"• Scrollable viewport when content exceeds panel height",
"• Configurable scroll step size",
"• Methods for navigation: set_position(), scroll_up(), scroll_down()",
"• Dynamic content management: set_lines(), add_line(), clear()",
"",
"Navigation:",
"• Use 'j' or ↓ arrow to scroll down",
"• Use 'k' or ↑ arrow to scroll up",
"• Use '[' and ']' to move the highlight",
"• Use 'g' to go to top",
"• Use 'G' to go to bottom",
"• Use 'r' to add a random line",
"• Use 'c' to clear content",
"• Use 's' to reset to this sample text",
"• Use 'f' to swicth line-formatters; trunc, wrap, word-wrap",
"• Use 'q' to quit",
"",
"The TextPanel class inherits from Panel and provides:",
"",
"• Automatic text truncation using terminal.text.width",
"• Viewport management for large text content",
"• Integration with the Panel layout system",
"• Support for borders and text attributes",
"",
"This is a long line that should be truncated when the panel width is insufficient to display the entire content. The truncation respects UTF-8 character boundaries and double-width characters.",
"",
"More content follows:",
"Line " .. string.rep("A", 50),
"Line " .. string.rep("B", 30),
"Line " .. string.rep("C", 40),
"Line " .. string.rep("D", 20),
"Line " .. string.rep("E", 60),
"",
"You can add more lines dynamically:",
"• Call add_line() to append new content",
"• Call set_lines() to replace all content",
"• Call clear() to remove all content",
"",
"The panel automatically handles:",
"• Empty lines and nil content",
"• Position clamping to valid ranges",
"• Efficient rendering (only when content changes)",
"",
"This concludes the TextPanel demonstration.",
"Thank you for trying out this example!"
}
local screen = Screen {
header = Bar {
left = {
text = "TextPanel Example",
attr = { fg = "cyan", brightness = "bright" }
},
center = {
text = "Scrollable Text Display",
attr = { fg = "yellow", brightness = "bright", underline = true }
},
right = {
text = "Press 'q' to quit",
attr = { fg = "green", brightness = "bright" }
},
attr = { bg = "blue" }
},
body = TextPanel {
lines = sample_text,
scroll_step = 1,
text_attr = { fg = "white", brightness = "bright" },
border = { format = terminal.draw.box_fmt.single },
auto_render = true,
},
footer = Bar {
left = {
text = "j/k or ↑/↓: scroll",
attr = { fg = "magenta", brightness = "bright" }
},
center = {
text = "pgup/pgdn: page, g/G: top/bottom",
attr = { fg = "yellow", brightness = "bright" }
},
right = {
text = "q: quit",
attr = { fg = "red", brightness = "bright" }
},
attr = { bg = "black", fg = "white" }
}
}
local formatters = {
TextPanel.format_line_truncate,
TextPanel.format_line_wrap,
TextPanel.format_line_wordwrap,
}
local current_formatter = 1
local function main()
local keymap = terminal.input.keymap.default_key_map
local keys = terminal.input.keymap.default_keys
screen:calculate_layout()
screen:render()
while true do
local key = terminal.input.readansi(0.1)
local keyname = keymap[key or ""]
if key == "q" or key == "Q" then
break
elseif key == "j" or keyname == keys.down then
screen:get_panel("body"):scroll_down()
elseif key == "k" or keyname == keys.up then
screen:get_panel("body"):scroll_up()
elseif keyname == keys.pageup then
screen:get_panel("body"):page_up()
elseif keyname == keys.pagedown then
screen:get_panel("body"):page_down()
elseif key == "[" then
screen:get_panel("body"):set_highlight((screen:get_panel("body"):get_highlight() or 2) - 1, true)
elseif key == "]" then
screen:get_panel("body"):set_highlight((screen:get_panel("body"):get_highlight() or 0) + 1, true)
elseif key == "g" then
screen:get_panel("body"):set_position(1)
elseif key == "G" then
screen:get_panel("body"):set_position(math.huge)
elseif key == "f" then
current_formatter = current_formatter % #formatters + 1
screen:get_panel("body"):set_line_formatter(formatters[current_formatter])
elseif key == "r" then
local random_line = "Random line " .. math.random(1000) .. " added at " .. os.date("%H:%M:%S")
screen:get_panel("body"):add_line(random_line)
elseif key == "c" then
screen:get_panel("body"):clear_lines()
elseif key == "s" then
screen:get_panel("body"):set_lines(sample_text)
end
screen:check_resize(true)
end
end
terminal.initwrap(main, {
displaybackup = true,
filehandle = io.stdout,
})()