mirror of
https://github.com/Hilbis/Hilbish
synced 2025-05-09 05:43:23 +00:00
Merge f9546e10e499ac356a99bdc0b423edb1fbcd03ef into 6729ecddea9379f2c2b65ec70e20d36da13e626a
This commit is contained in:
commit
0e4281ba3b
@ -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)
|
||||
|
28
nature/commands/greenhouse.lua
Normal file
28
nature/commands/greenhouse.lua
Normal 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)
|
166
nature/greenhouse/init.lua
Normal file
166
nature/greenhouse/init.lua
Normal 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
|
13
nature/greenhouse/page.lua
Normal file
13
nature/greenhouse/page.lua
Normal 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
Normal file
59
nature/object.lua
Normal 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
36
sink.go
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user