Skip to content

Commit aea1f72

Browse files
committed
ref: expose default summary methods
1 parent 4da2159 commit aea1f72

File tree

1 file changed

+116
-111
lines changed

1 file changed

+116
-111
lines changed

lua/neorg/modules/core/summary/module.lua

Lines changed: 116 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ local neorg = require("neorg.core")
2525
local lib, modules, utils = neorg.lib, neorg.modules, neorg.utils
2626

2727
local module = modules.create("core.summary")
28+
local ts
2829

2930
module.setup = function()
3031
return {
@@ -43,94 +44,34 @@ module.load = function()
4344
},
4445
})
4546
end)
46-
local ts = module.required["core.integrations.treesitter"]
4747

48-
-- declare query on load so that it's parsed once, on first use
49-
local heading_query
48+
ts = module.required["core.integrations.treesitter"]
5049

51-
local get_first_heading_title = function(bufnr)
52-
local document_root = ts.get_document_root(bufnr)
53-
if not heading_query then
54-
-- allow second level headings, just in case
55-
local heading_query_string = [[
56-
[
57-
(heading1
58-
title: (paragraph_segment) @next-segment
59-
)
60-
(heading2
61-
title: (paragraph_segment) @next-segment
62-
)
63-
]
64-
]]
65-
heading_query = utils.ts_parse_query("norg", heading_query_string)
66-
end
67-
-- search up to 20 lines (a doc could potentially have metadata without metadata.title)
68-
local _, heading = heading_query:iter_captures(document_root, bufnr)()
69-
if not heading then
70-
return nil
71-
end
72-
local start_line, _ = heading:start()
73-
local lines = vim.api.nvim_buf_get_lines(bufnr, start_line, start_line + 1, false)
74-
if #lines > 0 then
75-
local title = lines[1]:gsub("^%s*%*+%s*", "") -- strip out '*' prefix (handle '* title', ' **title', etc)
76-
if title ~= "" then -- exclude an empty heading like `*` (although the query should have excluded)
77-
return title
78-
end
79-
end
80-
end
50+
module.config.public.strategy = lib.match(module.config.public.strategy)(module.public.strategies) or
51+
module.config.public.strategy
52+
end
8153

82-
-- Return true if catagories_path is or is a subcategory of an entry in included_categories
83-
local is_included_category = function(included_categories, category_path)
84-
local found_match = false
85-
for _, included in ipairs(included_categories) do
86-
local included_path = vim.split(included, ".", { plain = true })
87-
for i, path in ipairs(included_path) do
88-
if path == category_path[i] and i == #included_path then
89-
found_match = true
90-
break
91-
elseif path ~= category_path[i] then
92-
break
93-
end
94-
end
95-
end
96-
return found_match
97-
end
54+
module.private = {
55+
heading_query = nil
56+
}
57+
58+
module.config.public = {
59+
-- The strategy to use to generate a summary.
60+
--
61+
-- Possible options are:
62+
-- - "default" - read the metadata to categorize and annotate files. Files
63+
-- without metadata will use the top level heading as the title. If no headings are present, the filename will be used.
64+
-- - "by_path" - Similar to "default" but uses the capitalized name of the folder containing a *.norg file as category.
65+
-- - A custom function with the signature:
66+
-- `fun(files: PathlibPath[], ws_root: PathlibPath, heading_level: number?, include_categories: string[]?): string[]?`.
67+
-- Returning a list of lines that make up the summary
68+
strategy = "default",
69+
}
9870

99-
-- Insert a categorized record for the given file into the categories table
100-
local insert_categorized = function(categories, category_path, norgname, metadata)
101-
local leaf_categories = categories
102-
for i, path in ipairs(category_path) do
103-
local titled_path = lib.title(path)
104-
if i == #category_path then
105-
-- There are no more sub catergories so insert the record
106-
table.insert(leaf_categories[titled_path], {
107-
title = tostring(metadata.title),
108-
norgname = norgname,
109-
description = metadata.description,
110-
})
111-
break
112-
end
113-
local sub_categories = vim.defaulttable()
114-
if leaf_categories[titled_path] then
115-
-- This category already been added so find it's sub_categories table
116-
for _, item in ipairs(leaf_categories[titled_path]) do
117-
if item.sub_categories then
118-
leaf_categories = item.sub_categories
119-
goto continue
120-
end
121-
end
122-
end
123-
-- This is a new sub category
124-
table.insert(leaf_categories[titled_path], {
125-
title = titled_path,
126-
sub_categories = sub_categories,
127-
})
128-
leaf_categories = sub_categories
129-
::continue::
130-
end
131-
end
13271

133-
module.config.public.strategy = lib.match(module.config.public.strategy)({
72+
---@class core.summary
73+
module.public = {
74+
strategies = {
13475
default = function()
13576
return function(files, ws_root, heading_level, include_categories)
13677
local categories = vim.defaulttable()
@@ -160,7 +101,7 @@ module.load = function()
160101
end
161102

162103
if not metadata.title then
163-
metadata.title = get_first_heading_title(bufnr)
104+
metadata.title = module.public.get_first_heading_title(bufnr)
164105
if not metadata.title then
165106
metadata.title = vim.fs.basename(norgname)
166107
end
@@ -174,11 +115,11 @@ module.load = function()
174115
local category_path = vim.split(category, ".", { plain = true })
175116

176117
if include_categories then
177-
if is_included_category(include_categories, category_path) then
178-
insert_categorized(categories, category_path, norgname, metadata)
118+
if module.public.is_included_category(include_categories, category_path) then
119+
module.public.insert_categorized(categories, category_path, norgname, metadata)
179120
end
180121
else
181-
insert_categorized(categories, category_path, norgname, metadata)
122+
module.public.insert_categorized(categories, category_path, norgname, metadata)
182123
end
183124
end
184125
end)
@@ -207,9 +148,9 @@ module.load = function()
207148
lib.title(datapoint.title),
208149
"]",
209150
})
210-
.. (
211-
datapoint.description and (table.concat({ " - ", datapoint.description })) or ""
212-
)
151+
.. (
152+
datapoint.description and (table.concat({ " - ", datapoint.description })) or ""
153+
)
213154
)
214155
end
215156
end
@@ -250,7 +191,7 @@ module.load = function()
250191
norgname = string.sub(norgname, ws_root:len() + 1)
251192

252193
if not metadata.title then
253-
metadata.title = get_first_heading_title(bufnr) or vim.fs.basename(norgname)
194+
metadata.title = module.public.get_first_heading_title(bufnr) or vim.fs.basename(norgname)
254195
end
255196

256197
if metadata.description == vim.NIL then
@@ -282,39 +223,103 @@ module.load = function()
282223
lib.title(datapoint.title),
283224
"]",
284225
})
285-
.. (datapoint.description and (table.concat({ " - ", datapoint.description })) or "")
226+
.. (datapoint.description and (table.concat({ " - ", datapoint.description })) or "")
286227
)
287228
end
288229
end
289230

290231
return result
291232
end
292233
end,
293-
}) or module.config.public.strategy
294-
end
234+
},
295235

296-
module.config.public = {
297-
-- The strategy to use to generate a summary.
298-
--
299-
-- Possible options are:
300-
-- - "default" - read the metadata to categorize and annotate files. Files
301-
-- without metadata will use the top level heading as the title. If no headings are present, the filename will be used.
302-
-- - "by_path" - Similar to "default" but uses the capitalized name of the folder containing a *.norg file as category.
303-
-- - A custom function with the signature:
304-
-- `fun(files: PathlibPath[], ws_root: PathlibPath, heading_level: number?, include_categories: string[]?): string[]?`.
305-
-- Returning a list of lines that make up the summary
306-
strategy = "default",
307-
}
236+
get_first_heading_title = function(bufnr)
237+
local document_root = ts.get_document_root(bufnr)
238+
if not module.private.heading_query then
239+
-- allow second level headings, just in case
240+
local heading_query_string = [[
241+
[
242+
(heading1
243+
title: (paragraph_segment) @next-segment
244+
)
245+
(heading2
246+
title: (paragraph_segment) @next-segment
247+
)
248+
]
249+
]]
250+
module.private.heading_query = utils.ts_parse_query("norg", heading_query_string) --[[@as vim.treesitter.Query]]
251+
end
252+
-- search up to 20 lines (a doc could potentially have metadata without metadata.title)
253+
local _, heading = module.private.heading_query:iter_captures(document_root, bufnr)()
254+
if not heading then
255+
return nil
256+
end
257+
local start_line, _ = heading:start()
258+
local lines = vim.api.nvim_buf_get_lines(bufnr, start_line, start_line + 1, false)
259+
if #lines > 0 then
260+
local title = lines[1]:gsub("^%s*%*+%s*", "") -- strip out '*' prefix (handle '* title', ' **title', etc)
261+
if title ~= "" then -- exclude an empty heading like `*` (although the query should have excluded)
262+
return title
263+
end
264+
end
265+
end,
266+
267+
-- Return true if catagories_path is or is a subcategory of an entry in included_categories
268+
is_included_category = function(included_categories, category_path)
269+
local found_match = false
270+
for _, included in ipairs(included_categories) do
271+
local included_path = vim.split(included, ".", { plain = true })
272+
for i, path in ipairs(included_path) do
273+
if path == category_path[i] and i == #included_path then
274+
found_match = true
275+
break
276+
elseif path ~= category_path[i] then
277+
break
278+
end
279+
end
280+
end
281+
return found_match
282+
end,
283+
284+
-- Insert a categorized record for the given file into the categories table
285+
insert_categorized = function(categories, category_path, norgname, metadata)
286+
local leaf_categories = categories
287+
for i, path in ipairs(category_path) do
288+
local titled_path = lib.title(path)
289+
if i == #category_path then
290+
-- There are no more sub categories so insert the record
291+
table.insert(leaf_categories[titled_path], {
292+
title = tostring(metadata.title),
293+
norgname = norgname,
294+
description = metadata.description,
295+
})
296+
break
297+
end
298+
local sub_categories = vim.defaulttable()
299+
if leaf_categories[titled_path] then
300+
-- This category already been added so find it's sub_categories table
301+
for _, item in ipairs(leaf_categories[titled_path]) do
302+
if item.sub_categories then
303+
leaf_categories = item.sub_categories
304+
goto continue
305+
end
306+
end
307+
end
308+
-- This is a new sub category
309+
table.insert(leaf_categories[titled_path], {
310+
title = titled_path,
311+
sub_categories = sub_categories,
312+
})
313+
leaf_categories = sub_categories
314+
::continue::
315+
end
316+
end,
308317

309-
---@class core.summary
310-
module.public = {
311318
---@param buf integer? the buffer to insert the summary to
312319
---@param cursor_pos integer[]? a tuple of row, col of the cursor positon (see nvim_win_get_cursor())
313320
---@param include_categories string[]? table of strings (ignores case) for categories that you wish to include in the summary.
314-
-- if excluded then all categories are written into the summary.
321+
---if excluded then all categories are written into the summary.
315322
generate_workspace_summary = function(buf, cursor_pos, include_categories)
316-
local ts = module.required["core.integrations.treesitter"]
317-
318323
local buffer = buf or 0
319324
local cursor_position = cursor_pos or vim.api.nvim_win_get_cursor(0)
320325

0 commit comments

Comments
 (0)