fix: cancel active process on contest switch (#316)
## Problem Switching contests while a run, interactive session, or stress test was active left orphaned callbacks and terminal jobs alive. Running `:CP run` twice also let the first run's stale output overwrite the buffer. ## Solution Replace the `io_view_running` bool in `views.lua` with a generation counter so concurrent `run_io_view` calls self-cancel via stale-gen checks in async callbacks. Add `cancel_io_view`, `cancel_interactive`, and `stress.cancel` for forceful teardown, and call them in `setup_contest` whenever `is_new_contest` is true.
This commit is contained in:
parent
916c9174a6
commit
7e7e135681
3 changed files with 57 additions and 18 deletions
|
|
@ -179,6 +179,19 @@ function M.setup_contest(platform, contest_id, problem_id, language)
|
||||||
|
|
||||||
local is_new_contest = old_platform ~= platform or old_contest_id ~= contest_id
|
local is_new_contest = old_platform ~= platform or old_contest_id ~= contest_id
|
||||||
|
|
||||||
|
if is_new_contest then
|
||||||
|
local views = require('cp.ui.views')
|
||||||
|
views.cancel_io_view()
|
||||||
|
local active = state.get_active_panel()
|
||||||
|
if active == 'interactive' then
|
||||||
|
views.cancel_interactive()
|
||||||
|
elseif active == 'stress' then
|
||||||
|
require('cp.stress').cancel()
|
||||||
|
elseif active == 'run' then
|
||||||
|
views.disable()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
cache.load()
|
cache.load()
|
||||||
|
|
||||||
local function proceed(contest_data)
|
local function proceed(contest_data)
|
||||||
|
|
|
||||||
|
|
@ -232,4 +232,18 @@ function M.toggle(generator_cmd, brute_cmd)
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function M.cancel()
|
||||||
|
if state.stress_buf and vim.api.nvim_buf_is_valid(state.stress_buf) then
|
||||||
|
local job = vim.b[state.stress_buf].terminal_job_id
|
||||||
|
if job then
|
||||||
|
vim.fn.jobstop(job)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if state.saved_stress_session then
|
||||||
|
vim.fn.delete(state.saved_stress_session)
|
||||||
|
state.saved_stress_session = nil
|
||||||
|
end
|
||||||
|
state.set_active_panel(nil)
|
||||||
|
end
|
||||||
|
|
||||||
return M
|
return M
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ local utils = require('cp.utils')
|
||||||
|
|
||||||
local current_diff_layout = nil
|
local current_diff_layout = nil
|
||||||
local current_mode = nil
|
local current_mode = nil
|
||||||
local io_view_running = false
|
local _run_gen = 0
|
||||||
|
|
||||||
function M.disable()
|
function M.disable()
|
||||||
local active_panel = state.get_active_panel()
|
local active_panel = state.get_active_panel()
|
||||||
|
|
@ -599,11 +599,8 @@ local function render_io_view_results(io_state, test_indices, mode, combined_res
|
||||||
end
|
end
|
||||||
|
|
||||||
function M.run_io_view(test_indices_arg, debug, mode)
|
function M.run_io_view(test_indices_arg, debug, mode)
|
||||||
if io_view_running then
|
_run_gen = _run_gen + 1
|
||||||
logger.log('Tests already running', { level = vim.log.levels.WARN })
|
local gen = _run_gen
|
||||||
return
|
|
||||||
end
|
|
||||||
io_view_running = true
|
|
||||||
|
|
||||||
logger.log(
|
logger.log(
|
||||||
('%s tests...'):format(debug and 'Debugging' or 'Running'),
|
('%s tests...'):format(debug and 'Debugging' or 'Running'),
|
||||||
|
|
@ -619,7 +616,6 @@ function M.run_io_view(test_indices_arg, debug, mode)
|
||||||
'No platform/contest/problem configured. Use :CP <platform> <contest> [...] first.',
|
'No platform/contest/problem configured. Use :CP <platform> <contest> [...] first.',
|
||||||
{ level = vim.log.levels.ERROR }
|
{ level = vim.log.levels.ERROR }
|
||||||
)
|
)
|
||||||
io_view_running = false
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -627,7 +623,6 @@ function M.run_io_view(test_indices_arg, debug, mode)
|
||||||
local contest_data = cache.get_contest_data(platform, contest_id)
|
local contest_data = cache.get_contest_data(platform, contest_id)
|
||||||
if not contest_data or not contest_data.index_map then
|
if not contest_data or not contest_data.index_map then
|
||||||
logger.log('No test cases available.', { level = vim.log.levels.ERROR })
|
logger.log('No test cases available.', { level = vim.log.levels.ERROR })
|
||||||
io_view_running = false
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -644,13 +639,11 @@ function M.run_io_view(test_indices_arg, debug, mode)
|
||||||
local combined = cache.get_combined_test(platform, contest_id, problem_id)
|
local combined = cache.get_combined_test(platform, contest_id, problem_id)
|
||||||
if not combined then
|
if not combined then
|
||||||
logger.log('No combined test available', { level = vim.log.levels.ERROR })
|
logger.log('No combined test available', { level = vim.log.levels.ERROR })
|
||||||
io_view_running = false
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
if not run.load_test_cases() then
|
if not run.load_test_cases() then
|
||||||
logger.log('No test cases available', { level = vim.log.levels.ERROR })
|
logger.log('No test cases available', { level = vim.log.levels.ERROR })
|
||||||
io_view_running = false
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -671,7 +664,6 @@ function M.run_io_view(test_indices_arg, debug, mode)
|
||||||
),
|
),
|
||||||
{ level = vim.log.levels.WARN }
|
{ level = vim.log.levels.WARN }
|
||||||
)
|
)
|
||||||
io_view_running = false
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -689,7 +681,6 @@ function M.run_io_view(test_indices_arg, debug, mode)
|
||||||
|
|
||||||
local io_state = state.get_io_view_state()
|
local io_state = state.get_io_view_state()
|
||||||
if not io_state then
|
if not io_state then
|
||||||
io_view_running = false
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -702,8 +693,10 @@ function M.run_io_view(test_indices_arg, debug, mode)
|
||||||
local execute = require('cp.runner.execute')
|
local execute = require('cp.runner.execute')
|
||||||
|
|
||||||
execute.compile_problem(debug, function(compile_result)
|
execute.compile_problem(debug, function(compile_result)
|
||||||
|
if gen ~= _run_gen then
|
||||||
|
return
|
||||||
|
end
|
||||||
if not vim.api.nvim_buf_is_valid(io_state.output_buf) then
|
if not vim.api.nvim_buf_is_valid(io_state.output_buf) then
|
||||||
io_view_running = false
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -723,7 +716,6 @@ function M.run_io_view(test_indices_arg, debug, mode)
|
||||||
|
|
||||||
local ns = vim.api.nvim_create_namespace('cp_io_view_compile_error')
|
local ns = vim.api.nvim_create_namespace('cp_io_view_compile_error')
|
||||||
utils.update_buffer_content(io_state.output_buf, lines, highlights, ns)
|
utils.update_buffer_content(io_state.output_buf, lines, highlights, ns)
|
||||||
io_view_running = false
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -731,35 +723,55 @@ function M.run_io_view(test_indices_arg, debug, mode)
|
||||||
local combined = cache.get_combined_test(platform, contest_id, problem_id)
|
local combined = cache.get_combined_test(platform, contest_id, problem_id)
|
||||||
if not combined then
|
if not combined then
|
||||||
logger.log('No combined test found', { level = vim.log.levels.ERROR })
|
logger.log('No combined test found', { level = vim.log.levels.ERROR })
|
||||||
io_view_running = false
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
run.load_test_cases()
|
run.load_test_cases()
|
||||||
|
|
||||||
run.run_combined_test(debug, function(result)
|
run.run_combined_test(debug, function(result)
|
||||||
|
if gen ~= _run_gen then
|
||||||
|
return
|
||||||
|
end
|
||||||
if not result then
|
if not result then
|
||||||
logger.log('Failed to run combined test', { level = vim.log.levels.ERROR })
|
logger.log('Failed to run combined test', { level = vim.log.levels.ERROR })
|
||||||
io_view_running = false
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if vim.api.nvim_buf_is_valid(io_state.output_buf) then
|
if vim.api.nvim_buf_is_valid(io_state.output_buf) then
|
||||||
render_io_view_results(io_state, test_indices, mode, result, combined.input)
|
render_io_view_results(io_state, test_indices, mode, result, combined.input)
|
||||||
end
|
end
|
||||||
io_view_running = false
|
|
||||||
end)
|
end)
|
||||||
else
|
else
|
||||||
run.run_all_test_cases(test_indices, debug, nil, function()
|
run.run_all_test_cases(test_indices, debug, nil, function()
|
||||||
|
if gen ~= _run_gen then
|
||||||
|
return
|
||||||
|
end
|
||||||
if vim.api.nvim_buf_is_valid(io_state.output_buf) then
|
if vim.api.nvim_buf_is_valid(io_state.output_buf) then
|
||||||
render_io_view_results(io_state, test_indices, mode, nil, nil)
|
render_io_view_results(io_state, test_indices, mode, nil, nil)
|
||||||
end
|
end
|
||||||
io_view_running = false
|
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function M.cancel_io_view()
|
||||||
|
_run_gen = _run_gen + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.cancel_interactive()
|
||||||
|
if state.interactive_buf and vim.api.nvim_buf_is_valid(state.interactive_buf) then
|
||||||
|
local job = vim.b[state.interactive_buf].terminal_job_id
|
||||||
|
if job then
|
||||||
|
vim.fn.jobstop(job)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if state.saved_interactive_session then
|
||||||
|
vim.fn.delete(state.saved_interactive_session)
|
||||||
|
state.saved_interactive_session = nil
|
||||||
|
end
|
||||||
|
state.set_active_panel(nil)
|
||||||
|
end
|
||||||
|
|
||||||
---@param panel_opts? PanelOpts
|
---@param panel_opts? PanelOpts
|
||||||
function M.toggle_panel(panel_opts)
|
function M.toggle_panel(panel_opts)
|
||||||
if state.get_active_panel() == 'run' then
|
if state.get_active_panel() == 'run' then
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue