zet.tlv: cross-links
We also made render dynamic, showing zettels in the first place it encounters them in depth-first order. Open question: how to show a collapsed outline view with the data model I'm experimenting with. Not even clear 'outline' has meaning in the presence of cross-links. Outliners privilege one view of the network. Zettelkasten also does so; changing child/sibling relationships is a lot of work. However, reading between the links it seems to try to provide an escape hatch for rethinking connections using cross-links. I'm trying to lean into that -- at the cost of providing outlines. We'll see if this is a good trade-off.
This commit is contained in:
parent
feb10708ae
commit
c55956bf96
820
zet.tlv
820
zet.tlv
|
@ -1467,3 +1467,823 @@
|
|||
> prev='id2',
|
||||
> },
|
||||
>}
|
||||
- __teliva_timestamp:
|
||||
>Thu Feb 10 20:24:13 2022
|
||||
menu:
|
||||
>-- To show app-specific hotkeys in the menu bar, add hotkey/command
|
||||
>-- arrays of strings to the menu array.
|
||||
>menu = {
|
||||
> {'a/b/c', 'insert'},
|
||||
> {'e', 'edit'},
|
||||
> {'j/k/l/h', 'move'},
|
||||
> {'x/X/y/Y', 'resize'},
|
||||
> {'s', 'stash'},
|
||||
> {'t', 'link with stash'},
|
||||
>}
|
||||
- __teliva_timestamp:
|
||||
>Thu Feb 10 20:25:14 2022
|
||||
stash:
|
||||
>stash = nil
|
||||
- __teliva_timestamp:
|
||||
>Thu Feb 10 20:32:38 2022
|
||||
update:
|
||||
>function update(window)
|
||||
> local key = curses.getch()
|
||||
> local h, w = window:getmaxyx()
|
||||
> local curr = zettels[current_zettel_id]
|
||||
> assert(curr, string.format('cursor fell off the edge of the world: %s', type(current_zettel_id)))
|
||||
> -- move along the graph
|
||||
> if key == string.byte('j') then
|
||||
> if curr.child then
|
||||
> current_zettel_id = curr.child
|
||||
> elseif curr.next then
|
||||
> current_zettel_id = curr.next
|
||||
> elseif curr.parent and zettels[curr.parent].next then
|
||||
> current_zettel_id = zettels[curr.parent].next
|
||||
> end
|
||||
> elseif key == string.byte('k') then
|
||||
> if curr.parent then current_zettel_id = curr.parent end
|
||||
> elseif key == string.byte('h') then
|
||||
> if curr.prev then
|
||||
> current_zettel_id = curr.prev
|
||||
> elseif curr.parent then
|
||||
> current_zettel_id = curr.parent
|
||||
> end
|
||||
> elseif key == string.byte('l') then
|
||||
> if curr.next then
|
||||
> current_zettel_id = curr.next
|
||||
> elseif curr.parent and zettels[curr.parent].next then
|
||||
> current_zettel_id = zettels[curr.parent].next
|
||||
> end
|
||||
> -- move along the screen
|
||||
> elseif key == curses.KEY_UP then
|
||||
> if render_state.curr_h > 1 then
|
||||
> current_zettel_id = render_state.wh2id[render_state.curr_w][render_state.curr_h - 1]
|
||||
> end
|
||||
> elseif key == curses.KEY_DOWN then
|
||||
> if render_state.wh2id[render_state.curr_w][render_state.curr_h + 1] then
|
||||
> current_zettel_id = render_state.wh2id[render_state.curr_w][render_state.curr_h + 1]
|
||||
> end
|
||||
> elseif key == curses.KEY_LEFT then
|
||||
> if render_state.curr_w > 1 then
|
||||
> current_zettel_id = render_state.wh2id[render_state.curr_w - 1][render_state.curr_h]
|
||||
> end
|
||||
> elseif key == curses.KEY_RIGHT then
|
||||
> if render_state.wh2id[render_state.curr_w + 1] and render_state.wh2id[render_state.curr_w + 1][render_state.curr_h] then
|
||||
> current_zettel_id = render_state.wh2id[render_state.curr_w + 1][render_state.curr_h]
|
||||
> end
|
||||
> -- mutations
|
||||
> elseif key == string.byte('e') then
|
||||
> editz(window)
|
||||
> elseif key == string.byte('a') then
|
||||
> -- insert sibling after
|
||||
> local old = curr.next
|
||||
> curr.next = new_id()
|
||||
> local new = zettels[curr.next]
|
||||
> new.data = ''
|
||||
> new.next = old
|
||||
> new.prev = current_zettel_id
|
||||
> if old then
|
||||
> zettels[old].prev = curr.next
|
||||
> assert(curr.parent == zettels[old].parent, 'siblings should have same parent')
|
||||
> end
|
||||
> new.parent = curr.parent
|
||||
> current_zettel_id = curr.next
|
||||
> render(window) -- recompute render_state
|
||||
> editz(window)
|
||||
> elseif key == string.byte('b') then
|
||||
> -- insert sibling before
|
||||
> local old = curr.prev
|
||||
> curr.prev = new_id()
|
||||
> local new = zettels[curr.prev]
|
||||
> new.data = ''
|
||||
> new.prev = old
|
||||
> new.next = current_zettel_id
|
||||
> if old then
|
||||
> zettels[old].next = curr.prev
|
||||
> assert(curr.parent == zettels[old].parent, 'siblings should have same parent')
|
||||
> end
|
||||
> new.parent = curr.parent
|
||||
> current_zettel_id = curr.prev
|
||||
> render(window) -- recompute render_state
|
||||
> editz(window)
|
||||
> elseif key == string.byte('c') then
|
||||
> -- insert child
|
||||
> local old = curr.child
|
||||
> curr.child = new_id()
|
||||
> local new = zettels[curr.child]
|
||||
> new.data = ''
|
||||
> new.next = old
|
||||
> if old then
|
||||
> assert(zettels[old].prev == nil, "first child shouldn't have a previous sibling")
|
||||
> zettels[old].prev = curr.child
|
||||
> end
|
||||
> new.parent = curr
|
||||
> current_zettel_id = curr.child
|
||||
> render(window) -- recompute render_state
|
||||
> editz(window)
|
||||
> -- cross-links
|
||||
> elseif key == string.byte('s') then
|
||||
> -- save zettel to a stash
|
||||
> stash = current_zettel_id
|
||||
> elseif key == string.byte('t') then
|
||||
> -- cross-link a zettel bidirectionally with what's on the stash
|
||||
> if curr.crosslinks then
|
||||
> curr.crosslinks.a = stash
|
||||
> else
|
||||
> curr.crosslinks = {a=stash}
|
||||
> end
|
||||
> -- view settings
|
||||
> elseif key == string.byte('x') then
|
||||
> if view_settings.width > 5 then
|
||||
> view_settings.width = view_settings.width - 5
|
||||
> end
|
||||
> elseif key == string.byte('X') then
|
||||
> if view_settings.width < w-5 then
|
||||
> view_settings.width = view_settings.width + 5
|
||||
> end
|
||||
> elseif key == string.byte('y') then
|
||||
> if view_settings.height > 0 then
|
||||
> view_settings.height = view_settings.height - 1
|
||||
> end
|
||||
> elseif key == string.byte('Y') then
|
||||
> if view_settings.height < h-2 then
|
||||
> view_settings.height = view_settings.height + 1
|
||||
> end
|
||||
> end
|
||||
>end
|
||||
- __teliva_timestamp:
|
||||
>Thu Feb 10 20:39:15 2022
|
||||
render:
|
||||
>function render(window)
|
||||
> window:clear()
|
||||
> local lines, cols = window:getmaxyx()
|
||||
> local bg=1
|
||||
> local y, x = 0, 0 -- units of characters (0-based)
|
||||
> local w, h = 1, 1 -- units of zettels (1-based)
|
||||
> -- render zettels depth-first, while tracking relative positions
|
||||
> local done = {}
|
||||
> local inprogress = {zettels.root}
|
||||
> render_state.wh2id = {{}}
|
||||
> while #inprogress > 0 do
|
||||
> local currid = table.remove(inprogress)
|
||||
> if not done[currid] then
|
||||
> done[currid] = true
|
||||
> table.insert(render_state.wh2id[w], currid)
|
||||
> local zettel = zettels[currid]
|
||||
> if currid == current_zettel_id then
|
||||
> render_state.curr_w = w
|
||||
> render_state.curr_h = h
|
||||
> end
|
||||
> local currbg = (currid == current_zettel_id) and view_settings.current_zettel_bg or bg
|
||||
> render_zettel(window, currbg, depth(zettel) * view_settings.indent, y, x, zettel)
|
||||
> if zettel.next then table.insert(inprogress, zettel.next) end
|
||||
> if zettel.child then table.insert(inprogress, zettel.child) end
|
||||
> if zettel.crosslinks then
|
||||
> for relation, target in pairs(zettel.crosslinks) do
|
||||
> table.insert(inprogress, target)
|
||||
> end
|
||||
> end
|
||||
> bg = 3 - bg -- toggle between color pairs 1 and 2
|
||||
> y = y + view_settings.height + view_settings.vmargin
|
||||
> h = h + 1
|
||||
> if y + view_settings.height > lines then
|
||||
> y = 0
|
||||
> h = 1
|
||||
> x = x + view_settings.width + view_settings.hmargin
|
||||
> w = w + 1
|
||||
> if x + view_settings.width > cols then break end
|
||||
> table.insert(render_state.wh2id, {})
|
||||
> end
|
||||
> end
|
||||
> end
|
||||
> window:mvaddstr(lines-1, 0, '')
|
||||
> bg = 1
|
||||
> x = 0
|
||||
> for i=1,3 do
|
||||
> local zettel = nil
|
||||
> if i == 1 and stash then
|
||||
> zettel = zettels[stash]
|
||||
> end
|
||||
> render_zettel(window, bg, 0, lines-1, x, zettel)
|
||||
> bg = 3 - bg
|
||||
> x = x + view_settings.width + view_settings.hmargin
|
||||
> end
|
||||
> curses.refresh()
|
||||
>end
|
||||
- __teliva_timestamp:
|
||||
>Thu Feb 10 20:40:08 2022
|
||||
__teliva_note:
|
||||
>initial support for cross-links
|
||||
>
|
||||
>Kinda confusing because zettels still show indent based on their
|
||||
>hierarchical location rather than the path they're rendered in.
|
||||
render_zettel:
|
||||
>function render_zettel(window, bg, indent, starty, startx, zettel)
|
||||
> window:attrset(curses.color_pair(bg))
|
||||
> for y=0,view_settings.height-1 do
|
||||
> for x=0,view_settings.width-1 do
|
||||
> window:mvaddch(y+starty, x+startx, ' ')
|
||||
> end
|
||||
> end
|
||||
> local y, x = 0, indent+1
|
||||
> local data = ''
|
||||
> if zettel then
|
||||
> data = zettel.data
|
||||
> end
|
||||
> for i=1,#data do
|
||||
> local c = data[i]
|
||||
> if c == '\n' then
|
||||
> y = y+1
|
||||
> x = indent+1
|
||||
> else
|
||||
> window:mvaddstr(y+starty, x+startx, c)
|
||||
> x = x+1
|
||||
> if x >= startx + view_settings.width then
|
||||
> y = y+1
|
||||
> x = indent+1
|
||||
> end
|
||||
> end
|
||||
> if y >= view_settings.height then
|
||||
> break
|
||||
> end
|
||||
> end
|
||||
>end
|
||||
- __teliva_timestamp:
|
||||
>Thu Feb 10 20:44:29 2022
|
||||
__teliva_note:
|
||||
>looks better after dynamically recomputing depth while rendering
|
||||
render:
|
||||
>function render(window)
|
||||
> window:clear()
|
||||
> local lines, cols = window:getmaxyx()
|
||||
> local bg=1
|
||||
> local y, x = 0, 0 -- units of characters (0-based)
|
||||
> local w, h = 1, 1 -- units of zettels (1-based)
|
||||
> -- render zettels depth-first, while tracking relative positions
|
||||
> local done = {}
|
||||
> local inprogress = {{id=zettels.root,depth=0}}
|
||||
> render_state.wh2id = {{}}
|
||||
> while #inprogress > 0 do
|
||||
> local curr = table.remove(inprogress)
|
||||
> if not done[curr.id] then
|
||||
> done[curr.id] = true
|
||||
> table.insert(render_state.wh2id[w], curr.id)
|
||||
> local zettel = zettels[curr.id]
|
||||
> if curr.id == current_zettel_id then
|
||||
> render_state.curr_w = w
|
||||
> render_state.curr_h = h
|
||||
> end
|
||||
> local currbg = (curr.id == current_zettel_id) and view_settings.current_zettel_bg or bg
|
||||
> render_zettel(window, currbg, curr.depth * view_settings.indent, y, x, zettel)
|
||||
> if zettel.next then table.insert(inprogress, {id=zettel.next, depth=curr.depth}) end
|
||||
> if zettel.child then table.insert(inprogress, {id=zettel.child, depth=curr.depth+1}) end
|
||||
> if zettel.crosslinks then
|
||||
> for relation, target in pairs(zettel.crosslinks) do
|
||||
> table.insert(inprogress, {id=target, depth=curr.depth+1})
|
||||
> end
|
||||
> end
|
||||
> bg = 3 - bg -- toggle between color pairs 1 and 2
|
||||
> y = y + view_settings.height + view_settings.vmargin
|
||||
> h = h + 1
|
||||
> if y + view_settings.height > lines then
|
||||
> y = 0
|
||||
> h = 1
|
||||
> x = x + view_settings.width + view_settings.hmargin
|
||||
> w = w + 1
|
||||
> if x + view_settings.width > cols then break end
|
||||
> table.insert(render_state.wh2id, {})
|
||||
> end
|
||||
> end
|
||||
> end
|
||||
> window:mvaddstr(lines-1, 0, '')
|
||||
> bg = 1
|
||||
> x = 0
|
||||
> for i=1,3 do
|
||||
> local zettel = nil
|
||||
> if i == 1 and stash then
|
||||
> zettel = zettels[stash]
|
||||
> end
|
||||
> render_zettel(window, bg, 0, lines-1, x, zettel)
|
||||
> bg = 3 - bg
|
||||
> x = x + view_settings.width + view_settings.hmargin
|
||||
> end
|
||||
> curses.refresh()
|
||||
>end
|
||||
- __teliva_timestamp:
|
||||
>Thu Feb 10 20:55:19 2022
|
||||
render_zettel:
|
||||
>function render_zettel(window, bg, indent, edge_label, starty, startx, zettel)
|
||||
> window:attrset(curses.color_pair(bg))
|
||||
> for y=0,view_settings.height-1 do
|
||||
> for x=0,view_settings.width-1 do
|
||||
> window:mvaddch(y+starty, x+startx, ' ')
|
||||
> end
|
||||
> end
|
||||
> if indent > 1 then
|
||||
> window:attrset(curses.color_pair(bg+1)) -- go from zettel color to its edge color
|
||||
> window:mvaddstr(starty, startx+indent-1, edge_label)
|
||||
> window:attrset(curses.color_pair(bg))
|
||||
> end
|
||||
> local y, x = 0, indent+1
|
||||
> local data = ''
|
||||
> if zettel then
|
||||
> data = zettel.data
|
||||
> end
|
||||
> for i=1,#data do
|
||||
> local c = data[i]
|
||||
> if c == '\n' then
|
||||
> y = y+1
|
||||
> x = indent+1
|
||||
> else
|
||||
> window:mvaddstr(y+starty, x+startx, c)
|
||||
> x = x+1
|
||||
> if x >= startx + view_settings.width then
|
||||
> y = y+1
|
||||
> x = indent+1
|
||||
> end
|
||||
> end
|
||||
> if y >= view_settings.height then
|
||||
> break
|
||||
> end
|
||||
> end
|
||||
>end
|
||||
- __teliva_timestamp:
|
||||
>Thu Feb 10 20:58:49 2022
|
||||
view_settings:
|
||||
>view_settings = {
|
||||
> -- dimensions for rendering a single zettel; extra text gets truncated
|
||||
> width=50,
|
||||
> height=3,
|
||||
> -- spacing between zettels
|
||||
> hmargin=1,
|
||||
> vmargin=1,
|
||||
> --
|
||||
> indent=2, -- how children of a zettel are indicated
|
||||
>}
|
||||
- __teliva_timestamp:
|
||||
>Thu Feb 10 20:59:18 2022
|
||||
render:
|
||||
>function render(window)
|
||||
> window:clear()
|
||||
> local lines, cols = window:getmaxyx()
|
||||
> local bg=3
|
||||
> local y, x = 0, 0 -- units of characters (0-based)
|
||||
> local w, h = 1, 1 -- units of zettels (1-based)
|
||||
> -- render zettels depth-first, while tracking relative positions
|
||||
> local done = {}
|
||||
> local inprogress = {{id=zettels.root,depth=0,edge=''}}
|
||||
> render_state.wh2id = {{}}
|
||||
> while #inprogress > 0 do
|
||||
> local curr = table.remove(inprogress)
|
||||
> if not done[curr.id] then
|
||||
> done[curr.id] = true
|
||||
> table.insert(render_state.wh2id[w], curr.id)
|
||||
> local zettel = zettels[curr.id]
|
||||
> if curr.id == current_zettel_id then
|
||||
> render_state.curr_w = w
|
||||
> render_state.curr_h = h
|
||||
> end
|
||||
> local currbg = (curr.id == current_zettel_id) and 1 or bg -- 1 is the color pair for the current zettel
|
||||
> render_zettel(window, currbg, curr.depth * view_settings.indent, curr.edge, y, x, zettel)
|
||||
> if zettel.next then table.insert(inprogress, {id=zettel.next, depth=curr.depth, edge='|'}) end
|
||||
> if zettel.child then table.insert(inprogress, {id=zettel.child, depth=curr.depth+1, edge='\\'}) end
|
||||
> if zettel.crosslinks then
|
||||
> for relation, target in pairs(zettel.crosslinks) do
|
||||
> table.insert(inprogress, {id=target, depth=curr.depth+1, edge=relation})
|
||||
> end
|
||||
> end
|
||||
> bg = 8 - bg -- toggle between color pairs 3 and 5
|
||||
> y = y + view_settings.height + view_settings.vmargin
|
||||
> h = h + 1
|
||||
> if y + view_settings.height > lines then
|
||||
> y = 0
|
||||
> h = 1
|
||||
> x = x + view_settings.width + view_settings.hmargin
|
||||
> w = w + 1
|
||||
> if x + view_settings.width > cols then break end
|
||||
> table.insert(render_state.wh2id, {})
|
||||
> end
|
||||
> end
|
||||
> end
|
||||
> window:mvaddstr(lines-1, 0, '')
|
||||
> bg = 3
|
||||
> x = 0
|
||||
> for i=1,3 do
|
||||
> local zettel = nil
|
||||
> if i == 1 and stash then
|
||||
> zettel = zettels[stash]
|
||||
> end
|
||||
> render_zettel(window, bg, 0, '', lines-1, x, zettel)
|
||||
> bg = 8 - bg -- toggle between color pairs 3 and 5
|
||||
> x = x + view_settings.width + view_settings.hmargin
|
||||
> end
|
||||
> curses.refresh()
|
||||
>end
|
||||
- __teliva_timestamp:
|
||||
>Thu Feb 10 21:02:41 2022
|
||||
__teliva_note:
|
||||
>label the incoming edge for each zettel
|
||||
>
|
||||
>Is it a child, sibling or other cross-link?
|
||||
init_colors:
|
||||
>function init_colors()
|
||||
> -- light background
|
||||
> -- current zettel
|
||||
> curses.init_pair(1, 236, 230)
|
||||
> curses.init_pair(2, 1, 230) -- edge label for current zettel
|
||||
> -- non-current zettel #1
|
||||
> curses.init_pair(3, 236, 250)
|
||||
> curses.init_pair(4, 1, 250) -- edge label for pair 3
|
||||
> -- non-current zettel #2
|
||||
> curses.init_pair(5, 236, 252)
|
||||
> curses.init_pair(6, 1, 252) -- edge label for pair 5
|
||||
> -- dark background
|
||||
>--? -- current zettel
|
||||
>--? curses.init_pair(7, 252, 130)
|
||||
>--? -- other zettels
|
||||
>--? curses.init_pair(1, 252, 240)
|
||||
>--? curses.init_pair(2, 252, 242)
|
||||
>--? -- edge labels
|
||||
>--? curses.init_pair(3, 1, 240) -- same bg as pair 1
|
||||
>--? curses.init_pair(4, 1, 242) -- same bg as pair 2
|
||||
>--? curses.init_pair(9, 1, 130) -- same bg as pair 7 for current zettel
|
||||
>end
|
||||
- __teliva_timestamp:
|
||||
>Thu Feb 10 21:11:35 2022
|
||||
menu:
|
||||
>-- To show app-specific hotkeys in the menu bar, add hotkey/command
|
||||
>-- arrays of strings to the menu array.
|
||||
>menu = {
|
||||
> {'a/b/c', 'insert'},
|
||||
> {'e', 'edit'},
|
||||
> {'j/k/l/h', 'move'},
|
||||
> {'x/X/y/Y', 'resize'},
|
||||
> {'s', 'stash'},
|
||||
> {'t', 'link with stash'},
|
||||
> {'z', 'scroll'},
|
||||
>}
|
||||
- __teliva_timestamp:
|
||||
>Thu Feb 10 21:13:19 2022
|
||||
main:
|
||||
>function main()
|
||||
> init_colors()
|
||||
> curses.curs_set(0) -- hide cursor except when editing
|
||||
>
|
||||
> local infile = io.open('zet', 'r')
|
||||
> if infile then
|
||||
> read_zettels(infile)
|
||||
> end
|
||||
> current_zettel_id = zettels.root -- cursor
|
||||
> view_settings.first_zettel = zettels.root -- start rendering here
|
||||
>
|
||||
> while true do
|
||||
> render(window)
|
||||
> update(window)
|
||||
>
|
||||
> -- save zettels, but hold on to previous state on disk
|
||||
> -- until last possible second
|
||||
> local filename = os.tmpname()
|
||||
> local outfile = io.open(filename, 'w')
|
||||
> if outfile then
|
||||
> write_zettels(outfile)
|
||||
> os.rename(filename, 'zet')
|
||||
> end
|
||||
> end
|
||||
>end
|
||||
- __teliva_timestamp:
|
||||
>Thu Feb 10 21:13:36 2022
|
||||
render:
|
||||
>function render(window)
|
||||
> window:clear()
|
||||
> local lines, cols = window:getmaxyx()
|
||||
> local bg=3
|
||||
> local y, x = 0, 0 -- units of characters (0-based)
|
||||
> local w, h = 1, 1 -- units of zettels (1-based)
|
||||
> -- render zettels depth-first, while tracking relative positions
|
||||
> local done = {}
|
||||
> local inprogress = {{id=view_settings.first_zettel,depth=0,edge=''}}
|
||||
> render_state.wh2id = {{}}
|
||||
> while #inprogress > 0 do
|
||||
> local curr = table.remove(inprogress)
|
||||
> if not done[curr.id] then
|
||||
> done[curr.id] = true
|
||||
> table.insert(render_state.wh2id[w], curr.id)
|
||||
> local zettel = zettels[curr.id]
|
||||
> if curr.id == current_zettel_id then
|
||||
> render_state.curr_w = w
|
||||
> render_state.curr_h = h
|
||||
> end
|
||||
> local currbg = (curr.id == current_zettel_id) and 1 or bg -- 1 is the color pair for the current zettel
|
||||
> render_zettel(window, currbg, curr.depth * view_settings.indent, curr.edge, y, x, zettel)
|
||||
> if zettel.next then table.insert(inprogress, {id=zettel.next, depth=curr.depth, edge='|'}) end
|
||||
> if zettel.child then table.insert(inprogress, {id=zettel.child, depth=curr.depth+1, edge='\\'}) end
|
||||
> if zettel.crosslinks then
|
||||
> for relation, target in pairs(zettel.crosslinks) do
|
||||
> table.insert(inprogress, {id=target, depth=curr.depth+1, edge=relation})
|
||||
> end
|
||||
> end
|
||||
> bg = 8 - bg -- toggle between color pairs 3 and 5
|
||||
> y = y + view_settings.height + view_settings.vmargin
|
||||
> h = h + 1
|
||||
> if y + view_settings.height > lines then
|
||||
> y = 0
|
||||
> h = 1
|
||||
> x = x + view_settings.width + view_settings.hmargin
|
||||
> w = w + 1
|
||||
> if x + view_settings.width > cols then break end
|
||||
> table.insert(render_state.wh2id, {})
|
||||
> end
|
||||
> end
|
||||
> end
|
||||
> window:mvaddstr(lines-1, 0, '')
|
||||
> bg = 3
|
||||
> x = 0
|
||||
> for i=1,3 do
|
||||
> local zettel = nil
|
||||
> if i == 1 and stash then
|
||||
> zettel = zettels[stash]
|
||||
> end
|
||||
> render_zettel(window, bg, 0, '', lines-1, x, zettel)
|
||||
> bg = 8 - bg -- toggle between color pairs 3 and 5
|
||||
> x = x + view_settings.width + view_settings.hmargin
|
||||
> end
|
||||
> curses.refresh()
|
||||
>end
|
||||
- __teliva_timestamp:
|
||||
>Thu Feb 10 21:19:26 2022
|
||||
__teliva_note:
|
||||
>bugfix: cross-links should be bidirectional
|
||||
update:
|
||||
>function update(window)
|
||||
> local key = curses.getch()
|
||||
> local h, w = window:getmaxyx()
|
||||
> local curr = zettels[current_zettel_id]
|
||||
> assert(curr, string.format('cursor fell off the edge of the world: %s', type(current_zettel_id)))
|
||||
> -- move along the graph
|
||||
> if key == string.byte('j') then
|
||||
> if curr.child then
|
||||
> current_zettel_id = curr.child
|
||||
> elseif curr.next then
|
||||
> current_zettel_id = curr.next
|
||||
> elseif curr.parent and zettels[curr.parent].next then
|
||||
> current_zettel_id = zettels[curr.parent].next
|
||||
> end
|
||||
> elseif key == string.byte('k') then
|
||||
> if curr.parent then current_zettel_id = curr.parent end
|
||||
> elseif key == string.byte('h') then
|
||||
> if curr.prev then
|
||||
> current_zettel_id = curr.prev
|
||||
> elseif curr.parent then
|
||||
> current_zettel_id = curr.parent
|
||||
> end
|
||||
> elseif key == string.byte('l') then
|
||||
> if curr.next then
|
||||
> current_zettel_id = curr.next
|
||||
> elseif curr.parent and zettels[curr.parent].next then
|
||||
> current_zettel_id = zettels[curr.parent].next
|
||||
> end
|
||||
> -- move along the screen
|
||||
> elseif key == curses.KEY_UP then
|
||||
> if render_state.curr_h > 1 then
|
||||
> current_zettel_id = render_state.wh2id[render_state.curr_w][render_state.curr_h - 1]
|
||||
> end
|
||||
> elseif key == curses.KEY_DOWN then
|
||||
> if render_state.wh2id[render_state.curr_w][render_state.curr_h + 1] then
|
||||
> current_zettel_id = render_state.wh2id[render_state.curr_w][render_state.curr_h + 1]
|
||||
> end
|
||||
> elseif key == curses.KEY_LEFT then
|
||||
> if render_state.curr_w > 1 then
|
||||
> current_zettel_id = render_state.wh2id[render_state.curr_w - 1][render_state.curr_h]
|
||||
> end
|
||||
> elseif key == curses.KEY_RIGHT then
|
||||
> if render_state.wh2id[render_state.curr_w + 1] and render_state.wh2id[render_state.curr_w + 1][render_state.curr_h] then
|
||||
> current_zettel_id = render_state.wh2id[render_state.curr_w + 1][render_state.curr_h]
|
||||
> end
|
||||
> -- mutations
|
||||
> elseif key == string.byte('e') then
|
||||
> editz(window)
|
||||
> elseif key == string.byte('a') then
|
||||
> -- insert sibling after
|
||||
> local old = curr.next
|
||||
> curr.next = new_id()
|
||||
> local new = zettels[curr.next]
|
||||
> new.data = ''
|
||||
> new.next = old
|
||||
> new.prev = current_zettel_id
|
||||
> if old then
|
||||
> zettels[old].prev = curr.next
|
||||
> assert(curr.parent == zettels[old].parent, 'siblings should have same parent')
|
||||
> end
|
||||
> new.parent = curr.parent
|
||||
> current_zettel_id = curr.next
|
||||
> render(window) -- recompute render_state
|
||||
> editz(window)
|
||||
> elseif key == string.byte('b') then
|
||||
> -- insert sibling before
|
||||
> local old = curr.prev
|
||||
> curr.prev = new_id()
|
||||
> local new = zettels[curr.prev]
|
||||
> new.data = ''
|
||||
> new.prev = old
|
||||
> new.next = current_zettel_id
|
||||
> if old then
|
||||
> zettels[old].next = curr.prev
|
||||
> assert(curr.parent == zettels[old].parent, 'siblings should have same parent')
|
||||
> end
|
||||
> new.parent = curr.parent
|
||||
> current_zettel_id = curr.prev
|
||||
> render(window) -- recompute render_state
|
||||
> editz(window)
|
||||
> elseif key == string.byte('c') then
|
||||
> -- insert child
|
||||
> local old = curr.child
|
||||
> curr.child = new_id()
|
||||
> local new = zettels[curr.child]
|
||||
> new.data = ''
|
||||
> new.next = old
|
||||
> if old then
|
||||
> assert(zettels[old].prev == nil, "first child shouldn't have a previous sibling")
|
||||
> zettels[old].prev = curr.child
|
||||
> end
|
||||
> new.parent = curr
|
||||
> current_zettel_id = curr.child
|
||||
> render(window) -- recompute render_state
|
||||
> editz(window)
|
||||
> -- cross-links
|
||||
> elseif key == string.byte('s') then
|
||||
> -- save zettel to a stash
|
||||
> stash = current_zettel_id
|
||||
> elseif key == string.byte('t') then
|
||||
> -- cross-link a zettel bidirectionally with what's on the stash
|
||||
> local insert_crosslink =
|
||||
> function(a, rel, b_id)
|
||||
> if a.crosslinks == nil then
|
||||
> a.crosslinks = {}
|
||||
> end
|
||||
> a.crosslinks[rel] = b_id
|
||||
> end
|
||||
> insert_crosslink(curr, 'a', stash)
|
||||
> insert_crosslink(zettels[stash], 'a', current_zettel_id)
|
||||
> -- view settings
|
||||
> elseif key == string.byte('x') then
|
||||
> if view_settings.width > 5 then
|
||||
> view_settings.width = view_settings.width - 5
|
||||
> end
|
||||
> elseif key == string.byte('X') then
|
||||
> if view_settings.width < w-5 then
|
||||
> view_settings.width = view_settings.width + 5
|
||||
> end
|
||||
> elseif key == string.byte('y') then
|
||||
> if view_settings.height > 0 then
|
||||
> view_settings.height = view_settings.height - 1
|
||||
> end
|
||||
> elseif key == string.byte('Y') then
|
||||
> if view_settings.height < h-2 then
|
||||
> view_settings.height = view_settings.height + 1
|
||||
> end
|
||||
> elseif key == string.byte('z') then
|
||||
> -- scroll to show the current zettel at top of screen
|
||||
> -- often has the effect of zooming in on its hierarchy
|
||||
> view_settings.first_zettel = current_zettel_id
|
||||
> end
|
||||
>end
|
||||
- __teliva_timestamp:
|
||||
>Thu Feb 10 21:20:45 2022
|
||||
__teliva_note:
|
||||
>clear stash after linking
|
||||
update:
|
||||
>function update(window)
|
||||
> local key = curses.getch()
|
||||
> local h, w = window:getmaxyx()
|
||||
> local curr = zettels[current_zettel_id]
|
||||
> assert(curr, string.format('cursor fell off the edge of the world: %s', type(current_zettel_id)))
|
||||
> -- move along the graph
|
||||
> if key == string.byte('j') then
|
||||
> if curr.child then
|
||||
> current_zettel_id = curr.child
|
||||
> elseif curr.next then
|
||||
> current_zettel_id = curr.next
|
||||
> elseif curr.parent and zettels[curr.parent].next then
|
||||
> current_zettel_id = zettels[curr.parent].next
|
||||
> end
|
||||
> elseif key == string.byte('k') then
|
||||
> if curr.parent then current_zettel_id = curr.parent end
|
||||
> elseif key == string.byte('h') then
|
||||
> if curr.prev then
|
||||
> current_zettel_id = curr.prev
|
||||
> elseif curr.parent then
|
||||
> current_zettel_id = curr.parent
|
||||
> end
|
||||
> elseif key == string.byte('l') then
|
||||
> if curr.next then
|
||||
> current_zettel_id = curr.next
|
||||
> elseif curr.parent and zettels[curr.parent].next then
|
||||
> current_zettel_id = zettels[curr.parent].next
|
||||
> end
|
||||
> -- move along the screen
|
||||
> elseif key == curses.KEY_UP then
|
||||
> if render_state.curr_h > 1 then
|
||||
> current_zettel_id = render_state.wh2id[render_state.curr_w][render_state.curr_h - 1]
|
||||
> end
|
||||
> elseif key == curses.KEY_DOWN then
|
||||
> if render_state.wh2id[render_state.curr_w][render_state.curr_h + 1] then
|
||||
> current_zettel_id = render_state.wh2id[render_state.curr_w][render_state.curr_h + 1]
|
||||
> end
|
||||
> elseif key == curses.KEY_LEFT then
|
||||
> if render_state.curr_w > 1 then
|
||||
> current_zettel_id = render_state.wh2id[render_state.curr_w - 1][render_state.curr_h]
|
||||
> end
|
||||
> elseif key == curses.KEY_RIGHT then
|
||||
> if render_state.wh2id[render_state.curr_w + 1] and render_state.wh2id[render_state.curr_w + 1][render_state.curr_h] then
|
||||
> current_zettel_id = render_state.wh2id[render_state.curr_w + 1][render_state.curr_h]
|
||||
> end
|
||||
> -- mutations
|
||||
> elseif key == string.byte('e') then
|
||||
> editz(window)
|
||||
> elseif key == string.byte('a') then
|
||||
> -- insert sibling after
|
||||
> local old = curr.next
|
||||
> curr.next = new_id()
|
||||
> local new = zettels[curr.next]
|
||||
> new.data = ''
|
||||
> new.next = old
|
||||
> new.prev = current_zettel_id
|
||||
> if old then
|
||||
> zettels[old].prev = curr.next
|
||||
> assert(curr.parent == zettels[old].parent, 'siblings should have same parent')
|
||||
> end
|
||||
> new.parent = curr.parent
|
||||
> current_zettel_id = curr.next
|
||||
> render(window) -- recompute render_state
|
||||
> editz(window)
|
||||
> elseif key == string.byte('b') then
|
||||
> -- insert sibling before
|
||||
> local old = curr.prev
|
||||
> curr.prev = new_id()
|
||||
> local new = zettels[curr.prev]
|
||||
> new.data = ''
|
||||
> new.prev = old
|
||||
> new.next = current_zettel_id
|
||||
> if old then
|
||||
> zettels[old].next = curr.prev
|
||||
> assert(curr.parent == zettels[old].parent, 'siblings should have same parent')
|
||||
> end
|
||||
> new.parent = curr.parent
|
||||
> current_zettel_id = curr.prev
|
||||
> render(window) -- recompute render_state
|
||||
> editz(window)
|
||||
> elseif key == string.byte('c') then
|
||||
> -- insert child
|
||||
> local old = curr.child
|
||||
> curr.child = new_id()
|
||||
> local new = zettels[curr.child]
|
||||
> new.data = ''
|
||||
> new.next = old
|
||||
> if old then
|
||||
> assert(zettels[old].prev == nil, "first child shouldn't have a previous sibling")
|
||||
> zettels[old].prev = curr.child
|
||||
> end
|
||||
> new.parent = curr
|
||||
> current_zettel_id = curr.child
|
||||
> render(window) -- recompute render_state
|
||||
> editz(window)
|
||||
> -- cross-links
|
||||
> elseif key == string.byte('s') then
|
||||
> -- save zettel to a stash
|
||||
> stash = current_zettel_id
|
||||
> elseif key == string.byte('t') then
|
||||
> -- cross-link a zettel bidirectionally with what's on the stash
|
||||
> local insert_crosslink =
|
||||
> function(a, rel, b_id)
|
||||
> if a.crosslinks == nil then
|
||||
> a.crosslinks = {}
|
||||
> end
|
||||
> a.crosslinks[rel] = b_id
|
||||
> end
|
||||
> insert_crosslink(curr, 'a', stash)
|
||||
> insert_crosslink(zettels[stash], 'a', current_zettel_id)
|
||||
> stash = nil
|
||||
> -- view settings
|
||||
> elseif key == string.byte('x') then
|
||||
> if view_settings.width > 5 then
|
||||
> view_settings.width = view_settings.width - 5
|
||||
> end
|
||||
> elseif key == string.byte('X') then
|
||||
> if view_settings.width < w-5 then
|
||||
> view_settings.width = view_settings.width + 5
|
||||
> end
|
||||
> elseif key == string.byte('y') then
|
||||
> if view_settings.height > 0 then
|
||||
> view_settings.height = view_settings.height - 1
|
||||
> end
|
||||
> elseif key == string.byte('Y') then
|
||||
> if view_settings.height < h-2 then
|
||||
> view_settings.height = view_settings.height + 1
|
||||
> end
|
||||
> elseif key == string.byte('z') then
|
||||
> -- scroll to show the current zettel at top of screen
|
||||
> -- often has the effect of zooming in on its hierarchy
|
||||
> view_settings.first_zettel = current_zettel_id
|
||||
> end
|
||||
>end
|
||||
|
|
Loading…
Reference in New Issue