From e454ab0d7003a039db2a5235fb217f5875977980 Mon Sep 17 00:00:00 2001 From: sammyette Date: Sat, 18 Feb 2023 16:57:27 -0400 Subject: [PATCH 01/39] 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 00000000..916c29aa --- /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 00000000..44947daf --- /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 00000000..053be4a9 --- /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 From 45eb3d17e30bd2aa066f701ae3e5a3b4a4078ecb Mon Sep 17 00:00:00 2001 From: sammyette Date: Sat, 18 Feb 2023 17:57:03 -0400 Subject: [PATCH 02/39] fix(nature/greenhouse): draw pager body properly --- nature/greenhouse.lua | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/nature/greenhouse.lua b/nature/greenhouse.lua index 44947daf..fb090c16 100644 --- a/nature/greenhouse.lua +++ b/nature/greenhouse.lua @@ -14,7 +14,7 @@ function Greenhouse:new(sink) local size = terminal.size() self.region = size self.start = 1 - self.offset = 0 + self.offset = 1 self.sink = sink return self @@ -27,11 +27,9 @@ 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)) + for i = self.offset, self.offset + (self.region.height - self.start) - 1 do + self.sink:write(ansikit.getCSI(2, 'K')) + self.sink:writeln(self.lines[i]:gsub('\t', ' '):sub(0, self.region.width - 2)) end end From e368ba3e0a10373ca742ea1d33127b842c7f40f2 Mon Sep 17 00:00:00 2001 From: sammyette Date: Sat, 18 Feb 2023 17:57:46 -0400 Subject: [PATCH 03/39] fix(nature/greenhouse): add limit to text offset for scrolling --- nature/greenhouse.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nature/greenhouse.lua b/nature/greenhouse.lua index fb090c16..390c4543 100644 --- a/nature/greenhouse.lua +++ b/nature/greenhouse.lua @@ -35,9 +35,9 @@ end function Greenhouse:scroll(direction) if direction == 'down' then - self.offset = self.offset + 1 + self.offset = math.min(self.offset + 1, #self.lines) elseif direction == 'up' then - self.offset = self.offset - 1 + self.offset = math.max(self.offset - 1, 1) end self:draw() end From bb9a6fe39edd66a8637d581806dbff8464a4c968 Mon Sep 17 00:00:00 2001 From: sammyette Date: Sat, 18 Feb 2023 18:58:16 -0400 Subject: [PATCH 04/39] fix(nature/greenhouse): handle raw mode and term resize --- nature/commands/greenhouse.lua | 8 ++++++-- nature/greenhouse.lua | 11 +++++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/nature/commands/greenhouse.lua b/nature/commands/greenhouse.lua index 916c29aa..df011964 100644 --- a/nature/commands/greenhouse.lua +++ b/nature/commands/greenhouse.lua @@ -13,12 +13,16 @@ commander.register('greenhouse', function(args, sinks) sinks.err:writeln(string.format('could not open file %s', fname)) end + local gh = Greenhouse(sinks.out) + gh:setText(f:read '*a') + bait.catch('signal.sigint', function() done = true end) - local gh = Greenhouse(sinks.out) - gh:setText(f:read '*a') + bait.catch('signal.resize', function() + gh:update() + end) ansikit.screenAlt() ansikit.clear(true) diff --git a/nature/greenhouse.lua b/nature/greenhouse.lua index 390c4543..1e292e28 100644 --- a/nature/greenhouse.lua +++ b/nature/greenhouse.lua @@ -1,4 +1,4 @@ --- Greenhouse is a simple text scrolling handler for terminal program. +-- 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 @@ -29,8 +29,9 @@ function Greenhouse:draw() for i = self.offset, self.offset + (self.region.height - self.start) - 1 do self.sink:write(ansikit.getCSI(2, 'K')) - self.sink:writeln(self.lines[i]:gsub('\t', ' '):sub(0, self.region.width - 2)) + self.sink:writeln('\r' .. self.lines[i]:gsub('\t', ' '):sub(0, self.region.width - 2)) end + self.sink:write '\r' end function Greenhouse:scroll(direction) @@ -39,6 +40,12 @@ function Greenhouse:scroll(direction) elseif direction == 'up' then self.offset = math.max(self.offset - 1, 1) end +end + +function Greenhouse:update() + local size = terminal.size() + self.region = size + self:draw() end From 8b5b9b3c1c7039500b5457da3b6019e57a4f8b17 Mon Sep 17 00:00:00 2001 From: sammyette Date: Sat, 18 Feb 2023 18:58:44 -0400 Subject: [PATCH 05/39] fix(nature/greenhouse): dont redraw if scroll pos stays the same --- nature/greenhouse.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/nature/greenhouse.lua b/nature/greenhouse.lua index 1e292e28..a2c9b972 100644 --- a/nature/greenhouse.lua +++ b/nature/greenhouse.lua @@ -35,11 +35,14 @@ function Greenhouse:draw() end function Greenhouse:scroll(direction) + local oldOffset = self.offset if direction == 'down' then self.offset = math.min(self.offset + 1, #self.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() From 179bec7ae5c7087ef6bcfbfbe3ba9fe8ef38afa6 Mon Sep 17 00:00:00 2001 From: sammyette Date: Sun, 19 Feb 2023 16:53:39 -0400 Subject: [PATCH 06/39] feat(nature/greenhouse): support setting multiple pages --- nature/commands/greenhouse.lua | 33 ++++++++++++---- .../{greenhouse.lua => greenhouse/init.lua} | 38 ++++++++++++++++--- nature/greenhouse/page.lua | 13 +++++++ 3 files changed, 71 insertions(+), 13 deletions(-) rename nature/{greenhouse.lua => greenhouse/init.lua} (53%) create mode 100644 nature/greenhouse/page.lua diff --git a/nature/commands/greenhouse.lua b/nature/commands/greenhouse.lua index df011964..2baf3cca 100644 --- a/nature/commands/greenhouse.lua +++ b/nature/commands/greenhouse.lua @@ -4,17 +4,21 @@ 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 fname = args[1] + local gh = Greenhouse(sinks.out) 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 - local gh = Greenhouse(sinks.out) - gh:setText(f:read '*a') + for _, name in ipairs(args) do + local f = 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 bait.catch('signal.sigint', function() done = true @@ -44,6 +48,21 @@ commander.register('greenhouse', function(args, sinks) elseif c2 == 65 then -- arrow up gh: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 + gh:next() + elseif c5 == 68 then + gh:previous() + end + end + end + end end goto continue end diff --git a/nature/greenhouse.lua b/nature/greenhouse/init.lua similarity index 53% rename from nature/greenhouse.lua rename to nature/greenhouse/init.lua index a2c9b972..ef1d3ff7 100644 --- a/nature/greenhouse.lua +++ b/nature/greenhouse/init.lua @@ -16,28 +16,43 @@ function Greenhouse:new(sink) self.start = 1 self.offset = 1 self.sink = sink + self.pages = {} + self.curPage = 1 return self end -function Greenhouse:setText(text) - self.lines = string.split(text, '\n') +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')) - for i = self.offset, self.offset + (self.region.height - self.start) - 1 do - self.sink:write(ansikit.getCSI(2, 'K')) - self.sink:writeln('\r' .. self.lines[i]:gsub('\t', ' '):sub(0, self.region.width - 2)) + -- 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('Page %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, #self.lines) + self.offset = math.min(self.offset + 1, #lines) elseif direction == 'up' then self.offset = math.max(self.offset - 1, 1) end @@ -52,4 +67,15 @@ function Greenhouse:update() self:draw() end +function Greenhouse:next() + self.curPage = math.min(self.curPage + 1, #self.pages) + self.sink:write(ansikit.getCSI(2, 'J')) + self:draw() +end + +function Greenhouse:previous() + self.curPage = math.max(self.curPage - 1, 1) + self:draw() +end + return Greenhouse diff --git a/nature/greenhouse/page.lua b/nature/greenhouse/page.lua new file mode 100644 index 00000000..09f1e91b --- /dev/null +++ b/nature/greenhouse/page.lua @@ -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 From ec0692edeb1c610ea04ee96aca990d7e4f6673fd Mon Sep 17 00:00:00 2001 From: sammyette Date: Sun, 19 Feb 2023 17:05:25 -0400 Subject: [PATCH 07/39] fix(nature/greenhouse): reset line offset when switching pages --- nature/greenhouse/init.lua | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/nature/greenhouse/init.lua b/nature/greenhouse/init.lua index ef1d3ff7..0b710c20 100644 --- a/nature/greenhouse/init.lua +++ b/nature/greenhouse/init.lua @@ -68,14 +68,21 @@ function Greenhouse:update() end function Greenhouse:next() + local oldCurrent = self.curPage self.curPage = math.min(self.curPage + 1, #self.pages) - self.sink:write(ansikit.getCSI(2, 'J')) - self:draw() + 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) - self:draw() + if self.curPage ~= oldCurrent then + self.offset = 1 + self:draw() + end end return Greenhouse From d196799abf5da57f397456193559c757e4af51ff Mon Sep 17 00:00:00 2001 From: sammyette Date: Sat, 25 Mar 2023 18:12:51 -0400 Subject: [PATCH 08/39] feat(commands/greenhouse): support reading from pipes --- nature/commands/greenhouse.lua | 5 +++++ sink.go | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/nature/commands/greenhouse.lua b/nature/commands/greenhouse.lua index 2baf3cca..351b1206 100644 --- a/nature/commands/greenhouse.lua +++ b/nature/commands/greenhouse.lua @@ -10,6 +10,11 @@ commander.register('greenhouse', function(args, sinks) local gh = Greenhouse(sinks.out) local done = false + if sinks['in'].pipe then + local page = Page(sinks['in']:readAll()) + gh:addPage(page) + end + for _, name in ipairs(args) do local f = io.open(name, 'r') if not f then diff --git a/sink.go b/sink.go index 2ecc19d3..62e9bec3 100644 --- a/sink.go +++ b/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,6 +67,38 @@ func setupSinkType(rtm *rt.Runtime) { l.SetRegistry(sinkMetaKey, rt.TableValue(sinkMeta)) } + +// #member +// read() -> string +// --- @returns string +// Reads 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 From 076118d2371abdcc2e79353236917bd91e66a87c Mon Sep 17 00:00:00 2001 From: sammyette Date: Tue, 11 Apr 2023 20:44:29 -0400 Subject: [PATCH 09/39] feat: make doc command use pager --- nature/commands/doc.lua | 7 ++- nature/commands/greenhouse.lua | 69 +---------------------------- nature/greenhouse/init.lua | 80 +++++++++++++++++++++++++++++++++- 3 files changed, 86 insertions(+), 70 deletions(-) diff --git a/nature/commands/doc.lua b/nature/commands/doc.lua index d37e6770..841f9127 100644 --- a/nature/commands/doc.lua +++ b/nature/commands/doc.lua @@ -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) diff --git a/nature/commands/greenhouse.lua b/nature/commands/greenhouse.lua index 351b1206..7b38d33b 100644 --- a/nature/commands/greenhouse.lua +++ b/nature/commands/greenhouse.lua @@ -8,7 +8,6 @@ local Page = require 'nature.greenhouse.page' commander.register('greenhouse', function(args, sinks) local gh = Greenhouse(sinks.out) - local done = false if sinks['in'].pipe then local page = Page(sinks['in']:readAll()) @@ -25,71 +24,5 @@ commander.register('greenhouse', function(args, sinks) gh:addPage(page) end - bait.catch('signal.sigint', function() - done = true - end) - - bait.catch('signal.resize', function() - gh:update() - end) - - 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 - - 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 - gh:next() - elseif c5 == 68 then - gh:previous() - end - end - end - end - end - goto continue - end - print('\nchar:') - print(c) - - ::continue:: - end - end) - - while not done do - -- - end - ansikit.clear() - ansikit.screenMain() + gh:initUi() end) - -function read() - terminal.saveState() - terminal.setRaw() - local c = io.read(1) - - terminal.restoreState() - return c:byte() -end diff --git a/nature/greenhouse/init.lua b/nature/greenhouse/init.lua index 0b710c20..3cd41338 100644 --- a/nature/greenhouse/init.lua +++ b/nature/greenhouse/init.lua @@ -44,7 +44,7 @@ function Greenhouse:draw() self.sink:write '\r' self.sink:write(ansikit.getCSI(self.region.height - self.start.. ';1', 'H')) - self.sink:writeln(string.format('Page %d', self.curPage)) + self.sink:writeln(string.format('\27[0mPage %d', self.curPage)) end function Greenhouse:scroll(direction) @@ -85,4 +85,82 @@ function Greenhouse:previous() 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 From f9546e10e499ac356a99bdc0b423edb1fbcd03ef Mon Sep 17 00:00:00 2001 From: sammyette Date: Fri, 14 Apr 2023 00:45:30 -0400 Subject: [PATCH 10/39] docs: update doc strings for sink read functions --- sink.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sink.go b/sink.go index 62e9bec3..3aa5507f 100644 --- a/sink.go +++ b/sink.go @@ -69,9 +69,9 @@ func setupSinkType(rtm *rt.Runtime) { // #member -// read() -> string +// readAll() -> string // --- @returns string -// Reads input from the sink. +// 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 @@ -102,7 +102,7 @@ func luaSinkReadAll(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { // #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 From b6315639b2b5537a6a140daa426c55e84fce6147 Mon Sep 17 00:00:00 2001 From: sammyette Date: Sun, 9 Jul 2023 16:27:11 -0400 Subject: [PATCH 11/39] feat: add getChar function to editor interface this is a simple command that returns a single key from the user. this can be used to read keystrokes in an interactive program like how greenhouse (the pager) does it --- editor.go | 11 ++++++++ nature/commands/doc.lua | 2 +- nature/greenhouse/init.lua | 20 +++++++++++---- readline/codes.go | 52 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 79 insertions(+), 6 deletions(-) diff --git a/editor.go b/editor.go index 3038f074..d720a419 100644 --- a/editor.go +++ b/editor.go @@ -16,6 +16,7 @@ func editorLoader(rtm *rt.Runtime) *rt.Table { "setVimRegister": {editorSetRegister, 1, false}, "getVimRegister": {editorGetRegister, 2, false}, "getLine": {editorGetLine, 0, false}, + "readChar": {editorReadChar, 0, false}, } mod := rt.NewTable() @@ -94,3 +95,13 @@ func editorGetLine(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { return c.PushingNext1(t.Runtime, rt.StringValue(string(buf))), nil } + +// #interface editor +// getChar() -> string +// Reads a keystroke from the user. This is in a format +// of something like Ctrl-L.. +func editorReadChar(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { + buf := lr.rl.ReadChar() + + return c.PushingNext1(t.Runtime, rt.StringValue(string(buf))), nil +} diff --git a/nature/commands/doc.lua b/nature/commands/doc.lua index 841f9127..a7162bf6 100644 --- a/nature/commands/doc.lua +++ b/nature/commands/doc.lua @@ -60,7 +60,7 @@ Available sections: ]] .. table.concat(modules, ', ') return lunacolors.underline(lunacolors.blue(string.gsub(fname, '.md', ''))) end) if #moddocs ~= 0 then - funcdocs = funcdocs .. '\nSubdocs: ' .. table.concat(subdocs, ', ') + funcdocs = funcdocs .. '\nSubdocs: ' .. table.concat(subdocs, ', ') .. '\nLMAO' end local valsStr = funcdocs:match '%-%-%-\n([^%-%-%-]+)\n' diff --git a/nature/greenhouse/init.lua b/nature/greenhouse/init.lua index 3cd41338..57a3fb3d 100644 --- a/nature/greenhouse/init.lua +++ b/nature/greenhouse/init.lua @@ -110,10 +110,21 @@ function Greenhouse:initUi() hilbish.goro(function() while not done do local c = read() - if c == 3 then + if c == 'Ctrl-D' then done = true end + if c == 'Up' then + self:scroll 'up' + end + if c == 'Down' then + self:scroll 'down' + end + + if c == 'Ctrl-Right' then self:next() end + if c == 'Ctrl-Left' then self:previous() end + + --[[ if c == 27 then local c1 = read() if c1 == 91 then @@ -141,8 +152,7 @@ function Greenhouse:initUi() end goto continue end - print('\nchar:') - print(c) + ]]-- ::continue:: end @@ -157,10 +167,10 @@ end function read() terminal.saveState() terminal.setRaw() - local c = io.read(1) + local c = hilbish.editor.readChar() terminal.restoreState() - return c:byte() + return c end return Greenhouse diff --git a/readline/codes.go b/readline/codes.go index 492bc721..aeb042a8 100644 --- a/readline/codes.go +++ b/readline/codes.go @@ -1,5 +1,7 @@ package readline +import "os" + // Character codes const ( charCtrlA = iota + 1 @@ -134,3 +136,53 @@ const ( const ( seqCtermFg255 = "\033[48;5;255m" ) + +// TODO: return whether its actually a sequence or not +// remedies the edge case of someone literally typing Ctrl-A for example. +func (rl *Instance) ReadChar() string { + b := make([]byte, 1024) + i, _ := os.Stdin.Read(b) + r := []rune(string(b)) + s := string(r[:i]) + + switch b[0] { + case charCtrlA: return "Ctrl-A" + case charCtrlB: return "Ctrl-B" + case charCtrlC: return "Ctrl-C" + case charEOF: return "Ctrl-D" + case charCtrlE: return "Ctrl-E" + case charCtrlF: return "Ctrl-F" + case charCtrlG: return "Ctrl-G" + case charBackspace, charBackspace2: return "Backspace" + case charTab: return "Tab" + case charCtrlJ: return "Ctrl-J" + case charCtrlK: return "Ctrl-K" + case charCtrlL: return "Ctrl-L" + case charCtrlM: return "Ctrl-M" + case charCtrlN: return "Ctrl-N" + case charCtrlO: return "Ctrl-O" + case charCtrlP: return "Ctrl-P" + case charCtrlQ: return "Ctrl-Q" + case charCtrlR: return "Ctrl-R" + case charCtrlS: return "Ctrl-S" + case charCtrlT: return "Ctrl-T" + case charCtrlU: return "Ctrl-U" + case charCtrlV: return "Ctrl-V" + case charCtrlW: return "Ctrl-W" + case charCtrlX: return "Ctrl-X" + case charCtrlY: return "Ctrl-Y" + case charCtrlZ: return "Ctrl-Z" + case charEscape: + switch s { + case string(charEscape): return "Escape" + case seqUp: return "Up" + case seqDown: return "Down" + case seqBackwards: return "Left" + case seqForwards: return "Right" + case seqCtrlLeftArrow: return "Ctrl-Left" + case seqCtrlRightArrow: return "Ctrl-Right" + } + } + + return "???" +} From e0d59a3239453fce76c084e319b1ccbc1f40d049 Mon Sep 17 00:00:00 2001 From: sammyette Date: Sun, 9 Jul 2023 16:32:19 -0400 Subject: [PATCH 12/39] ci: run docgen on prs and every branch --- .github/workflows/docs.yml | 5 ++--- editor.go | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 6515d25b..d3e2d582 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -1,9 +1,8 @@ name: Generate docs on: - push: - branches: - - master + - push + - pull_requests jobs: gen: diff --git a/editor.go b/editor.go index d720a419..60eeb0b1 100644 --- a/editor.go +++ b/editor.go @@ -99,7 +99,7 @@ func editorGetLine(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { // #interface editor // getChar() -> string // Reads a keystroke from the user. This is in a format -// of something like Ctrl-L.. +// of something like Ctrl-L. func editorReadChar(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { buf := lr.rl.ReadChar() From d5e31850bbaba907c870206bb2b33054f7191bb9 Mon Sep 17 00:00:00 2001 From: sammyette Date: Sun, 9 Jul 2023 16:45:42 -0400 Subject: [PATCH 13/39] ci: fix docs action --- .github/workflows/docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index d3e2d582..4197999b 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -2,7 +2,7 @@ name: Generate docs on: - push - - pull_requests + - pull_request jobs: gen: From 47582e167ecabd9c5724d2385e3030110b853525 Mon Sep 17 00:00:00 2001 From: sammyette Date: Sun, 9 Jul 2023 16:48:51 -0400 Subject: [PATCH 14/39] ci: stop using deprecated method of setting branch name --- .github/workflows/website.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/website.yml b/.github/workflows/website.yml index 6ee43492..2a14ec3e 100644 --- a/.github/workflows/website.yml +++ b/.github/workflows/website.yml @@ -21,27 +21,28 @@ jobs: - name: Set branch name id: branch + run: echo "BRANCH_NAME=${GITHUB_REF##*/}" >> "$GITHUB_ENV" run: echo "::set-output name=BRANCH_NAME::${GITHUB_REF##*/}" - name: Fix base URL - if: steps.branch.outputs.BRANCH_NAME != 'master' && github.repository_owner == 'Rosettea' - run: sed -i "s%baseURL = 'https://rosettea.github.io/Hilbish/'%baseURL = 'https://rosettea.github.io/Hilbish/versions/${{ steps.branch.outputs.BRANCH_NAME }}'%" website/config.toml + if: env.BRANCH_NAME != 'master' && github.repository_owner == 'Rosettea' + run: sed -i "s%baseURL = 'https://rosettea.github.io/Hilbish/'%baseURL = 'https://rosettea.github.io/Hilbish/versions/${{ env.BRANCH_NAME }}'%" website/config.toml - name: Build run: 'cd website && hugo --minify' - name: Deploy - if: steps.branch.outputs.BRANCH_NAME == 'master' && github.repository_owner == 'Rosettea' + if: env.BRANCH_NAME == 'master' && github.repository_owner == 'Rosettea' uses: peaceiris/actions-gh-pages@v3 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: ./website/public keep_files: true - name: Deploy - if: steps.branch.outputs.BRANCH_NAME != 'master' && github.repository_owner == 'Rosettea' + if: env.BRANCH_NAME != 'master' && github.repository_owner == 'Rosettea' uses: peaceiris/actions-gh-pages@v3 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: ./website/public - destination_dir: versions/${{ steps.branch.outputs.BRANCH_NAME }} + destination_dir: versions/${{ env.BRANCH_NAME }} keep_files: true From 99a121b6fa492936055e67810589238ddcfb7f51 Mon Sep 17 00:00:00 2001 From: TorchedSammy Date: Sun, 9 Jul 2023 20:49:25 +0000 Subject: [PATCH 15/39] docs: [ci] generate new docs --- docs/api/hilbish/_index.md | 5 ++++- docs/api/hilbish/hilbish.editor.md | 4 ++++ emmyLuaDocs/hilbish.lua | 10 +++++++++- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/docs/api/hilbish/_index.md b/docs/api/hilbish/_index.md index 8fb587a4..bb00b145 100644 --- a/docs/api/hilbish/_index.md +++ b/docs/api/hilbish/_index.md @@ -125,7 +125,10 @@ A call with no argument will toggle the value. Flush writes all buffered input to the sink. #### read() -> string -Reads input from the sink. +Reads a liine of input from the sink. + +#### readAll() -> string +Reads all input from the sink. #### write(str) Writes data to a sink. diff --git a/docs/api/hilbish/hilbish.editor.md b/docs/api/hilbish/hilbish.editor.md index 30a3842d..55c49ec2 100644 --- a/docs/api/hilbish/hilbish.editor.md +++ b/docs/api/hilbish/hilbish.editor.md @@ -21,6 +21,10 @@ Returns the text that is at the register. ### insert(text) Inserts text into the line. +### getChar() -> string +Reads a keystroke from the user. This is in a format +of something like Ctrl-L. + ### setVimRegister(register, text) Sets the vim register at `register` to hold the passed text. diff --git a/emmyLuaDocs/hilbish.lua b/emmyLuaDocs/hilbish.lua index c26c7ecc..50de52cf 100644 --- a/emmyLuaDocs/hilbish.lua +++ b/emmyLuaDocs/hilbish.lua @@ -40,6 +40,10 @@ function hilbish.editor.getVimRegister(register) end --- Inserts text into the line. function hilbish.editor.insert(text) end +--- Reads a keystroke from the user. This is in a format +--- of something like Ctrl-L. +function hilbish.editor.getChar() end + --- Sets the vim register at `register` to hold the passed text. --- @param register string --- @param text string @@ -196,10 +200,14 @@ function hilbish:autoFlush(auto) end --- Flush writes all buffered input to the sink. function hilbish:flush() end ---- Reads input from the sink. +--- Reads a liine of input from the sink. --- @returns string function hilbish:read() end +--- Reads all input from the sink. +--- @returns string +function hilbish:readAll() end + --- Writes data to a sink. function hilbish:write(str) end From 2dcae512adfee4a29b0225debd8aac464242a916 Mon Sep 17 00:00:00 2001 From: sammyette Date: Sun, 9 Jul 2023 16:50:31 -0400 Subject: [PATCH 16/39] ci: remove duplicate run command --- .github/workflows/website.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/website.yml b/.github/workflows/website.yml index 2a14ec3e..3f3a5f91 100644 --- a/.github/workflows/website.yml +++ b/.github/workflows/website.yml @@ -22,7 +22,6 @@ jobs: - name: Set branch name id: branch run: echo "BRANCH_NAME=${GITHUB_REF##*/}" >> "$GITHUB_ENV" - run: echo "::set-output name=BRANCH_NAME::${GITHUB_REF##*/}" - name: Fix base URL if: env.BRANCH_NAME != 'master' && github.repository_owner == 'Rosettea' From 157984e16c9b1350a424298b90b0528620f6ab5e Mon Sep 17 00:00:00 2001 From: sammyette Date: Sun, 9 Jul 2023 16:53:35 -0400 Subject: [PATCH 17/39] ci: revert "ci: run docgen on prs and every branch" This reverts commit e0d59a3239453fce76c084e319b1ccbc1f40d049. --- .github/workflows/docs.yml | 5 +++-- editor.go | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 4197999b..6515d25b 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -1,8 +1,9 @@ name: Generate docs on: - - push - - pull_request + push: + branches: + - master jobs: gen: diff --git a/editor.go b/editor.go index 60eeb0b1..d720a419 100644 --- a/editor.go +++ b/editor.go @@ -99,7 +99,7 @@ func editorGetLine(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { // #interface editor // getChar() -> string // Reads a keystroke from the user. This is in a format -// of something like Ctrl-L. +// of something like Ctrl-L.. func editorReadChar(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { buf := lr.rl.ReadChar() From e013ecdb7bc91cb0d4aec75b10e04fa7f61d4c94 Mon Sep 17 00:00:00 2001 From: sammyette Date: Sun, 9 Jul 2023 17:06:29 -0400 Subject: [PATCH 18/39] ci: fix branch name --- .github/workflows/website.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/website.yml b/.github/workflows/website.yml index 3f3a5f91..322f921f 100644 --- a/.github/workflows/website.yml +++ b/.github/workflows/website.yml @@ -21,7 +21,7 @@ jobs: - name: Set branch name id: branch - run: echo "BRANCH_NAME=${GITHUB_REF##*/}" >> "$GITHUB_ENV" + run: echo "BRANCH_NAME=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}} >> "$GITHUB_ENV" - name: Fix base URL if: env.BRANCH_NAME != 'master' && github.repository_owner == 'Rosettea' From e4c30761896e8df34042a29fe81a97538d7f05a4 Mon Sep 17 00:00:00 2001 From: sammyette Date: Sun, 9 Jul 2023 17:08:14 -0400 Subject: [PATCH 19/39] ci: add missing quote --- .github/workflows/website.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/website.yml b/.github/workflows/website.yml index 322f921f..88a78ae1 100644 --- a/.github/workflows/website.yml +++ b/.github/workflows/website.yml @@ -21,7 +21,7 @@ jobs: - name: Set branch name id: branch - run: echo "BRANCH_NAME=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}} >> "$GITHUB_ENV" + run: echo "BRANCH_NAME=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}" >> "$GITHUB_ENV" - name: Fix base URL if: env.BRANCH_NAME != 'master' && github.repository_owner == 'Rosettea' From 60f267260b3ebbaca04a92328d7367023459365a Mon Sep 17 00:00:00 2001 From: sammyette Date: Sun, 9 Jul 2023 20:15:57 -0400 Subject: [PATCH 20/39] feat: add more keys for readchar function --- readline/codes.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/readline/codes.go b/readline/codes.go index aeb042a8..d5eda591 100644 --- a/readline/codes.go +++ b/readline/codes.go @@ -181,6 +181,10 @@ func (rl *Instance) ReadChar() string { case seqForwards: return "Right" case seqCtrlLeftArrow: return "Ctrl-Left" case seqCtrlRightArrow: return "Ctrl-Right" + case seqCtrlDelete, seqCtrlDelete2: return "Ctrl-Delete" + case seqHome, seqHomeSc: return "Home" + case seqEnd, seqEndSc: return "End" + case seqDelete, seqDelete2: return "Delete" } } From 713f24aa3e67e55fa5d7fba62b46204aaca2f065 Mon Sep 17 00:00:00 2001 From: sammyette Date: Sun, 9 Jul 2023 20:22:59 -0400 Subject: [PATCH 21/39] feat(greenhouse): add functions for custom keybinds --- nature/greenhouse/init.lua | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/nature/greenhouse/init.lua b/nature/greenhouse/init.lua index 57a3fb3d..8896a865 100644 --- a/nature/greenhouse/init.lua +++ b/nature/greenhouse/init.lua @@ -18,6 +18,12 @@ function Greenhouse:new(sink) self.sink = sink self.pages = {} self.curPage = 1 + self.keybinds = { + ['Up'] = function(self) self:scroll 'up' end, + ['Down'] = function(self) self:scroll 'down' end, + ['Ctrl-Left'] = self.previous, + ['Ctrl-Right'] = self.next + } return self end @@ -85,6 +91,10 @@ function Greenhouse:previous() end end +function Greenhouse:keybind(key, callback) + self.keybinds[key] = callback +end + function Greenhouse:initUi() local ansikit = require 'ansikit' local bait = require 'bait' @@ -114,15 +124,9 @@ function Greenhouse:initUi() done = true end - if c == 'Up' then - self:scroll 'up' + if self.keybinds[c] then + self.keybinds[c](self) end - if c == 'Down' then - self:scroll 'down' - end - - if c == 'Ctrl-Right' then self:next() end - if c == 'Ctrl-Left' then self:previous() end --[[ if c == 27 then From 0bb97a6f3b14000da9bff673c81c3ef774ce464a Mon Sep 17 00:00:00 2001 From: sammyette Date: Sun, 9 Jul 2023 22:38:34 -0400 Subject: [PATCH 22/39] feat: add table of contents to pager another change in this commit is having a separate render function for the greenhouse caller to handle ui this means there isnt a hardcoded space at the bottom to display command and status line --- nature/commands/greenhouse.lua | 40 +++++++++++- nature/greenhouse/init.lua | 115 ++++++++++++++++++++++++++++----- nature/greenhouse/page.lua | 7 +- readline/codes.go | 4 +- 4 files changed, 144 insertions(+), 22 deletions(-) diff --git a/nature/commands/greenhouse.lua b/nature/commands/greenhouse.lua index 7b38d33b..b147db40 100644 --- a/nature/commands/greenhouse.lua +++ b/nature/commands/greenhouse.lua @@ -8,9 +8,45 @@ local Page = require 'nature.greenhouse.page' commander.register('greenhouse', function(args, sinks) local gh = Greenhouse(sinks.out) + function gh:resize() + local size = terminal.size() + self.region = { + width = size.width, + height = size.height - 2 + } + end + local oldDraw = gh.draw + function gh:draw() + oldDraw(self) + local workingPage = self.pages[self.curPage] + local offset = self.offset + if self.isToc then + offset = self.tocOffset + workingPage = self.tocPage + end + + self.sink:write(ansikit.getCSI((self.region.height + 2) - self.start.. ';1', 'H')) + if not self.isToc then + self.sink:write(string.format('\27[0mPage %d', self.curPage)) + if workingPage.title ~= '' then + self.sink:writeln(' — ' .. workingPage.title) + else + self.sink:writeln('') + end + end + self.sink:write(buffer) + end + gh:resize() + + gh:keybind('Enter', function(self) + if self.isToc then + self:jump(self.tocPageIdx) + self:toc(true) + end + end) if sinks['in'].pipe then - local page = Page(sinks['in']:readAll()) + local page = Page('', sinks['in']:readAll()) gh:addPage(page) end @@ -20,7 +56,7 @@ commander.register('greenhouse', function(args, sinks) sinks.err:writeln(string.format('could not open file %s', name)) end - local page = Page(f:read '*a') + local page = Page(name, f:read '*a') gh:addPage(page) end diff --git a/nature/greenhouse/init.lua b/nature/greenhouse/init.lua index 8896a865..3995befc 100644 --- a/nature/greenhouse/init.lua +++ b/nature/greenhouse/init.lua @@ -5,7 +5,9 @@ -- and flowerbook. local ansikit = require 'ansikit' +local lunacolors = require 'lunacolors' local terminal = require 'terminal' +local Page = require 'nature.greenhouse.page' local Object = require 'nature.object' local Greenhouse = Object:extend() @@ -14,7 +16,7 @@ function Greenhouse:new(sink) local size = terminal.size() self.region = size self.start = 1 - self.offset = 1 + self.offset = 1 -- vertical text offset self.sink = sink self.pages = {} self.curPage = 1 @@ -22,8 +24,13 @@ function Greenhouse:new(sink) ['Up'] = function(self) self:scroll 'up' end, ['Down'] = function(self) self:scroll 'down' end, ['Ctrl-Left'] = self.previous, - ['Ctrl-Right'] = self.next + ['Ctrl-Right'] = self.next, + ['Ctrl-N'] = function(self) self:toc(true) end, } + self.isToc = false + self.tocPage = nil + self.tocPageIdx = 1 + self.tocOffset = 1 return self end @@ -38,22 +45,39 @@ function Greenhouse:updateCurrentPage(text) end function Greenhouse:draw() - local lines = self.pages[self.curPage].lines + local workingPage = self.pages[self.curPage] + local offset = self.offset + if self.isToc then + offset = self.tocOffset + workingPage = self.tocPage + end + + local lines = workingPage.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 + for i = offset, offset + (self.region.height - self.start) 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:render() +end - self.sink:write(ansikit.getCSI(self.region.height - self.start.. ';1', 'H')) - self.sink:writeln(string.format('\27[0mPage %d', self.curPage)) +function Greenhouse:render() end function Greenhouse:scroll(direction) + if self.isToc then + if direction == 'down' then + self:next(true) + elseif direction == 'up' then + self:previous(true) + end + return + end + local lines = self.pages[self.curPage].lines local oldOffset = self.offset @@ -67,34 +91,91 @@ function Greenhouse:scroll(direction) end function Greenhouse:update() + self:resize() + if self.isToc then + self:toc() + end + + self:draw() +end + +function Greenhouse:resize() local size = terminal.size() self.region = size +end - self:draw() +function Greenhouse:next(toc) + local oldCurrent = toc and self.tocPageIdx or self.curPage + local pageIdx = math.min(oldCurrent + 1, #self.pages) + + if toc then + self.tocPageIdx = pageIdx + else + self.curPage = pageIdx + end + + if pageIdx ~= oldCurrent then + self.offset = 1 + self:update() + end end -function Greenhouse:next() - local oldCurrent = self.curPage - self.curPage = math.min(self.curPage + 1, #self.pages) - if self.curPage ~= oldCurrent then +function Greenhouse:previous(toc) + local oldCurrent = toc and self.tocPageIdx or self.curPage + local pageIdx = math.max(self.curPage - 1, 1) + + if toc then + self.tocPageIdx = pageIdx + else + self.curPage = pageIdx + end + + if pageIdx ~= oldCurrent then self.offset = 1 - self:draw() + self:update() end end -function Greenhouse:previous() - local oldCurrent = self.curPage - self.curPage = math.max(self.curPage - 1, 1) - if self.curPage ~= oldCurrent then +function Greenhouse:jump(idx) + if idx ~= self.curPage then self.offset = 1 - self:draw() end + self.curPage = idx + self:update() end function Greenhouse:keybind(key, callback) self.keybinds[key] = callback end +function Greenhouse:toc(toggle) + if not self.isToc then + self.tocPageIdx = self.curPage + end + if toggle then self.isToc = not self.isToc end + -- Generate a special page for our table of contents + local tocText = string.format([[ +%s + +]], lunacolors.cyan(lunacolors.bold '―― Table of Contents ――')) + + local genericPageCount = 1 + for i, page in ipairs(self.pages) do + local title = page.title + if title == 'Page' then + title = 'Page #' .. genericPageCount + genericPageCount = genericPageCount + 1 + end + if i == self.tocPageIdx then + title = lunacolors.invert(title) + end + + tocText = tocText .. title .. '\n' + end + self.tocPage = Page('TOC', tocText) + self:draw() +end + function Greenhouse:initUi() local ansikit = require 'ansikit' local bait = require 'bait' diff --git a/nature/greenhouse/page.lua b/nature/greenhouse/page.lua index 09f1e91b..b26f8e2e 100644 --- a/nature/greenhouse/page.lua +++ b/nature/greenhouse/page.lua @@ -2,12 +2,17 @@ local Object = require 'nature.object' local Page = Object:extend() -function Page:new(text) +function Page:new(title, text) self:setText(text) + self.title = title or 'Page' end function Page:setText(text) self.lines = string.split(text, '\n') end +function Page:setTitle(title) + self.title = title +end + return Page diff --git a/readline/codes.go b/readline/codes.go index d5eda591..98159948 100644 --- a/readline/codes.go +++ b/readline/codes.go @@ -155,10 +155,8 @@ func (rl *Instance) ReadChar() string { case charCtrlG: return "Ctrl-G" case charBackspace, charBackspace2: return "Backspace" case charTab: return "Tab" - case charCtrlJ: return "Ctrl-J" case charCtrlK: return "Ctrl-K" case charCtrlL: return "Ctrl-L" - case charCtrlM: return "Ctrl-M" case charCtrlN: return "Ctrl-N" case charCtrlO: return "Ctrl-O" case charCtrlP: return "Ctrl-P" @@ -172,6 +170,8 @@ func (rl *Instance) ReadChar() string { case charCtrlX: return "Ctrl-X" case charCtrlY: return "Ctrl-Y" case charCtrlZ: return "Ctrl-Z" + case '\r': fallthrough + case '\n': return "Enter" case charEscape: switch s { case string(charEscape): return "Escape" From 8b672f5b955a5ec1b2caba894782d1d9bfdad690 Mon Sep 17 00:00:00 2001 From: sammyette Date: Sun, 9 Jul 2023 23:07:32 -0400 Subject: [PATCH 23/39] feat(greenhouse): add command handling --- nature/commands/greenhouse.lua | 41 ++++++++++++++++++++++++++++++++++ nature/greenhouse/init.lua | 9 ++++++-- readline/codes.go | 2 +- 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/nature/commands/greenhouse.lua b/nature/commands/greenhouse.lua index b147db40..b5a1ee49 100644 --- a/nature/commands/greenhouse.lua +++ b/nature/commands/greenhouse.lua @@ -8,6 +8,15 @@ local Page = require 'nature.greenhouse.page' commander.register('greenhouse', function(args, sinks) local gh = Greenhouse(sinks.out) + + local buffer = '' + local command = false + local commands = { + q = function() + gh.keybinds['Ctrl-D'](gh) + end + } + function gh:resize() local size = terminal.size() self.region = { @@ -15,6 +24,7 @@ commander.register('greenhouse', function(args, sinks) height = size.height - 2 } end + local oldDraw = gh.draw function gh:draw() oldDraw(self) @@ -36,12 +46,43 @@ commander.register('greenhouse', function(args, sinks) end self.sink:write(buffer) end + function gh:input(c) + -- command handling + if c == ':' and not command then + command = true + end + if c == 'Escape' then + command = false + buffer = '' + goto update + elseif c == 'Backspace' then + buffer = buffer:sub(0, -2) + goto update + end + + if command then + buffer = buffer .. c + end + + ::update:: + gh:update() + end gh:resize() gh:keybind('Enter', function(self) if self.isToc then self:jump(self.tocPageIdx) self:toc(true) + else + if buffer:len() < 2 then return end + + local splitBuf = string.split(buffer, " ") + local command = commands[splitBuf[1]:sub(2)] + if command then + table.remove(splitBuf, 1) + command(splitBuf) + end + self:update() end end) diff --git a/nature/greenhouse/init.lua b/nature/greenhouse/init.lua index 3995befc..2e2d4d10 100644 --- a/nature/greenhouse/init.lua +++ b/nature/greenhouse/init.lua @@ -176,6 +176,9 @@ function Greenhouse:toc(toggle) self:draw() end +function Greenhouse:input(char) +end + function Greenhouse:initUi() local ansikit = require 'ansikit' local bait = require 'bait' @@ -201,12 +204,14 @@ function Greenhouse:initUi() hilbish.goro(function() while not done do local c = read() - if c == 'Ctrl-D' then + self:keybind('Ctrl-D', function() done = true - end + end) if self.keybinds[c] then self.keybinds[c](self) + else + self:input(c) end --[[ diff --git a/readline/codes.go b/readline/codes.go index 98159948..dd8495d0 100644 --- a/readline/codes.go +++ b/readline/codes.go @@ -188,5 +188,5 @@ func (rl *Instance) ReadChar() string { } } - return "???" + return s } From 11da2c0c4549d33a2154cbe0b9bbff3412a5db89 Mon Sep 17 00:00:00 2001 From: sammyette Date: Sun, 9 Jul 2023 23:39:11 -0400 Subject: [PATCH 24/39] feat(greenhouse): add goto command made some other minor changes (in terms of how much it matters to the user) the toc page is now a "special page" in a next commit itll also be used for a help page cursor gets hidden unless typing a command --- nature/commands/greenhouse.lua | 45 +++++++++++----- nature/greenhouse/init.lua | 98 ++++++++++++++++++---------------- 2 files changed, 83 insertions(+), 60 deletions(-) diff --git a/nature/commands/greenhouse.lua b/nature/commands/greenhouse.lua index b5a1ee49..ac96991c 100644 --- a/nature/commands/greenhouse.lua +++ b/nature/commands/greenhouse.lua @@ -10,10 +10,17 @@ commander.register('greenhouse', function(args, sinks) local gh = Greenhouse(sinks.out) local buffer = '' + local display = '' local command = false local commands = { q = function() gh.keybinds['Ctrl-D'](gh) + end, + ['goto'] = function(args) + if not args[1] then + return 'nuh uh' + end + gh:jump(tonumber(args[1])) end } @@ -30,13 +37,13 @@ commander.register('greenhouse', function(args, sinks) oldDraw(self) local workingPage = self.pages[self.curPage] local offset = self.offset - if self.isToc then - offset = self.tocOffset - workingPage = self.tocPage + if self.isSpecial then + offset = self.specialOffset + workingPage = self.specialPage end self.sink:write(ansikit.getCSI((self.region.height + 2) - self.start.. ';1', 'H')) - if not self.isToc then + if not self.isSpecial then self.sink:write(string.format('\27[0mPage %d', self.curPage)) if workingPage.title ~= '' then self.sink:writeln(' — ' .. workingPage.title) @@ -44,7 +51,7 @@ commander.register('greenhouse', function(args, sinks) self.sink:writeln('') end end - self.sink:write(buffer) + self.sink:write(buffer == '' and display or buffer) end function gh:input(c) -- command handling @@ -52,16 +59,26 @@ commander.register('greenhouse', function(args, sinks) command = true end if c == 'Escape' then - command = false - buffer = '' - goto update + if command then + command = false + buffer = '' + else + if self.isSpecial then gh:special() end + end elseif c == 'Backspace' then buffer = buffer:sub(0, -2) - goto update + if buffer == '' then + command = false + else + goto update + end end if command then - buffer = buffer .. c + ansikit.showCursor() + if buffer:match '^:' then buffer = buffer .. c else buffer = c end + else + ansikit.hideCursor() end ::update:: @@ -70,9 +87,9 @@ commander.register('greenhouse', function(args, sinks) gh:resize() gh:keybind('Enter', function(self) - if self.isToc then - self:jump(self.tocPageIdx) - self:toc(true) + if self.isSpecial then + self:jump(self.specialPageIdx) + self:special(true) else if buffer:len() < 2 then return end @@ -80,7 +97,7 @@ commander.register('greenhouse', function(args, sinks) local command = commands[splitBuf[1]:sub(2)] if command then table.remove(splitBuf, 1) - command(splitBuf) + buffer = command(splitBuf) or '' end self:update() end diff --git a/nature/greenhouse/init.lua b/nature/greenhouse/init.lua index 2e2d4d10..1e899969 100644 --- a/nature/greenhouse/init.lua +++ b/nature/greenhouse/init.lua @@ -27,10 +27,10 @@ function Greenhouse:new(sink) ['Ctrl-Right'] = self.next, ['Ctrl-N'] = function(self) self:toc(true) end, } - self.isToc = false - self.tocPage = nil - self.tocPageIdx = 1 - self.tocOffset = 1 + self.isSpecial = false + self.specialPage = nil + self.specialPageIdx = 1 + self.specialOffset = 1 return self end @@ -47,9 +47,9 @@ end function Greenhouse:draw() local workingPage = self.pages[self.curPage] local offset = self.offset - if self.isToc then - offset = self.tocOffset - workingPage = self.tocPage + if self.isSpecial then + offset = self.specialOffset + workingPage = self.specialPage end local lines = workingPage.lines @@ -69,7 +69,7 @@ function Greenhouse:render() end function Greenhouse:scroll(direction) - if self.isToc then + if self.isSpecial then if direction == 'down' then self:next(true) elseif direction == 'up' then @@ -92,24 +92,56 @@ end function Greenhouse:update() self:resize() - if self.isToc then - self:toc() + if self.isSpecial then + self:special() end self:draw() end +function Greenhouse:special() + self.isSpecial = not self.isSpecial +end + +function Greenhouse:toc(toggle) + if not self.isSpecial then + self.specialPageIdx = self.curPage + end + if toggle then self.isSpecial = not self.isSpecial end + -- Generate a special page for our table of contents + local tocText = string.format([[ +%s + +]], lunacolors.cyan(lunacolors.bold '―― Table of Contents ――')) + + local genericPageCount = 1 + for i, page in ipairs(self.pages) do + local title = page.title + if title == 'Page' then + title = 'Page #' .. genericPageCount + genericPageCount = genericPageCount + 1 + end + if i == self.specialPageIdx then + title = lunacolors.invert(title) + end + + tocText = tocText .. title .. '\n' + end + self.specialPage = Page('TOC', tocText) + self:draw() +end + function Greenhouse:resize() local size = terminal.size() self.region = size end -function Greenhouse:next(toc) - local oldCurrent = toc and self.tocPageIdx or self.curPage +function Greenhouse:next(special) + local oldCurrent = special and self.specialPageIdx or self.curPage local pageIdx = math.min(oldCurrent + 1, #self.pages) - if toc then - self.tocPageIdx = pageIdx + if special then + self.specialPageIdx = pageIdx else self.curPage = pageIdx end @@ -120,12 +152,12 @@ function Greenhouse:next(toc) end end -function Greenhouse:previous(toc) - local oldCurrent = toc and self.tocPageIdx or self.curPage +function Greenhouse:previous(special) + local oldCurrent = special and self.specialPageIdx or self.curPage local pageIdx = math.max(self.curPage - 1, 1) - if toc then - self.tocPageIdx = pageIdx + if special then + self.specialPageIdx = pageIdx else self.curPage = pageIdx end @@ -148,34 +180,6 @@ function Greenhouse:keybind(key, callback) self.keybinds[key] = callback end -function Greenhouse:toc(toggle) - if not self.isToc then - self.tocPageIdx = self.curPage - end - if toggle then self.isToc = not self.isToc end - -- Generate a special page for our table of contents - local tocText = string.format([[ -%s - -]], lunacolors.cyan(lunacolors.bold '―― Table of Contents ――')) - - local genericPageCount = 1 - for i, page in ipairs(self.pages) do - local title = page.title - if title == 'Page' then - title = 'Page #' .. genericPageCount - genericPageCount = genericPageCount + 1 - end - if i == self.tocPageIdx then - title = lunacolors.invert(title) - end - - tocText = tocText .. title .. '\n' - end - self.tocPage = Page('TOC', tocText) - self:draw() -end - function Greenhouse:input(char) end @@ -198,6 +202,7 @@ function Greenhouse:initUi() end) ansikit.screenAlt() + ansikit.hideCursor() ansikit.clear(true) self:draw() @@ -251,6 +256,7 @@ function Greenhouse:initUi() while not done do -- end + ansikit.showCursor() ansikit.screenMain() end From 1f5ab90586e6f41cb827966dac789c2deab9a359 Mon Sep 17 00:00:00 2001 From: sammyette Date: Sun, 9 Jul 2023 23:41:25 -0400 Subject: [PATCH 25/39] docs: update --- docs/api/hilbish/hilbish.editor.md | 2 +- emmyLuaDocs/hilbish.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/api/hilbish/hilbish.editor.md b/docs/api/hilbish/hilbish.editor.md index 55c49ec2..d75d4c2e 100644 --- a/docs/api/hilbish/hilbish.editor.md +++ b/docs/api/hilbish/hilbish.editor.md @@ -23,7 +23,7 @@ Inserts text into the line. ### getChar() -> string Reads a keystroke from the user. This is in a format -of something like Ctrl-L. +of something like Ctrl-L.. ### setVimRegister(register, text) Sets the vim register at `register` to hold the passed text. diff --git a/emmyLuaDocs/hilbish.lua b/emmyLuaDocs/hilbish.lua index 50de52cf..9646b8ed 100644 --- a/emmyLuaDocs/hilbish.lua +++ b/emmyLuaDocs/hilbish.lua @@ -41,7 +41,7 @@ function hilbish.editor.getVimRegister(register) end function hilbish.editor.insert(text) end --- Reads a keystroke from the user. This is in a format ---- of something like Ctrl-L. +--- of something like Ctrl-L.. function hilbish.editor.getChar() end --- Sets the vim register at `register` to hold the passed text. From ade14a62388a2ab1914228f969add1987df39dc8 Mon Sep 17 00:00:00 2001 From: sammyette Date: Mon, 10 Jul 2023 18:00:49 -0400 Subject: [PATCH 26/39] fix(greenhouse): fix toc disappearing on any key press --- nature/commands/greenhouse.lua | 3 ++- nature/greenhouse/init.lua | 21 +++++++++++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/nature/commands/greenhouse.lua b/nature/commands/greenhouse.lua index ac96991c..5f08cb3b 100644 --- a/nature/commands/greenhouse.lua +++ b/nature/commands/greenhouse.lua @@ -89,7 +89,7 @@ commander.register('greenhouse', function(args, sinks) gh:keybind('Enter', function(self) if self.isSpecial then self:jump(self.specialPageIdx) - self:special(true) + self:special(false) else if buffer:len() < 2 then return end @@ -118,5 +118,6 @@ commander.register('greenhouse', function(args, sinks) gh:addPage(page) end + ansikit.hideCursor() gh:initUi() end) diff --git a/nature/greenhouse/init.lua b/nature/greenhouse/init.lua index 1e899969..7e0b2c19 100644 --- a/nature/greenhouse/init.lua +++ b/nature/greenhouse/init.lua @@ -93,14 +93,25 @@ end function Greenhouse:update() self:resize() if self.isSpecial then - self:special() + self:updateSpecial() end self:draw() end -function Greenhouse:special() - self.isSpecial = not self.isSpecial + +function Greenhouse:special(val) + self.isSpecial = val + self:update() +end + +function Greenhouse:toggleSpecial() + self:special(not self.isSpecial) +end + +--- This function will be called when the special page +--- is on and needs to be updated. +function Greenhouse:updateSpecial() end function Greenhouse:toc(toggle) @@ -128,6 +139,9 @@ function Greenhouse:toc(toggle) tocText = tocText .. title .. '\n' end self.specialPage = Page('TOC', tocText) + function self:updateSpecial() + self:toc() + end self:draw() end @@ -202,7 +216,6 @@ function Greenhouse:initUi() end) ansikit.screenAlt() - ansikit.hideCursor() ansikit.clear(true) self:draw() From 9b39d5ffcf2418ba3427e3cd7f255032317e03f2 Mon Sep 17 00:00:00 2001 From: sammyette Date: Tue, 11 Jul 2023 20:24:20 -0400 Subject: [PATCH 27/39] fix(commands/greenhouse): set nil page title --- nature/commands/doc.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nature/commands/doc.lua b/nature/commands/doc.lua index a7162bf6..7dc33ee2 100644 --- a/nature/commands/doc.lua +++ b/nature/commands/doc.lua @@ -60,7 +60,7 @@ Available sections: ]] .. table.concat(modules, ', ') return lunacolors.underline(lunacolors.blue(string.gsub(fname, '.md', ''))) end) if #moddocs ~= 0 then - funcdocs = funcdocs .. '\nSubdocs: ' .. table.concat(subdocs, ', ') .. '\nLMAO' + funcdocs = funcdocs .. '\nSubdocs: ' .. table.concat(subdocs, ', ') end local valsStr = funcdocs:match '%-%-%-\n([^%-%-%-]+)\n' @@ -89,7 +89,7 @@ Available sections: ]] .. table.concat(modules, ', ') local gh = Greenhouse(sinks.out) local backtickOccurence = 0 - local page = Page(lunacolors.format(doc:gsub('`', function() + local page = Page(nil, lunacolors.format(doc:gsub('`', function() backtickOccurence = backtickOccurence + 1 if backtickOccurence % 2 == 0 then return '{reset}' From 5b4b055c6cbb9532f42901310db5ba26a93a1b3b Mon Sep 17 00:00:00 2001 From: sammyette Date: Tue, 11 Jul 2023 20:24:38 -0400 Subject: [PATCH 28/39] fix(greenhouse): set scroll boundary properly, fix text cutoff this means you can no longer scroll away the text until it isnt seen this commit also fixes text cutoff when using lunacolors (like in the doc command) --- nature/greenhouse/init.lua | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/nature/greenhouse/init.lua b/nature/greenhouse/init.lua index 7e0b2c19..5206089b 100644 --- a/nature/greenhouse/init.lua +++ b/nature/greenhouse/init.lua @@ -44,6 +44,21 @@ function Greenhouse:updateCurrentPage(text) page:setText(text) end +local function sub(str, limit) + local overhead = 0 + local function addOverhead(s) + overhead = overhead + string.len(s) + end + + local s = str:gsub('\x1b%[%d+;%d+;%d+;%d+;%d+%w', addOverhead) + :gsub('\x1b%[%d+;%d+;%d+;%d+%w', addOverhead) + :gsub('\x1b%[%d+;%d+;%d+%w',addOverhead) + :gsub('\x1b%[%d+;%d+%w', addOverhead) + :gsub('\x1b%[%d+%w', addOverhead) + + return s:sub(0, limit + overhead) +end + function Greenhouse:draw() local workingPage = self.pages[self.curPage] local offset = self.offset @@ -56,10 +71,9 @@ function Greenhouse:draw() 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 = offset, offset + (self.region.height - self.start) do + for i = offset, offset + (self.region.height - 1) do if i > #lines then break end - self.sink:writeln('\r' .. lines[i]:gsub('\t', ' '):sub(0, self.region.width - 2)) + self.sink:writeln('\r' .. sub(lines[i]:gsub('\t', ' '), self.region.width - 2)) end self.sink:write '\r' self:render() @@ -82,7 +96,7 @@ function Greenhouse:scroll(direction) local oldOffset = self.offset if direction == 'down' then - self.offset = math.min(self.offset + 1, #lines) + self.offset = math.min(self.offset + 1, math.max(1, #lines - self.region.height + 1)) elseif direction == 'up' then self.offset = math.max(self.offset - 1, 1) end From 48a06f8022303c4b8d501c581718996b9ddfbe7e Mon Sep 17 00:00:00 2001 From: sammyette Date: Tue, 11 Jul 2023 20:56:24 -0400 Subject: [PATCH 29/39] fix: doc command not displaying correct subdocs when using shorthand api doc access --- nature/commands/doc.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/nature/commands/doc.lua b/nature/commands/doc.lua index 7dc33ee2..15714d8b 100644 --- a/nature/commands/doc.lua +++ b/nature/commands/doc.lua @@ -34,18 +34,18 @@ Available sections: ]] .. table.concat(modules, ', ') local funcdocs = nil local subdocName = args[2] if not f then - -- assume subdir - -- dataDir/docs//.md moddocPath = moddocPath .. mod .. '/' if not subdocName then subdocName = '_index' end f = io.open(moddocPath .. subdocName .. '.md', 'rb') + local oldmoddocPath if not f then - f = io.open(moddocPath .. subdocName:match '%w+' .. '/' .. subdocName .. '.md', 'rb') + moddocPath = moddocPath .. subdocName:match '%w+' .. '/' + f = io.open(moddocPath .. subdocName .. '.md', 'rb') end if not f then - moddocPath = moddocPath .. subdocName .. '/' + moddocPath = oldmoddocPath .. subdocName .. '/' subdocName = args[3] or '_index' f = io.open(moddocPath .. subdocName .. '.md', 'rb') end From 7d0c3f3bf085d96dad2e1ac1f606f0d53f376d69 Mon Sep 17 00:00:00 2001 From: sammyette Date: Tue, 11 Jul 2023 22:27:11 -0400 Subject: [PATCH 30/39] fix: set old moddocpath --- CHANGELOG.md | 1 + nature/commands/doc.lua | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c3a2c66b..63f17783 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - `flush()` and `autoFlush()` related to flushing outputs - `pipe` property to check if a sink with input is a pipe (like stdin) - Show indexes on cdr list +- Fix doc command not displaying correct subdocs when using shorthand api doc access (`doc api hilbish.jobs` as an example) ### Fixed - Replaced `sed` in-place editing with `grep` and `mv` for compatibility with BSD utils diff --git a/nature/commands/doc.lua b/nature/commands/doc.lua index 15714d8b..9653657d 100644 --- a/nature/commands/doc.lua +++ b/nature/commands/doc.lua @@ -39,7 +39,7 @@ Available sections: ]] .. table.concat(modules, ', ') subdocName = '_index' end f = io.open(moddocPath .. subdocName .. '.md', 'rb') - local oldmoddocPath + local oldmoddocPath = moddocPath if not f then moddocPath = moddocPath .. subdocName:match '%w+' .. '/' f = io.open(moddocPath .. subdocName .. '.md', 'rb') From b9bb14497fc20ecc1a47e9c74b13b3b0329c2d52 Mon Sep 17 00:00:00 2001 From: sammyette Date: Tue, 11 Jul 2023 22:28:11 -0400 Subject: [PATCH 31/39] fix(greenhouse): print contents properly on the last line that can be displayed, don't print with a newline this removes the space at the end --- nature/greenhouse/init.lua | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/nature/greenhouse/init.lua b/nature/greenhouse/init.lua index 5206089b..c2054fd7 100644 --- a/nature/greenhouse/init.lua +++ b/nature/greenhouse/init.lua @@ -71,11 +71,14 @@ function Greenhouse:draw() self.sink:write(ansikit.getCSI(self.start .. ';1', 'H')) self.sink:write(ansikit.getCSI(2, 'J')) - for i = offset, offset + (self.region.height - 1) do + for i = offset, offset + self.region.height - 1 do if i > #lines then break end - self.sink:writeln('\r' .. sub(lines[i]:gsub('\t', ' '), self.region.width - 2)) + + local writer = self.sink.writeln + if i == offset + self.region.height - 1 then writer = self.sink.write end + + writer(self.sink, sub(lines[i]:gsub('\t', ' '), self.region.width)) end - self.sink:write '\r' self:render() end @@ -96,7 +99,7 @@ function Greenhouse:scroll(direction) local oldOffset = self.offset if direction == 'down' then - self.offset = math.min(self.offset + 1, math.max(1, #lines - self.region.height + 1)) + self.offset = math.min(self.offset + 1, math.max(1, #lines - self.region.height)) elseif direction == 'up' then self.offset = math.max(self.offset - 1, 1) end From 19bb05f001b3315d6c15311b9a8a04e42036f615 Mon Sep 17 00:00:00 2001 From: sammyette Date: Tue, 11 Jul 2023 22:29:15 -0400 Subject: [PATCH 32/39] feat: pager improvements - make use of full terminal space properly in doc and greenhouse commands - add some info in doc command like currently viewed doc and description at the bottom instead of top of doc (this makes it persistent) - add contents function to Greenhouse to allow showing custom contents in the table of contents (this will be used for lazy loading in the future) --- nature/commands/doc.lua | 42 ++++++++++++++++++++++++++-------- nature/commands/greenhouse.lua | 6 ++--- nature/greenhouse/init.lua | 36 +++++++++++++++++++++-------- 3 files changed, 60 insertions(+), 24 deletions(-) diff --git a/nature/commands/doc.lua b/nature/commands/doc.lua index 9653657d..3ba6e382 100644 --- a/nature/commands/doc.lua +++ b/nature/commands/doc.lua @@ -1,3 +1,4 @@ +local ansikit = require 'ansikit' local commander = require 'commander' local fs = require 'fs' local lunacolors = require 'lunacolors' @@ -11,11 +12,6 @@ commander.register('doc', function(args, sinks) -- hilbish git moddocPath = './docs/' end - local apidocHeader = [[ -# %s -{grayBg} {white}{italic}%s {reset} - -]] local modules = table.map(fs.readdir(moddocPath), function(f) return lunacolors.underline(lunacolors.blue(string.gsub(f, '.md', ''))) @@ -27,6 +23,8 @@ to Hilbish. Usage: doc
[subdoc] Available sections: ]] .. table.concat(modules, ', ') + local vals = {} + if #args > 0 then local mod = args[1] @@ -60,11 +58,10 @@ Available sections: ]] .. table.concat(modules, ', ') return lunacolors.underline(lunacolors.blue(string.gsub(fname, '.md', ''))) end) if #moddocs ~= 0 then - funcdocs = funcdocs .. '\nSubdocs: ' .. table.concat(subdocs, ', ') + funcdocs = funcdocs .. '\nSubdocs: ' .. table.concat(subdocs, ', ') .. '\n\n' end local valsStr = funcdocs:match '%-%-%-\n([^%-%-%-]+)\n' - local vals = {} if valsStr then local _, endpos = funcdocs:find('---\n' .. valsStr .. '\n---\n\n', 1, true) funcdocs = funcdocs:sub(endpos + 1, #funcdocs) @@ -80,14 +77,38 @@ Available sections: ]] .. table.concat(modules, ', ') end end end - if mod == 'api' then - funcdocs = string.format(apidocHeader, vals.title, vals.description or 'no description.') .. funcdocs - end doc = funcdocs:sub(1, #funcdocs - 1) f:close() end local gh = Greenhouse(sinks.out) + function gh:resize() + local size = terminal.size() + self.region = { + width = size.width, + height = size.height - 3 + } + end + gh:resize() + + function gh:render() + local workingPage = self.pages[self.curPage] + local offset = self.offset + if self.isSpecial then + offset = self.specialOffset + workingPage = self.specialPage + end + + self.sink:write(ansikit.getCSI(self.region.height + 2 .. ';1', 'H')) + if not self.isSpecial then + if args[1] == 'api' then + self.sink:writeln(lunacolors.reset(string.format('%s', vals.title))) + self.sink:write(lunacolors.format(string.format('{grayBg} ↳ {white}{italic}%s {reset}', vals.description))) + else + self.sink:write(lunacolors.reset(string.format('Viewing doc page %s', moddocPath))) + end + end + end local backtickOccurence = 0 local page = Page(nil, lunacolors.format(doc:gsub('`', function() backtickOccurence = backtickOccurence + 1 @@ -101,5 +122,6 @@ Available sections: ]] .. table.concat(modules, ', ') return '{bold}{yellow}' .. signature .. '{reset}' end))) gh:addPage(page) + ansikit.hideCursor() gh:initUi() end) diff --git a/nature/commands/greenhouse.lua b/nature/commands/greenhouse.lua index 5f08cb3b..e85ff229 100644 --- a/nature/commands/greenhouse.lua +++ b/nature/commands/greenhouse.lua @@ -32,9 +32,7 @@ commander.register('greenhouse', function(args, sinks) } end - local oldDraw = gh.draw - function gh:draw() - oldDraw(self) + function gh:render() local workingPage = self.pages[self.curPage] local offset = self.offset if self.isSpecial then @@ -42,7 +40,7 @@ commander.register('greenhouse', function(args, sinks) workingPage = self.specialPage end - self.sink:write(ansikit.getCSI((self.region.height + 2) - self.start.. ';1', 'H')) + self.sink:write(ansikit.getCSI(self.region.height + 1 .. ';1', 'H')) if not self.isSpecial then self.sink:write(string.format('\27[0mPage %d', self.curPage)) if workingPage.title ~= '' then diff --git a/nature/greenhouse/init.lua b/nature/greenhouse/init.lua index c2054fd7..673b8092 100644 --- a/nature/greenhouse/init.lua +++ b/nature/greenhouse/init.lua @@ -15,7 +15,8 @@ local Greenhouse = Object:extend() function Greenhouse:new(sink) local size = terminal.size() self.region = size - self.start = 1 + self.contents = nil -- or can be a table + self.start = 1 -- where to start drawing from (should replace with self.region.y) self.offset = 1 -- vertical text offset self.sink = sink self.pages = {} @@ -131,6 +132,9 @@ end function Greenhouse:updateSpecial() end +function Greenhouse:contents() +end + function Greenhouse:toc(toggle) if not self.isSpecial then self.specialPageIdx = self.curPage @@ -143,17 +147,29 @@ function Greenhouse:toc(toggle) ]], lunacolors.cyan(lunacolors.bold '―― Table of Contents ――')) local genericPageCount = 1 - for i, page in ipairs(self.pages) do - local title = page.title - if title == 'Page' then - title = 'Page #' .. genericPageCount - genericPageCount = genericPageCount + 1 - end - if i == self.specialPageIdx then - title = lunacolors.invert(title) + local contents = self:contents() + if contents then + for i, c in ipairs(contents) do + local title = c.title + if c.active then + title = lunacolors.invert(title) + end + + tocText = tocText .. title .. '\n' end + else + for i, page in ipairs(self.pages) do + local title = page.title + if title == 'Page' then + title = 'Page #' .. genericPageCount + genericPageCount = genericPageCount + 1 + end + if i == self.specialPageIdx then + title = lunacolors.invert(title) + end - tocText = tocText .. title .. '\n' + tocText = tocText .. title .. '\n' + end end self.specialPage = Page('TOC', tocText) function self:updateSpecial() From 264043dc1e7db5dd53a7e3a7914976c5a50310c5 Mon Sep 17 00:00:00 2001 From: sammyette Date: Tue, 24 Oct 2023 20:10:53 -0400 Subject: [PATCH 33/39] fix: show usage when no args are passed to greenhouse also niced up the display of the page title --- nature/commands/doc.lua | 2 +- nature/commands/greenhouse.lua | 31 +++++++++++++++++-------------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/nature/commands/doc.lua b/nature/commands/doc.lua index 3ba6e382..27f657ee 100644 --- a/nature/commands/doc.lua +++ b/nature/commands/doc.lua @@ -103,7 +103,7 @@ Available sections: ]] .. table.concat(modules, ', ') if not self.isSpecial then if args[1] == 'api' then self.sink:writeln(lunacolors.reset(string.format('%s', vals.title))) - self.sink:write(lunacolors.format(string.format('{grayBg} ↳ {white}{italic}%s {reset}', vals.description))) + self.sink:write(lunacolors.format(string.format('{grayBg} ↳ {white}{italic}%s {reset}', vals.description or 'No description.'))) else self.sink:write(lunacolors.reset(string.format('Viewing doc page %s', moddocPath))) end diff --git a/nature/commands/greenhouse.lua b/nature/commands/greenhouse.lua index e85ff229..8e0d0e18 100644 --- a/nature/commands/greenhouse.lua +++ b/nature/commands/greenhouse.lua @@ -2,6 +2,7 @@ local ansikit = require 'ansikit' local bait = require 'bait' local commander = require 'commander' local hilbish = require 'hilbish' +local lunacolors = require 'lunacolors' local terminal = require 'terminal' local Greenhouse = require 'nature.greenhouse' local Page = require 'nature.greenhouse.page' @@ -42,12 +43,7 @@ commander.register('greenhouse', function(args, sinks) self.sink:write(ansikit.getCSI(self.region.height + 1 .. ';1', 'H')) if not self.isSpecial then - self.sink:write(string.format('\27[0mPage %d', self.curPage)) - if workingPage.title ~= '' then - self.sink:writeln(' — ' .. workingPage.title) - else - self.sink:writeln('') - end + self.sink:writeln(lunacolors.format(string.format('{grayBg} ↳ Page %d %s{reset}', self.curPage, workingPage.title and ' — ' .. workingPage.title .. ' ' or ''))) end self.sink:write(buffer == '' and display or buffer) end @@ -106,16 +102,23 @@ commander.register('greenhouse', function(args, sinks) gh:addPage(page) end - for _, name in ipairs(args) do - local f = io.open(name, 'r') - if not f then - sinks.err:writeln(string.format('could not open file %s', name)) + if #args ~= 0 then + for _, name in ipairs(args) do + local f = io.open(name, 'r') + if not f then + sinks.err:writeln(string.format('could not open file %s', name)) + end + + local page = Page(name, f:read '*a') + gh:addPage(page) end + ansikit.hideCursor() + gh:initUi() + else + sinks.out:writeln [[greenhouse is the Hilbish pager library and command! +usage: greenhouse ... - local page = Page(name, f:read '*a') - gh:addPage(page) +example: greenhouse hello.md]] end - ansikit.hideCursor() - gh:initUi() end) From 554fb009f8c4b403c86aa4c9b9e07a02650f9a01 Mon Sep 17 00:00:00 2001 From: sammyette Date: Tue, 24 Oct 2023 23:38:19 -0400 Subject: [PATCH 34/39] fix(greenhouse): add enter bind to goto page on table of contents --- nature/greenhouse/init.lua | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/nature/greenhouse/init.lua b/nature/greenhouse/init.lua index 673b8092..604ed5b9 100644 --- a/nature/greenhouse/init.lua +++ b/nature/greenhouse/init.lua @@ -27,6 +27,12 @@ function Greenhouse:new(sink) ['Ctrl-Left'] = self.previous, ['Ctrl-Right'] = self.next, ['Ctrl-N'] = function(self) self:toc(true) end, + ['Enter'] = function(self) + if self.isSpecial then + self:jump(self.specialPageIdx) + self:special(false) + end + end } self.isSpecial = false self.specialPage = nil From 7288f85e9a65163fcc9b025af910993ea30383ab Mon Sep 17 00:00:00 2001 From: sammyette Date: Tue, 24 Oct 2023 23:51:42 -0400 Subject: [PATCH 35/39] feat(commands/doc): add subdocs as additional pages --- nature/commands/doc.lua | 111 +++++++++++++++++++++++-------------- nature/greenhouse/init.lua | 4 ++ nature/greenhouse/page.lua | 14 +++++ 3 files changed, 88 insertions(+), 41 deletions(-) diff --git a/nature/commands/doc.lua b/nature/commands/doc.lua index 27f657ee..2f8938f8 100644 --- a/nature/commands/doc.lua +++ b/nature/commands/doc.lua @@ -23,12 +23,36 @@ to Hilbish. Usage: doc
[subdoc] Available sections: ]] .. table.concat(modules, ', ') - local vals = {} + local f + local function handleYamlInfo(d) + local vals = {} + local docs = d + + local valsStr = docs:match '%-%-%-\n([^%-%-%-]+)\n' + print(valsStr) + if valsStr then + docs = docs:sub(valsStr:len() + 10, #docs) + + -- parse vals + local lines = string.split(valsStr, '\n') + for _, line in ipairs(lines) do + local key = line:match '(%w+): ' + local val = line:match '^%w+: (.-)$' + + if key then + vals[key] = val + end + end + end + + --docs = docs:sub(1, #docs - 1) + return docs, vals + end if #args > 0 then local mod = args[1] - local f = io.open(moddocPath .. mod .. '.md', 'rb') + f = io.open(moddocPath .. mod .. '.md', 'rb') local funcdocs = nil local subdocName = args[2] if not f then @@ -52,35 +76,14 @@ Available sections: ]] .. table.concat(modules, ', ') return 1 end end - funcdocs = f:read '*a':gsub('-([%d]+)', '%1') - local moddocs = table.filter(fs.readdir(moddocPath), function(f) return f ~= '_index.md' and f ~= 'index.md' end) - local subdocs = table.map(moddocs, function(fname) - return lunacolors.underline(lunacolors.blue(string.gsub(fname, '.md', ''))) - end) - if #moddocs ~= 0 then - funcdocs = funcdocs .. '\nSubdocs: ' .. table.concat(subdocs, ', ') .. '\n\n' - end - - local valsStr = funcdocs:match '%-%-%-\n([^%-%-%-]+)\n' - if valsStr then - local _, endpos = funcdocs:find('---\n' .. valsStr .. '\n---\n\n', 1, true) - funcdocs = funcdocs:sub(endpos + 1, #funcdocs) - - -- parse vals - local lines = string.split(valsStr, '\n') - for _, line in ipairs(lines) do - local key = line:match '(%w+): ' - local val = line:match '^%w+: (.-)$' - if key then - vals[key] = val - end - end - end - doc = funcdocs:sub(1, #funcdocs - 1) - f:close() end + local moddocs = table.filter(fs.readdir(moddocPath), function(f) return f ~= '_index.md' and f ~= 'index.md' end) + local subdocs = table.map(moddocs, function(fname) + return lunacolors.underline(lunacolors.blue(string.gsub(fname, '.md', ''))) + end) + local gh = Greenhouse(sinks.out) function gh:resize() local size = terminal.size() @@ -102,26 +105,52 @@ Available sections: ]] .. table.concat(modules, ', ') self.sink:write(ansikit.getCSI(self.region.height + 2 .. ';1', 'H')) if not self.isSpecial then if args[1] == 'api' then - self.sink:writeln(lunacolors.reset(string.format('%s', vals.title))) - self.sink:write(lunacolors.format(string.format('{grayBg} ↳ {white}{italic}%s {reset}', vals.description or 'No description.'))) + self.sink:writeln(lunacolors.reset(string.format('%s', workingPage.title))) + self.sink:write(lunacolors.format(string.format('{grayBg} ↳ {white}{italic}%s {reset}', workingPage.description or 'No description.'))) else self.sink:write(lunacolors.reset(string.format('Viewing doc page %s', moddocPath))) end end end local backtickOccurence = 0 - local page = Page(nil, lunacolors.format(doc:gsub('`', function() - backtickOccurence = backtickOccurence + 1 - if backtickOccurence % 2 == 0 then - return '{reset}' - else - return '{underline}{green}' - end - end):gsub('\n#+.-\n', function(t) - local signature = t:gsub('<.->(.-)', '{underline}%1'):gsub('\\', '<') - return '{bold}{yellow}' .. signature .. '{reset}' - end))) + local function formatDocText(d) + return lunacolors.format(d:gsub('`', function() + backtickOccurence = backtickOccurence + 1 + if backtickOccurence % 2 == 0 then + return '{reset}' + else + return '{underline}{green}' + end + end):gsub('\n#+.-\n', function(t) + local signature = t:gsub('<.->(.-)', '{underline}%1'):gsub('\\', '<') + return '{bold}{yellow}' .. signature .. '{reset}' + end)) + end + + + local doc, vals = handleYamlInfo(#args == 0 and doc or formatDocText(f:read '*a':gsub('-([%d]+)', '%1'))) + if #moddocs ~= 0 then + doc = doc .. '\nSubdocs: ' .. table.concat(subdocs, ', ') .. '\n\n' + end + if f then f:close() end + + local page = Page(vals.title, doc) + page.description = vals.description gh:addPage(page) + + -- add subdoc pages + for _, sdName in ipairs(moddocs) do + local sdFile = fs.join(sdName, '_index.md') + if sdName:match '.md$' then + sdFile = sdName + end + + local f = io.open(moddocPath .. sdFile, 'rb') + local doc, vals = handleYamlInfo(f:read '*a':gsub('-([%d]+)', '%1')) + local page = Page(vals.title, formatDocText(doc)) + page.description = vals.description + gh:addPage(page) + end ansikit.hideCursor() gh:initUi() end) diff --git a/nature/greenhouse/init.lua b/nature/greenhouse/init.lua index 604ed5b9..d5877e82 100644 --- a/nature/greenhouse/init.lua +++ b/nature/greenhouse/init.lua @@ -74,6 +74,10 @@ function Greenhouse:draw() workingPage = self.specialPage end + if workingPage.lazy and not workingPage.loaded then + workingPage.initialize() + end + local lines = workingPage.lines self.sink:write(ansikit.getCSI(self.start .. ';1', 'H')) self.sink:write(ansikit.getCSI(2, 'J')) diff --git a/nature/greenhouse/page.lua b/nature/greenhouse/page.lua index b26f8e2e..51d1440f 100644 --- a/nature/greenhouse/page.lua +++ b/nature/greenhouse/page.lua @@ -5,6 +5,9 @@ local Page = Object:extend() function Page:new(title, text) self:setText(text) self.title = title or 'Page' + self.lazy = false + self.loaded = true + self.children = {} end function Page:setText(text) @@ -15,4 +18,15 @@ function Page:setTitle(title) self.title = title end +function Page:dynamic(initializer) + self.initializer = initializer + self.lazy = true + self.loaded = false +end + +function Page:initialize() + self.initializer() + self.loaded = true +end + return Page From 003100d3c4fc01770db98b5efe5d1642d12865a8 Mon Sep 17 00:00:00 2001 From: sammyette Date: Tue, 24 Oct 2023 23:52:53 -0400 Subject: [PATCH 36/39] fix: dont concat subdocs list if on main page --- nature/commands/doc.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nature/commands/doc.lua b/nature/commands/doc.lua index 2f8938f8..ee1e37cc 100644 --- a/nature/commands/doc.lua +++ b/nature/commands/doc.lua @@ -129,7 +129,7 @@ Available sections: ]] .. table.concat(modules, ', ') local doc, vals = handleYamlInfo(#args == 0 and doc or formatDocText(f:read '*a':gsub('-([%d]+)', '%1'))) - if #moddocs ~= 0 then + if #moddocs ~= 0 and f then doc = doc .. '\nSubdocs: ' .. table.concat(subdocs, ', ') .. '\n\n' end if f then f:close() end From 8fabdf4502d90563ff86929e3f8e08b41a83b335 Mon Sep 17 00:00:00 2001 From: sammyette Date: Tue, 24 Oct 2023 23:59:53 -0400 Subject: [PATCH 37/39] fix: correct no files check to compensate for pipes --- nature/commands/greenhouse.lua | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/nature/commands/greenhouse.lua b/nature/commands/greenhouse.lua index 8e0d0e18..0f7971e0 100644 --- a/nature/commands/greenhouse.lua +++ b/nature/commands/greenhouse.lua @@ -102,23 +102,23 @@ commander.register('greenhouse', function(args, sinks) gh:addPage(page) end - if #args ~= 0 then - for _, name in ipairs(args) do - local f = io.open(name, 'r') - if not f then - sinks.err:writeln(string.format('could not open file %s', name)) - end - - local page = Page(name, f:read '*a') - gh:addPage(page) + for _, name in ipairs(args) do + local f = io.open(name, 'r') + if not f then + sinks.err:writeln(string.format('could not open file %s', name)) end - ansikit.hideCursor() - gh:initUi() - else + local page = Page(name, f:read '*a') + gh:addPage(page) + end + + if #gh.pages == 0 then sinks.out:writeln [[greenhouse is the Hilbish pager library and command! usage: greenhouse ... example: greenhouse hello.md]] + return 1 end + ansikit.hideCursor() + gh:initUi() end) From d8a7a4332d7dc9e5ef9e450634c430d162350893 Mon Sep 17 00:00:00 2001 From: sammyette Date: Wed, 25 Oct 2023 00:00:59 -0400 Subject: [PATCH 38/39] fix(commands/greenhouse): remove extra space in title, set pipe page title to stdin --- nature/commands/greenhouse.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nature/commands/greenhouse.lua b/nature/commands/greenhouse.lua index 0f7971e0..9c155b0d 100644 --- a/nature/commands/greenhouse.lua +++ b/nature/commands/greenhouse.lua @@ -43,7 +43,7 @@ commander.register('greenhouse', function(args, sinks) self.sink:write(ansikit.getCSI(self.region.height + 1 .. ';1', 'H')) if not self.isSpecial then - self.sink:writeln(lunacolors.format(string.format('{grayBg} ↳ Page %d %s{reset}', self.curPage, workingPage.title and ' — ' .. workingPage.title .. ' ' or ''))) + self.sink:writeln(lunacolors.format(string.format('{grayBg} ↳ Page %d%s{reset}', self.curPage, workingPage.title and ' — ' .. workingPage.title .. ' ' or ''))) end self.sink:write(buffer == '' and display or buffer) end @@ -98,7 +98,7 @@ commander.register('greenhouse', function(args, sinks) end) if sinks['in'].pipe then - local page = Page('', sinks['in']:readAll()) + local page = Page('stdin', sinks['in']:readAll()) gh:addPage(page) end From ae356f6ffaa45ad5a3123187434a0aab0728b281 Mon Sep 17 00:00:00 2001 From: sammyette Date: Wed, 25 Oct 2023 00:24:17 -0400 Subject: [PATCH 39/39] docs: add details to changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 63f17783..f73c4cb8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ - `pipe` property to check if a sink with input is a pipe (like stdin) - Show indexes on cdr list - Fix doc command not displaying correct subdocs when using shorthand api doc access (`doc api hilbish.jobs` as an example) +- Greenhouse + - Greenhouse is a pager library and program. Basic usage is `greenhouse ` + - Using this also brings enhancements to the `doc` command like easy + navigation of neighboring doc files. ### Fixed - Replaced `sed` in-place editing with `grep` and `mv` for compatibility with BSD utils