sammyette 2023-04-19 06:20:20 +09:00 committed by GitHub
commit 0e4281ba3b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 307 additions and 2 deletions

View File

@ -1,6 +1,8 @@
local commander = require 'commander'
local fs = require 'fs'
local lunacolors = require 'lunacolors'
local Greenhouse = require 'nature.greenhouse'
local Page = require 'nature.greenhouse.page'
commander.register('doc', function(args, sinks)
local moddocPath = hilbish.dataDir .. '/docs/'
@ -85,8 +87,9 @@ Available sections: ]] .. table.concat(modules, ', ')
f:close()
end
local gh = Greenhouse(sinks.out)
local backtickOccurence = 0
sinks.out:writeln(lunacolors.format(doc:gsub('`', function()
local page = Page(lunacolors.format(doc:gsub('`', function()
backtickOccurence = backtickOccurence + 1
if backtickOccurence % 2 == 0 then
return '{reset}'
@ -97,4 +100,6 @@ Available sections: ]] .. table.concat(modules, ', ')
local signature = t:gsub('<.->(.-)</.->', '{underline}%1'):gsub('\\', '<')
return '{bold}{yellow}' .. signature .. '{reset}'
end)))
gh:addPage(page)
gh:initUi()
end)

View File

@ -0,0 +1,28 @@
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'
local Page = require 'nature.greenhouse.page'
commander.register('greenhouse', function(args, sinks)
local gh = Greenhouse(sinks.out)
if sinks['in'].pipe then
local page = Page(sinks['in']:readAll())
gh:addPage(page)
end
for _, name in ipairs(args) do
local f <close> = io.open(name, 'r')
if not f then
sinks.err:writeln(string.format('could not open file %s', name))
end
local page = Page(f:read '*a')
gh:addPage(page)
end
gh:initUi()
end)

View File

@ -0,0 +1,166 @@
-- Greenhouse is a simple text scrolling handler for terminal programs.
-- 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 = 1
self.sink = sink
self.pages = {}
self.curPage = 1
return self
end
function Greenhouse:addPage(page)
table.insert(self.pages, page)
end
function Greenhouse:updateCurrentPage(text)
local page = self.pages[self.curPage]
page:setText(text)
end
function Greenhouse:draw()
local lines = self.pages[self.curPage].lines
self.sink:write(ansikit.getCSI(self.start .. ';1', 'H'))
self.sink:write(ansikit.getCSI(2, 'J'))
-- the -2 negate is for the command and status line
for i = self.offset, self.offset + (self.region.height - self.start) - 2 do
if i > #lines then break end
self.sink:writeln('\r' .. lines[i]:gsub('\t', ' '):sub(0, self.region.width - 2))
end
self.sink:write '\r'
self.sink:write(ansikit.getCSI(self.region.height - self.start.. ';1', 'H'))
self.sink:writeln(string.format('\27[0mPage %d', self.curPage))
end
function Greenhouse:scroll(direction)
local lines = self.pages[self.curPage].lines
local oldOffset = self.offset
if direction == 'down' then
self.offset = math.min(self.offset + 1, #lines)
elseif direction == 'up' then
self.offset = math.max(self.offset - 1, 1)
end
if self.offset ~= oldOffset then self:draw() end
end
function Greenhouse:update()
local size = terminal.size()
self.region = size
self:draw()
end
function Greenhouse:next()
local oldCurrent = self.curPage
self.curPage = math.min(self.curPage + 1, #self.pages)
if self.curPage ~= oldCurrent then
self.offset = 1
self:draw()
end
end
function Greenhouse:previous()
local oldCurrent = self.curPage
self.curPage = math.max(self.curPage - 1, 1)
if self.curPage ~= oldCurrent then
self.offset = 1
self:draw()
end
end
function Greenhouse:initUi()
local ansikit = require 'ansikit'
local bait = require 'bait'
local commander = require 'commander'
local hilbish = require 'hilbish'
local terminal = require 'terminal'
local Page = require 'nature.greenhouse.page'
local done = false
bait.catch('signal.sigint', function()
ansikit.clear()
done = true
end)
bait.catch('signal.resize', function()
self:update()
end)
ansikit.screenAlt()
ansikit.clear(true)
self: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
self:scroll 'down'
elseif c2 == 65 then -- arrow up
self:scroll 'up'
end
if c2 == 49 then
local c3 = read()
if c3 == 59 then
local c4 = read()
if c4 == 53 then
local c5 = read()
if c5 == 67 then
self:next()
elseif c5 == 68 then
self:previous()
end
end
end
end
end
goto continue
end
print('\nchar:')
print(c)
::continue::
end
end)
while not done do
--
end
ansikit.screenMain()
end
function read()
terminal.saveState()
terminal.setRaw()
local c = io.read(1)
terminal.restoreState()
return c:byte()
end
return Greenhouse

View File

@ -0,0 +1,13 @@
local Object = require 'nature.object'
local Page = Object:extend()
function Page:new(text)
self:setText(text)
end
function Page:setText(text)
self.lines = string.split(text, '\n')
end
return Page

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

36
sink.go
View File

@ -5,6 +5,7 @@ import (
"fmt"
"io"
"os"
"strings"
"hilbish/util"
@ -31,6 +32,7 @@ func setupSinkType(rtm *rt.Runtime) {
sinkFuncs := map[string]util.LuaExport{
"flush": {luaSinkFlush, 1, false},
"read": {luaSinkRead, 1, false},
"readAll": {luaSinkReadAll, 1, false},
"autoFlush": {luaSinkAutoFlush, 2, false},
"write": {luaSinkWrite, 2, false},
"writeln": {luaSinkWriteln, 2, false},
@ -65,10 +67,42 @@ func setupSinkType(rtm *rt.Runtime) {
l.SetRegistry(sinkMetaKey, rt.TableValue(sinkMeta))
}
// #member
// readAll() -> string
// --- @returns string
// Reads all input from the sink.
func luaSinkReadAll(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil {
return nil, err
}
s, err := sinkArg(c, 0)
if err != nil {
return nil, err
}
lines := []string{}
for {
line, err := s.reader.ReadString('\n')
if err != nil {
if err == io.EOF {
break
}
return nil, err
}
lines = append(lines, line)
}
return c.PushingNext1(t.Runtime, rt.StringValue(strings.Join(lines, ""))), nil
}
// #member
// read() -> string
// --- @returns string
// Reads input from the sink.
// Reads a liine of input from the sink.
func luaSinkRead(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil {
return nil, err