From e454ab0d7003a039db2a5235fb217f5875977980 Mon Sep 17 00:00:00 2001 From: sammyette Date: Sat, 18 Feb 2023 16:57:27 -0400 Subject: [PATCH] feat: add greenhouse pager --- nature/commands/greenhouse.lua | 67 ++++++++++++++++++++++++++++++++++ nature/greenhouse.lua | 47 ++++++++++++++++++++++++ nature/object.lua | 59 ++++++++++++++++++++++++++++++ 3 files changed, 173 insertions(+) create mode 100644 nature/commands/greenhouse.lua create mode 100644 nature/greenhouse.lua create mode 100644 nature/object.lua diff --git a/nature/commands/greenhouse.lua b/nature/commands/greenhouse.lua new file mode 100644 index 0000000..916c29a --- /dev/null +++ b/nature/commands/greenhouse.lua @@ -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 = 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 diff --git a/nature/greenhouse.lua b/nature/greenhouse.lua new file mode 100644 index 0000000..44947da --- /dev/null +++ b/nature/greenhouse.lua @@ -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 diff --git a/nature/object.lua b/nature/object.lua new file mode 100644 index 0000000..053be4a --- /dev/null +++ b/nature/object.lua @@ -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