Refactor open actions
Open actions now make use of a 'link' data structure containing a text and ref string, and the respective start and end positions on the line. Additionally, parsers are now simple objects containing extraction regex for extracting their text and ref link individually.
This commit is contained in:
parent
587fa47268
commit
3a9e04d3ce
2 changed files with 116 additions and 56 deletions
|
@ -2,16 +2,19 @@ local A = {}
|
|||
|
||||
local o = require 'zettelkasten.options'
|
||||
|
||||
local parsers = {markdown = "%[.-%]%((.-)%)", wiki = "%[%[(.+)|?.-%]%]"}
|
||||
local BIGNUMBER = 10000000
|
||||
|
||||
-- Extracts a file name from a link and opens the corresponding file
|
||||
-- in the current buffer.
|
||||
-- Takes an optional input parameter
|
||||
function A.open(input)
|
||||
local fname = A.extract_link(input)
|
||||
if not fname then return end
|
||||
local parsers = {
|
||||
markdown = {ref = "%[.-%]%((.-)%)", text = "%[(.-)%]%(.-%)"},
|
||||
wiki = {ref = "%[%[(.-)|?.-%]%]", text = "%[%[.-|?(.-)%]%]"}
|
||||
}
|
||||
|
||||
-- Opens the link passed in in the editor's current buffer.
|
||||
-- Requires a link object passed in.
|
||||
function A.open(link)
|
||||
if not link or not link.ref then return end
|
||||
-- TODO follow: go to anchor, fall back to filename
|
||||
vim.api.nvim_command(string.format("edit %s", fname))
|
||||
vim.api.nvim_command(string.format("edit %s", link.ref))
|
||||
end
|
||||
|
||||
-- Gets the input at the current buffer cursor and opens it
|
||||
|
@ -27,29 +30,56 @@ function A.open_selected(style)
|
|||
end
|
||||
end
|
||||
|
||||
-- Return only the link reference portion of a markdown/wiki style link.
|
||||
-- For example, for a markdown link [my text](my-link.md)
|
||||
-- it would only return my-link.md
|
||||
function A.extract_link(input)
|
||||
-- Return all links contained in the input given in an array.
|
||||
-- Returned link tables have the following structure:
|
||||
-- link = { text=, ref=, startpos=27, endpos=65 }
|
||||
function A.extract_all_links(input)
|
||||
if not input then return end
|
||||
for _, parser in pairs(parsers) do return input:match(parser) end
|
||||
return
|
||||
local links = {}
|
||||
local curpos = 1
|
||||
for _, parser in pairs(parsers) do
|
||||
while input:find(parser.ref, curpos) do
|
||||
local ref = input:match(parser.ref, curpos)
|
||||
local text = input:match(parser.text, curpos)
|
||||
local startpos, endpos = input:find(parser.ref, curpos)
|
||||
table.insert(links, {
|
||||
ref = ref,
|
||||
text = text,
|
||||
startpos = startpos,
|
||||
endpos = endpos
|
||||
})
|
||||
curpos = endpos
|
||||
end
|
||||
end
|
||||
return links
|
||||
end
|
||||
|
||||
-- Returns the word currently under cursor, the vim equivalent of yiW.
|
||||
-- Takes an optional boolean flag to set the word being caught
|
||||
-- to the vim equivalent of doing yiw, a more exclusive version.
|
||||
function A.get_link_under_cursor(small)
|
||||
local c = "<cWORD>"
|
||||
if small then c = "<cword>" end
|
||||
local word = vim.fn.expand(c)
|
||||
return word
|
||||
-- Returns the link currently under cursor, roughly the vim equivalent of yiW.
|
||||
-- Works for links containing spaces in their text or reference link.
|
||||
function A.get_link_under_cursor()
|
||||
local curpos = vim.api.nvim_win_get_cursor(0)[2]
|
||||
local links = A.extract_all_links(vim.api.nvim_get_current_line())
|
||||
for _, link in pairs(links) do
|
||||
if link.startpos <= curpos + 1 and link.endpos > curpos then
|
||||
return link
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Returns the content of the line from the cursor onwards.
|
||||
-- Returns the next link of the line from the cursor onwards.
|
||||
function A.get_next_link_on_line()
|
||||
local line = vim.api.nvim_get_current_line()
|
||||
return line:sub(vim.api.nvim_win_get_cursor(0)[2])
|
||||
local curpos = vim.api.nvim_win_get_cursor(0)[2]
|
||||
local links = A.extract_all_links(vim.api.nvim_get_current_line())
|
||||
local nearestpos = BIGNUMBER
|
||||
local nearestlink
|
||||
for k, link in pairs(links) do
|
||||
if link.endpos > curpos and link.endpos < nearestpos then
|
||||
nearestpos = link.endpos
|
||||
nearestlink = link
|
||||
end
|
||||
end
|
||||
return nearestlink
|
||||
end
|
||||
|
||||
return {open = A.open, open_selected = A.open_selected}
|
||||
|
|
|
@ -4,10 +4,10 @@ before_each(function() _G.vim = {g = {}, b = {}} end)
|
|||
after_each(function() _G.vim = nil end)
|
||||
|
||||
describe("open", function()
|
||||
it("should open file in editor if it is a valid link", function()
|
||||
it("should open file in editor if it contains a valid link ref", function()
|
||||
vim.api = {nvim_command = mock(function() end)}
|
||||
|
||||
action.open("[some text](1910271456_link-to-my-file.md)")
|
||||
action.open({ref = "1910271456_link-to-my-file.md"})
|
||||
assert.spy(vim.api.nvim_command).was_called_with(
|
||||
"edit 1910271456_link-to-my-file.md")
|
||||
end)
|
||||
|
@ -28,37 +28,67 @@ describe("open_selected", function()
|
|||
nvim_win_get_cursor = function(winnum) return {0, 0} end
|
||||
}
|
||||
end)
|
||||
it("should use the style passed to it, above the one set in options",
|
||||
function()
|
||||
vim.g['zettel_link_following'] = 'cursor'
|
||||
describe("when looking under cursor", function()
|
||||
it("should open link", function()
|
||||
vim.g['zettel_link_following'] = 'cursor'
|
||||
vim.api.nvim_win_get_cursor =
|
||||
function(winnum) return {0, 30} end
|
||||
action.open_selected()
|
||||
assert.spy(vim.api.nvim_command).was_called_with(
|
||||
"edit 1910271456_link-to-my-file.md")
|
||||
end)
|
||||
it("should detect correct position for link start", function()
|
||||
vim.g['zettel_link_following'] = 'cursor'
|
||||
|
||||
vim.api.nvim_get_current_line = mock(vim.api.nvim_get_current_line)
|
||||
action.open_selected("line")
|
||||
vim.api.nvim_win_get_cursor =
|
||||
function(winnum) return {0, 25} end
|
||||
action.open_selected()
|
||||
assert.spy(vim.api.nvim_command).was_not_called()
|
||||
|
||||
assert.spy(vim.api.nvim_get_current_line).was_called()
|
||||
vim.api.nvim_win_get_cursor =
|
||||
function(winnum) return {0, 26} end
|
||||
action.open_selected()
|
||||
assert.spy(vim.api.nvim_command).was_called_with(
|
||||
"edit 1910271456_link-to-my-file.md")
|
||||
end)
|
||||
it("should detect correct position for link end", function()
|
||||
vim.g['zettel_link_following'] = 'cursor'
|
||||
|
||||
vim.api.nvim_win_get_cursor =
|
||||
function(winnum) return {0, 65} end
|
||||
action.open_selected()
|
||||
assert.spy(vim.api.nvim_command).was_not_called()
|
||||
|
||||
vim.api.nvim_win_get_cursor =
|
||||
function(winnum) return {0, 64} end
|
||||
action.open_selected()
|
||||
assert.spy(vim.api.nvim_command).was_called_with(
|
||||
"edit 1910271456_link-to-my-file.md")
|
||||
end)
|
||||
end)
|
||||
it("should open link under cursor if option set", function()
|
||||
vim.g['zettel_link_following'] = 'cursor'
|
||||
vim.fn = {
|
||||
expand = function(sure)
|
||||
return "[" .. sure .. "](1910271456_link-to-my-file.md)"
|
||||
end
|
||||
}
|
||||
action.open_selected()
|
||||
assert.spy(vim.api.nvim_command).was_called_with(
|
||||
"edit 1910271456_link-to-my-file.md")
|
||||
end)
|
||||
it("should open next link on line if option set", function()
|
||||
vim.g['zettel_link_following'] = 'line'
|
||||
action.open_selected()
|
||||
assert.spy(vim.api.nvim_command).was_called_with(
|
||||
"edit 1910271456_link-to-my-file.md")
|
||||
end)
|
||||
it("should ignore links before cursor position", function()
|
||||
vim.g['zettel_link_following'] = 'line'
|
||||
vim.api.nvim_win_get_cursor = function(winnum) return {0, 65} end
|
||||
action.open_selected()
|
||||
assert.spy(vim.api.nvim_command).was_called_with(
|
||||
"edit 2030101158 another-link-now.md")
|
||||
describe("when looking until end of line", function()
|
||||
it("should use the style passed to it, above the one set in options",
|
||||
function()
|
||||
vim.g['zettel_link_following'] = 'cursor'
|
||||
|
||||
vim.api.nvim_get_current_line = mock(vim.api.nvim_get_current_line)
|
||||
action.open_selected("line")
|
||||
|
||||
assert.spy(vim.api.nvim_get_current_line).was_called()
|
||||
end)
|
||||
it("should open next link on line if option set", function()
|
||||
vim.g['zettel_link_following'] = 'line'
|
||||
action.open_selected()
|
||||
assert.spy(vim.api.nvim_command).was_called_with(
|
||||
"edit 1910271456_link-to-my-file.md")
|
||||
end)
|
||||
it("should ignore links before cursor position", function()
|
||||
vim.g['zettel_link_following'] = 'line'
|
||||
vim.api.nvim_win_get_cursor =
|
||||
function(winnum) return {0, 65} end
|
||||
action.open_selected()
|
||||
assert.spy(vim.api.nvim_command).was_called_with(
|
||||
"edit 2030101158 another-link-now.md")
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
|
|
Loading…
Reference in a new issue