From b68ecbbe96be13484253e30b6beab3f5a703892b Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Sun, 5 Oct 2025 11:59:24 -0400 Subject: [PATCH] rename and simplify things --- README.md | 2 - after/ftplugin/cp.lua | 1 + after/ftplugin/cpin.lua | 6 -- after/ftplugin/cpout.lua | 7 -- after/ftplugin/cptest.lua | 7 -- after/syntax/cp.vim | 17 ----- doc/cp.nvim.txt | 37 ++--------- ftdetect/cp.lua | 6 -- lua/cp/commands/init.lua | 29 ++++----- lua/cp/config.lua | 2 - lua/cp/health.lua | 16 +---- lua/cp/init.lua | 6 -- lua/cp/setup.lua | 20 ------ lua/cp/snippets.lua | 134 -------------------------------------- lua/cp/ui/layouts.lua | 12 ++-- lua/cp/ui/panel.lua | 38 +++++------ 16 files changed, 43 insertions(+), 297 deletions(-) delete mode 100644 after/ftplugin/cpin.lua delete mode 100644 after/ftplugin/cpout.lua delete mode 100644 after/ftplugin/cptest.lua delete mode 100644 after/syntax/cp.vim delete mode 100644 ftdetect/cp.lua delete mode 100644 lua/cp/snippets.lua diff --git a/README.md b/README.md index c2da671..bf9032d 100644 --- a/README.md +++ b/README.md @@ -12,13 +12,11 @@ https://github.com/user-attachments/assets/50b19481-8e6d-47b4-bebc-15e16c61a9c9 - **Automatic problem setup**: Scrape test cases and metadata in seconds - **Rich test output**: ANSI color support for compiler errors and program output - **Language agnostic**: Works with any compiled language -- **Template integration**: Contest-specific snippets via LuaSnip - **Diff viewer**: Compare expected vs actual output with precision ## Optional Dependencies - [uv](https://docs.astral.sh/uv/) for problem scraping -- [LuaSnip](https://github.com/L3MON4D3/LuaSnip) for templates - GNU [time](https://www.gnu.org/software/time/) and [timeout](https://www.gnu.org/software/coreutils/manual/html_node/timeout-invocation.html) ## Quick Start diff --git a/after/ftplugin/cp.lua b/after/ftplugin/cp.lua index 622ad6a..eab89a5 100644 --- a/after/ftplugin/cp.lua +++ b/after/ftplugin/cp.lua @@ -4,3 +4,4 @@ vim.opt_local.statuscolumn = '' vim.opt_local.signcolumn = 'no' vim.opt_local.wrap = true vim.opt_local.linebreak = true +vim.opt_local.foldcolumn = '0' diff --git a/after/ftplugin/cpin.lua b/after/ftplugin/cpin.lua deleted file mode 100644 index 622ad6a..0000000 --- a/after/ftplugin/cpin.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/ftplugin/cpout.lua b/after/ftplugin/cpout.lua deleted file mode 100644 index 1f4855f..0000000 --- a/after/ftplugin/cpout.lua +++ /dev/null @@ -1,7 +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 -vim.opt_local.modifiable = true diff --git a/after/ftplugin/cptest.lua b/after/ftplugin/cptest.lua deleted file mode 100644 index eab89a5..0000000 --- a/after/ftplugin/cptest.lua +++ /dev/null @@ -1,7 +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 -vim.opt_local.foldcolumn = '0' diff --git a/after/syntax/cp.vim b/after/syntax/cp.vim deleted file mode 100644 index fe9eef7..0000000 --- a/after/syntax/cp.vim +++ /dev/null @@ -1,17 +0,0 @@ -if exists("b:current_syntax") - finish -endif - -syntax match cpOutputCode /^\[code\]:/ -syntax match cpOutputTime /^\[time\]:/ -syntax match cpOutputDebug /^\[debug\]:/ -syntax match cpOutputOkTrue /^\[ok\]:\ze true$/ -syntax match cpOutputOkFalse /^\[ok\]:\ze false$/ - -highlight default link cpOutputCode DiagnosticInfo -highlight default link cpOutputTime Comment -highlight default link cpOutputDebug Comment -highlight default link cpOutputOkTrue DiffAdd -highlight default link cpOutputOkFalse DiffDelete - -let b:current_syntax = "cp" diff --git a/doc/cp.nvim.txt b/doc/cp.nvim.txt index 0dfc82d..2879db9 100644 --- a/doc/cp.nvim.txt +++ b/doc/cp.nvim.txt @@ -16,10 +16,7 @@ REQUIREMENTS *cp-requirements* - Neovim 0.10.0+ - Unix-like operating system - -Optional: - uv package manager (https://docs.astral.sh/uv/) -- LuaSnip for template expansion (https://github.com/L3MON4D3/LuaSnip) ============================================================================== COMMANDS *cp-commands* @@ -51,12 +48,16 @@ COMMANDS *cp-commands* :CP codeforces 1951 < Action Commands ~ - :CP run [--debug] Toggle run panel for individual test case - debugging. Shows per-test results with redesigned + :CP run Toggle run panel for individual test cases. + Shows per-test results with redesigned layout for efficient comparison. Use --debug flag to compile with debug flags. Requires contest setup first. + :CP debug + Same as above but with the debug mode configured + settings. + :CP pick Launch configured picker for interactive platform/contest selection. @@ -136,7 +137,6 @@ Here's an example configuration with lazy.nvim: >lua }, }, }, - platforms = { cses = { enabled_languages = { 'cpp', 'python' }, @@ -154,10 +154,7 @@ Here's an example configuration with lazy.nvim: >lua default_language = 'cpp', }, }, - - snippets = {}, debug = false, - ui = { run_panel = { ansi = true, @@ -223,7 +220,6 @@ run CSES problems with Rust using the single schema: {platforms} (table) Per-platform enablement, default language, and optional overrides. {hooks} (|cp.Hooks|) Hook functions called at various stages. - {snippets} (table[]) LuaSnip snippet definitions. {debug} (boolean, default: false) Show info messages. {scrapers} (string[]) Supported platform ids. {filename} (function, optional) @@ -586,27 +582,6 @@ cp.nvim creates the following file structure upon problem setup: > {problem_id}.n.cpout " nth program output {problem_id}.expected " Expected output < -============================================================================== -SNIPPETS *cp-snippets* - -cp.nvim integrates with LuaSnip for automatic template expansion. Built-in -snippets include basic C++ and Python templates for each contest type. - -Snippet trigger names must match the following format exactly: > - - cp.nvim/{platform}.{language} -< -Where {platform} is the contest platform (atcoder, codeforces, cses) and -{language} is the programming language (cpp, python). - -Examples: > - cp.nvim/atcoder.cpp - cp.nvim/codeforces.python - cp.nvim/cses.cpp -< - -Custom snippets can be added via the `snippets` configuration field. - ============================================================================== HEALTH CHECK *cp-health* diff --git a/ftdetect/cp.lua b/ftdetect/cp.lua deleted file mode 100644 index d5c6327..0000000 --- a/ftdetect/cp.lua +++ /dev/null @@ -1,6 +0,0 @@ -vim.filetype.add({ - extension = { - cpin = 'cpin', - cpout = 'cpout', - }, -}) diff --git a/lua/cp/commands/init.lua b/lua/cp/commands/init.lua index 6923a0f..2b58be3 100644 --- a/lua/cp/commands/init.lua +++ b/lua/cp/commands/init.lua @@ -10,7 +10,6 @@ local actions = constants.ACTIONS ---@class ParsedCommand ---@field type string ---@field error string? ----@field debug? boolean ---@field action? string ---@field message? string ---@field contest? string @@ -26,22 +25,16 @@ local function parse_command(args) } end - local debug = vim.tbl_contains(args, '--debug') - - local filtered_args = vim.tbl_filter(function(arg) - return arg ~= '--debug' - end, args) - - local first = filtered_args[1] + local first = args[1] if vim.tbl_contains(actions, first) then if first == 'cache' then - local subcommand = filtered_args[2] + local subcommand = args[2] if not subcommand then return { type = 'error', message = 'cache command requires subcommand: clear' } end if vim.tbl_contains({ 'clear', 'read' }, subcommand) then - local platform = filtered_args[3] + local platform = args[3] return { type = 'cache', subcommand = subcommand, @@ -51,26 +44,26 @@ local function parse_command(args) return { type = 'error', message = 'unknown cache subcommand: ' .. subcommand } end else - return { type = 'action', action = first, debug = debug } + return { type = 'action', action = first } end end if vim.tbl_contains(platforms, first) then - if #filtered_args == 1 then + if #args == 1 then return { type = 'error', message = 'Too few arguments - specify a contest.', } - elseif #filtered_args == 2 then + elseif #args == 2 then return { type = 'contest_setup', platform = first, - contest = filtered_args[2], + contest = args[2], } - elseif #filtered_args == 3 then + elseif #args == 3 then return { type = 'error', - message = 'Setup contests with :CP ', + message = 'Setup contests with :CP .', } else return { type = 'error', message = 'Too many arguments' } @@ -109,7 +102,9 @@ function M.handle_command(opts) if cmd.action == 'interact' then ui.toggle_interactive() elseif cmd.action == 'run' then - ui.toggle_run_panel(cmd.debug) + ui.toggle_run_panel() + elseif cmd.action == 'debug' then + ui.toggle_run_panel({ debug = true }) elseif cmd.action == 'next' then setup.navigate_problem(1) elseif cmd.action == 'prev' then diff --git a/lua/cp/config.lua b/lua/cp/config.lua index f58c369..31540cf 100644 --- a/lua/cp/config.lua +++ b/lua/cp/config.lua @@ -42,7 +42,6 @@ ---@field languages table ---@field platforms table ---@field hooks Hooks ----@field snippets any[] ---@field debug boolean ---@field scrapers string[] ---@field filename? fun(contest: string, contest_id: string, problem_id?: string, config: cp.Config, language?: string): string @@ -100,7 +99,6 @@ M.defaults = { default_language = 'cpp', }, }, - snippets = {}, hooks = { before_run = nil, before_debug = nil, setup_code = nil }, debug = false, scrapers = constants.PLATFORMS, diff --git a/lua/cp/health.lua b/lua/cp/health.lua index c5e5113..ba3879a 100644 --- a/lua/cp/health.lua +++ b/lua/cp/health.lua @@ -2,7 +2,7 @@ local M = {} local utils = require('cp.utils') -local function check_required() +local function check() vim.health.start('cp.nvim [required] ~') if vim.fn.has('nvim-0.10.0') == 1 then @@ -49,24 +49,12 @@ local function check_required() end end -local function check_optional() - vim.health.start('cp.nvim [optional] ~') - - local has_luasnip = pcall(require, 'luasnip') - if has_luasnip then - vim.health.ok('LuaSnip integration available') - else - vim.health.info('LuaSnip not available (templates optional)') - end -end - function M.check() local version = require('cp.version') vim.health.start('cp.nvim health check ~') vim.health.info('Version: ' .. version.version) - check_required() - check_optional() + check() end return M diff --git a/lua/cp/init.lua b/lua/cp/init.lua index 88467ee..4e2be8a 100644 --- a/lua/cp/init.lua +++ b/lua/cp/init.lua @@ -2,7 +2,6 @@ local M = {} local config_module = require('cp.config') local logger = require('cp.log') -local snippets = require('cp.snippets') if vim.fn.has('nvim-0.10.0') == 0 then logger.log('Requires nvim-0.10.0+', vim.log.levels.ERROR) @@ -11,7 +10,6 @@ end local user_config = {} local config = nil -local snippets_initialized = false local initialized = false --- Root handler for all `:CP ...` commands @@ -27,10 +25,6 @@ function M.setup(opts) config = config_module.setup(user_config) config_module.set_current_config(config) - if not snippets_initialized then - snippets.setup(config) - snippets_initialized = true - end initialized = true end diff --git a/lua/cp/setup.lua b/lua/cp/setup.lua index 0e7c8f4..4127c93 100644 --- a/lua/cp/setup.lua +++ b/lua/cp/setup.lua @@ -107,26 +107,6 @@ function M.setup_problem(problem_id, language) local lang = language or config.platforms[platform].default_language local source_file = state.get_source_file(lang) vim.cmd.e(source_file) - local source_buf = vim.api.nvim_get_current_buf() - - if vim.api.nvim_buf_get_lines(source_buf, 0, -1, true)[1] == '' then - local ok, luasnip = pcall(require, 'luasnip') - if ok then - local trigger = ('cp.nvim/%s.%s'):format(platform, lang) - vim.api.nvim_buf_set_lines(0, 0, -1, false, { trigger }) - vim.api.nvim_win_set_cursor(0, { 1, #trigger }) - vim.cmd.startinsert({ bang = true }) - vim.schedule(function() - if luasnip.expandable() then - luasnip.expand() - else - vim.api.nvim_buf_set_lines(0, 0, 1, false, { '' }) - vim.api.nvim_win_set_cursor(0, { 1, 0 }) - end - vim.cmd.stopinsert() - end) - end - end if config.hooks and config.hooks.setup_code then config.hooks.setup_code(state) diff --git a/lua/cp/snippets.lua b/lua/cp/snippets.lua deleted file mode 100644 index 9108286..0000000 --- a/lua/cp/snippets.lua +++ /dev/null @@ -1,134 +0,0 @@ -local M = {} -local logger = require('cp.log') - -function M.setup(config) - local ok, ls = pcall(require, 'luasnip') - if not ok then - logger.log('LuaSnip not available - snippets are disabled.', vim.log.levels.INFO, true) - return - end - - local s, i, fmt = ls.snippet, ls.insert_node, require('luasnip.extras.fmt').fmt - - local constants = require('cp.constants') - local filetype_to_language = constants.filetype_to_language - - local language_to_filetype = {} - for ext, lang in pairs(filetype_to_language) do - if not language_to_filetype[lang] then - language_to_filetype[lang] = ext - end - end - - local template_definitions = { - cpp = { - codeforces = [[#include - -using namespace std; - -void solve() {{ - {} -}} - -int main() {{ - std::cin.tie(nullptr)->sync_with_stdio(false); - - int tc = 1; - std::cin >> tc; - - for (int t = 0; t < tc; ++t) {{ - solve(); - }} - - return 0; -}}]], - - atcoder = [[#include - -using namespace std; - -void solve() {{ - {} -}} - -int main() {{ - std::cin.tie(nullptr)->sync_with_stdio(false); - -#ifdef LOCAL - int tc; - std::cin >> tc; - - for (int t = 0; t < tc; ++t) {{ - solve(); - }} -#else - solve(); -#endif - - return 0; -}}]], - - cses = [[#include - -using namespace std; - -int main() {{ - std::cin.tie(nullptr)->sync_with_stdio(false); - - {} - - return 0; -}}]], - }, - - python = { - codeforces = [[def solve(): - {} - -if __name__ == "__main__": - tc = int(input()) - for _ in range(tc): - solve()]], - - atcoder = [[def solve(): - {} - -if __name__ == "__main__": - solve()]], - - cses = [[def solve(): - {} - -if __name__ == "__main__": - solve()]], - }, - } - - local user_overrides = {} - for _, snippet in ipairs(config.snippets or {}) do - user_overrides[snippet.trigger:lower()] = snippet - end - - for language, template_set in pairs(template_definitions) do - local snippets = {} - local filetype = constants.canonical_filetypes[language] - - for contest, template in pairs(template_set) do - local prefixed_trigger = ('cp.nvim/%s.%s'):format(contest:lower(), language) - if not user_overrides[prefixed_trigger:lower()] then - table.insert(snippets, s(prefixed_trigger, fmt(template, { i(1) }))) - end - end - - for trigger, snippet in pairs(user_overrides) do - local prefix_match = trigger:lower():match('^cp%.nvim/[^.]+%.(.+)$') - if prefix_match == language then - table.insert(snippets, snippet) - end - end - - ls.add_snippets(filetype, snippets) - end -end - -return M diff --git a/lua/cp/ui/layouts.lua b/lua/cp/ui/layouts.lua index c2613a5..ea73cd7 100644 --- a/lua/cp/ui/layouts.lua +++ b/lua/cp/ui/layouts.lua @@ -16,8 +16,8 @@ local function create_none_diff_layout(parent_win, expected_content, actual_cont local expected_win = vim.api.nvim_get_current_win() vim.api.nvim_win_set_buf(expected_win, expected_buf) - vim.api.nvim_set_option_value('filetype', 'cptest', { buf = expected_buf }) - vim.api.nvim_set_option_value('filetype', 'cptest', { buf = actual_buf }) + vim.api.nvim_set_option_value('filetype', 'cp', { buf = expected_buf }) + vim.api.nvim_set_option_value('filetype', 'cp', { buf = actual_buf }) vim.api.nvim_set_option_value('winbar', 'Expected', { win = expected_win }) vim.api.nvim_set_option_value('winbar', 'Actual', { win = actual_win }) @@ -53,8 +53,8 @@ local function create_vim_diff_layout(parent_win, expected_content, actual_conte local expected_win = vim.api.nvim_get_current_win() vim.api.nvim_win_set_buf(expected_win, expected_buf) - vim.api.nvim_set_option_value('filetype', 'cptest', { buf = expected_buf }) - vim.api.nvim_set_option_value('filetype', 'cptest', { buf = actual_buf }) + vim.api.nvim_set_option_value('filetype', 'cp', { buf = expected_buf }) + vim.api.nvim_set_option_value('filetype', 'cp', { buf = actual_buf }) vim.api.nvim_set_option_value('winbar', 'Expected', { win = expected_win }) vim.api.nvim_set_option_value('winbar', 'Actual', { win = actual_win }) @@ -96,7 +96,7 @@ local function create_git_diff_layout(parent_win, expected_content, actual_conte local diff_win = vim.api.nvim_get_current_win() vim.api.nvim_win_set_buf(diff_win, diff_buf) - vim.api.nvim_set_option_value('filetype', 'cptest', { buf = diff_buf }) + vim.api.nvim_set_option_value('filetype', 'cp', { buf = diff_buf }) vim.api.nvim_set_option_value('winbar', 'Expected vs Actual', { win = diff_win }) local diff_backend = require('cp.ui.diff') @@ -132,7 +132,7 @@ local function create_single_layout(parent_win, content) vim.cmd('resize ' .. math.floor(vim.o.lines * 0.35)) local win = vim.api.nvim_get_current_win() vim.api.nvim_win_set_buf(win, buf) - vim.api.nvim_set_option_value('filetype', 'cptest', { buf = buf }) + vim.api.nvim_set_option_value('filetype', 'cp', { buf = buf }) return { buffers = { buf }, diff --git a/lua/cp/ui/panel.lua b/lua/cp/ui/panel.lua index 4467f0e..d758080 100644 --- a/lua/cp/ui/panel.lua +++ b/lua/cp/ui/panel.lua @@ -1,5 +1,8 @@ local M = {} +---@class RunOpts +---@field debug? boolean + local config_module = require('cp.config') local layouts = require('cp.ui.layouts') local logger = require('cp.log') @@ -51,19 +54,13 @@ function M.toggle_interactive() local platform, contest_id = state.get_platform(), state.get_contest_id() if not platform then - logger.log( - 'No platform configured. Use :CP [--{lang=,debug}] first.', - vim.log.levels.ERROR - ) + logger.log('No platform configured.', vim.log.levels.ERROR) return end if not contest_id then logger.log( - ('No contest %s configured for platform %s. Use :CP [--{lang=,debug}] to set up first.'):format( - contest_id, - platform - ), + ('No contest %s configured for platform %s.'):format(contest_id, platform), vim.log.levels.ERROR ) return @@ -118,8 +115,8 @@ function M.toggle_interactive() state.set_active_panel('interactive') end ----@param debug? boolean -function M.toggle_run_panel(debug) +---@param run_opts? RunOpts +function M.toggle_run_panel(run_opts) if state.get_active_panel() == 'run' then if current_diff_layout then current_diff_layout.cleanup() @@ -152,10 +149,7 @@ function M.toggle_run_panel(debug) if not contest_id then logger.log( - ('No contest %s configured for platform %s. Use :CP [--{lang=,debug}] to set up first.'):format( - contest_id, - platform - ), + ('No contest %s configured for platform %s.'):format(contest_id, platform), vim.log.levels.ERROR ) return @@ -187,13 +181,6 @@ function M.toggle_run_panel(debug) ) local config = config_module.get_config() - if config.hooks and config.hooks.before_run then - config.hooks.before_run(state) - end - if debug and config.hooks and config.hooks.before_debug then - config.hooks.before_debug(state) - end - local run = require('cp.runner.run') local input_file = state.get_input_file() logger.log(('run panel: checking test cases for %s'):format(input_file or 'none')) @@ -210,7 +197,7 @@ function M.toggle_run_panel(debug) local tab_buf = utils.create_buffer_with_options() local main_win = vim.api.nvim_get_current_win() vim.api.nvim_win_set_buf(main_win, tab_buf) - vim.api.nvim_set_option_value('filetype', 'cptest', { buf = tab_buf }) + vim.api.nvim_set_option_value('filetype', 'cp', { buf = tab_buf }) local test_windows = { tab_win = main_win } local test_buffers = { tab_buf = tab_buf } @@ -282,6 +269,13 @@ function M.toggle_run_panel(debug) setup_keybindings_for_buffer(test_buffers.tab_buf) + if config.hooks and config.hooks.before_run then + config.hooks.before_run(state) + end + if run_opts.debug and config.hooks and config.hooks.before_debug then + config.hooks.before_debug(state) + end + local execute = require('cp.runner.execute') local compile_result = execute.compile_problem() if compile_result.success then