Gopher + Markdown = something kinda nice

mdbrowse.lua 4.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. local curses = require "curses"
  2. local md = require "mdparse"
  3. local socket = require "socket"
  4. local surl = require "socket.url"
  5. local sx,sy,pc = 80, 25, "@"
  6. local function pgopher(gm)
  7. local s = ""
  8. for line in gm:gmatch("[^\n]+") do
  9. local t = line:sub(1,1)
  10. if t == "i" then
  11. if line:find("\t") then
  12. line=line:sub(1,line:find("\t"))
  13. end
  14. s=s..line:sub(2).."\n"
  15. elseif t == "0" or t == "1" then
  16. line=line:gsub("(.)(.+)\t/?([%w%./]+)\t([%w%.]+)\t(%d+)","%1 [%2](gopher://%4:%5/%3")..")" -- we gsub now
  17. line=line:gsub("\n","")
  18. s=s..line.."\n"
  19. else
  20. s=s..line.."\n"
  21. end
  22. end
  23. return s
  24. end
  25. local function geturl(url)
  26. local ds = {}
  27. ds.scheme = "gopher"
  28. ds.port = "70"
  29. ds.path = ""
  30. local c = ""
  31. local ourl = url
  32. tURL = surl.parse(url,ds)
  33. if not tURL.host then tURL.host = tURL.path tURL.path = "" end
  34. local dn, po, pt = tURL.host, tURL.port, tURL.path
  35. print(dn,po,pt)
  36. if dn and po then
  37. local s=socket.tcp()
  38. s:connect(dn,po)
  39. s:send(pt.."\n")
  40. c=s:receive("*a")
  41. s:close()
  42. local w,tpg = pcall(pgopher,c)
  43. if w then
  44. print(tpg)
  45. c=tpg
  46. end
  47. else
  48. c="Unable to load URL "..ourl
  49. end
  50. --[[--
  51. else
  52. local f=io.open(url,"rb")
  53. if not f then
  54. return "\r\nPage could not be loaded."
  55. end
  56. c=f:read("*a")
  57. print(c)
  58. f:close()
  59. end
  60. --]]--
  61. return c
  62. end
  63. local function settings()
  64. while true do
  65. local scr = curses.initscr ()
  66. curses.cbreak ()
  67. curses.echo (false) -- not noecho !
  68. curses.nl (false) -- not nonl !
  69. local selection = 1
  70. while true do
  71. local menu = {"Screen width: "..tostring(sx),"Screen height: "..tostring(sy),"Back"}
  72. scr:clear()
  73. scr:refresh()
  74. for k,v in ipairs(menu) do
  75. if k == selection then
  76. io.write(" * ")
  77. end
  78. print("\t"..v.."\r")
  79. end
  80. local ch = scr:getch()
  81. if ch == 66 then
  82. selection = selection + 1
  83. elseif ch == 65 then
  84. selection = selection - 1
  85. elseif ch == 13 then break
  86. end
  87. if selection > #menu then
  88. selection = #menu
  89. elseif selection < 1 then
  90. selection = 1
  91. end
  92. end
  93. if selection == 1 then
  94. scr:clear()
  95. scr:refresh()
  96. scr:addstr("New screen width: ")
  97. curses.echo (true)
  98. scr:refresh()
  99. sx = tonumber(scr:getstr()) or 80
  100. curses.echo (false)
  101. elseif selection == 2 then
  102. scr:clear()
  103. scr:refresh()
  104. scr:addstr("New screen height: ")
  105. curses.echo (true)
  106. scr:refresh()
  107. sy = tonumber(scr:getstr()) or 80
  108. curses.echo (false)
  109. else
  110. scr:close()
  111. break
  112. end
  113. end
  114. end
  115. local function main ()
  116. local scr = curses.initscr ()
  117. local mode = 1
  118. local p = false
  119. local sc = "#"
  120. local history = {}
  121. curses.cbreak ()
  122. curses.echo(false) -- not noecho !
  123. curses.nl(false) -- not nonl !
  124. cy = 1
  125. local ts = [[
  126. **SKS Markdown Gopher Client**
  127. See the [SKS gopher hole](gopher://shadowkat.net) for more info.
  128. Use *f* to follow a link, *o* to open a URL directly, *j* and *k* to scroll, and *s* for settings.
  129. Scrolling test:
  130. a
  131. b
  132. c
  133. d
  134. e
  135. f
  136. g
  137. h
  138. i
  139. j
  140. k
  141. l
  142. m
  143. n
  144. o
  145. p
  146. q
  147. r
  148. s
  149. t
  150. u
  151. v
  152. w
  153. x
  154. y
  155. z]]
  156. local url = "homepage"
  157. local lt = {}
  158. while true do
  159. scr:clear()
  160. scr:refresh()
  161. local ds = ""
  162. local dt = {}
  163. lt = md.parse(ts).l
  164. for k,v in ipairs(md.parse(ts)) do
  165. --[[--
  166. if v.bold then -- note to self: fix bold
  167. v.content = "\27[n1"..v.content.."\27[n0"
  168. end
  169. --]]--
  170. if v.addrid then
  171. ds=ds.."["..tostring(v.addrid).."]"..v.content
  172. else
  173. ds=ds..v.content
  174. end
  175. end
  176. for line in ds:gmatch("[^\n]*") do
  177. while line:len() > 0 do
  178. dt[#dt+1] = line:sub(1,sx)
  179. line = line:sub(sx+1)
  180. end
  181. end
  182. if sy < #dt then
  183. ms = sy
  184. else
  185. ms = #dt
  186. end
  187. for i = cy, cy+ms do
  188. io.write((dt[i] or "").."\r\n")
  189. end
  190. print("\r\n["..url.." "..tostring(cy).."/"..tostring(#dt).." "..tostring(ts:len()).."]\r")
  191. ch = scr:getch() or 0
  192. if ch < 256 then
  193. if string.char(ch) == "q" then
  194. break
  195. elseif string.char(ch) == "s" then
  196. settings()
  197. elseif string.char(ch) == "o" then
  198. scr:addstr("\rURL: ")
  199. curses.echo(true)
  200. scr:refresh()
  201. local nurl = scr:getstr()
  202. local w,nts=pcall(geturl,nurl)
  203. --print(w,nts)
  204. if w then ts = nts url=nurl end
  205. local nurl = scr:getstr()
  206. elseif string.char(ch) == "f" then
  207. scr:addstr("\rLink: ")
  208. curses.echo(true)
  209. scr:refresh()
  210. local nurl = lt[tonumber(scr:getstr())]
  211. local w,nts=pcall(geturl,nurl)
  212. if w then ts = nts url=nurl end
  213. scr:refresh()
  214. elseif string.char(ch) == "j" then
  215. if cy < #dt then
  216. cy = cy + 1
  217. end
  218. elseif string.char(ch) == "k" then
  219. if cy > 1 then
  220. cy = cy - 1
  221. end
  222. end
  223. end
  224. end
  225. end
  226. local function err (err)
  227. curses.endwin ()
  228. print "Caught an error:"
  229. print (debug.traceback (err, 2))
  230. os.exit (2)
  231. end
  232. xpcall (main, err)