mirror of https://github.com/Hilbis/Hilbish
feat: add greenhouse pager
parent
26c8f28034
commit
e454ab0d70
|
@ -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
|
|
@ -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
|
|
@ -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
|
Loading…
Reference in New Issue