feat: add greenhouse pager

pull/240/head
sammyette 2023-02-18 16:57:27 -04:00
parent 26c8f28034
commit e454ab0d70
Signed by: sammyette
GPG Key ID: 904FC49417B44DCD
3 changed files with 173 additions and 0 deletions

View File

@ -0,0 +1,67 @@
local ansikit = require 'ansikit'
local bait = require 'bait'
local commander = require 'commander'
local hilbish = require 'hilbish'
local terminal = require 'terminal'
local Greenhouse = require 'nature.greenhouse'
commander.register('greenhouse', function(args, sinks)
local fname = args[1]
local done = false
local f <close> = io.open(fname, 'r')
if not f then
sinks.err:writeln(string.format('could not open file %s', fname))
end
bait.catch('signal.sigint', function()
done = true
end)
local gh = Greenhouse(sinks.out)
gh:setText(f:read '*a')
ansikit.screenAlt()
ansikit.clear(true)
gh:draw()
hilbish.goro(function()
while not done do
local c = read()
if c == 3 then
done = true
end
if c == 27 then
local c1 = read()
if c1 == 91 then
local c2 = read()
if c2 == 66 then -- arrow down
gh:scroll 'down'
elseif c2 == 65 then -- arrow up
gh:scroll 'up'
end
end
goto continue
end
print('\nchar:')
print(c)
::continue::
end
end)
while not done do
--
end
ansikit.clear()
ansikit.screenMain()
end)
function read()
terminal.saveState()
terminal.setRaw()
local c = io.read(1)
terminal.restoreState()
return c:byte()
end

View File

@ -0,0 +1,47 @@
-- Greenhouse is a simple text scrolling handler for terminal program.
-- The idea is that it can be set a region to do its scrolling and paging
-- job and then the user can draw whatever outside it.
-- This reduces code duplication for the message viewer
-- and flowerbook.
local ansikit = require 'ansikit'
local terminal = require 'terminal'
local Object = require 'nature.object'
local Greenhouse = Object:extend()
function Greenhouse:new(sink)
local size = terminal.size()
self.region = size
self.start = 1
self.offset = 0
self.sink = sink
return self
end
function Greenhouse:setText(text)
self.lines = string.split(text, '\n')
end
function Greenhouse:draw()
self.sink:write(ansikit.getCSI(self.start .. ';1', 'H'))
for i = 1, #self.lines do
if i > self.region.height - 1 then break end
if not self.lines[i + self.offset] then break end
self.sink:writeln(self.lines[i + self.offset]:gsub('\t', ' '):sub(0, self.region.width - 2))
end
end
function Greenhouse:scroll(direction)
if direction == 'down' then
self.offset = self.offset + 1
elseif direction == 'up' then
self.offset = self.offset - 1
end
self:draw()
end
return Greenhouse

59
nature/object.lua 100644
View File

@ -0,0 +1,59 @@
---@class nature.object
---@field super nature.object
local Object = {}
Object.__index = Object
---Can be overrided by child objects to implement a constructor.
function Object:new() end
---@return nature.object
function Object:extend()
local cls = {}
for k, v in pairs(self) do
if k:find("__") == 1 then
cls[k] = v
end
end
cls.__index = cls
cls.super = self
setmetatable(cls, self)
return cls
end
---Check if the object is strictly of the given type.
---@param T any
---@return boolean
function Object:is(T)
return getmetatable(self) == T
end
---Check if the object inherits from the given type.
---@param T any
---@return boolean
function Object:extends(T)
local mt = getmetatable(self)
while mt do
if mt == T then
return true
end
mt = getmetatable(mt)
end
return false
end
---Metamethod to get a string representation of an object.
---@return string
function Object:__tostring()
return "Object"
end
---Methamethod to allow using the object call as a constructor.
---@return nature.object
function Object:__call(...)
local obj = setmetatable({}, self)
obj:new(...)
return obj
end
return Object