refactor(hooks): replace flat hooks API with setup/on namespaces
Problem: the hooks API conflated distinct lifecycle scopes under a flat
table with inconsistent naming (setup_code, before_run, setup_io_input),
making it hard to reason about when each hook fires.
Solution: introduce two namespaces — hooks.setup.{contest,code,io} for
one-time initialization and hooks.on.{enter,run,debug} for recurring
events. hooks.setup.contest fires once when a contest dir is newly
created; hooks.on.enter is registered as a buffer-scoped BufEnter
autocmd and fires immediately after setup.code. The provisional buffer
setup_code callsite is removed as it ran on an unresolved temp buffer.
This commit is contained in:
parent
6a395af98f
commit
add022af8c
3 changed files with 95 additions and 46 deletions
|
|
@ -33,12 +33,23 @@
|
||||||
---@class DiffConfig
|
---@class DiffConfig
|
||||||
---@field git DiffGitConfig
|
---@field git DiffGitConfig
|
||||||
|
|
||||||
|
---@class CpSetupIOHooks
|
||||||
|
---@field input? fun(bufnr: integer, state: cp.State)
|
||||||
|
---@field output? fun(bufnr: integer, state: cp.State)
|
||||||
|
|
||||||
|
---@class CpSetupHooks
|
||||||
|
---@field contest? fun(state: cp.State)
|
||||||
|
---@field code? fun(state: cp.State)
|
||||||
|
---@field io? CpSetupIOHooks
|
||||||
|
|
||||||
|
---@class CpOnHooks
|
||||||
|
---@field enter? fun(state: cp.State)
|
||||||
|
---@field run? fun(state: cp.State)
|
||||||
|
---@field debug? fun(state: cp.State)
|
||||||
|
|
||||||
---@class Hooks
|
---@class Hooks
|
||||||
---@field before_run? fun(state: cp.State)
|
---@field setup? CpSetupHooks
|
||||||
---@field before_debug? fun(state: cp.State)
|
---@field on? CpOnHooks
|
||||||
---@field setup_code? fun(state: cp.State)
|
|
||||||
---@field setup_io_input? fun(bufnr: integer, state: cp.State)
|
|
||||||
---@field setup_io_output? fun(bufnr: integer, state: cp.State)
|
|
||||||
|
|
||||||
---@class VerdictFormatData
|
---@class VerdictFormatData
|
||||||
---@field index integer
|
---@field index integer
|
||||||
|
|
@ -156,11 +167,19 @@ M.defaults = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
hooks = {
|
hooks = {
|
||||||
before_run = nil,
|
setup = {
|
||||||
before_debug = nil,
|
contest = nil,
|
||||||
setup_code = nil,
|
code = nil,
|
||||||
setup_io_input = helpers.clearcol,
|
io = {
|
||||||
setup_io_output = helpers.clearcol,
|
input = helpers.clearcol,
|
||||||
|
output = helpers.clearcol,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
on = {
|
||||||
|
enter = nil,
|
||||||
|
run = nil,
|
||||||
|
debug = nil,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
debug = false,
|
debug = false,
|
||||||
scrapers = constants.PLATFORMS,
|
scrapers = constants.PLATFORMS,
|
||||||
|
|
@ -352,12 +371,29 @@ function M.setup(user_config)
|
||||||
end,
|
end,
|
||||||
('one of {%s}'):format(table.concat(constants.PLATFORMS, ',')),
|
('one of {%s}'):format(table.concat(constants.PLATFORMS, ',')),
|
||||||
},
|
},
|
||||||
before_run = { cfg.hooks.before_run, { 'function', 'nil' }, true },
|
|
||||||
before_debug = { cfg.hooks.before_debug, { 'function', 'nil' }, true },
|
|
||||||
setup_code = { cfg.hooks.setup_code, { 'function', 'nil' }, true },
|
|
||||||
setup_io_input = { cfg.hooks.setup_io_input, { 'function', 'nil' }, true },
|
|
||||||
setup_io_output = { cfg.hooks.setup_io_output, { 'function', 'nil' }, true },
|
|
||||||
})
|
})
|
||||||
|
if cfg.hooks.setup ~= nil then
|
||||||
|
vim.validate({ setup = { cfg.hooks.setup, 'table' } })
|
||||||
|
vim.validate({
|
||||||
|
contest = { cfg.hooks.setup.contest, { 'function', 'nil' }, true },
|
||||||
|
code = { cfg.hooks.setup.code, { 'function', 'nil' }, true },
|
||||||
|
})
|
||||||
|
if cfg.hooks.setup.io ~= nil then
|
||||||
|
vim.validate({ io = { cfg.hooks.setup.io, 'table' } })
|
||||||
|
vim.validate({
|
||||||
|
input = { cfg.hooks.setup.io.input, { 'function', 'nil' }, true },
|
||||||
|
output = { cfg.hooks.setup.io.output, { 'function', 'nil' }, true },
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if cfg.hooks.on ~= nil then
|
||||||
|
vim.validate({ on = { cfg.hooks.on, 'table' } })
|
||||||
|
vim.validate({
|
||||||
|
enter = { cfg.hooks.on.enter, { 'function', 'nil' }, true },
|
||||||
|
run = { cfg.hooks.on.run, { 'function', 'nil' }, true },
|
||||||
|
debug = { cfg.hooks.on.debug, { 'function', 'nil' }, true },
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
local layouts = require('cp.ui.layouts')
|
local layouts = require('cp.ui.layouts')
|
||||||
vim.validate({
|
vim.validate({
|
||||||
|
|
|
||||||
|
|
@ -196,13 +196,6 @@ function M.setup_contest(platform, contest_id, problem_id, language)
|
||||||
|
|
||||||
state.set_language(lang)
|
state.set_language(lang)
|
||||||
|
|
||||||
if cfg.hooks and cfg.hooks.setup_code and not vim.b[bufnr].cp_setup_done then
|
|
||||||
local ok = pcall(cfg.hooks.setup_code, state)
|
|
||||||
if ok then
|
|
||||||
vim.b[bufnr].cp_setup_done = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
state.set_provisional({
|
state.set_provisional({
|
||||||
bufnr = bufnr,
|
bufnr = bufnr,
|
||||||
platform = platform,
|
platform = platform,
|
||||||
|
|
@ -281,7 +274,15 @@ function M.setup_problem(problem_id, language)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
vim.fn.mkdir(vim.fn.fnamemodify(source_file, ':h'), 'p')
|
local contest_dir = vim.fn.fnamemodify(source_file, ':h')
|
||||||
|
local is_new_dir = vim.fn.isdirectory(contest_dir) == 0
|
||||||
|
vim.fn.mkdir(contest_dir, 'p')
|
||||||
|
if is_new_dir then
|
||||||
|
local s = config.hooks and config.hooks.setup
|
||||||
|
if s and s.contest then
|
||||||
|
pcall(s.contest, state)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local prov = state.get_provisional()
|
local prov = state.get_provisional()
|
||||||
if prov and prov.platform == platform and prov.contest_id == (state.get_contest_id() or '') then
|
if prov and prov.platform == platform and prov.contest_id == (state.get_contest_id() or '') then
|
||||||
|
|
@ -302,15 +303,23 @@ function M.setup_problem(problem_id, language)
|
||||||
state.set_solution_win(vim.api.nvim_get_current_win())
|
state.set_solution_win(vim.api.nvim_get_current_win())
|
||||||
if not vim.b[prov.bufnr].cp_setup_done then
|
if not vim.b[prov.bufnr].cp_setup_done then
|
||||||
apply_template(prov.bufnr, lang, platform)
|
apply_template(prov.bufnr, lang, platform)
|
||||||
if config.hooks and config.hooks.setup_code then
|
local s = config.hooks and config.hooks.setup
|
||||||
local ok = pcall(config.hooks.setup_code, state)
|
if s and s.code then
|
||||||
if ok then
|
local ok = pcall(s.code, state)
|
||||||
vim.b[prov.bufnr].cp_setup_done = true
|
if ok then vim.b[prov.bufnr].cp_setup_done = true end
|
||||||
end
|
|
||||||
else
|
else
|
||||||
helpers.clearcol(prov.bufnr)
|
helpers.clearcol(prov.bufnr)
|
||||||
vim.b[prov.bufnr].cp_setup_done = true
|
vim.b[prov.bufnr].cp_setup_done = true
|
||||||
end
|
end
|
||||||
|
local o = config.hooks and config.hooks.on
|
||||||
|
if o and o.enter then
|
||||||
|
local bufnr = prov.bufnr
|
||||||
|
vim.api.nvim_create_autocmd('BufEnter', {
|
||||||
|
buffer = bufnr,
|
||||||
|
callback = function() pcall(o.enter, state) end,
|
||||||
|
})
|
||||||
|
pcall(o.enter, state)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
cache.set_file_state(
|
cache.set_file_state(
|
||||||
vim.fn.fnamemodify(source_file, ':p'),
|
vim.fn.fnamemodify(source_file, ':p'),
|
||||||
|
|
@ -339,15 +348,22 @@ function M.setup_problem(problem_id, language)
|
||||||
if is_new then
|
if is_new then
|
||||||
apply_template(bufnr, lang, platform)
|
apply_template(bufnr, lang, platform)
|
||||||
end
|
end
|
||||||
if config.hooks and config.hooks.setup_code then
|
local s = config.hooks and config.hooks.setup
|
||||||
local ok = pcall(config.hooks.setup_code, state)
|
if s and s.code then
|
||||||
if ok then
|
local ok = pcall(s.code, state)
|
||||||
vim.b[bufnr].cp_setup_done = true
|
if ok then vim.b[bufnr].cp_setup_done = true end
|
||||||
end
|
|
||||||
else
|
else
|
||||||
helpers.clearcol(bufnr)
|
helpers.clearcol(bufnr)
|
||||||
vim.b[bufnr].cp_setup_done = true
|
vim.b[bufnr].cp_setup_done = true
|
||||||
end
|
end
|
||||||
|
local o = config.hooks and config.hooks.on
|
||||||
|
if o and o.enter then
|
||||||
|
vim.api.nvim_create_autocmd('BufEnter', {
|
||||||
|
buffer = bufnr,
|
||||||
|
callback = function() pcall(o.enter, state) end,
|
||||||
|
})
|
||||||
|
pcall(o.enter, state)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
cache.set_file_state(
|
cache.set_file_state(
|
||||||
vim.fn.expand('%:p'),
|
vim.fn.expand('%:p'),
|
||||||
|
|
|
||||||
|
|
@ -444,12 +444,12 @@ function M.ensure_io_view()
|
||||||
|
|
||||||
local cfg = config_module.get_config()
|
local cfg = config_module.get_config()
|
||||||
|
|
||||||
if cfg.hooks and cfg.hooks.setup_io_output then
|
local io = cfg.hooks and cfg.hooks.setup and cfg.hooks.setup.io
|
||||||
pcall(cfg.hooks.setup_io_output, output_buf, state)
|
if io and io.output then
|
||||||
|
pcall(io.output, output_buf, state)
|
||||||
end
|
end
|
||||||
|
if io and io.input then
|
||||||
if cfg.hooks and cfg.hooks.setup_io_input then
|
pcall(io.input, input_buf, state)
|
||||||
pcall(cfg.hooks.setup_io_input, input_buf, state)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local test_cases = cache.get_test_cases(platform, contest_id, problem_id)
|
local test_cases = cache.get_test_cases(platform, contest_id, problem_id)
|
||||||
|
|
@ -958,15 +958,12 @@ function M.toggle_panel(panel_opts)
|
||||||
|
|
||||||
setup_keybindings_for_buffer(test_buffers.tab_buf)
|
setup_keybindings_for_buffer(test_buffers.tab_buf)
|
||||||
|
|
||||||
if config.hooks and config.hooks.before_run then
|
local o = config.hooks and config.hooks.on
|
||||||
vim.schedule_wrap(function()
|
if o and o.run then
|
||||||
config.hooks.before_run(state)
|
vim.schedule(function() o.run(state) end)
|
||||||
end)
|
|
||||||
end
|
end
|
||||||
if panel_opts and panel_opts.debug and config.hooks and config.hooks.before_debug then
|
if panel_opts and panel_opts.debug and o and o.debug then
|
||||||
vim.schedule_wrap(function()
|
vim.schedule(function() o.debug(state) end)
|
||||||
config.hooks.before_debug(state)
|
|
||||||
end)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
vim.api.nvim_set_current_win(test_windows.tab_win)
|
vim.api.nvim_set_current_win(test_windows.tab_win)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue