feat: file conflict prompt, empty submit guard, and lint fixes (#366)

## Problem

Loading a problem whose source file already exists silently overwrites
user code. Submitting an empty file sends a blank submission to the
platform. Two ruff lint violations existed in the scrapers.

## Solution

- `setup.lua`: when the target source file exists on the filesystem
(`vim.uv.fs_stat`), show an inline `Overwrite? [y/N]:` prompt. Declining
keeps the existing file open and registers state normally. Skipped when
the file is already loaded in a buffer.
- `submit.lua`: resolve path to absolute, use `vim.uv.fs_stat` to verify
existence, abort with WARN if `stat.size == 0` ("Submit aborted: source
file has no content").
- `scrapers/atcoder.py`: remove unused `pathlib.Path` import (F401).
- `scrapers/base.py`: move local imports to top of file (E402).

Closes #364, #365.
This commit is contained in:
Barrett Ruth 2026-03-07 16:30:51 -05:00 committed by GitHub
parent b7ddf4c253
commit 573b335646
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 145 additions and 560 deletions

View file

@ -328,6 +328,64 @@ function M.setup_problem(problem_id, language)
end
end
local _abs_sf = vim.fn.fnamemodify(source_file, ':p')
if vim.uv.fs_stat(_abs_sf) and vim.fn.bufnr(_abs_sf) == -1 then
local ans = vim.fn.input(
('File %q already exists. Overwrite? [y/N]: '):format(vim.fn.fnamemodify(source_file, ':~:.'))
)
vim.cmd.redraw()
if ans:lower() ~= 'y' then
local prov0 = state.get_provisional()
if
prov0
and prov0.platform == platform
and prov0.contest_id == (state.get_contest_id() or '')
then
if vim.api.nvim_buf_is_valid(prov0.bufnr) then
vim.api.nvim_buf_delete(prov0.bufnr, { force = true })
end
state.set_provisional(nil)
end
vim.cmd.only({ mods = { silent = true } })
if vim.fn.expand('%:p') ~= vim.fn.fnamemodify(source_file, ':p') then
vim.cmd.e(source_file)
end
local declined_bufnr = vim.api.nvim_get_current_buf()
state.set_solution_win(vim.api.nvim_get_current_win())
require('cp.ui.views').ensure_io_view()
if not vim.b[declined_bufnr].cp_setup_done then
local s = config.hooks and config.hooks.setup
if s and s.code then
local ok = pcall(s.code, state)
if ok then
vim.b[declined_bufnr].cp_setup_done = true
end
else
helpers.clearcol(declined_bufnr)
vim.b[declined_bufnr].cp_setup_done = true
end
local o = config.hooks and config.hooks.on
if o and o.enter then
vim.api.nvim_create_autocmd('BufEnter', {
buffer = declined_bufnr,
callback = function()
pcall(o.enter, state)
end,
})
pcall(o.enter, state)
end
end
cache.set_file_state(
vim.fn.expand('%:p'),
platform,
state.get_contest_id() or '',
state.get_problem_id() or '',
lang
)
return
end
end
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')

View file

@ -53,11 +53,20 @@ function M.submit(opts)
end
local source_file = state.get_source_file()
if not source_file or vim.fn.filereadable(source_file) ~= 1 then
if not source_file then
logger.log('Source file not found', { level = vim.log.levels.ERROR })
return
end
source_file = vim.fn.fnamemodify(source_file, ':p')
local _stat = vim.uv.fs_stat(source_file)
if not _stat then
logger.log('Source file not found', { level = vim.log.levels.ERROR })
return
end
if _stat.size == 0 then
logger.log('Submit aborted: source file has no content', { level = vim.log.levels.WARN })
return
end
local submit_language = language
local cfg = config.get_config()