gemini: links

This commit is contained in:
Kartik K. Agaram 2021-12-21 23:38:04 -08:00
parent 712d80e48a
commit a9e400bbb4
1 changed files with 101 additions and 19 deletions

View File

@ -177,12 +177,49 @@
> window:addstr(line[i]) > window:addstr(line[i])
> end > end
>end >end
- __teliva_timestamp: original
render_link:
>function render_link(window, y, line)
> local rendered_line = string.gsub(line, '=>%s*%S*%s*', '')
> if trim(rendered_line) == '' then
> rendered_line = line
> end
> render_line(window, y, rendered_line)
>end
- __teliva_timestamp: original
state:
>state = {
> lines={},
> highlight_index=0,
> source=false, -- show source (link urls, etc.)
>}
- __teliva_timestamp: original - __teliva_timestamp: original
render_page: render_page:
>function render_page(window, lines) >function render_page(window)
> local y = 0 > local y = 0
> for _, line in pairs(lines) do > window:attron(curses.color_pair(6))
> render_line(window, y, line) > print(state.url)
> window:attroff(curses.color_pair(6))
> y = y+2
>--? dbg(window, state.highlight_index)
> for i, line in pairs(state.lines) do
> if not state.source and string.find(line, '=> ') == 1 then
> if state.highlight_index == 0 or i == state.highlight_index then
> -- highlighted link
> state.highlight_index = i -- TODO: ugly state update while rendering, just for first render after gemini_get
> curses.attron(curses.A_REVERSE)
> render_link(window, y, line)
> curses.attroff(curses.A_REVERSE)
> else
> -- link
> curses.attron(curses.A_BOLD)
> render_link(window, y, line)
> curses.attroff(curses.A_BOLD)
> end
> else
> -- non-link
> render_line(window, y, line)
> end
> y = y+1 > y = y+1
> end > end
>end >end
@ -197,7 +234,9 @@
- __teliva_timestamp: original - __teliva_timestamp: original
menu: menu:
>menu = {} >menu = {}
>menu['^g'] = 'go' >menu['^g'] = 'enter url'
>menu['enter'] = 'go to highlight'
>menu['^u'] = 'view source'
- __teliva_timestamp: original - __teliva_timestamp: original
edit_line: edit_line:
>function edit_line(window) >function edit_line(window)
@ -241,11 +280,51 @@
> end > end
> end > end
>end >end
- __teliva_timestamp: original
is_link:
>function is_link(line)
> return string.find(line, '=>%s*%S*%s*') == 1
>end
- __teliva_timestamp: original
next_link:
>function next_link()
> local new_index = state.highlight_index
> while true do
> new_index = new_index+1
> if new_index > #state.lines then return end
> if is_link(state.lines[new_index]) then break end
> end
> state.highlight_index = new_index
>end
- __teliva_timestamp: original
previous_link:
>function previous_link()
> local new_index = state.highlight_index
> while true do
> new_index = new_index - 1
> if new_index < 1 then return end
> if is_link(state.lines[new_index]) then break end
> end
> state.highlight_index = new_index
>end
- __teliva_timestamp: original - __teliva_timestamp: original
update: update:
>function update(window, lines) >function update(window)
> local key = curses.getch() > local key = curses.getch()
> local screen_rows, screen_cols = window:getmaxyx() > local screen_rows, screen_cols = window:getmaxyx()
> if key == 258 then -- down arrow
> next_link()
> end
> if key == 259 then -- up arrow
> previous_link()
> end
> if key == 21 then -- ctrl-u
> state.source = not state.source
> end
> if key == 10 then -- enter
> local s, e, new_url = string.find(state.lines[state.highlight_index], '=>%s*(%S*)')
> gemini_get(url.absolute(state.url, new_url))
> end
> if key == 7 then -- ctrl-g > if key == 7 then -- ctrl-g
> window:mvaddstr(screen_rows-2, 0, '') > window:mvaddstr(screen_rows-2, 0, '')
> window:clrtoeol() > window:clrtoeol()
@ -255,8 +334,8 @@
> curses.curs_set(2) > curses.curs_set(2)
> local new_url = edit_line(window) > local new_url = edit_line(window)
> if new_url then > if new_url then
> local new_lines = gemini_get(new_url) > state.url = new_url
> zap(lines, new_lines) > gemini_get(new_url)
> end > end
> curses.curs_set(0) > curses.curs_set(0)
> end > end
@ -283,8 +362,8 @@
> local lines = {} > local lines = {}
> local url = '' > local url = ''
> if #arg > 0 then > if #arg > 0 then
> url = arg[1] > state.url = arg[1]
> lines = gemini_get(url) > lines = gemini_get(state.url)
> end > end
> while true do > while true do
> render(window, lines) > render(window, lines)
@ -355,21 +434,19 @@
- __teliva_timestamp: original - __teliva_timestamp: original
parse_gemini_body: parse_gemini_body:
>function parse_gemini_body(conn, type) >function parse_gemini_body(conn, type)
> local result = {}
> if type == 'text/gemini' then > if type == 'text/gemini' then
> while true do > while true do
> local line, err = conn:receive() > local line, err = conn:receive()
> if line == nil then break end > if line == nil then break end
> table.insert(result, line) > table.insert(state.lines, line)
> end > end
> elseif string.sub(type, 1, 5) == 'text/' then > elseif string.sub(type, 1, 5) == 'text/' then
> while true do > while true do
> local line, err = conn:receive() > local line, err = conn:receive()
> if line == nil then break end > if line == nil then break end
> table.insert(result, line) > table.insert(state.lines, line)
> end > end
> end > end
> return result
>end >end
- __teliva_timestamp: original - __teliva_timestamp: original
gemini_get: gemini_get:
@ -395,18 +472,23 @@
> os.exit(1) > os.exit(1)
> end > end
> conn:dohandshake() > conn:dohandshake()
>
> conn:send(url .. "\r\n") > conn:send(url .. "\r\n")
> clear(state.lines)
> state.highlight_index = 0 -- highlighted link not computed yet
> local line, err = conn:receive() > local line, err = conn:receive()
> if line == nil then return {err} end > if line == nil then
> table.insert(state.lines, err)
> return
> end
> local status, meta = string.match(line, "(%S+) (%S+)") > local status, meta = string.match(line, "(%S+) (%S+)")
> if status[1] == '2' then > if status[1] == '2' then
> return parse_gemini_body(conn, meta) > parse_gemini_body(conn, meta)
> state.url = url
> elseif status[1] == '3' then > elseif status[1] == '3' then
> return gemini_get(socket.url.absolute(url, meta)) > gemini_get(socket.url.absolute(url, meta))
> elseif status[1] == '4' or line[1] == '5' then > elseif status[1] == '4' or line[1] == '5' then
> return {'Error: '..meta} > table.insert(state.lines, 'Error: '..meta)
> else > else
> return {'invalid response from server: '..line} > table.insert(state.lines, 'invalid response from server: '..line)
> end > end
>end >end