I forget
This commit is contained in:
parent
2b99c43a94
commit
9bad03be52
@ -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
196
mdbrowse.lua
Normal 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")
|
35
mdparse.lua
35
mdparse.lua
@ -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}
|
||||||
|
Loading…
Reference in New Issue
Block a user