171 lines
3.2 KiB
Lua
171 lines
3.2 KiB
Lua
-- mod-version:3
|
|
|
|
local core = require "core"
|
|
local common = require "core.common"
|
|
local command = require "core.command"
|
|
local keymap = require "core.keymap"
|
|
local Doc = require "core.doc"
|
|
local DocView = require "core.docview"
|
|
|
|
local navigate = {
|
|
list = {},
|
|
current = nil,
|
|
index = 0
|
|
}
|
|
|
|
--
|
|
-- Private functions
|
|
--
|
|
local function get_active_view()
|
|
if getmetatable(core.active_view) == DocView then
|
|
return core.active_view
|
|
end
|
|
return nil
|
|
end
|
|
|
|
-- Solution to safely remove elements from array table:
|
|
-- found at https://stackoverflow.com/a/53038524
|
|
local function array_remove(t, fnKeep)
|
|
local j, n = 1, #t;
|
|
|
|
for i=1, n do
|
|
if (fnKeep(t, i, j)) then
|
|
if (i ~= j) then
|
|
t[j] = t[i];
|
|
t[i] = nil;
|
|
end
|
|
j = j + 1;
|
|
else
|
|
t[i] = nil;
|
|
end
|
|
end
|
|
|
|
return t;
|
|
end
|
|
|
|
local function add(doc)
|
|
-- Make new navigation point last in list
|
|
if navigate.index > 0 and navigate.index < #navigate.list then
|
|
local remove_start = navigate.index + 1
|
|
local remove_end = #navigate.list
|
|
array_remove(navigate.list, function(_, i)
|
|
if i >= remove_start and i <= remove_end then
|
|
return false
|
|
end
|
|
return true
|
|
end)
|
|
end
|
|
|
|
local line, col = doc:get_selection()
|
|
table.insert(navigate.list, {
|
|
filename = doc.filename,
|
|
line = line,
|
|
col = col
|
|
})
|
|
|
|
navigate.current = navigate.list[#navigate.list]
|
|
navigate.index = #navigate.list
|
|
end
|
|
|
|
local function open_doc(doc)
|
|
core.root_view:open_doc(
|
|
core.open_doc(
|
|
common.home_expand(
|
|
doc.filename
|
|
)
|
|
)
|
|
)
|
|
|
|
local av_doc = get_active_view().doc
|
|
local line, col = av_doc:get_selection()
|
|
if doc.line ~= line or doc.col ~= col then
|
|
av_doc:set_selection(doc.line, doc.col, doc.line, doc.col)
|
|
end
|
|
end
|
|
|
|
--
|
|
-- Public functions
|
|
--
|
|
function navigate.next()
|
|
if navigate.index < #navigate.list then
|
|
navigate.index = navigate.index + 1
|
|
navigate.current = navigate.list[navigate.index]
|
|
open_doc(navigate.current)
|
|
end
|
|
end
|
|
|
|
function navigate.prev()
|
|
if navigate.index > 1 then
|
|
navigate.index = navigate.index - 1
|
|
navigate.current = navigate.list[navigate.index]
|
|
open_doc(navigate.current)
|
|
end
|
|
end
|
|
|
|
--
|
|
-- Thread
|
|
--
|
|
core.add_thread(function()
|
|
while true do
|
|
local av = get_active_view()
|
|
if av and av.doc and av.doc.filename then
|
|
local doc = av.doc
|
|
local line, col = doc:get_selection()
|
|
local current = navigate.current
|
|
if
|
|
not current
|
|
or
|
|
current.filename ~= doc.filename
|
|
or
|
|
current.line ~= line
|
|
then
|
|
add(doc)
|
|
else
|
|
current.col = col
|
|
end
|
|
end
|
|
coroutine.yield(0.5)
|
|
end
|
|
end)
|
|
|
|
--
|
|
-- Patching
|
|
--
|
|
local doc_on_close = Doc.on_close
|
|
|
|
function Doc:on_close()
|
|
local filename = self.filename
|
|
-- remove all positions referencing closed file
|
|
array_remove(navigate.list, function(t, i)
|
|
if t[i].filename == filename then
|
|
return false
|
|
end
|
|
return true
|
|
end)
|
|
|
|
doc_on_close(self)
|
|
end
|
|
|
|
--
|
|
-- Commands
|
|
--
|
|
command.add("core.docview", {
|
|
["navigate:previous"] = function()
|
|
navigate.prev()
|
|
end,
|
|
|
|
["navigate:next"] = function()
|
|
navigate.next()
|
|
end,
|
|
})
|
|
|
|
--
|
|
-- Default Keybindings
|
|
--
|
|
keymap.add {
|
|
["alt+left"] = "navigate:previous",
|
|
["alt+right"] = "navigate:next",
|
|
}
|
|
|
|
return navigate
|