From 0db6fa96b4cc247bdc3d9364a897f3b97592e683 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Fri, 12 Sep 2025 17:19:20 -0500 Subject: [PATCH] cleanup window layout --- after/ftdetect/cp.lua | 13 ------ after/ftplugin/{cpinput.lua => cp.lua} | 0 after/ftplugin/cpoutput.lua | 6 --- after/syntax/{cpoutput.vim => cp.vim} | 2 +- lua/cp/init.lua | 30 ++----------- lua/cp/scrape.lua | 59 ++++++++++++++++++++++-- lua/cp/window.lua | 62 ++++++++++++++++++++------ scrapers/atcoder.py | 7 ++- scrapers/codeforces.py | 15 ++----- 9 files changed, 118 insertions(+), 76 deletions(-) delete mode 100644 after/ftdetect/cp.lua rename after/ftplugin/{cpinput.lua => cp.lua} (100%) delete mode 100644 after/ftplugin/cpoutput.lua rename after/syntax/{cpoutput.vim => cp.vim} (94%) diff --git a/after/ftdetect/cp.lua b/after/ftdetect/cp.lua deleted file mode 100644 index 16634eb..0000000 --- a/after/ftdetect/cp.lua +++ /dev/null @@ -1,13 +0,0 @@ -vim.api.nvim_create_autocmd({ "BufRead", "BufNewFile" }, { - pattern = "*/io/*.in", - callback = function() - vim.bo.filetype = "cpinput" - end, -}) - -vim.api.nvim_create_autocmd({ "BufRead", "BufNewFile" }, { - pattern = "*/io/*.out", - callback = function() - vim.bo.filetype = "cpoutput" - end, -}) diff --git a/after/ftplugin/cpinput.lua b/after/ftplugin/cp.lua similarity index 100% rename from after/ftplugin/cpinput.lua rename to after/ftplugin/cp.lua diff --git a/after/ftplugin/cpoutput.lua b/after/ftplugin/cpoutput.lua deleted file mode 100644 index 76a9f86..0000000 --- a/after/ftplugin/cpoutput.lua +++ /dev/null @@ -1,6 +0,0 @@ -vim.opt_local.number = false -vim.opt_local.relativenumber = false -vim.opt_local.statuscolumn = "" -vim.opt_local.signcolumn = "no" -vim.opt_local.wrap = true -vim.opt_local.linebreak = true diff --git a/after/syntax/cpoutput.vim b/after/syntax/cp.vim similarity index 94% rename from after/syntax/cpoutput.vim rename to after/syntax/cp.vim index 28092a7..331d80f 100644 --- a/after/syntax/cpoutput.vim +++ b/after/syntax/cp.vim @@ -14,4 +14,4 @@ highlight default link cpOutputDebug Comment highlight default link cpOutputMatchesTrue DiffAdd highlight default link cpOutputMatchesFalse DiffDelete -let b:current_syntax = "cpoutput" \ No newline at end of file +let b:current_syntax = "cp" \ No newline at end of file diff --git a/lua/cp/init.lua b/lua/cp/init.lua index 75b8250..55680b3 100644 --- a/lua/cp/init.lua +++ b/lua/cp/init.lua @@ -21,30 +21,6 @@ local function get_plugin_path() return vim.fn.fnamemodify(plugin_path, ":h:h:h") end -local function setup_python_env() - local plugin_path = get_plugin_path() - local venv_dir = plugin_path .. "/.venv" - - if vim.fn.executable("uv") == 0 then - log( - "uv is not installed. Install it to enable problem scraping: https://docs.astral.sh/uv/", - vim.log.levels.WARN - ) - return false - end - - if vim.fn.isdirectory(venv_dir) == 0 then - log("setting up Python environment for scrapers...") - local result = vim.system({ "uv", "sync" }, { cwd = plugin_path, text = true }):wait() - if result.code ~= 0 then - log("failed to setup Python environment: " .. result.stderr, vim.log.levels.ERROR) - return false - end - log("python environment setup complete") - end - - return true -end local competition_types = { "atcoder", "codeforces", "cses" } @@ -82,7 +58,7 @@ local function setup_problem(problem_id, problem_letter) vim.g.cp_diff_mode = false end - vim.cmd.only() + vim.cmd('silent only') local scrape_result = scrape.scrape_problem(vim.g.cp_contest, problem_id, problem_letter) @@ -136,10 +112,12 @@ local function setup_problem(problem_id, problem_letter) vim.cmd.vsplit(output) vim.cmd.w() + vim.bo.filetype = "cp" window.clearcol() vim.cmd(("vertical resize %d"):format(math.floor(vim.o.columns * 0.3))) vim.cmd.split(input) vim.cmd.w() + vim.bo.filetype = "cp" window.clearcol() vim.cmd.wincmd("h") @@ -251,8 +229,6 @@ function M.setup(user_config) end initialized = true - setup_python_env() - vim.api.nvim_create_user_command("CP", function(opts) local args = opts.fargs if #args == 0 then diff --git a/lua/cp/scrape.lua b/lua/cp/scrape.lua index 1d54faf..656ebd8 100644 --- a/lua/cp/scrape.lua +++ b/lua/cp/scrape.lua @@ -9,9 +9,45 @@ local function ensure_io_directory() vim.fn.mkdir("io", "p") end +local function log(msg, level) + vim.notify(("[cp.nvim]: %s"):format(msg), level or vim.log.levels.INFO) +end + +local function setup_python_env() + local plugin_path = get_plugin_path() + local venv_dir = plugin_path .. "/.venv" + + if vim.fn.executable("uv") == 0 then + log( + "uv is not installed. Install it to enable problem scraping: https://docs.astral.sh/uv/", + vim.log.levels.WARN + ) + return false + end + + if vim.fn.isdirectory(venv_dir) == 0 then + log("setting up Python environment for scrapers...") + local result = vim.system({ "uv", "sync" }, { cwd = plugin_path, text = true }):wait() + if result.code ~= 0 then + log("failed to setup Python environment: " .. result.stderr, vim.log.levels.ERROR) + return false + end + log("python environment setup complete") + end + + return true +end + function M.scrape_problem(contest, problem_id, problem_letter) ensure_io_directory() + if not setup_python_env() then + return { + success = false, + error = "Python environment setup failed", + } + end + local plugin_path = get_plugin_path() local scraper_path = plugin_path .. "/scrapers/" .. contest .. ".py" @@ -47,14 +83,29 @@ function M.scrape_problem(contest, problem_id, problem_letter) return data end - local full_problem_id = data.problem_id + local full_problem_id = data.problem_id:lower() local input_file = "io/" .. full_problem_id .. ".in" local expected_file = "io/" .. full_problem_id .. ".expected" if #data.test_cases > 0 then - local first_test = data.test_cases[1] - vim.fn.writefile(vim.split(first_test.input, "\n"), input_file) - vim.fn.writefile(vim.split(first_test.output, "\n"), expected_file) + local all_inputs = {} + local all_outputs = {} + + for i, test_case in ipairs(data.test_cases) do + local input_lines = vim.split(test_case.input:gsub("\r", ""):gsub("\n+$", ""), "\n") + local output_lines = vim.split(test_case.output:gsub("\r", ""):gsub("\n+$", ""), "\n") + + for _, line in ipairs(input_lines) do + table.insert(all_inputs, line) + end + + for _, line in ipairs(output_lines) do + table.insert(all_outputs, line) + end + end + + vim.fn.writefile(all_inputs, input_file) + vim.fn.writefile(all_outputs, expected_file) end return { diff --git a/lua/cp/window.lua b/lua/cp/window.lua index 8c7ba11..df3e4f2 100644 --- a/lua/cp/window.lua +++ b/lua/cp/window.lua @@ -35,41 +35,77 @@ function M.restore_layout(state) end vim.cmd.diffoff() - vim.cmd(state.layout) - - for win, win_state in pairs(state.windows) do - if vim.api.nvim_win_is_valid(win) then - vim.api.nvim_set_current_win(win) - if vim.api.nvim_get_current_buf() == win_state.bufnr then - vim.fn.winrestview(win_state.view) + + local problem_id = vim.fn.expand("%:t:r") + if problem_id == "" then + for win, win_state in pairs(state.windows) do + if vim.api.nvim_win_is_valid(win) and vim.api.nvim_buf_is_valid(win_state.bufnr) then + local bufname = vim.api.nvim_buf_get_name(win_state.bufnr) + if bufname:match("%.cc$") then + problem_id = vim.fn.fnamemodify(bufname, ":t:r") + break + end end end end - if vim.api.nvim_win_is_valid(state.current_win) then - vim.api.nvim_set_current_win(state.current_win) + if problem_id ~= "" then + vim.cmd('silent only') + + local base_fp = vim.fn.getcwd() + local input = ("%s/io/%s.in"):format(base_fp, problem_id) + local output = ("%s/io/%s.out"):format(base_fp, problem_id) + local source = problem_id .. ".cc" + + vim.cmd.edit(source) + vim.cmd.vsplit(output) + vim.bo.filetype = "cp" + M.clearcol() + vim.cmd(("vertical resize %d"):format(math.floor(vim.o.columns * 0.3))) + vim.cmd.split(input) + vim.bo.filetype = "cp" + M.clearcol() + vim.cmd.wincmd("h") + else + vim.cmd(state.layout) + + for win, win_state in pairs(state.windows) do + if vim.api.nvim_win_is_valid(win) then + vim.api.nvim_set_current_win(win) + if vim.api.nvim_get_current_buf() == win_state.bufnr then + vim.fn.winrestview(win_state.view) + end + end + end + + if vim.api.nvim_win_is_valid(state.current_win) then + vim.api.nvim_set_current_win(state.current_win) + end end end function M.setup_diff_layout(actual_output, expected_output, input_file) vim.cmd.diffoff() - vim.cmd.only() + vim.cmd('silent only') local output_lines = vim.split(actual_output, "\n") local output_buf = vim.api.nvim_create_buf(false, true) vim.api.nvim_buf_set_lines(output_buf, 0, -1, false, output_lines) - vim.bo[output_buf].filetype = "cpoutput" + vim.bo[output_buf].filetype = "cp" vim.cmd.edit() vim.api.nvim_set_current_buf(output_buf) - vim.cmd.diffthis() M.clearcol() + vim.cmd.diffthis() vim.cmd.vsplit(expected_output) - vim.cmd.diffthis() + vim.bo.filetype = "cp" M.clearcol() + vim.cmd.diffthis() + vim.cmd.wincmd("h") vim.cmd(("botright split %s"):format(input_file)) + vim.bo.filetype = "cp" M.clearcol() vim.cmd.wincmd("k") end diff --git a/scrapers/atcoder.py b/scrapers/atcoder.py index 788a573..9eff826 100644 --- a/scrapers/atcoder.py +++ b/scrapers/atcoder.py @@ -68,7 +68,7 @@ def main(): contest_id = sys.argv[1] problem_letter = sys.argv[2] - problem_id = contest_id + problem_letter + problem_id = contest_id + problem_letter.lower() url = parse_problem_url(contest_id, problem_letter) print(f"Scraping: {url}", file=sys.stderr) @@ -88,6 +88,11 @@ def main(): test_cases = [] for input_data, output_data in tests: test_cases.append({"input": input_data, "output": output_data}) + + if test_cases: + combined_input = str(len(test_cases)) + "\n" + "\n".join(tc["input"] for tc in test_cases) + combined_output = "\n".join(tc["output"] for tc in test_cases) + test_cases = [{"input": combined_input, "output": combined_output}] result = { "success": True, diff --git a/scrapers/codeforces.py b/scrapers/codeforces.py index d1c24fa..35589a0 100644 --- a/scrapers/codeforces.py +++ b/scrapers/codeforces.py @@ -43,16 +43,9 @@ def scrape(url: str): output_lines.append(line_div.get_text().strip()) if input_lines and output_lines: - if len(input_lines) > 1 and input_lines[0].isdigit(): - test_count = int(input_lines[0]) - remaining_input = input_lines[1:] - for i in range(min(test_count, len(output_lines))): - if i < len(remaining_input): - tests.append((remaining_input[i], output_lines[i])) - else: - input_text = "\n".join(input_lines) - output_text = "\n".join(output_lines) - tests.append((input_text, output_text)) + input_text = "\n".join(input_lines) + output_text = "\n".join(output_lines) + tests.append((input_text, output_text)) return tests @@ -84,7 +77,7 @@ def main(): contest_id = sys.argv[1] problem_letter = sys.argv[2] - problem_id = contest_id + problem_letter.upper() + problem_id = contest_id + problem_letter.lower() url = parse_problem_url(contest_id, problem_letter) tests = scrape_sample_tests(url)