This commit is contained in:
Izaya 2018-07-15 06:55:36 +10:00
parent 2b99c43a94
commit 9bad03be52
3 changed files with 227 additions and 7 deletions

View File

@ -2,7 +2,4 @@
A markdown FRequest browser for OpenComputers. A markdown FRequest browser for OpenComputers.
## mdparse ## mdparse
mdparse is the Markdown parsing library used for mdbrowser. It works under standard Lua as well as OpenComputers.
- `mdparse.parse(text:string): - table` Parses *text* into a table of tables. Each table should contain a .contents string, and if it is a link, then an .address string.
- `mdparse.reflow(text:string, linewidth:number): table, table` - Returns a table of formatted lines, and a table of links, as `{x, y, label, address}`.

196
mdbrowse.lua Normal file
View File

@ -0,0 +1,196 @@
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")

View File

@ -6,7 +6,7 @@ function md.parse(md)
it[#it+1] = {["content"]="",["bold"]=false,["italic"]=false} it[#it+1] = {["content"]="",["bold"]=false,["italic"]=false}
local lc,llc = "","" local lc,llc = "",""
local function newpart() local function newpart()
it[#it+1] = {["content"]=""} it[#it+1] = {["content"]="",["bold"]=it[#it].bold,["italic"]=it[#it].italic}
end end
newpart() newpart()
local lm = false local lm = false
@ -24,6 +24,15 @@ function md.parse(md)
it.l[#it.l+1] = it[#it].address it.l[#it.l+1] = it[#it].address
it[#it].addrid = #it.l it[#it].addrid = #it.l
newpart() newpart()
elseif c == "*" then
if lc == "*" then
it[#it].italic = false
it[#it].italic = it[#it-1].italic
it[#it].bold = not it[#it].bold
else
newpart()
it[#it].italic = not it[#it].italic
end
elseif c == "\n" and lc == "\n" then elseif c == "\n" and lc == "\n" then
if it[#it-1].content == "\n" then if it[#it-1].content == "\n" then
table.remove(it,#it-1) table.remove(it,#it-1)
@ -33,11 +42,15 @@ function md.parse(md)
newpart() newpart()
elseif c == "\n" then elseif c == "\n" then
local line = md:sub(1,cc):match(".+\n(.+)") or it[#it].content local line = md:sub(1,cc):match(".+\n(.+)") or it[#it].content
if line:sub(1,1) == "-" then if line:sub(line:find("%S")) == "-" then
newpart() newpart()
it[#it].content = "\n" it[#it].content = "\n"
newpart() newpart()
elseif line:sub(1,1) == "#" then elseif line:sub(line:find("%S")) == "#" then
newpart()
it[#it].content = "\n"
newpart()
elseif line:find("%s-%d+%.") == 1 then
newpart() newpart()
it[#it].content = "\n" it[#it].content = "\n"
newpart() newpart()
@ -58,13 +71,27 @@ function md.parse(md)
end end
function md.reflow(text,len) function md.reflow(text,len)
local words, lines, links = {}, {""}, {} local words, lines, links, lastitalic, lastbold = {}, {""}, {}, false, false
for k,v in ipairs(md.parse(text)) do for k,v in ipairs(md.parse(text)) do
if v.content == "\n\n" or v.content == "\n" then if v.content == "\n\n" or v.content == "\n" then
words[#words+1] = {v.content} words[#words+1] = {v.content}
elseif not v.address then elseif not v.address then
for word in v.content:gmatch("%S+") do for word in v.content:gmatch("%S+") do
words[#words+1] = {word} words[#words+1] = {word}
if v.italic and not lastitalic then
words[#words][1] = "\27[30;47m"..words[#words][1]
lastitalic = not lastitalic
elseif not v.italic and lastitalic then
words[#words-1][1] = words[#words-1][1].."\27[0m"
lastitalic = not lastitalic
end
if v.bold and not lastbold then
words[#words][1] = "\27[31m"..words[#words][1]
lastbold = not lastbold
elseif not v.bold and lastbold then
words[#words-1][1] = words[#words-1][1].."\27[0m"
lastbold = not lastbold
end
end end
else else
words[#words+1] = {v.content,v.address} words[#words+1] = {v.content,v.address}