From 0bb97a6f3b14000da9bff673c81c3ef774ce464a Mon Sep 17 00:00:00 2001 From: sammyette Date: Sun, 9 Jul 2023 22:38:34 -0400 Subject: [PATCH] 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 | 119 +++++++++++++++++++++++++++------ nature/greenhouse/page.lua | 7 +- readline/codes.go | 4 +- 4 files changed, 146 insertions(+), 24 deletions(-) diff --git a/nature/commands/greenhouse.lua b/nature/commands/greenhouse.lua index 7b38d33..b147db4 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 8896a86..3995bef 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() - local size = terminal.size() - self.region = size + self:resize() + if self.isToc then + self:toc() + end self:draw() end -function Greenhouse:next() - local oldCurrent = self.curPage - self.curPage = math.min(self.curPage + 1, #self.pages) - if self.curPage ~= oldCurrent then +function Greenhouse:resize() + local size = terminal.size() + self.region = size +end + +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: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 - self.offset = 1 - self:draw() +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:update() + end +end + +function Greenhouse:jump(idx) + if idx ~= self.curPage then + self.offset = 1 + 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 09f1e91..b26f8e2 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 d5eda59..9815994 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"