diff --git a/anagrams.tlv b/anagrams.tlv index 4678bfa..14f3d21 100644 --- a/anagrams.tlv +++ b/anagrams.tlv @@ -61,21 +61,6 @@ >end > >-- TODO: backport utf-8 support from Lua 5.3 -- __teliva_timestamp: original - debugy: - >debugy = 5 -- __teliva_timestamp: original - dbg: - >-- helper for debug by print; overlay debug information towards the right - >-- reset debugy every time you refresh screen - >function dbg(window, s) - > local oldy = 0 - > local oldx = 0 - > oldy, oldx = window:getyx() - > window:mvaddstr(debugy, 60, s) - > debugy = debugy+1 - > window:mvaddstr(oldy, oldx, '') - >end - __teliva_timestamp: original check_eq: >function check_eq(x, expected, msg) @@ -177,8 +162,7 @@ > end > return result >end -- __teliva_timestamp: - >Mon Feb 21 17:45:04 2022 +- __teliva_timestamp: original sort_letters: >function sort_letters(s) > tmp = {} @@ -220,12 +204,6 @@ > l[#l+1] = elems[i] > end >end -- __teliva_timestamp: original - Window: - >Window = curses.stdscr() -- __teliva_timestamp: original - doc:blurb: - >Show all anagrams of a given word - __teliva_timestamp: original menu: >-- To show app-specific hotkeys in the menu bar, add hotkey/command @@ -233,6 +211,12 @@ >menu = { > {'^h', 'backspace'}, >} +- __teliva_timestamp: original + Window: + >Window = curses.stdscr() +- __teliva_timestamp: original + doc:blurb: + >Show all anagrams of a given word - __teliva_timestamp: original word: >word = '' diff --git a/commander.tlv b/commander.tlv index 5416f64..6b80304 100644 --- a/commander.tlv +++ b/commander.tlv @@ -62,90 +62,10 @@ > >-- TODO: backport utf-8 support from Lua 5.3 - __teliva_timestamp: original - debugy: - >debugy = 5 -- __teliva_timestamp: original - dbg: - >-- helper for debug by print; overlay debug information towards the right - >-- reset debugy every time you refresh screen - >function dbg(window, s) - > local oldy = 0 - > local oldx = 0 - > oldy, oldx = window:getyx() - > window:mvaddstr(debugy, 60, s) - > debugy = debugy+1 - > window:mvaddstr(oldy, oldx, '') - >end -- __teliva_timestamp: original - check_eq: - >function check_eq(x, expected, msg) - > if x == expected then - > Window:addch('.') - > else - > print('F - '..msg) - > print(' expected '..tostring(expected)..' but got '..x) - > teliva_num_test_failures = teliva_num_test_failures + 1 - > -- overlay first test failure on editors - > if teliva_first_failure == nil then - > teliva_first_failure = msg - > end - > end - >end -- __teliva_timestamp: original - map: - >-- only for arrays - >function map(l, f) - > result = {} - > for _, x in ipairs(l) do - > table.insert(result, f(x)) - > end - > return result - >end -- __teliva_timestamp: original - reduce: - >-- only for arrays - >function reduce(l, f, init) - > result = init - > for _, x in ipairs(l) do - > result = f(result, x) - > end - > return result - >end -- __teliva_timestamp: original - filter: - >-- only for arrays - >function filter(l, f) - > result = {} - > for _, x in ipairs(l) do - > if f(x) then - > table.insert(result, x) - > end - > end - > return result - >end -- __teliva_timestamp: original - find_index: - >function find_index(arr, x) - > for n, y in ipairs(arr) do - > if x == y then - > return n - > end - > end - >end -- __teliva_timestamp: original - trim: - >function trim(s) - > return s:gsub('^%s*', ''):gsub('%s*$', '') - >end -- __teliva_timestamp: original - split: - >function split(s, d) - > result = {} - > for match in (s..d):gmatch("(.-)"..d) do - > table.insert(result, match); - > end - > return result - >end + menu: + >-- To show app-specific hotkeys in the menu bar, add hotkey/command + >-- arrays of strings to the menu array. + >menu = {} - __teliva_timestamp: original Window: >Window = curses.stdscr() @@ -161,11 +81,6 @@ > end > window:refresh() >end -- __teliva_timestamp: original - menu: - >-- To show app-specific hotkeys in the menu bar, add hotkey/command - >-- arrays of strings to the menu array. - >menu = {} - __teliva_timestamp: original update: >function update(window) @@ -197,3 +112,6 @@ > update(Window) > end >end +- __teliva_timestamp: original + doc:blurb: + >beginnings of a file browser.. diff --git a/gemini.tlv b/gemini.tlv index ed0cad7..3a163f0 100644 --- a/gemini.tlv +++ b/gemini.tlv @@ -76,21 +76,6 @@ > debugy = debugy+1 > window:mvaddstr(oldy, oldx, '') >end -- __teliva_timestamp: original - check_eq: - >function check_eq(x, expected, msg) - > if x == expected then - > Window:addch('.') - > else - > print('F - '..msg) - > print(' expected '..tostring(expected)..' but got '..x) - > teliva_num_test_failures = teliva_num_test_failures + 1 - > -- overlay first test failure on editors - > if teliva_first_failure == nil then - > teliva_first_failure = msg - > end - > end - >end - __teliva_timestamp: original map: >-- only for arrays @@ -355,7 +340,7 @@ init_colors: >function init_colors() > for i=0,7 do - > curses.init_pair(i, i, 8) + > curses.init_pair(i, i, -1) > end > curses.init_pair(8, 7, 0) > curses.init_pair(9, 7, 1) @@ -364,7 +349,7 @@ > curses.init_pair(12, 7, 4) > curses.init_pair(13, 7, 5) > curses.init_pair(14, 7, 6) - > curses.init_pair(15, 8, 15) + > curses.init_pair(15, -1, 15) >end - __teliva_timestamp: original main: diff --git a/life.tlv b/life.tlv index 0693e7f..78cfa9f 100644 --- a/life.tlv +++ b/life.tlv @@ -16,6 +16,370 @@ # # If these constraints are violated, Teliva may unceremoniously crash. Please # report bugs at http://akkartik.name/contact +- __teliva_timestamp: original + str_helpers: + >-- some string helpers from http://lua-users.org/wiki/StringIndexing + > + >-- index characters using [] + >getmetatable('').__index = function(str,i) + > if type(i) == 'number' then + > return string.sub(str,i,i) + > else + > return string[i] + > end + >end + > + >-- ranges using (), selected bytes using {} + >getmetatable('').__call = function(str,i,j) + > if type(i)~='table' then + > return string.sub(str,i,j) + > else + > local t={} + > for k,v in ipairs(i) do + > t[k]=string.sub(str,v,v) + > end + > return table.concat(t) + > end + >end + > + >-- iterate over an ordered sequence + >function q(x) + > if type(x) == 'string' then + > return x:gmatch('.') + > else + > return ipairs(x) + > end + >end + > + >-- insert within string + >function string.insert(str1, str2, pos) + > return str1:sub(1,pos)..str2..str1:sub(pos+1) + >end + > + >function string.remove(s, pos) + > return s:sub(1,pos-1)..s:sub(pos+1) + >end + > + >-- TODO: backport utf-8 support from Lua 5.3 +- __teliva_timestamp: original + debugy: + >debugy = 5 +- __teliva_timestamp: original + dbg: + >-- helper for debug by print; overlay debug information towards the right + >-- reset debugy every time you refresh screen + >function dbg(window, s) + > local oldy = 0 + > local oldx = 0 + > oldy, oldx = window:getyx() + > window:mvaddstr(debugy, 60, s) + > debugy = debugy+1 + > window:mvaddstr(oldy, oldx, '') + >end +- __teliva_timestamp: original + check_eq: + >function check_eq(x, expected, msg) + > if eq(x, expected) then + > Window:addch('.') + > else + > print('F - '..msg) + > print(' expected '..str(expected)..' but got '..str(x)) + > teliva_num_test_failures = teliva_num_test_failures + 1 + > -- overlay first test failure on editors + > if teliva_first_failure == nil then + > teliva_first_failure = msg + > end + > end + >end +- __teliva_timestamp: original + eq: + >function eq(a, b) + > if type(a) ~= type(b) then return false end + > if type(a) == 'table' then + > if #a ~= #b then return false end + > for k, v in pairs(a) do + > if b[k] ~= v then + > return false + > end + > return true + > end + > end + > return a == b + >end +- __teliva_timestamp: original + str: + >-- smarter tostring + >-- slow; used only for debugging + >function str(x) + > if type(x) == 'table' then + > local result = '' + > result = result..#x..'{' + > for k, v in pairs(x) do + > result = result..str(k)..'='..str(v)..', ' + > end + > result = result..'}' + > return result + > end + > return tostring(x) + >end +- __teliva_timestamp: original + map: + >-- only for arrays + >function map(l, f) + > result = {} + > for _, x in ipairs(l) do + > table.insert(result, f(x)) + > end + > return result + >end +- __teliva_timestamp: original + reduce: + >-- only for arrays + >function reduce(l, f, init) + > result = init + > for _, x in ipairs(l) do + > result = f(result, x) + > end + > return result + >end +- __teliva_timestamp: original + filter: + >-- only for arrays + >function filter(l, f) + > result = {} + > for _, x in ipairs(l) do + > if f(x) then + > table.insert(result, x) + > end + > end + > return result + >end +- __teliva_timestamp: original + find_index: + >function find_index(arr, x) + > for n, y in ipairs(arr) do + > if x == y then + > return n + > end + > end + >end +- __teliva_timestamp: original + trim: + >function trim(s) + > return s:gsub('^%s*', ''):gsub('%s*$', '') + >end +- __teliva_timestamp: original + split: + >function split(s, d) + > result = {} + > for match in (s..d):gmatch("(.-)"..d) do + > table.insert(result, match); + > end + > return result + >end +- __teliva_timestamp: + >Mon Feb 21 17:45:04 2022 + sort_letters: + >function sort_letters(s) + > tmp = {} + > for i=1,#s do + > table.insert(tmp, s[i]) + > end + > table.sort(tmp) + > local result = '' + > for _, c in pairs(tmp) do + > result = result..c + > end + > return result + >end + > + >function test_sort_letters(s) + > check_eq(sort_letters(''), '', 'test_sort_letters: empty') + > check_eq(sort_letters('ba'), 'ab', 'test_sort_letters: non-empty') + > check_eq(sort_letters('abba'), 'aabb', 'test_sort_letters: duplicates') + >end +- __teliva_timestamp: original + count_letters: + >function count_letters(s) + > local result = {} + > for i=1,string.len(s) do + > local c = s[i] + > if result[c] == nil then + > result[c] = 1 + > else + > result[c] = result[c] + 1 + > end + > end + > return result + >end +- __teliva_timestamp: original + append: + >-- concatenate list 'elems' into 'l', modifying 'l' in the process + >function append(l, elems) + > for i=1,#elems do + > l[#l+1] = elems[i] + > end + >end +- __teliva_timestamp: original + menu: + >-- To show app-specific hotkeys in the menu bar, add hotkey/command + >-- arrays of strings to the menu array. + >menu = {} +- __teliva_timestamp: original + window: + >-- constructor for fake screen and window + >-- call it like this: + >-- local w = window{ + >-- kbd=kbd('abc'), + >-- scr=scr{h=5, w=4}, + >-- } + >-- eventually it'll do everything a real ncurses window can + >function window(h) + > h.__index = h + > setmetatable(h, h) + > h.__index = function(table, key) + > return rawget(h, key) + > end + > h.getch = function(self) + > return table.remove(h.kbd, 1) + > end + > h.addch = function(self, c) + > local scr = self.scr + > if scr.cursy <= scr.h then + > scr[scr.cursy][scr.cursx] = c + > scr.cursx = scr.cursx+1 + > if scr.cursx > scr.w then + > scr.cursy = scr.cursy+1 + > scr.cursx = 1 + > end + > end + > end + > h.addstr = function(self, s) + > for i=1,string.len(s) do + > self:addch(s[i]) + > end + > end + > h.mvaddch = function(self, y, x, c) + > self.scr.cursy = y + > self.scr.cursx = x + > self.addch(c) + > end + > h.mvaddstr = function(self, y, x, s) + > self.scr.cursy = y + > self.scr.cursx = x + > self:addstr(s) + > end + > return h + >end +- __teliva_timestamp: original + kbd: + >function kbd(keys) + > local result = {} + > for i=1,string.len(keys) do + > table.insert(result, keys[i]) + > end + > return result + >end +- __teliva_timestamp: original + scr: + >function scr(props) + > props.cursx = 1 + > props.cursy = 1 + > for y=1,props.h do + > props[y] = {} + > for x=1,props.w do + > props[y][x] = ' ' + > end + > end + > return props + >end +- __teliva_timestamp: + >Thu Mar 3 22:04:15 2022 + check_screen: + >function check_screen(window, contents, message) + > local x, y = 1, 1 + > for i=1,string.len(contents) do + > check_eq(contents[i], window.scr[y][x], message..'/'..y..','..x) + > x = x+1 + > if x > window.scr.w then + > y = y+1 + > x = 1 + > end + > end + >end + > + >-- putting it all together, an example test of both keyboard and screen + >function test_check_screen() + > local lines = { + > c='123', + > d='234', + > a='345', + > b='456', + > } + > local w = window{ + > kbd=kbd('abc'), + > scr=scr{h=3, w=5}, + > } + > local y = 1 + > while true do + > local c = w:getch() + > if c == nil then break end + > w:mvaddstr(y, 1, lines[c]) + > y = y+1 + > end + > check_screen(w, '345 '.. + > '456 '.. + > '123 ', + > 'test_check_screen') + >end +- __teliva_timestamp: original + start_reading: + >-- primitive for reading files from a file system (or, later, network) + >-- returns a channel or nil on error + >-- read lines from the channel using :recv() + >-- recv() on the channel will indicate end of file. + >function start_reading(fs, filename) + > local result = task.Channel:new() + > local infile = io.open(filename) + > if infile == nil then return nil end + > task.spawn(reading_task, infile, result) + > return result + >end + > + >function reading_task(infile, chanout) + > for line in infile:lines() do + > chanout:send(line) + > end + > chanout:send(nil) -- eof + >end +- __teliva_timestamp: original + start_writing: + >-- primitive for writing files to a file system (or, later, network) + >-- returns a channel or nil on error + >-- write to the channel using :send() + >-- indicate you're done writing by calling :close() + >-- file will not be externally visible until :close() + >function start_writing(fs, filename) + > local result = task.Channel:new() + > local initial_filename = os.tmpname() + > local outfile = io.open(initial_filename, 'w') + > if outfile == nil then return nil end + > result.close = function() + > result:send(nil) -- end of file + > outfile:close() + > os.rename(initial_filename, filename) + > end + > task.spawn(writing_task, outfile, result) + > return result + >end + > + >function writing_task(outfile, chanin) + > while true do + > local line = chanin:recv() + > if line == nil then break end -- end of file + > outfile:write(line) + > end + >end - __teliva_timestamp: original grid: >-- main data structure diff --git a/sieve.tlv b/sieve.tlv index 92c086a..9677af4 100644 --- a/sieve.tlv +++ b/sieve.tlv @@ -16,249 +16,14 @@ # # If these constraints are violated, Teliva may unceremoniously crash. Please # report bugs at http://akkartik.name/contact -- __teliva_timestamp: original - str_helpers: - >-- some string helpers from http://lua-users.org/wiki/StringIndexing - > - >-- index characters using [] - >getmetatable('').__index = function(str,i) - > if type(i) == 'number' then - > return string.sub(str,i,i) - > else - > return string[i] - > end - >end - > - >-- ranges using (), selected bytes using {} - >getmetatable('').__call = function(str,i,j) - > if type(i)~='table' then - > return string.sub(str,i,j) - > else - > local t={} - > for k,v in ipairs(i) do - > t[k]=string.sub(str,v,v) - > end - > return table.concat(t) - > end - >end - > - >-- iterate over an ordered sequence - >function q(x) - > if type(x) == 'string' then - > return x:gmatch('.') - > else - > return ipairs(x) - > end - >end - > - >-- insert within string - >function string.insert(str1, str2, pos) - > return str1:sub(1,pos)..str2..str1:sub(pos+1) - >end - > - >function string.remove(s, pos) - > return s:sub(1,pos-1)..s:sub(pos+1) - >end - > - >-- TODO: backport utf-8 support from Lua 5.3 -- __teliva_timestamp: original - debugy: - >debugy = 5 -- __teliva_timestamp: original - dbg: - >-- helper for debug by print; overlay debug information towards the right - >-- reset debugy every time you refresh screen - >function dbg(window, s) - > local oldy = 0 - > local oldx = 0 - > oldy, oldx = window:getyx() - > window:mvaddstr(debugy, 60, s) - > debugy = debugy+1 - > window:mvaddstr(oldy, oldx, '') - >end -- __teliva_timestamp: original - check_eq: - >function check_eq(x, expected, msg) - > if eq(x, expected) then - > Window:addch('.') - > else - > print('F - '..msg) - > print(' expected '..str(expected)..' but got '..str(x)) - > teliva_num_test_failures = teliva_num_test_failures + 1 - > -- overlay first test failure on editors - > if teliva_first_failure == nil then - > teliva_first_failure = msg - > end - > end - >end -- __teliva_timestamp: original - eq: - >function eq(a, b) - > if type(a) ~= type(b) then return false end - > if type(a) == 'table' then - > if #a ~= #b then return false end - > for k, v in pairs(a) do - > if b[k] ~= v then - > return false - > end - > return true - > end - > end - > return a == b - >end -- __teliva_timestamp: original - str: - >-- smarter tostring - >-- slow; used only for debugging - >function str(x) - > if type(x) == 'table' then - > local result = '' - > result = result..#x..'{' - > for k, v in pairs(x) do - > result = result..str(k)..'='..str(v)..', ' - > end - > result = result..'}' - > return result - > end - > return tostring(x) - >end -- __teliva_timestamp: original - map: - >-- only for arrays - >function map(l, f) - > result = {} - > for _, x in ipairs(l) do - > table.insert(result, f(x)) - > end - > return result - >end -- __teliva_timestamp: original - reduce: - >-- only for arrays - >function reduce(l, f, init) - > result = init - > for _, x in ipairs(l) do - > result = f(result, x) - > end - > return result - >end -- __teliva_timestamp: original - filter: - >-- only for arrays - >function filter(l, f) - > result = {} - > for _, x in ipairs(l) do - > if f(x) then - > table.insert(result, x) - > end - > end - > return result - >end -- __teliva_timestamp: original - find_index: - >function find_index(arr, x) - > for n, y in ipairs(arr) do - > if x == y then - > return n - > end - > end - >end -- __teliva_timestamp: original - trim: - >function trim(s) - > return s:gsub('^%s*', ''):gsub('%s*$', '') - >end -- __teliva_timestamp: original - split: - >function split(s, d) - > result = {} - > for match in (s..d):gmatch("(.-)"..d) do - > table.insert(result, match); - > end - > return result - >end -- __teliva_timestamp: - >Mon Feb 21 17:45:04 2022 - sort_string: - >function sort_string(s) - > tmp = {} - > for i=1,#s do - > table.insert(tmp, s[i]) - > end - > table.sort(tmp) - > local result = '' - > for _, c in pairs(tmp) do - > result = result..c - > end - > return result - >end - > - >function test_sort_string(s) - > check_eq(sort_string(''), '', 'test_sort_string: empty') - > check_eq(sort_string('ba'), 'ab', 'test_sort_string: non-empty') - > check_eq(sort_string('abba'), 'aabb', 'test_sort_string: duplicates') - >end -- __teliva_timestamp: original - append: - >-- concatenate list 'elems' into 'l', modifying 'l' in the process - >function append(l, elems) - > for i=1,#elems do - > l[#l+1] = elems[i] - > end - >end -- __teliva_timestamp: original - Window: - >Window = curses.stdscr() -- __teliva_timestamp: original - render: - >function render(window) - > window:clear() - > -- draw stuff to screen here - > window:attron(curses.A_BOLD) - > window:mvaddstr(1, 5, "example app") - > window:attrset(curses.A_NORMAL) - > for i=0,15 do - > window:attrset(curses.color_pair(i)) - > window:mvaddstr(3+i, 5, "========================") - > end - > window:refresh() - >end - __teliva_timestamp: original menu: >-- To show app-specific hotkeys in the menu bar, add hotkey/command >-- arrays of strings to the menu array. >menu = {} - __teliva_timestamp: original - update: - >function update(window) - > local key = window:getch() - > -- process key here - >end -- __teliva_timestamp: original - init_colors: - >function init_colors() - > for i=0,7 do - > curses.init_pair(i, i, -1) - > end - > curses.init_pair(8, 7, 0) - > curses.init_pair(9, 7, 1) - > curses.init_pair(10, 7, 2) - > curses.init_pair(11, 7, 3) - > curses.init_pair(12, 7, 4) - > curses.init_pair(13, 7, 5) - > curses.init_pair(14, 7, 6) - > curses.init_pair(15, -1, 15) - >end -- __teliva_timestamp: original - main: - >function main() - > init_colors() - > - > while true do - > render(Window) - > update(Window) - > end - >end + Window: + >Window = curses.stdscr() - __teliva_timestamp: original doc:blurb: >To show a brief description of the app on the 'big picture' screen, put the text in a special buffer called 'doc:blurb'. diff --git a/template.tlv b/template.tlv index 63210d1..4ec78b2 100644 --- a/template.tlv +++ b/template.tlv @@ -177,8 +177,7 @@ > end > return result >end -- __teliva_timestamp: - >Mon Feb 21 17:45:04 2022 +- __teliva_timestamp: original sort_letters: >function sort_letters(s) > tmp = {} @@ -220,64 +219,14 @@ > l[#l+1] = elems[i] > end >end -- __teliva_timestamp: original - Window: - >Window = curses.stdscr() -- __teliva_timestamp: original - render: - >function render(window) - > window:clear() - > -- draw stuff to screen here - > window:attron(curses.A_BOLD) - > window:mvaddstr(1, 5, "example app") - > window:attrset(curses.A_NORMAL) - > for i=0,15 do - > window:attrset(curses.color_pair(i)) - > window:mvaddstr(3+i, 5, "========================") - > end - > window:refresh() - >end - __teliva_timestamp: original menu: >-- To show app-specific hotkeys in the menu bar, add hotkey/command >-- arrays of strings to the menu array. >menu = {} - __teliva_timestamp: original - update: - >function update(window) - > local key = window:getch() - > -- process key here - >end -- __teliva_timestamp: original - init_colors: - >function init_colors() - > for i=0,7 do - > curses.init_pair(i, i, -1) - > end - > curses.init_pair(8, 7, 0) - > curses.init_pair(9, 7, 1) - > curses.init_pair(10, 7, 2) - > curses.init_pair(11, 7, 3) - > curses.init_pair(12, 7, 4) - > curses.init_pair(13, 7, 5) - > curses.init_pair(14, 7, 6) - > curses.init_pair(15, -1, 15) - >end -- __teliva_timestamp: original - main: - >function main() - > init_colors() - > - > while true do - > render(Window) - > update(Window) - > end - >end -- __teliva_timestamp: original - doc:blurb: - >To show a brief description of the app on the 'big picture' screen, put the text in a special buffer called 'doc:blurb'. - > - >You can also override the default big picture screen entirely by creating a buffer called 'doc:main'. + Window: + >Window = curses.stdscr() - __teliva_timestamp: original window: >-- constructor for fake screen and window @@ -346,8 +295,7 @@ > end > return props >end -- __teliva_timestamp: - >Thu Mar 3 22:04:15 2022 +- __teliva_timestamp: original check_screen: >function check_screen(window, contents, message) > local x, y = 1, 1 @@ -433,3 +381,53 @@ > outfile:write(line) > end >end +- __teliva_timestamp: original + render: + >function render(window) + > window:clear() + > -- draw stuff to screen here + > window:attron(curses.A_BOLD) + > window:mvaddstr(1, 5, "example app") + > window:attrset(curses.A_NORMAL) + > for i=0,15 do + > window:attrset(curses.color_pair(i)) + > window:mvaddstr(3+i, 5, "========================") + > end + > window:refresh() + >end +- __teliva_timestamp: original + update: + >function update(window) + > local key = window:getch() + > -- process key here + >end +- __teliva_timestamp: original + init_colors: + >function init_colors() + > for i=0,7 do + > curses.init_pair(i, i, -1) + > end + > curses.init_pair(8, 7, 0) + > curses.init_pair(9, 7, 1) + > curses.init_pair(10, 7, 2) + > curses.init_pair(11, 7, 3) + > curses.init_pair(12, 7, 4) + > curses.init_pair(13, 7, 5) + > curses.init_pair(14, 7, 6) + > curses.init_pair(15, -1, 15) + >end +- __teliva_timestamp: original + main: + >function main() + > init_colors() + > + > while true do + > render(Window) + > update(Window) + > end + >end +- __teliva_timestamp: original + doc:blurb: + >To show a brief description of the app on the 'big picture' screen, put the text in a special buffer called 'doc:blurb'. + > + >You can also override the default big picture screen entirely by creating a buffer called 'doc:main'. diff --git a/toot-toot.tlv b/toot-toot.tlv index 8d03654..66b0d9e 100644 --- a/toot-toot.tlv +++ b/toot-toot.tlv @@ -79,11 +79,11 @@ - __teliva_timestamp: original check_eq: >function check_eq(x, expected, msg) - > if x == expected then + > if eq(x, expected) then > Window:addch('.') > else > print('F - '..msg) - > print(' expected '..tostring(expected)..' but got '..x) + > print(' expected '..str(expected)..' but got '..str(x)) > teliva_num_test_failures = teliva_num_test_failures + 1 > -- overlay first test failure on editors > if teliva_first_failure == nil then @@ -91,6 +91,37 @@ > end > end >end +- __teliva_timestamp: original + eq: + >function eq(a, b) + > if type(a) ~= type(b) then return false end + > if type(a) == 'table' then + > if #a ~= #b then return false end + > for k, v in pairs(a) do + > if b[k] ~= v then + > return false + > end + > return true + > end + > end + > return a == b + >end +- __teliva_timestamp: original + str: + >-- smarter tostring + >-- slow; used only for debugging + >function str(x) + > if type(x) == 'table' then + > local result = '' + > result = result..#x..'{' + > for k, v in pairs(x) do + > result = result..str(k)..'='..str(v)..', ' + > end + > result = result..'}' + > return result + > end + > return tostring(x) + >end - __teliva_timestamp: original map: >-- only for arrays @@ -146,16 +177,18 @@ > end > return result >end -- __teliva_timestamp: original - Window: - >Window = curses.stdscr() - >curses.curs_set(0) -- we'll simulate our own cursor - __teliva_timestamp: original menu: + >-- To show app-specific hotkeys in the menu bar, add hotkey/command + >-- arrays of strings to the menu array. >menu = { > {'^k', 'clear'}, > {'^w', 'write prose to file "toot" (edit hotkey does NOT save)'}, >} +- __teliva_timestamp: original + Window: + >Window = curses.stdscr() + >curses.curs_set(0) -- we'll simulate our own cursor - __teliva_timestamp: original main: >function main() diff --git a/zet.tlv b/zet.tlv index 7a718aa..6105fda 100644 --- a/zet.tlv +++ b/zet.tlv @@ -79,11 +79,11 @@ - __teliva_timestamp: original check_eq: >function check_eq(x, expected, msg) - > if x == expected then + > if eq(x, expected) then > Window:addch('.') > else > print('F - '..msg) - > print(' expected '..tostring(expected)..' but got '..x) + > print(' expected '..str(expected)..' but got '..str(x)) > teliva_num_test_failures = teliva_num_test_failures + 1 > -- overlay first test failure on editors > if teliva_first_failure == nil then @@ -91,6 +91,37 @@ > end > end >end +- __teliva_timestamp: original + eq: + >function eq(a, b) + > if type(a) ~= type(b) then return false end + > if type(a) == 'table' then + > if #a ~= #b then return false end + > for k, v in pairs(a) do + > if b[k] ~= v then + > return false + > end + > return true + > end + > end + > return a == b + >end +- __teliva_timestamp: original + str: + >-- smarter tostring + >-- slow; used only for debugging + >function str(x) + > if type(x) == 'table' then + > local result = '' + > result = result..#x..'{' + > for k, v in pairs(x) do + > result = result..str(k)..'='..str(v)..', ' + > end + > result = result..'}' + > return result + > end + > return tostring(x) + >end - __teliva_timestamp: original map: >-- only for arrays @@ -147,15 +178,47 @@ > return result >end - __teliva_timestamp: original - spaces: - >function spaces(n) - > for i=1,n do - > Window:addch(' ') + sort_letters: + >function sort_letters(s) + > tmp = {} + > for i=1,#s do + > table.insert(tmp, s[i]) > end + > table.sort(tmp) + > local result = '' + > for _, c in pairs(tmp) do + > result = result..c + > end + > return result + >end + > + >function test_sort_letters(s) + > check_eq(sort_letters(''), '', 'test_sort_letters: empty') + > check_eq(sort_letters('ba'), 'ab', 'test_sort_letters: non-empty') + > check_eq(sort_letters('abba'), 'aabb', 'test_sort_letters: duplicates') >end - __teliva_timestamp: original - Window: - >Window = curses.stdscr() + count_letters: + >function count_letters(s) + > local result = {} + > for i=1,string.len(s) do + > local c = s[i] + > if result[c] == nil then + > result[c] = 1 + > else + > result[c] = result[c] + 1 + > end + > end + > return result + >end +- __teliva_timestamp: original + append: + >-- concatenate list 'elems' into 'l', modifying 'l' in the process + >function append(l, elems) + > for i=1,#elems do + > l[#l+1] = elems[i] + > end + >end - __teliva_timestamp: original menu: >-- To show app-specific hotkeys in the menu bar, add hotkey/command @@ -163,6 +226,170 @@ >menu = { > {'^e', 'edit'}, >} +- __teliva_timestamp: original + Window: + >Window = curses.stdscr() +- __teliva_timestamp: original + window: + >-- constructor for fake screen and window + >-- call it like this: + >-- local w = window{ + >-- kbd=kbd('abc'), + >-- scr=scr{h=5, w=4}, + >-- } + >-- eventually it'll do everything a real ncurses window can + >function window(h) + > h.__index = h + > setmetatable(h, h) + > h.__index = function(table, key) + > return rawget(h, key) + > end + > h.getch = function(self) + > return table.remove(h.kbd, 1) + > end + > h.addch = function(self, c) + > local scr = self.scr + > if scr.cursy <= scr.h then + > scr[scr.cursy][scr.cursx] = c + > scr.cursx = scr.cursx+1 + > if scr.cursx > scr.w then + > scr.cursy = scr.cursy+1 + > scr.cursx = 1 + > end + > end + > end + > h.addstr = function(self, s) + > for i=1,string.len(s) do + > self:addch(s[i]) + > end + > end + > h.mvaddch = function(self, y, x, c) + > self.scr.cursy = y + > self.scr.cursx = x + > self.addch(c) + > end + > h.mvaddstr = function(self, y, x, s) + > self.scr.cursy = y + > self.scr.cursx = x + > self:addstr(s) + > end + > return h + >end +- __teliva_timestamp: original + kbd: + >function kbd(keys) + > local result = {} + > for i=1,string.len(keys) do + > table.insert(result, keys[i]) + > end + > return result + >end +- __teliva_timestamp: original + scr: + >function scr(props) + > props.cursx = 1 + > props.cursy = 1 + > for y=1,props.h do + > props[y] = {} + > for x=1,props.w do + > props[y][x] = ' ' + > end + > end + > return props + >end +- __teliva_timestamp: original + check_screen: + >function check_screen(window, contents, message) + > local x, y = 1, 1 + > for i=1,string.len(contents) do + > check_eq(contents[i], window.scr[y][x], message..'/'..y..','..x) + > x = x+1 + > if x > window.scr.w then + > y = y+1 + > x = 1 + > end + > end + >end + > + >-- putting it all together, an example test of both keyboard and screen + >function test_check_screen() + > local lines = { + > c='123', + > d='234', + > a='345', + > b='456', + > } + > local w = window{ + > kbd=kbd('abc'), + > scr=scr{h=3, w=5}, + > } + > local y = 1 + > while true do + > local c = w:getch() + > if c == nil then break end + > w:mvaddstr(y, 1, lines[c]) + > y = y+1 + > end + > check_screen(w, '345 '.. + > '456 '.. + > '123 ', + > 'test_check_screen') + >end +- __teliva_timestamp: original + start_reading: + >-- primitive for reading files from a file system (or, later, network) + >-- returns a channel or nil on error + >-- read lines from the channel using :recv() + >-- recv() on the channel will indicate end of file. + >function start_reading(fs, filename) + > local result = task.Channel:new() + > local infile = io.open(filename) + > if infile == nil then return nil end + > task.spawn(reading_task, infile, result) + > return result + >end + > + >function reading_task(infile, chanout) + > for line in infile:lines() do + > chanout:send(line) + > end + > chanout:send(nil) -- eof + >end +- __teliva_timestamp: original + start_writing: + >-- primitive for writing files to a file system (or, later, network) + >-- returns a channel or nil on error + >-- write to the channel using :send() + >-- indicate you're done writing by calling :close() + >-- file will not be externally visible until :close() + >function start_writing(fs, filename) + > local result = task.Channel:new() + > local initial_filename = os.tmpname() + > local outfile = io.open(initial_filename, 'w') + > if outfile == nil then return nil end + > result.close = function() + > result:send(nil) -- end of file + > outfile:close() + > os.rename(initial_filename, filename) + > end + > task.spawn(writing_task, outfile, result) + > return result + >end + > + >function writing_task(outfile, chanin) + > while true do + > local line = chanin:recv() + > if line == nil then break end -- end of file + > outfile:write(line) + > end + >end +- __teliva_timestamp: original + spaces: + >function spaces(n) + > for i=1,n do + > Window:addch(' ') + > end + >end - __teliva_timestamp: original init_colors: >function init_colors()