Added basic piping and started refactor. Things are a mess.

This commit is contained in:
sloumdrone 2019-01-08 22:54:38 -08:00
parent 546cc6ad5c
commit 7a127f573d
1 changed files with 423 additions and 283 deletions

706
stubb
View File

@ -9,6 +9,13 @@ session = { tabs = { }, favorites = {} }
local save_file_location = string.format('%s/.stubbfaves', assert(os.getenv('HOME'), 'Unable to get home directory'))
--||__||--||__||--||__||--||__||--||__||--||__||--||__||--||
------------------------------------------------------------
-- Helper methods ------------------------------------------
------------------------------------------------------------
function string.split(str, sep)
assert(str and sep, 'sting.split requires both an input string and a field separator string')
local start = 1
@ -58,8 +65,11 @@ table.truncate = function(t, i)
end
--based on:
--https://stackoverflow.com/questions/9013290/lua-socket-client/9014261#9014261
--||__||--||__||--||__||--||__||--||__||--||__||--||__||--||
------------------------------------------------------------
-- TCP Requests and processing -----------------------------
------------------------------------------------------------
function request_gopher(host, port, query)
local tcp = assert(socket.tcp())
local response = {}
@ -91,6 +101,59 @@ function request_gopher(host, port, query)
end
function parse_url(u) -- takes URL string
if not string.find(u, '://', 1, true) then
u = 'gopher://'..u
end
local default = {port=70, scheme='gopher'}
local parsed = urlparser.parse(u, default)
if not parsed.path then
parsed.path = '/'
end
if string.find(parsed.path, '^/[%d%a]') then
parsed.gophertype = string.sub(parsed.path, 2, 2)
parsed.path = string.sub(parsed.path, 3) or '/'
elseif string.sub(parsed.path, -1) == '/' then
parsed.gophertype = '1'
else
parsed.gophertype = '0'
end
parsed.full = parsed.scheme .. '://' .. parsed.host .. ':' .. parsed.port .. '/' .. parsed.gophertype .. parsed.path
return parsed
end
function go_to_url(u, add2history, noprint)
local url = parse_url(u)
local t = session.tabs[session.current_tab]
if not url.host or url.scheme ~= 'gopher' then
print(separator)
print('Invalid url')
elseif table.has(valid_types, url.gophertype) then
t.filedata = request_gopher(url.host, url.port, url.path)
print(separator)
local res = handle_response(t.filedata, url.gophertype)
if noprint then
return res
else
print(res)
end
local o = url.scheme .. '://' .. url.host .. ':' .. url.port .. '/' .. url.gophertype .. url.path
print('\n\n')
print(o)
if add2history then
table.truncate(t.history.items, t.history.loc + 1)
table.insert(t.history.items, o)
t.history.loc = t.history.loc + 1
end
end
end
function display_gophermap_row(row)
local t = session.tabs[session.current_tab]
local val = string.split(row, '\t')
@ -98,13 +161,13 @@ function display_gophermap_row(row)
local text = string.sub(val[1], 2)
local spacer = ' '
if gophertype == 'i' then
print(spacer..text)
return spacer .. (text or '')
elseif table.has(valid_types, gophertype) then
local leader = gophertype == '0' and 'TXT' or 'MAP'
local url = string.format('%s:%s/%s%s', val[3] or '', val[4] or '', gophertype, val[2] or '/')
table.insert(t.current_links, url)
local linknum = string.format('(%d)', #t.current_links)
print(string.format(' %s %5s %s', leader, linknum, text))
return string.format(' %s %5s %s', leader, linknum, text) or ''
end
end
@ -115,7 +178,24 @@ function getch()
local key = io.read(1)
os.execute("stty -cbreak </dev/tty >/dev/tty 2>&1");
print('\27[1D ')
return(key);
return string.lower(key);
end
--||__||--||__||--||__||--||__||--||__||--||__||--||__||--||
------------------------------------------------------------
-- Initialize and run application --------------------------
------------------------------------------------------------
function init()
new_tab()
if file_exists(save_file_location) then
dofile(save_file_location)
end
mainloop()
end
@ -125,215 +205,39 @@ function mainloop()
while true do
local bar = string.format('\27[7m o--[ S t u b b ]--> (H)elp, (Q)uit TAB:%d/%d HST: %d/%d \27[0m', session.current_tab, #session.tabs,th.loc, #th.items)
print(bar)
-- print('\27[7m (G)o to url, (B)ack, (V)isit link, (Q)uit \27[0m')
local key = string.lower(getch())
if key == 'q' then
save_favorites()
os.exit(0)
elseif key == 'h' then
print_help()
elseif key == 's' then
save_file()
elseif key == 'b' then
back()
elseif key == 'f' then
forward()
elseif key == 'u' then
update_favorite()
elseif key == 'r' then
refresh()
elseif key == 'a' then
io.write('Add: (B)ookmark, (T)ab')
local subkey = string.lower(getch())
if subkey == 'b' then
add_favorite()
elseif subkey == 't' then
new_tab()
end
elseif key == 'l' then
io.write('List: (B)ookmarks, (T)abs')
local subkey = string.lower(getch())
if subkey == 'b' then
show_favorites()
elseif subkey == 't' then
show_tabs()
end
elseif key == 'd' then
io.write('Delete: (B)ookmark, (T)ab')
local subkey = string.lower(getch())
if subkey == 'b' then
remove_favorite()
elseif subkey == 't' then
remove_tab()
end
elseif key == 'g' then
io.write('Go to: (B)ookmark, (L)ink, (T)ab, (U)rl')
local subkey = string.lower(getch())
if subkey == 'b' then
visit_link(true)
elseif subkey == 'l' then
visit_link()
elseif subkey == 't' then
io.write('Enter tab id (! to cancel): ')
local t = io.read()
local tabid = tonumber(t)
if t ~= '!' and tabid and session.tabs[tabid] then
session.current_tab = tabid
refresh()
else
local x = tabid and print('Invalid tab id') or print('Cancelled')
end
elseif subkey == 'u' then
io.write('Enter gopher url (! to cancel): ')
local url = io.read()
if url ~= '!' and url ~= '' then
go_to_url(url, true)
else
print('Cancelled')
end
end
end
local key = getch()
if key == 'q' then save_favorites(); os.exit(0)
elseif key == 'h' then print_help()
elseif key == 's' then search()
elseif key == 'b' then back()
elseif key == 'f' then forward()
elseif key == 'u' then update_favorite()
elseif key == 'r' then refresh()
elseif key == 'p' then pipe()
elseif key == 'a' then add()
elseif key == 'l' then list()
elseif key == 'd' then delete()
elseif key == 'g' then go_to()
else print('Invalid entry') end
end
end
function refresh()
local th = session.tabs[session.current_tab].history
if th.loc > 0 then
go_to_url(th.items[th.loc])
end
end
function add_favorite()
local th = session.tabs[session.current_tab].history
if #th.items == 0 then return false end
local title
repeat
io.write('Enter title for bookmark (! to cancel): ')
title = io.read()
until title
if title == '!' then return print('Cancelled') end
table.insert(session.favorites,{display = title, link = th.items[th.loc]})
print('Bookmark added')
save_favorites()
end
function update_favorite()
local title
io.write('Enter the bookmark id (! to cancel): ')
local favid = io.read()
if favid == '!' then return print('Cancelled') end
local id = tonumber(favid) or tonumber(string.sub(favid,2))
if id then
local item = session.favorites[id]
if item then
print(string.format('Old title: %s', item.display))
while not title or title == '' do
io.write('Enter new title (! to cancel): ')
title = io.read()
if title == '!' then return print('Cancelled') end
end
item.display = title
print('Bookmark has been updated')
save_favorites()
else
print('Invalid bookmark id')
end
else
print('Invalid bookmark id')
end
end
function remove_favorite()
io.write('Enter the bookmark id to remove (! to cancel): ')
local favid = io.read()
if favid == '!' then return print('Cancelled') end
local id = tonumber(favid) or tonumber(string.sub(favid,2))
if id then
local item = session.favorites[id]
if item then
table.remove(session.favorites, id)
print('Bookmark has been removed')
save_favorites()
else
print('Invalid bookmark id')
end
else
print('Invalid bookmark id')
end
end
function remove_tab()
io.write('Enter the tab id to remove (! to cancel): ')
local tabid = io.read()
if tabid == '!' then return print('Cancelled') end
local id = tonumber(tabid)
if id then
local item = session.tabs[id]
if item then
table.remove(session.tabs, id)
print('Tab has been removed')
else
print('Invalid tab id')
end
else
print('Invalid tab id')
end
end
function visit_link(favorite)
local t = session.tabs[session.current_tab]
local linkid
repeat
io.write('Enter link id (! to cancel): ')
local inp = io.read()
if inp == '!' then return print('Cancelled') end
linkid = tonumber(inp)
if not linkid and string.sub(inp, 1, 1) == 'f' then
linkid = tonumber(string.sub(inp, 2))
end
until linkid
local linkurl
if favorite then
selection = session.favorites[linkid]
if selection then
linkurl = session.favorites[linkid].link
else
return print('Invalid bookmark id')
end
else
linkurl = t.current_links[linkid]
end
if linkurl then
table.truncate(t.history.items, t.history.loc + 1)
go_to_url(linkurl, true)
else
local out = string.format('Link id %d does not exist...', linkid)
print_gopher_error(out)
end
end
function back()
local th = session.tabs[session.current_tab].history
if th.loc > 1 and #th.items > 1 then
th.loc = th.loc - 1
go_to_url(th.items[th.loc])
end
end
function forward()
local th = session.tabs[session.current_tab].history
if th.loc < #th.items then
th.loc = th.loc + 1
go_to_url(th.items[th.loc])
--||__||--||__||--||__||--||__||--||__||--||__||--||__||--||
------------------------------------------------------------
-- Top Level Menu Options ----------------------------------
------------------------------------------------------------
function save_favorites()
local file = io.open(save_file_location, 'w+')
file:write("session.favorites = {\n")
for _,v in ipairs(session.favorites) do
file:write(string.format(" {[%q] = %q, [%q] = %q},\n", 'display', v.display, 'link', v.link))
end
file:write("}\n")
file:close()
end
@ -391,6 +295,295 @@ function print_help()
end
function search()
-- Do search here
end
function back()
local th = session.tabs[session.current_tab].history
if th.loc > 1 and #th.items > 1 then
th.loc = th.loc - 1
go_to_url(th.items[th.loc])
end
end
function forward()
local th = session.tabs[session.current_tab].history
if th.loc < #th.items then
th.loc = th.loc + 1
go_to_url(th.items[th.loc])
end
end
function update_favorite()
local title
io.write('Enter the bookmark id (! to cancel): ')
local favid = io.read()
if favid == '!' then return print('Cancelled') end
local id = tonumber(favid) or tonumber(string.sub(favid,2))
if id then
local item = session.favorites[id]
if item then
print(string.format('Old title: %s', item.display))
while not title or title == '' do
io.write('Enter new title (! to cancel): ')
title = io.read()
if title == '!' then return print('Cancelled') end
end
item.display = title
print('Bookmark has been updated')
save_favorites()
else
print('Invalid bookmark id')
end
else
print('Invalid bookmark id')
end
end
function refresh()
local th = session.tabs[session.current_tab].history
if th.loc > 0 then
go_to_url(th.items[th.loc])
end
end
function pipe()
io.write('Pipe to: (D)isk, (R)eader, New (T)ab')
local subkey = getch()
if subkey == 'd' then
save_file()
elseif subkey == 't' then
open_in_tab()
elseif subkey == 'r' then
open_in_less()
end
end
function add()
io.write('Add: (B)ookmark, (T)ab')
local subkey = getch()
if subkey == 'b' then
add_favorite()
elseif subkey == 't' then
new_tab()
end
end
function list()
io.write('List: (B)ookmarks, (T)abs')
local subkey = getch()
if subkey == 'b' then
show_favorites()
elseif subkey == 't' then
show_tabs()
end
end
function delete()
io.write('Delete: (B)ookmark, (T)ab')
local subkey = getch()
if subkey == 'b' then
remove_favorite()
elseif subkey == 't' then
remove_tab()
end
end
function go_to()
io.write('Go to: (B)ookmark, (L)ink, (T)ab, (U)rl')
local subkey = getch()
if subkey == 'b' then
go_to_link(true)
elseif subkey == 'l' then
go_to_link()
elseif subkey == 't' then
io.write('Enter tab id (! to cancel): ')
local t = io.read()
local tabid = tonumber(t)
if t ~= '!' and tabid and session.tabs[tabid] then
session.current_tab = tabid
refresh()
else
local x = tabid and print('Invalid tab id') or print('Cancelled')
end
elseif subkey == 'u' then
io.write('Enter gopher url (! to cancel): ')
local url = io.read()
if url ~= '!' and url ~= '' then
go_to_url(url, true)
else
print('Cancelled')
end
end
end
--||__||--||__||--||__||--||__||--||__||--||__||--||__||--||
------------------------------------------------------------
-- Secondary actions ---------------------------------------
------------------------------------------------------------
function go_to_link(favorite)
local t = session.tabs[session.current_tab]
local linkid
repeat
io.write('Enter link id (! to cancel): ')
local inp = io.read()
if inp == '!' then return print('Cancelled') end
linkid = tonumber(inp)
if not linkid and string.sub(inp, 1, 1) == 'f' then
linkid = tonumber(string.sub(inp, 2))
end
until linkid
local linkurl
if favorite then
selection = session.favorites[linkid]
if selection then
linkurl = session.favorites[linkid].link
else
return print('Invalid bookmark id')
end
else
linkurl = t.current_links[linkid]
end
if linkurl then
table.truncate(t.history.items, t.history.loc + 1)
go_to_url(linkurl, true)
else
local out = string.format('Link id %d does not exist...', linkid)
print_gopher_error(out)
end
end
function open_in_tab()
local t = session.tabs[session.current_tab]
local sub_menu = 'Pipe what: (C)urrent, (L)ink'
local favorite
io.write('Pipe what: (C)urrent, (L)ink')
local subkey = getch()
if subkey == 'c' then
local target_url = t.history.items[t.history.loc]
if not target_url then return print('No current page. Cancelled.') end
new_tab()
go_to_url(target_url, true)
elseif subkey == 'l' then
local linkid
repeat
io.write('Enter link id (! to cancel): ')
local inp = io.read()
if inp == '!' then return print('Cancelled') end
linkid = tonumber(inp)
if not linkid and string.sub(inp, 1, 1) == 'f' then
linkid = tonumber(string.sub(inp, 2))
favorite = true
end
until linkid
local linkurl
if favorite then
selection = session.favorites[linkid]
if selection then
linkurl = session.favorites[linkid].link
else
return print('Invalid bookmark id')
end
else
linkurl = t.current_links[linkid]
end
if linkurl then
new_tab()
go_to_url(linkurl, true)
else
local out = string.format('Link id %d does not exist...', linkid)
print_gopher_error(out)
end
end
end
function open_in_less()
local th = session.tabs[session.current_tab].history
local str
if th.loc > 0 then
str = go_to_url(th.items[th.loc], false, true)
end
if str then
local less = io.popen('less', 'w')
less:write(str)
less:close()
end
end
function add_favorite()
local th = session.tabs[session.current_tab].history
if #th.items == 0 then return false end
local title
repeat
io.write('Enter title for bookmark (! to cancel): ')
title = io.read()
until title
if title == '!' then return print('Cancelled') end
table.insert(session.favorites,{display = title, link = th.items[th.loc]})
print('Bookmark added')
save_favorites()
end
function remove_favorite()
io.write('Enter the bookmark id to remove (! to cancel): ')
local favid = io.read()
if favid == '!' then return print('Cancelled') end
local id = tonumber(favid) or tonumber(string.sub(favid,2))
if id then
local item = session.favorites[id]
if item then
table.remove(session.favorites, id)
print('Bookmark has been removed')
save_favorites()
else
print('Invalid bookmark id')
end
else
print('Invalid bookmark id')
end
end
function remove_tab()
io.write('Enter the tab id to remove (! to cancel): ')
local tabid = io.read()
if tabid == '!' then return print('Cancelled') end
local id = tonumber(tabid)
if id then
local item = session.tabs[id]
if item then
table.remove(session.tabs, id)
print('Tab has been removed')
else
print('Invalid tab id')
end
else
print('Invalid tab id')
end
end
function print_gopher_error(text)
print(separator)
print(text)
@ -398,17 +591,29 @@ end
function save_file()
local t = session.tabs[session.current_tab]
if not t.filedata then return print('No file available. Save cancelled.') end
io.write('Save to disk: (C)urrent, (L)ink')
local subkey = getch()
local out
if subkey == 'c' then
local t = session.tabs[session.current_tab]
out = t.filedata
if not out then return print('No file available. Save cancelled.') end
elseif subkey == 'l' then
local linkid = io.read()
local location = t.currentlinks[linkid]
-- handle getting data from the link
-- maybe set a flag on the get from url to return the data?
end
local homedir = assert(os.getenv('HOME'), 'Unable to find home directory')
io.write('Enter the filename to save as (! to cancel): ' .. homedir .. '/')
local filename = io.read()
if filename == '!' or filename == '' then
return print('Cancelled')
elseif string.match(filename, '^[%.%w_-]+$') then
print('Saving...')
local filepath = homedir .. '/' .. filename
local f = io.open(filepath, 'w+')
f:write(table.concat(t.filedata,'\n'))
f:write(table.concat(out,'\n'))
f:close()
print(string.format('File saved as: %s', filepath))
else
@ -417,63 +622,18 @@ function save_file()
end
function go_to_url(u, add2history)
local url = parse_url(u)
local t = session.tabs[session.current_tab]
if not url.host or url.scheme ~= 'gopher' then
print(separator)
print(' I n v a l i d u r l')
elseif table.has(valid_types, url.gophertype) then
t.filedata = request_gopher(url.host, url.port, url.path)
print(separator)
handle_response(t.filedata, url.gophertype)
local o = url.scheme .. '://' .. url.host .. ':' .. url.port .. '/' .. url.gophertype .. url.path
print('\n\n')
print(o)
if add2history then
table.truncate(t.history.items, t.history.loc + 1)
table.insert(t.history.items, o)
t.history.loc = t.history.loc + 1
end
end
end
function handle_response(res_table, gtype)
local out = ''
if gtype == '0' or gtype == 0 then
local o = table.concat(res_table, '\n')
print(o)
out = table.concat(res_table, '\n')
else
session.tabs[session.current_tab].current_links = {}
for i, v in ipairs(res_table) do
display_gophermap_row(v)
out = out .. (display_gophermap_row(v) or '').. '\n'
end
end
end
-- Modified version of socket.url.parse
-- Sets up defaults and adds parsing of gophertype
function parse_url(u)
if not string.find(u, '://', 1, true) then
u = 'gopher://'..u
end
local default = {port=70, scheme='gopher'}
local parsed = urlparser.parse(u, default)
if not parsed.path then
parsed.path = '/'
end
if string.find(parsed.path, '^/[%d%a]') then
parsed.gophertype = string.sub(parsed.path, 2, 2)
parsed.path = string.sub(parsed.path, 3) or '/'
elseif string.sub(parsed.path, -1) == '/' then
parsed.gophertype = '1'
else
parsed.gophertype = '0'
end
return parsed
return out
end
@ -499,17 +659,6 @@ function show_tabs()
end
function save_favorites()
local file = io.open(save_file_location, 'w+')
file:write("session.favorites = {\n")
for _,v in ipairs(session.favorites) do
file:write(string.format(" {[%q] = %q, [%q] = %q},\n", 'display', v.display, 'link', v.link))
end
file:write("}\n")
file:close()
end
function file_exists(name)
local f=io.open(name,"r")
if f~=nil then io.close(f) return true else return false end
@ -526,20 +675,11 @@ function new_tab()
favorites={}
}
if #session.tabs < 4 then
table.insert(session.tabs, t)
session.current_tab = #session.tabs
end
table.insert(session.tabs, t)
session.current_tab = #session.tabs
end
function init()
new_tab()
if file_exists(save_file_location) then
dofile(save_file_location)
end
mainloop()
end
-- run the program
init()