diff --git a/sieve.tlv b/sieve.tlv index ef2c661..92c086a 100644 --- a/sieve.tlv +++ b/sieve.tlv @@ -265,18 +265,9 @@ > >You can also override the default big picture screen entirely by creating a buffer called 'doc:main'. - __teliva_timestamp: - >Sat Feb 26 21:49:00 2022 + >Sat Feb 26 21:50:11 2022 main: >function main() - > task.spawn(main_task) - > task.scheduler() - > print('out of scheduler') - > Window:getch() - >end -- __teliva_timestamp: - >Sat Feb 26 21:50:11 2022 - main_task: - >function main_task() > local c = task.Channel:new() > task.spawn(counter, c) > for i=1,10 do @@ -308,8 +299,8 @@ >end - __teliva_timestamp: >Sat Feb 26 21:55:46 2022 - main_task: - >function main_task() + main: + >function main() > local primes = task.Channel:new() > task.spawn(sieve, primes) > for i=1,10 do @@ -346,29 +337,17 @@ >end - __teliva_timestamp: >Sat Feb 26 22:09:47 2022 - main_task: - >function main_task(window) - > local primes = task.Channel:new() - > task.spawn(sieve, primes) - > while true do - > window:addstr(primes:recv()) - > window:addstr(' ') - > window:refresh() - > end - >end -- __teliva_timestamp: - >Sat Feb 26 22:08:52 2022 __teliva_note: >infinite primes main: >function main() - > Window:nodelay(true) - > Window:clear() - > task.spawn(main_task, Window) - > task.scheduler() - > print('key pressed; done') - > Window:nodelay(false) - > Window:getch() + > local primes = task.Channel:new() + > task.spawn(sieve, primes) + > while true do + > Window:addstr(primes:recv()) + > Window:addstr(' ') + > Window:refresh() + > end >end - __teliva_timestamp: >Sat Feb 26 22:09:47 2022 @@ -376,21 +355,26 @@ >clear screen when it fills up; pause on keypress > >In Teliva getch() implicitly refreshes the screen. - main_task: - >function main_task(window) + main: + >function main() + > Window:nodelay(true) + > Window:clear() > local primes = task.Channel:new() > task.spawn(sieve, primes) - > local h, w = window:getmaxyx() + > local h, w = Window:getmaxyx() > while true do - > window:addstr(primes:recv()) - > window:addstr(' ') - > local c = window:getch() + > Window:addstr(primes:recv()) + > Window:addstr(' ') + > local c = Window:getch() > if c then break end -- key pressed - > local y, x = window:getyx() + > local y, x = Window:getyx() > if y > h-1 then - > window:clear() + > Window:clear() > end > end + > print('key pressed; done') + > Window:nodelay(false) + > Window:getch() >end - __teliva_timestamp: >Sat Feb 26 22:27:25 2022 diff --git a/src/task.lua b/src/task.lua index 8d03316..3b00ef6 100644 --- a/src/task.lua +++ b/src/task.lua @@ -380,6 +380,17 @@ _M.RECV = RECV _M.SEND = SEND _M.NOP = NOP +-- Specific to Teliva +function spawn_main() + task.spawn(main) + task.scheduler() + assert(false, "Teliva's scheduler ran out of work; this shouldn't happen.\n".. + "Either a channel is blocked forever or you're reading past\n".. + "the end of a file (after recv() returned nil).\n") + curses.nodelay(true) + curses.getch() +end + ---------------------------------------------------------------------------- ---------------------------------------------------------------------------- -- Tests diff --git a/src/teliva.c b/src/teliva.c index 90da6f1..2e9c9d9 100644 --- a/src/teliva.c +++ b/src/teliva.c @@ -1794,7 +1794,7 @@ int handle_image(lua_State* L, char** argv, int n) { /* initialize permissions */ load_permissions_from_user_configuration(L); /* call main() */ - lua_getglobal(L, "main"); + lua_getglobal(L, "spawn_main"); status = docall(L, 0, 1); if (status != 0) return report_in_developer_mode(L, status); return 0; diff --git a/template.tlv b/template.tlv index 6721d2b..63210d1 100644 --- a/template.tlv +++ b/template.tlv @@ -385,3 +385,51 @@ > '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