Skip to content

Commit 57daf53

Browse files
committed
chore: proper LuaCATS annotations for esupports.hop
1 parent f33a491 commit 57daf53

File tree

2 files changed

+83
-35
lines changed

2 files changed

+83
-35
lines changed

lua/neorg/core/init.lua

+3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ local neorg = {
44
log = require("neorg.core.log"),
55
modules = require("neorg.core.modules"),
66
utils = require("neorg.core.utils"),
7+
8+
---@module "lua-utils"
9+
lib = nil,
710
}
811

912
return neorg

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

+80-35
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,53 @@ local function range_contains(r_out, r_in)
6262
and xy_le(r_in.row_end, r_in.column_end, r_out.row_end, r_out.column_end)
6363
end
6464

65+
---@alias LinkType
66+
---|"url"
67+
---|"generic"
68+
---|"external_file"
69+
---|"definition"
70+
---|"timestamp"
71+
---|"footnote"
72+
---|"heading1"
73+
---|"heading2"
74+
---|"heading3"
75+
---|"heading4"
76+
---|"heading5"
77+
---|"heading6"
78+
---|"line_number"
79+
---|"wiki"
80+
81+
---@class (exact) Link
82+
---@field link_node TSNode The treesitter node of the link.
83+
---@field link_file_text string? A provided path, if any.
84+
---@field link_type LinkType? The type of link that was provided.
85+
---@field link_location_text string? The target title/URL of the link.
86+
---@field link_description string? The description of the link, if provided.
87+
88+
---@alias LinkTargetType
89+
--- |"buffer"
90+
--- |"external_app"
91+
--- |"external_file"
92+
--- |"wiki"
93+
--- |"calendar"
94+
95+
---@class LinkTarget
96+
---@field original_title string The title of the link that points to this target.
97+
---@field node TSNode The node of the target.
98+
---@field type LinkTargetType The type of target that was located.
99+
---@field buffer number The buffer ID in which the target was found.
100+
101+
---@class (exact) PotentialLinkFixes
102+
---@field similarity number The similarity of this candidate to the current title of the link.
103+
---@field text string The title of the candidate link title (will replace the existing link target).
104+
---@field node TSNode The node the fixed link points to.
105+
65106
---@class core.esupports.hop
66107
module.public = {
67108
--- Follow link from a specific node
68-
---@param node table
69-
---@param open_mode string|nil if not nil, will open a new split with the split mode defined (vsplitr...) or new tab (mode="tab") or with external app (mode="external")
70-
---@param parsed_link table a table of link information gathered from parse_link()
109+
---@param node TSNode
110+
---@param open_mode string? if not nil, will open a new split with the split mode defined (vsplitr...) or new tab (mode="tab") or with external app (mode="external")
111+
---@param parsed_link Link A table of link information gathered from parse_link()
71112
follow_link = function(node, open_mode, parsed_link)
72113
if node:type() == "anchor_declaration" then
73114
local located_anchor_declaration = module.public.locate_anchor_declaration_target(node)
@@ -85,7 +126,7 @@ module.public = {
85126
end
86127

87128
if not parsed_link then
88-
log.warn("Please parse your link before calling this function")
129+
log.warn("Please parse your link before calling this function.")
89130
return
90131
end
91132

@@ -281,7 +322,7 @@ module.public = {
281322
end,
282323

283324
--- Locate a `link` or `anchor` node under the cursor
284-
---@return userdata|nil #A `link` or `anchor` node if present under the cursor, else `nil`
325+
---@return TSNode? #A `link` or `anchor` node if present under the cursor, else `nil`
285326
extract_link_node = function()
286327
local ts_utils = module.required["core.integrations.treesitter"].get_ts_utils()
287328

@@ -303,7 +344,7 @@ module.public = {
303344
end,
304345

305346
--- Attempts to locate a `link` or `anchor` node after the cursor on the same line
306-
---@return userdata|nil #A `link` or `anchor` node if present on the current line, else `nil`
347+
---@return TSNode? #A `link` or `anchor` node if present on the current line, else `nil`
307348
lookahead_link_node = function()
308349
local ts_utils = module.required["core.integrations.treesitter"].get_ts_utils()
309350

@@ -346,7 +387,8 @@ module.public = {
346387
end,
347388

348389
--- Locates the node that an anchor is pointing to
349-
---@param anchor_decl_node table #A valid anchod declaration node
390+
---@param anchor_decl_node TSNode #A valid anchor declaration node
391+
---@return LinkTarget? #The target of the link if it was found.
350392
locate_anchor_declaration_target = function(anchor_decl_node)
351393
if not anchor_decl_node:named_child(0) then
352394
return
@@ -355,7 +397,7 @@ module.public = {
355397
local target = module
356398
.required
357399
["core.integrations.treesitter"]
358-
.get_node_text(anchor_decl_node:named_child(0):named_child(0)) ---@diagnostic disable-line -- TODO: type error workaround <pysan3>
400+
.get_node_text(anchor_decl_node:named_child(0):named_child(0))
359401
:gsub("[%s\\]", "")
360402

361403
local query_str = [[
@@ -392,12 +434,13 @@ module.public = {
392434
end,
393435

394436
--- Converts a link node into a table of data related to the link
395-
---@param link_node userdata #The link node that was found by e.g. `extract_link_node()`
437+
---@param link_node TSNode #The link node that was found by e.g. `extract_link_node()`
396438
---@param buf number #The buffer to parse the link in
397-
---@return table? #A table of data about the link
439+
---@return Link? #A table of data about the link
398440
parse_link = function(link_node, buf)
399441
buf = buf or 0
400-
if not link_node or not vim.tbl_contains({ "link", "anchor_definition" }, link_node:type()) then ---@diagnostic disable-line -- TODO: type error workaround <pysan3>
442+
443+
if not link_node or not vim.tbl_contains({ "link", "anchor_definition" }, link_node:type()) then
401444
return
402445
end
403446

@@ -459,15 +502,18 @@ module.public = {
459502
]
460503
]]
461504

505+
---@type TSNode?
462506
local document_root = module.required["core.integrations.treesitter"].get_document_root(buf)
463507

464508
if not document_root then
465509
return
466510
end
467511

512+
---@type vim.treesitter.Query
468513
local query = utils.ts_parse_query("norg", query_text)
469514
local range = module.required["core.integrations.treesitter"].get_node_range(link_node)
470515

516+
---@type Link
471517
local parsed_link_information = {
472518
link_node = link_node,
473519
}
@@ -500,8 +546,8 @@ module.public = {
500546
end,
501547

502548
--- Locate the target that a link points to
503-
---@param parsed_link_information table #A table returned by `parse_link()`
504-
---@return table #A table containing data about the link target
549+
---@param parsed_link_information Link #A table returned by `parse_link()`
550+
---@return LinkTarget #A table containing data about the link target
505551
locate_link_target = function(parsed_link_information)
506552
--- A pointer to the target buffer we will be parsing.
507553
-- This may change depending on the target file the user gave.
@@ -537,7 +583,9 @@ module.public = {
537583
end,
538584

539585
external_file = function()
540-
local destination = parsed_link_information.link_location_text
586+
-- There has to be a link location present for a link to be recognized as an external file,
587+
-- therefore we can safely assert here.
588+
local destination = assert(parsed_link_information.link_location_text)
541589
local path, line = string.match(destination, "^(.*):(%d+)$")
542590
if line then
543591
destination = path
@@ -550,11 +598,11 @@ module.public = {
550598
return lib.match(vim.fn.fnamemodify(destination, ":e"))({
551599
[{ "jpg", "jpeg", "png", "pdf" }] = {
552600
type = "external_app",
553-
uri = vim.uri_from_fname(vim.fn.expand(destination)), ---@diagnostic disable-line -- TODO: type error workaround <pysan3>
601+
uri = vim.uri_from_fname(vim.fn.expand(destination)),
554602
},
555603
[module.config.public.external_filetypes] = {
556604
type = "external_app",
557-
uri = vim.uri_from_fname(vim.fn.expand(destination)), ---@diagnostic disable-line -- TODO: type error workaround <pysan3>
605+
uri = vim.uri_from_fname(vim.fn.expand(destination)),
558606
},
559607
_ = function()
560608
return {
@@ -629,7 +677,7 @@ module.public = {
629677
end
630678
end
631679
end,
632-
})
680+
} --[[@as table<string, fun(): LinkTarget?>]])
633681
end,
634682
}
635683

@@ -692,8 +740,8 @@ module.private = {
692740
end,
693741

694742
--- Fuzzy fixes a link with a loose type checking query
695-
---@param parsed_link_information table #A table as returned by `parse_link()`
696-
---@return table #A table of similarities (fuzzed items)
743+
---@param parsed_link_information Link #A table as returned by `parse_link()`
744+
---@return PotentialLinkFixes[]? #A table of similarities (fuzzed items)
697745
fix_link_loose = function(parsed_link_information)
698746
local generic_query = [[
699747
[(_
@@ -716,8 +764,8 @@ module.private = {
716764
end,
717765

718766
--- Fuzzy fixes a link with a strict type checking query
719-
---@param parsed_link_information table #A table as returned by `parse_link()`
720-
---@return table #A table of similarities (fuzzed items)
767+
---@param parsed_link_information Link #A table as returned by `parse_link()`
768+
---@return PotentialLinkFixes[]? #A table of similarities (fuzzed items)
721769
fix_link_strict = function(parsed_link_information)
722770
local query = lib.match(parsed_link_information.link_type)({
723771
generic = [[
@@ -790,7 +838,7 @@ module.private = {
790838
--- Query all similar targets that a link could be pointing to
791839
---@param parsed_link_information table #A table as returned by `parse_link()`
792840
---@param query_str string #The query to be used during the search
793-
---@return table #A table of similarities (fuzzed items)
841+
---@return PotentialLinkFixes[]? #A table of similarities (fuzzed items)
794842
fix_link = function(parsed_link_information, query_str)
795843
local buffer = vim.api.nvim_get_current_buf()
796844

@@ -808,12 +856,11 @@ module.private = {
808856
local document_root = module.required["core.integrations.treesitter"].get_document_root(buffer)
809857

810858
if not document_root then
811-
return ---@diagnostic disable-line -- TODO: type error workaround <pysan3>
859+
return
812860
end
813861

814-
local similarities = {
815-
-- Example: { 0.6, "title", node }
816-
}
862+
---@type PotentialLinkFixes[]
863+
local similarities = {}
817864

818865
for id, node in query:iter_captures(document_root, buffer) do
819866
local capture_name = query.captures[id]
@@ -841,9 +888,9 @@ module.private = {
841888
end,
842889

843890
--- Writes a link that was fixed through fuzzing into the buffer
844-
---@param link_node userdata #The treesitter node of the link, extracted by e.g. `extract_link_node()`
845-
---@param parsed_link_information table #A table as returned by `parse_link()`
846-
---@param similarities table #The table of similarities as returned by `fix_link_*()`
891+
---@param link_node TSNode #The treesitter node of the link, extracted by e.g. `extract_link_node()`
892+
---@param parsed_link_information Link #A table as returned by `parse_link()`
893+
---@param similarities PotentialLinkFixes[] #The table of similarities as returned by `fix_link_*()`
847894
---@param force_type boolean #If true will forcefully overwrite the link type to the target type as well (e.g. would convert `#` -> `*`)
848895
write_fixed_link = function(link_node, parsed_link_information, similarities, force_type)
849896
local most_similar = similarities[1]
@@ -882,19 +929,18 @@ module.private = {
882929
{ replace }
883930
)
884931
end
885-
886932
callback(
887933
"{"
888934
.. lib.when(
889-
parsed_link_information.link_file_text,
935+
parsed_link_information.link_file_text --[[@as boolean]],
890936
lib.lazy_string_concat(":", parsed_link_information.link_file_text, ":"),
891937
""
892938
)
893939
.. prefix
894940
.. most_similar.text
895941
.. "}"
896942
.. lib.when(
897-
parsed_link_information.link_description,
943+
parsed_link_information.link_description --[[@as boolean]],
898944
lib.lazy_string_concat("[", parsed_link_information.link_description, "]"),
899945
""
900946
)
@@ -906,17 +952,16 @@ module.on_event = function(event)
906952
if event.split_type[2] == "core.esupports.hop.hop-link" then
907953
local split_mode = event.content[1]
908954

909-
-- Get link node at cursor
910955
local link_node_at_cursor = module.public.extract_link_node()
911956

912957
if not link_node_at_cursor then
913958
log.trace("No link under cursor.")
914959
return
915960
end
916961

917-
local parsed_link = module.public.parse_link(link_node_at_cursor) ---@diagnostic disable-line -- TODO: type error workaround <pysan3>
962+
local parsed_link = module.public.parse_link(link_node_at_cursor)
918963

919-
module.public.follow_link(link_node_at_cursor, split_mode, parsed_link) ---@diagnostic disable-line -- TODO: type error workaround <pysan3>
964+
module.public.follow_link(link_node_at_cursor, split_mode, parsed_link)
920965
end
921966
end
922967

0 commit comments

Comments
 (0)