OC-mdbrowser/mdbrowse.lua

197 lines
4.6 KiB
Lua

local net = require "net"
local md = require "mdparse"
local event = require "event"
local fs = require "filesystem"
local computer = require "computer"
local home = "file:///usr/doc/mdbrowse.md"
local url = home
local cline = 1
local lines, links, listeners, history = {}, {}, {}, {}
local width, height = 80, 23
local run = true
local function pushhistory(url)
history[#history+1] = url
end
local function pophistory()
local rurl = history[#history] or home
history[#history] = nil
return rurl
end
local function parseurl(url)
local proto,addr = url:match("(.-)://(.+)")
addr = addr or url
local hp, path = addr:match("(.-)(/.*)")
hp, path = hp or addr, path or "/"
local host, port = hp:match("(.+):(.+)")
host = host or hp
path = fs.canonical(path)
return proto, host, port, path
end
function addButton(x,y,l,a)
local len = l:len() + 2
local function hf(_,_,tx,ty)
if y == ty and tx >= x and tx <= x+len then
io.write("\a")
computer.pushSignal("mdbrowsebutton",a)
end
end
event.listen("touch",hf)
listeners[#listeners+1] = hf
end
function dropButtons()
for k,v in pairs(listeners) do
event.ignore("touch",v)
end
end
function loadpage()
local protocol, host, port, path = parseurl(url)
protocol = protocol or "file"
if protocol == "file" then
local f = io.open(host..path,"rb")
if not f then
url = pophistory()
return false, "not found"
end
lines, links = md.reflow(f:read("*a"),width)
f:close()
return true
elseif protocol == "fget" then
port = tonumber(port) or 70
local socket = net.open(host,port)
if socket then
io.write("\27[u\27[2KConnection established.")
local buf = ""
socket:write("t"..path.."\n")
local c = socket:read(1)
repeat
c = socket:read(1)
os.sleep(0.5)
until c ~= ""
if c == "n" then
buf = path..": Not found.\n"
elseif c == "f" then
buf = "Failure: \n"
elseif c == "d" then
buf = "# Directory listing for "..path.."\n"
end
repeat
l = socket:read(1024)
buf = buf .. l
io.write("\27[u\27[2KRead "..tonumber(buf:len()).." bytes")
os.sleep(0.5)
until socket.state == "closed" and l == ""
if c == "d" then
local first, nbuf = false, ""
for line in buf:gmatch("[^\n]+") do
if first then
line = "- ["..line.."]("..line..")"
end
nbuf = nbuf .. line .. "\n"
first = true
end
buf = nbuf
end
lines, links = md.reflow(buf,width)
return true
else
url = pophistory()
return false, "unable to load"
end
end
end
function drawpage()
dropButtons()
if cline < 1 then
cline = 1
elseif cline > #lines then
cline = #lines
end
io.write("\27[2J\27[H")
for i = cline, cline+height do
print((lines[i] or ""):sub(1,width))
end
for k,v in pairs(links) do
if v[1] >= cline and v[1] <= height+cline then
addButton(v[2],(v[1])-cline+1,v[3],v[4])
end
end
local lstring = tostring(cline).."-"..tostring(cline+height).."/"..tostring(#lines)
io.write("\27[s"..lstring.." "..url)
end
function gourl(nurl)
pushhistory(url)
-- check for a protocol:// part
if nurl:match(".+://") then
url = nurl
-- check for a / -- root relative
elseif nurl:sub(1,1) == "/" then
url = (url:match(".+://.-/" or url:match(".+://.+/?").."/")) .. nurl
-- fail and assume relative
else
local host = (url:match(".+://.-/") or url:match(".+://.+/?").."/")
local path = url:sub(host:len()+1)
local tPath = fs.segments(path)
local ntPath = fs.segments(nurl)
if path:sub(path:len(),path:len()) ~= "/" then
tPath[#tPath] = nil
end
for k,v in ipairs(ntPath) do
tPath[#tPath+1] = v
end
url = host:sub(1,-2)
for k,v in ipairs(tPath) do
url = url .. "/" .. v
end
if nurl:sub(nurl:len(),nurl:len()) == "/" then
url = url .. "/"
end
end
end
loadpage()
drawpage()
while run do
local tev = {event.pull()}
if tev[1] == "key_down" then
if tev[3] == 0 and tev[4] == 200 then -- up
cline = cline - 1
drawpage()
elseif tev[3] == 0 and tev[4] == 208 then -- down
cline = cline + 1
drawpage()
elseif tev[3] == 0 and tev[4] == 203 then -- left
url = pophistory()
cline = 1
loadpage()
drawpage()
elseif tev[3] == 0 and tev[4] == 209 then -- page down
cline = cline + height
drawpage()
elseif tev[3] == 0 and tev[4] == 201 then -- page up
cline = cline - height
drawpage()
elseif tev[3] == 113 and tev[4] == 16 then -- q
run = false
elseif tev[3] == 111 then -- o
io.write("\27[u\27[2K\27[sURL: ")
gourl(io.read())
cline = 1
loadpage()
drawpage()
end
elseif tev[1] == "mdbrowsebutton" then
gourl(tev[2])
cline = 1
loadpage()
drawpage()
end
end
dropButtons()
io.write("\27[2J\27[H")