Skip to content

Commit 83637f1

Browse files
authored
fix(toc): various fixes (#1500)
1 parent 99b3249 commit 83637f1

File tree

3 files changed

+82
-49
lines changed

3 files changed

+82
-49
lines changed

lua/neorg/modules/core/looking-glass/module.lua

+2-1
Original file line numberDiff line numberDiff line change
@@ -225,10 +225,11 @@ module.on_event = function(event)
225225
-- TODO: Make the vsplit location configurable (i.e. whether it spawns on the left or the right)
226226
local vsplit = module.required["core.ui"].create_vsplit(
227227
"code-block-" .. tostring(code_block_info.start.row) .. tostring(code_block_info["end"].row), -- This is done to make the name of the vsplit unique
228+
true,
228229
{
229230
filetype = (code_block_info.parameters[1] or "none"),
230231
},
231-
true
232+
{ split = "left" }
232233
)
233234

234235
if not vsplit then

lua/neorg/modules/core/qol/toc/module.lua

+60-23
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ module.setup = function()
2727
}
2828
end
2929

30+
---Track if the next TOC open was automatic. Used to determine if we should enter the TOC or not.
31+
local next_open_is_auto = false
3032
module.load = function()
3133
modules.await("core.neorgcmd", function(neorgcmd)
3234
neorgcmd.add_commands_from_table({
@@ -42,14 +44,13 @@ module.load = function()
4244
end)
4345

4446
if module.config.public.auto_toc.open then
45-
vim.api.nvim_create_autocmd("BufEnter", {
47+
vim.api.nvim_create_autocmd("BufWinEnter", {
4648
pattern = "*.norg",
4749
callback = function()
48-
local win = vim.api.nvim_get_current_win()
49-
vim.cmd([[Neorg toc]])
50-
if not module.config.public.auto_toc.enter then
51-
vim.api.nvim_set_current_win(win)
52-
end
50+
vim.schedule(function()
51+
next_open_is_auto = true
52+
vim.cmd([[Neorg toc]])
53+
end)
5354
end,
5455
})
5556
end
@@ -63,12 +64,19 @@ module.config.public = {
6364
-- `max_width`
6465
fit_width = true,
6566

67+
-- max width of the ToC window when `fit_width = true` (in columns)
68+
max_width = 30,
69+
70+
-- when set, the ToC window will always be this many cols wide.
71+
-- will override `fit_width` and ignore `max_width`
72+
fixed_width = nil,
73+
6674
-- enable `cursorline` in the ToC window, and sync the cursor position between ToC and content
6775
-- window
6876
sync_cursorline = true,
6977

70-
-- max width of the ToC window when `fit_width = true` (in columns)
71-
max_width = 30,
78+
-- Enter a ToC window opened manually (any ToC window not opened by auto_toc)
79+
enter = true,
7280

7381
-- options for automatically opening/entering the ToC window
7482
auto_toc = {
@@ -303,9 +311,9 @@ module.public = {
303311
)
304312

305313
for _, line in
306-
ipairs(
307-
vim.api.nvim_buf_get_text(norg_buffer, row_start_0b, col_start_0b, row_end_0bin, col_end_0bex, {})
308-
)
314+
ipairs(
315+
vim.api.nvim_buf_get_text(norg_buffer, row_start_0b, col_start_0b, row_end_0bin, col_end_0bex, {})
316+
)
309317
do
310318
table.insert(heading_texts, line)
311319
end
@@ -355,19 +363,24 @@ module.public = {
355363
}
356364

357365
module.private = {
358-
---set the width of the ToC window
366+
---get the width of the ToC window
367+
---@param ui_data table
368+
---@return number
359369
get_toc_width = function(ui_data)
360-
local max_virtcol_1bex = module.private.get_max_virtcol()
361-
local current_winwidth = vim.fn.winwidth(vim.fn.bufwinid(ui_data.buffer))
362-
local new_winwidth = math.min(current_winwidth, math.max(module.config.public.max_width, max_virtcol_1bex - 1))
370+
if type(module.config.public.fixed_width) == "number" then
371+
return module.config.public.fixed_width
372+
end
373+
local max_virtcol_1bex = module.private.get_max_virtcol(ui_data.window)
374+
local current_winwidth = vim.api.nvim_win_get_width(ui_data.window)
375+
local new_winwidth = math.min(current_winwidth, module.config.public.max_width, max_virtcol_1bex - 1)
363376
return new_winwidth + 1
364377
end,
365378

366-
get_max_virtcol = function()
367-
local n_line = vim.fn.line("$")
379+
get_max_virtcol = function(win)
380+
local n_line = vim.fn.line("$", win)
368381
local result = 1
369382
for i = 1, n_line do
370-
result = math.max(result, vim.fn.virtcol({ i, "$" }))
383+
result = math.max(result, vim.fn.virtcol({ i, "$" }, 0, win))
371384
end
372385
return result
373386
end,
@@ -397,12 +410,22 @@ local function unlisten_if_closed(listener)
397410
end
398411
end
399412

400-
local function create_ui(tabpage, mode)
413+
---Create a split window and buffer for the table of contents. Set buffer and window options
414+
---accordingly
415+
---@param tabpage number
416+
---@param split_dir "left" | "right"
417+
---@param enter boolean
418+
---@return table
419+
local function create_ui(tabpage, split_dir, enter)
401420
assert(tabpage == vim.api.nvim_get_current_tabpage())
402421

403422
toc_namespace = toc_namespace or vim.api.nvim_create_namespace("neorg/toc")
404-
local ui_buffer, ui_window =
405-
module.required["core.ui"].create_vsplit(("toc-%d"):format(tabpage), { ft = "norg" }, mode)
423+
local ui_buffer, ui_window = module.required["core.ui"].create_vsplit(
424+
("toc-%d"):format(tabpage),
425+
enter,
426+
{ ft = "norg" },
427+
{ split = split_dir, win = 0, style = "minimal" }
428+
)
406429

407430
local ui_wo = vim.wo[ui_window]
408431
ui_wo.scrolloff = 999
@@ -427,6 +450,15 @@ local function create_ui(tabpage, mode)
427450
return ui_data
428451
end
429452

453+
--- should we enter the ToC window?
454+
local function enter_toc_win()
455+
local do_enter = module.config.public.enter
456+
if next_open_is_auto then
457+
do_enter = module.config.public.auto_toc.enter
458+
end
459+
return do_enter
460+
end
461+
430462
module.on_event = function(event)
431463
if event.split_type[2] ~= module.name then
432464
return
@@ -456,15 +488,20 @@ module.on_event = function(event)
456488
return
457489
end
458490
module.public.update_toc(toc_title, ui_data_of_tabpage[tabpage], norg_buffer)
491+
492+
if enter_toc_win() then
493+
vim.api.nvim_set_current_win(ui_data_of_tabpage[tabpage].window)
494+
end
459495
return
460496
end
461497

462-
local ui_data = create_ui(tabpage, (event.content[1] or "left") == "left")
498+
local ui_data = create_ui(tabpage, event.content[1] or "left", enter_toc_win())
499+
next_open_is_auto = false
463500

464501
module.public.update_toc(toc_title, ui_data_of_tabpage[tabpage], norg_buffer)
465502

466503
if module.config.public.fit_width then
467-
vim.cmd(("vertical resize %d"):format(module.private.get_toc_width(ui_data)))
504+
vim.api.nvim_win_set_width(ui_data.window, module.private.get_toc_width(ui_data))
468505
end
469506

470507
local close_buffer_callback = function()

lua/neorg/modules/core/ui/module.lua

+20-25
Original file line numberDiff line numberDiff line change
@@ -151,24 +151,18 @@ module.public = {
151151

152152
--- Creates a new vertical split
153153
---@param name string the name of the buffer
154-
---@param config table a table of <option> = <value> keypairs signifying buffer-local options for the buffer contained within the split
155-
---@param left boolean if true will spawn the vertical split on the left (default is right)
156-
---@return number?, number? #The buffer of the vertical split
157-
create_vsplit = function(name, config, left)
154+
---@param enter boolean enter the window or not
155+
---@param buf_config table a table of <option> = <value> keypairs signifying buffer-local options for the buffer contained within the split
156+
---@param win_config table table of <option>=<value> keypairs for `nvim_open_win`, must provide `win`
157+
---@return number?, number? #The buffer and window numbers of the vertical split
158+
create_vsplit = function(name, enter, buf_config, win_config)
158159
vim.validate({
159160
name = { name, "string" },
160-
config = { config, "table" },
161-
left = { left, "boolean", true },
161+
enter = { enter, "boolean", true },
162+
config = { buf_config, "table" },
163+
win_config = { win_config, "table" },
162164
})
163165

164-
left = left or false
165-
166-
vim.cmd("vsplit")
167-
168-
if left then
169-
vim.cmd("wincmd H")
170-
end
171-
172166
local buf = vim.api.nvim_create_buf(false, true)
173167

174168
local default_options = {
@@ -180,17 +174,18 @@ module.public = {
180174
}
181175

182176
vim.api.nvim_buf_set_name(buf, "neorg://" .. name)
183-
vim.api.nvim_win_set_buf(0, buf)
184177

185-
vim.api.nvim_set_option_value("number", false, { win = 0 })
186-
vim.api.nvim_set_option_value("relativenumber", false, { win = 0 })
178+
local win_options = {
179+
vertical = true,
180+
}
181+
win_options = vim.tbl_deep_extend("keep", win_options, win_config)
182+
local window = vim.api.nvim_open_win(buf, enter, win_options)
187183

188-
vim.api.nvim_win_set_buf(0, buf)
184+
vim.api.nvim_set_option_value("number", false, { win = window })
185+
vim.api.nvim_set_option_value("relativenumber", false, { win = window })
189186

190187
-- Merge the user provided options with the default options and apply them to the new buffer
191-
module.public.apply_buffer_options(buf, vim.tbl_extend("keep", config or {}, default_options))
192-
193-
local window = vim.api.nvim_get_current_win()
188+
module.public.apply_buffer_options(buf, vim.tbl_extend("keep", buf_config or {}, default_options))
194189

195190
-- Make sure to clean up the window if the user leaves the popup at any time
196191
vim.api.nvim_create_autocmd({ "BufDelete", "WinClosed" }, {
@@ -225,9 +220,9 @@ module.public = {
225220
name = "display/" .. name
226221

227222
if split_type == "vsplitl" then
228-
return module.public.create_vsplit(name, {}, true)
223+
return module.public.create_vsplit(name, true, {}, { split = "left" })
229224
elseif split_type == "vsplitr" then
230-
return module.public.create_vsplit(name, {}, false)
225+
return module.public.create_vsplit(name, true, {}, { split = "right" })
231226
elseif split_type == "split" then
232227
return module.public.create_split(name, {})
233228
else
@@ -329,9 +324,9 @@ module.public = {
329324
name = "norg/" .. name .. ".norg"
330325

331326
if split_type == "vsplitl" then
332-
return module.public.create_vsplit(name, {}, true)
327+
return module.public.create_vsplit(name, true, {}, { split = "left" })
333328
elseif split_type == "vsplitr" then
334-
return module.public.create_vsplit(name, {}, false)
329+
return module.public.create_vsplit(name, true, {}, { split = "right" })
335330
elseif split_type == "split" then
336331
return module.public.create_split(name, {})
337332
else

0 commit comments

Comments
 (0)