@@ -46,31 +46,113 @@ local function calc_ref_item(note, insert_text, insert_start, insert_end, line_n
46
46
}
47
47
end
48
48
49
+ local state = {
50
+ --- @type obsidian.Note
51
+ current_note = nil ,
52
+ }
53
+
54
+ --- Collect matching anchor links.
55
+ --- @param note obsidian.Note
56
+ --- @param anchor_link string ?
57
+ --- @return obsidian.note.HeaderAnchor[] ?
58
+ local function collect_matching_anchors (note , anchor_link )
59
+ --- @type obsidian.note.HeaderAnchor[] |?
60
+ local matching_anchors
61
+ if anchor_link then
62
+ assert (note .anchor_links )
63
+ matching_anchors = {}
64
+ for anchor , anchor_data in pairs (note .anchor_links ) do
65
+ if vim .startswith (anchor , anchor_link ) then
66
+ table.insert (matching_anchors , anchor_data )
67
+ end
68
+ end
69
+
70
+ if # matching_anchors == 0 then
71
+ -- Unmatched, create a mock one.
72
+ table.insert (matching_anchors , { anchor = anchor_link , header = string.sub (anchor_link , 2 ), level = 1 , line = 1 })
73
+ end
74
+ end
75
+
76
+ return matching_anchors
77
+ end
78
+
79
+ --- @client obsidian.Client
49
80
local function handle_ref (client , partial , ref_start , cursor_col , line_num , handler )
50
81
--- @type string |?
51
82
-- local block_link
52
83
-- cc.search, block_link = util.strip_block_links(cc.search)
53
84
--
54
- -- ---@type string|?
55
- -- local anchor_link
56
- -- cc.search, anchor_link = util.strip_anchor_links(cc.search)
85
+ --- @type string |?
86
+ local anchor_link
87
+ partial , anchor_link = util .strip_anchor_links (partial )
88
+ print (partial )
57
89
58
90
local items = {}
59
- client :find_notes_async (
60
- partial ,
61
- vim .schedule_wrap (function (notes )
62
- for _ , note in ipairs (notes ) do
63
- local title = note .title
64
- local pattern = vim .pesc (lower (partial ))
65
- if title and find (lower (title ), pattern ) then
66
- local link_text = client :format_link (note )
67
- local style = client .opts .preferred_link_style
68
- items [# items + 1 ] = calc_ref_item (note , link_text , ref_start , cursor_col , line_num , style )
91
+ if not anchor_link then
92
+ client :find_notes_async (
93
+ partial ,
94
+ vim .schedule_wrap (function (notes )
95
+ for _ , note in ipairs (notes ) do
96
+ local title = note .title
97
+ local pattern = vim .pesc (lower (partial ))
98
+ if title and find (lower (title ), pattern ) then
99
+ local link_text = client :format_link (note )
100
+ local style = client .opts .preferred_link_style
101
+ items [# items + 1 ] = calc_ref_item (note , link_text , ref_start , cursor_col , line_num , style )
102
+ end
103
+ handler (nil , { items = items })
69
104
end
70
- end
71
- handler (nil , { items = items })
72
- end )
73
- )
105
+ end )
106
+ )
107
+ else
108
+ local Note = require " obsidian.note"
109
+ -- state.current_note = state.current_note or client:find_notes(partial)[2]
110
+ -- TODO: calc current_note once
111
+ -- TODO: handle two cases:
112
+ -- 1. typing partial note name, no completeed text after cursor, insert the full link
113
+ -- 2. jumped to heading, only insert anchor
114
+ -- TODO: need to do more textEdit to insert additional #title to path so that app supports?
115
+ client :find_notes_async (
116
+ partial ,
117
+ vim .schedule_wrap (function (notes )
118
+ for _ , note in ipairs (notes ) do
119
+ local title = note .title
120
+ local pattern = vim .pesc (lower (partial ))
121
+ if title and find (lower (title ), pattern ) then
122
+ local note2 = Note .from_file (note .path .filename , { collect_anchor_links = true })
123
+
124
+ local note_anchors = collect_matching_anchors (note2 , anchor_link )
125
+ if not note_anchors then
126
+ return
127
+ end
128
+ for _ , anchor in ipairs (note_anchors ) do
129
+ items [# items + 1 ] = {
130
+ kind = 17 ,
131
+ label = anchor .header ,
132
+ filterText = anchor .header ,
133
+ insertText = anchor .header ,
134
+ -- insertTextFormat = 2, -- is snippet
135
+ -- textEdit = {
136
+ -- range = {
137
+ -- start = { line = line_num, character = insert_start },
138
+ -- ["end"] = { line = line_num, character = insert_end },
139
+ -- },
140
+ -- newText = insert_snippet_marker(insert_text, style),
141
+ -- },
142
+ labelDetails = { description = " ObsidianAnchor" },
143
+ data = {
144
+ file = note .path .filename ,
145
+ kind = " anchor" ,
146
+ },
147
+ }
148
+ end
149
+ end
150
+ handler (nil , { items = items })
151
+ end
152
+ end )
153
+ )
154
+ vim .print (state .current_note )
155
+ end
74
156
end
75
157
76
158
local function calc_tag_item (tag )
@@ -99,6 +181,18 @@ local function handle_tag(client, partial, handler)
99
181
)
100
182
end
101
183
184
+ local function handle_heading (client )
185
+ -- TODO: client:find_headings_async
186
+ -- client:find_
187
+ end
188
+
189
+ -- util.BLOCK_PATTERN = "%^[%w%d][%w%d-]*"
190
+ local anchor_trigger_pattern = {
191
+ markdown = " %[%S+#(%w*)" ,
192
+ }
193
+
194
+ local heading_trigger_pattern = " [##"
195
+
102
196
--- @param client obsidian.Client
103
197
--- @param params table
104
198
--- @param handler function
@@ -118,10 +212,16 @@ return function(client, params, handler, _)
118
212
--
119
213
local text_before_cursor = sub (line_text , 1 , char_num )
120
214
121
- local tag_start = find (text_before_cursor , " #" , 1 , true )
122
215
local ref_start = find (text_before_cursor , ref_trigger_pattern [link_style ], 1 , true )
216
+ local tag_start = find (text_before_cursor , " #" , 1 , true )
217
+ local heading_start = find (text_before_cursor , heading_trigger_pattern , 1 , true )
123
218
124
- if ref_start then
219
+ if heading_start then
220
+ local partial = sub (text_before_cursor , heading_start + # heading_trigger_pattern )
221
+ -- if #partial >= min_chars then
222
+ -- handle_heading(client, partial, ref_start - 1, char_num, line_num, handler)
223
+ -- end
224
+ elseif ref_start then
125
225
local partial = sub (text_before_cursor , ref_start + # ref_trigger_pattern [link_style ])
126
226
if # partial >= min_chars then
127
227
handle_ref (client , partial , ref_start - 1 , char_num , line_num , handler )
@@ -131,5 +231,6 @@ return function(client, params, handler, _)
131
231
if # partial >= min_chars then
132
232
handle_tag (client , partial , handler )
133
233
end
234
+ else
134
235
end
135
236
end
0 commit comments