Skip to content

Commit 8e40697

Browse files
committed
feat(hop): wiki links
1 parent a1e1961 commit 8e40697

File tree

1 file changed

+73
-38
lines changed

1 file changed

+73
-38
lines changed

lua/neorg/modules/core/esupports/hop/module.lua

Lines changed: 73 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ mapping them):
2525

2626
local neorg = require("neorg.core")
2727
local config, lib, log, modules, utils = neorg.config, neorg.lib, neorg.log, neorg.modules, neorg.utils
28-
local links, dirman_utils
28+
29+
---@type core.links, core.dirman.utils, core.dirman
30+
local links, dirman_utils, dirman
2931

3032
local module = modules.create("core.esupports.hop")
3133

@@ -36,6 +38,7 @@ module.setup = function()
3638
"core.integrations.treesitter",
3739
"core.ui",
3840
"core.dirman.utils",
41+
"core.dirman",
3942
"core.links",
4043
},
4144
}
@@ -44,6 +47,7 @@ end
4447
module.load = function()
4548
links = module.required["core.links"]
4649
dirman_utils = module.required["core.dirman.utils"]
50+
dirman = module.required["core.dirman"]
4751
vim.keymap.set("", "<Plug>(neorg.esupports.hop.hop-link)", module.public.hop_link)
4852
vim.keymap.set("", "<Plug>(neorg.esupports.hop.hop-link.vsplit)", lib.wrap(module.public.hop_link, "vsplit"))
4953
vim.keymap.set("", "<Plug>(neorg.esupports.hop.hop-link.drop)", lib.wrap(module.public.hop_link, "drop"))
@@ -110,6 +114,9 @@ end
110114
---@field node TSNode The node of the target.
111115
---@field type LinkTargetType The type of target that was located.
112116
---@field buffer number The buffer ID in which the target was found.
117+
---@field path string? file path where the target resides
118+
---@field line number?
119+
---@field uri string?
113120

114121
---@class (exact) PotentialLinkFixes
115122
---@field similarity number The similarity of this candidate to the current title of the link.
@@ -183,7 +190,7 @@ module.public = {
183190
end
184191

185192
local function jump_to_line(line)
186-
local status, _ = pcall(vim.api.nvim_win_set_cursor, 0, { line, 1 })
193+
local status, _ = pcall(vim.api.nvim_win_set_cursor, 0, { line, 0 })
187194

188195
if not status then
189196
log.error("Failed to jump to line:", line, "- make sure the line number exists!")
@@ -197,14 +204,6 @@ module.public = {
197204
end
198205

199206
lib.match(located_link_information.type)({
200-
-- Filter the currently unsupported link types and let the user know that they do not work
201-
wiki = function()
202-
vim.notify(
203-
"Neorg doesn't support wiki links yet, please use a more specific link type instead.",
204-
vim.log.levels.WARN
205-
)
206-
end,
207-
208207
-- If we're dealing with a URI, simply open the URI in the user's preferred method
209208
external_app = function()
210209
os_open_link(located_link_information.uri)
@@ -568,7 +567,7 @@ module.public = {
568567
---@param parsed_link_information Link #A table returned by `parse_link()`
569568
---@return LinkTarget #A table containing data about the link target
570569
locate_link_target = function(parsed_link_information)
571-
--- A pointer to the target buffer we will be parsing.
570+
-- A pointer to the target buffer we will be parsing.
572571
-- This may change depending on the target file the user gave.
573572
local buf_pointer = vim.api.nvim_get_current_buf()
574573

@@ -592,11 +591,6 @@ module.public = {
592591
end
593592

594593
return lib.match(parsed_link_information.link_type)({
595-
-- Wiki links are currently unsupported, so we simply forward the link type
596-
wiki = function()
597-
return { type = "wiki" }
598-
end,
599-
600594
url = function()
601595
return { type = "external_app", uri = parsed_link_information.link_location_text }
602596
end,
@@ -663,15 +657,25 @@ module.public = {
663657
}
664658
end,
665659

660+
-- wiki falls through to here
666661
_ = function()
667-
local query_str = links.get_link_target_query_string(parsed_link_information.link_type)
662+
local typ = parsed_link_information.link_type
663+
if typ == "wiki" then
664+
typ = "generic"
665+
end
666+
local query_str = links.get_link_target_query_string(typ)
668667
local document_root = module.required["core.integrations.treesitter"].get_document_root(buf_pointer)
669668

670669
if not document_root then
671670
return
672671
end
673672

674673
local query = utils.ts_parse_query("norg", query_str)
674+
local link_target = parsed_link_information.link_location_text
675+
if not link_target then
676+
return
677+
end
678+
local target = link_target:gsub("[%s\\]", ""):lower()
675679

676680
for id, node in query:iter_captures(document_root, buf_pointer) do
677681
local capture = query.captures[id]
@@ -682,9 +686,8 @@ module.public = {
682686

683687
if original_title then
684688
local title = original_title:gsub("[%s\\]", "")
685-
local target = parsed_link_information.link_location_text:gsub("[%s\\]", "")
686689

687-
if title:lower() == target:lower() then
690+
if title:lower() == target then
688691
return {
689692
type = "buffer",
690693
original_title = original_title,
@@ -695,6 +698,34 @@ module.public = {
695698
end
696699
end
697700
end
701+
702+
-- if we didn't find in the current file, search every other file, doesn't matter
703+
-- which file wins.
704+
local target_regex = target:gsub(" ", " ?"):lower()
705+
local heading_regex = ([[^\*+ %s$]]):format(target_regex)
706+
local workspace_path = dirman.get_current_workspace()[2]
707+
708+
local res = vim.system(
709+
{ "rg", "-i", "--column", "-o", heading_regex },
710+
{ cwd = tostring(workspace_path), text = true }
711+
):wait()
712+
713+
if res.code == 0 then
714+
local best = vim.iter(vim.split(res.stdout, "\n", { trimempty = true })):map(function(line)
715+
return { line:match("(.-):(%d+):(%d+)") }
716+
end):fold({}, function(acc, val)
717+
if acc[1] and acc[1]:len() < val[1]:len() then
718+
return acc
719+
end
720+
return val
721+
end)
722+
return {
723+
type = "buffer",
724+
buffer = vim.uri_to_bufnr((workspace_path / best[1]):as_uri()),
725+
line = tonumber(best[2]),
726+
column = tonumber(best[3]),
727+
}
728+
end
698729
end,
699730
} --[[@as table<string, fun(): LinkTarget?>]])
700731
end,
@@ -800,7 +831,7 @@ module.private = {
800831
---@return PotentialLinkFixes[]? #A table of similarities (fuzzed items)
801832
fix_link_strict = function(parsed_link_information)
802833
local query = lib.match(parsed_link_information.link_type)({
803-
generic = [[
834+
[{ "generic", "wiki" }] = [[
804835
[(_
805836
[(strong_carryover_set
806837
(strong_carryover
@@ -933,10 +964,13 @@ module.private = {
933964

934965
local range = module.required["core.integrations.treesitter"].get_node_range(link_node)
935966

936-
local prefix = lib.when(
937-
parsed_link_information.link_type == "generic" and not force_type,
938-
"#",
939-
lib.match(most_similar.node:type())({
967+
local prefix
968+
if parsed_link_information.link_type == "generic" and not force_type then
969+
prefix = "#"
970+
elseif parsed_link_information.link_type == "wiki" and not force_type then
971+
prefix = "?"
972+
else
973+
prefix = lib.match(most_similar.node:type())({
940974
heading1 = "*",
941975
heading2 = "**",
942976
heading3 = "***",
@@ -949,7 +983,8 @@ module.private = {
949983
multi_footnote = "^",
950984
_ = "#",
951985
})
952-
) .. " "
986+
end
987+
prefix = prefix .. " "
953988

954989
local function callback(replace)
955990
vim.api.nvim_buf_set_text(
@@ -963,19 +998,19 @@ module.private = {
963998
end
964999
callback(
9651000
"{"
966-
.. lib.when(
967-
parsed_link_information.link_file_text --[[@as boolean]],
968-
lib.lazy_string_concat(":", parsed_link_information.link_file_text, ":"),
969-
""
970-
)
971-
.. prefix
972-
.. most_similar.text
973-
.. "}"
974-
.. lib.when(
975-
parsed_link_information.link_description --[[@as boolean]],
976-
lib.lazy_string_concat("[", parsed_link_information.link_description, "]"),
977-
""
978-
)
1001+
.. lib.when(
1002+
parsed_link_information.link_file_text --[[@as boolean]],
1003+
lib.lazy_string_concat(":", parsed_link_information.link_file_text, ":"),
1004+
""
1005+
)
1006+
.. prefix
1007+
.. most_similar.text
1008+
.. "}"
1009+
.. lib.when(
1010+
parsed_link_information.link_description --[[@as boolean]],
1011+
lib.lazy_string_concat("[", parsed_link_information.link_description, "]"),
1012+
""
1013+
)
9791014
)
9801015
end,
9811016
}

0 commit comments

Comments
 (0)