Merge pull request #34 from barrett-ruth/fix/move-to-defaults

Fix Default Configs
This commit is contained in:
Barrett Ruth 2025-09-15 20:33:38 +02:00 committed by GitHub
commit a825df595e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 126 additions and 223 deletions

View file

@ -77,7 +77,7 @@ Optional configuration with lazy.nvim: >
opts = { opts = {
debug = false, debug = false,
contests = { contests = {
default = { codeforces = {
cpp = { cpp = {
compile = { compile = {
'g++', '-std=c++{version}', '-O2', '-Wall', '-Wextra', 'g++', '-std=c++{version}', '-O2', '-Wall', '-Wextra',
@ -89,7 +89,7 @@ Optional configuration with lazy.nvim: >
'-fsanitize=address,undefined', '-DLOCAL', '-fsanitize=address,undefined', '-DLOCAL',
'{source}', '-o', '{binary}', '{source}', '-o', '{binary}',
}, },
version = 20, version = 23,
extension = "cc", extension = "cc",
}, },
python = { python = {
@ -97,9 +97,9 @@ Optional configuration with lazy.nvim: >
debug = { 'python3', '{source}' }, debug = { 'python3', '{source}' },
extension = "py", extension = "py",
}, },
default_language = "cpp",
timeout_ms = 2000, timeout_ms = 2000,
}, },
codeforces = { cpp = { version = 23 } },
}, },
hooks = { hooks = {
before_run = function(ctx) vim.cmd.w() end, before_run = function(ctx) vim.cmd.w() end,
@ -107,64 +107,65 @@ Optional configuration with lazy.nvim: >
-- ctx.problem_id, ctx.platform, ctx.source_file, etc. -- ctx.problem_id, ctx.platform, ctx.source_file, etc.
vim.cmd.w() vim.cmd.w()
end, end,
setup_code = function(ctx)
vim.wo.foldmethod = "marker"
vim.wo.foldmarker = "{{{,}}}"
vim.diagnostic.enable(false)
end,
}, },
snippets = { ... }, -- LuaSnip snippets snippets = { ... }, -- LuaSnip snippets
tile = function(source_buf, input_buf, output_buf) ... end, tile = function(source_buf, input_buf, output_buf) ... end,
filename = function(contest, problem_id, problem_letter) ... end, filename = function(contest, contest_id, problem_id, config, language) ... end,
} }
} }
< <
Configuration options: *cp.Config*
contests Dictionary of contest configurations - each contest inherits from 'default'. Fields: ~
• {contests} (`table<string,ContestConfig>`) Contest configurations.
• {hooks} (`cp.Hooks`) Hook functions called at various stages.
• {snippets} (`table[]`) LuaSnip snippet definitions.
• {debug} (`boolean`, default: `false`) Show info messages
during operation.
• {tile}? (`function`) Custom window arrangement function.
`function(source_buf, input_buf, output_buf)`
• {filename}? (`function`) Custom filename generation function.
`function(contest, contest_id, problem_id, config, language)`
Should return full filename with extension.
(default: uses problem_id or contest_id)
cpp C++ language configuration *cp.ContestConfig*
compile Compile command template with {version}, {source}, {binary} placeholders
run Run command template with {binary} placeholder
debug Debug compile command template
version C++ standard version (e.g. 20, 23)
extension File extension for C++ files (default: "cc")
python Python language configuration Fields: ~
run Run command template with {source} placeholder • {cpp} (`LanguageConfig`) C++ language configuration.
debug Debug run command template • {python} (`LanguageConfig`) Python language configuration.
extension File extension for Python files (default: "py") • {default_language} (`string`, default: `"cpp"`) Default language when
`--lang` not specified.
• {timeout_ms} (`number`, default: `2000`) Execution timeout in
milliseconds.
default_language Default language when --lang not specified (default: "cpp") *cp.LanguageConfig*
timeout_ms Duration (ms) to run/debug before timeout Fields: ~
• {compile}? (`string[]`) Compile command template with
`{version}`, `{source}`, `{binary}` placeholders.
• {run} (`string[]`) Run command template.
• {debug}? (`string[]`) Debug compile command template.
• {version}? (`number`) Language version (e.g. 20, 23 for C++).
• {extension} (`string`) File extension (e.g. "cc", "py").
• {executable}? (`string`) Executable name for interpreted languages.
snippets LuaSnip snippets by contest type *cp.Hooks*
hooks Functions called at specific events Fields: ~
before_run Called before :CP run • {before_run}? (`function`) Called before `:CP run`.
function(ctx) `function(ctx: ProblemContext)`
ctx contains: • {before_debug}? (`function`) Called before `:CP debug`.
- problem_id: string `function(ctx: ProblemContext)`
- platform: string (atcoder/codeforces/cses) • {setup_code}? (`function`) Called after source file is opened.
- contest_id: string Used to configure buffer settings.
- source_file: string (path to source) `function(ctx: ProblemContext)`
- input_file: string (path to .cpin)
- output_file: string (path to .cpout)
- expected_file: string (path to .expected)
- contest_config: table (language configs)
(default: nil, do nothing)
before_debug Called before :CP debug
function(ctx)
Same ctx as before_run
(default: nil, do nothing)
debug Show info messages during operation
(default: false, silent operation)
tile Custom function to arrange windows
function(source_buf, input_buf, output_buf)
(default: nil, uses built-in layout)
filename Custom function to generate filenames
function(contest, problem_id, problem_letter)
(default: nil, uses problem_id + letter + ".cc")
WORKFLOW *cp-workflow* WORKFLOW *cp-workflow*
@ -232,7 +233,7 @@ Example: Setting up and solving AtCoder contest ABC324
3. Start with problem A: > 3. Start with problem A: >
:CP a :CP a
< This creates abc324a.cc and scrapes test cases < This creates a.cc and scrapes test cases
4. Code your solution, then test: > 4. Code your solution, then test: >
:CP run :CP run
@ -259,32 +260,26 @@ FILE STRUCTURE *cp-files*
cp.nvim creates the following file structure upon problem setup: cp.nvim creates the following file structure upon problem setup:
{contest_id}{problem_id}.cc " Source file (e.g. abc324a.cc) {problem_id}.{ext} " Source file (e.g. a.cc, b.py)
build/ build/
{contest_id}{problem_id}.run " Compiled binary {problem_id}.run " Compiled binary
io/ io/
{contest_id}{problem_id}.cpin " Test input {problem_id}.cpin " Test input
{contest_id}{problem_id}.cpout " Program output {problem_id}.cpout " Program output
{contest_id}{problem_id}.expected " Expected output {problem_id}.expected " Expected output
The plugin automatically manages this structure and navigation between problems The plugin automatically manages this structure and navigation between problems
maintains proper file associations. maintains proper file associations.
SNIPPETS *cp-snippets* SNIPPETS *cp-snippets*
cp.nvim integrates with LuaSnip for automatic template expansion. When you cp.nvim integrates with LuaSnip for automatic template expansion. Built-in
open a new problem file, type the contest name and press <Tab> to expand. snippets include basic C++ and Python templates for each contest type.
Built-in snippets include basic C++ and Python templates for each contest type. Snippet trigger names must EXACTLY match platform names ("codeforces" for
Custom snippets can be added via configuration. CodeForces, "cses" for CSES, etc.).
IMPORTANT: Snippet trigger names must exactly match the contest/platform names: Custom snippets can be added via the `snippets` configuration field.
- "codeforces" for Codeforces problems
- "atcoder" for AtCoder problems
- "cses" for CSES problems
The plugin automatically selects the appropriate template based on the file
extension (e.g., .cc files get C++ templates, .py files get Python templates).
HEALTH CHECK *cp-health* HEALTH CHECK *cp-health*

View file

@ -26,19 +26,10 @@
---@field default_language? string ---@field default_language? string
---@field timeout_ms? number ---@field timeout_ms? number
---@class HookContext
---@field problem_id string
---@field platform string
---@field contest_id string
---@field source_file string
---@field input_file string
---@field output_file string
---@field expected_file string
---@field contest_config table
---@class Hooks ---@class Hooks
---@field before_run? fun(ctx: HookContext) ---@field before_run? fun(ctx: ProblemContext)
---@field before_debug? fun(ctx: HookContext) ---@field before_debug? fun(ctx: ProblemContext)
---@field setup_code? fun(ctx: ProblemContext)
---@class cp.Config ---@class cp.Config
---@field contests table<string, ContestConfig> ---@field contests table<string, ContestConfig>
@ -57,89 +48,22 @@
---@field filename? fun(contest: string, contest_id: string, problem_id?: string, config: cp.Config, language?: string): string ---@field filename? fun(contest: string, contest_id: string, problem_id?: string, config: cp.Config, language?: string): string
local M = {} local M = {}
local languages = require("cp.languages")
local filetype_to_language = {
cc = "cpp",
c = "cpp",
py = "python",
py3 = "python",
}
---@type cp.Config ---@type cp.Config
M.defaults = { M.defaults = {
contests = { contests = {},
default = {
cpp = {
compile = {
"g++",
"-std=c++{version}",
"-O2",
"-DLOCAL",
"-Wall",
"-Wextra",
"{source}",
"-o",
"{binary}",
},
run = { "{binary}" },
debug = {
"g++",
"-std=c++{version}",
"-g3",
"-fsanitize=address,undefined",
"-DLOCAL",
"{source}",
"-o",
"{binary}",
},
executable = nil,
version = 20,
extension = "cc",
},
python = {
compile = nil,
run = { "{source}" },
debug = { "{source}" },
executable = "python3",
extension = "py",
},
default_language = "cpp",
timeout_ms = 2000,
},
---@type PartialContestConfig
atcoder = {
---@type PartialLanguageConfig
cpp = { version = 23 },
},
---@type PartialContestConfig
codeforces = {
---@type PartialLanguageConfig
cpp = { version = 23 },
},
---@type PartialContestConfig
cses = {
---@type PartialLanguageConfig
cpp = { version = 20 },
},
},
snippets = {}, snippets = {},
hooks = { hooks = {
before_run = nil, before_run = nil,
before_debug = nil, before_debug = nil,
setup_code = nil,
}, },
debug = false, debug = false,
tile = nil, tile = nil,
filename = nil, filename = nil,
} }
---@param base_config table
---@param contest_config table
---@return table
local function extend_contest_config(base_config, contest_config)
local result = vim.tbl_deep_extend("force", base_config, contest_config)
return result
end
---@param user_config cp.UserConfig|nil ---@param user_config cp.UserConfig|nil
---@return cp.Config ---@return cp.Config
function M.setup(user_config) function M.setup(user_config)
@ -161,6 +85,7 @@ function M.setup(user_config)
vim.validate({ vim.validate({
before_run = { user_config.hooks.before_run, { "function", "nil" }, true }, before_run = { user_config.hooks.before_run, { "function", "nil" }, true },
before_debug = { user_config.hooks.before_debug, { "function", "nil" }, true }, before_debug = { user_config.hooks.before_debug, { "function", "nil" }, true },
setup_code = { user_config.hooks.setup_code, { "function", "nil" }, true },
}) })
end end
@ -168,13 +93,15 @@ function M.setup(user_config)
for contest_name, contest_config in pairs(user_config.contests) do for contest_name, contest_config in pairs(user_config.contests) do
for lang_name, lang_config in pairs(contest_config) do for lang_name, lang_config in pairs(contest_config) do
if type(lang_config) == "table" and lang_config.extension then if type(lang_config) == "table" and lang_config.extension then
if not vim.tbl_contains(vim.tbl_keys(filetype_to_language), lang_config.extension) then if
not vim.tbl_contains(vim.tbl_keys(languages.filetype_to_language), lang_config.extension)
then
error( error(
("Invalid extension '%s' for language '%s' in contest '%s'. Valid extensions: %s"):format( ("Invalid extension '%s' for language '%s' in contest '%s'. Valid extensions: %s"):format(
lang_config.extension, lang_config.extension,
lang_name, lang_name,
contest_name, contest_name,
table.concat(vim.tbl_keys(filetype_to_language), ", ") table.concat(vim.tbl_keys(languages.filetype_to_language), ", ")
) )
) )
end end
@ -185,45 +112,25 @@ function M.setup(user_config)
end end
local config = vim.tbl_deep_extend("force", M.defaults, user_config or {}) local config = vim.tbl_deep_extend("force", M.defaults, user_config or {})
local default_contest = config.contests.default
for contest_name, contest_config in pairs(config.contests) do
if contest_name ~= "default" then
config.contests[contest_name] = extend_contest_config(default_contest, contest_config)
end
end
return config return config
end end
---@param contest string
---@param contest_id string ---@param contest_id string
---@param problem_id? string ---@param problem_id? string
---@param config cp.Config
---@param language? string
---@return string ---@return string
local function default_filename(contest, contest_id, problem_id, config, language) local function default_filename(contest_id, problem_id)
vim.validate({ vim.validate({
contest = { contest, "string" },
contest_id = { contest_id, "string" }, contest_id = { contest_id, "string" },
problem_id = { problem_id, { "string", "nil" }, true }, problem_id = { problem_id, { "string", "nil" }, true },
config = { config, "table" },
language = { language, { "string", "nil" }, true },
}) })
local full_problem_id = contest_id:lower()
if contest == "atcoder" or contest == "codeforces" then
if problem_id then if problem_id then
full_problem_id = full_problem_id .. problem_id:lower() return problem_id:lower()
else
return contest_id:lower()
end end
end end
local contest_config = config.contests[contest] or config.contests.default
local target_language = language or contest_config.default_language
local language_config = contest_config[target_language]
return full_problem_id .. "." .. language_config.extension
end
M.default_filename = default_filename M.default_filename = default_filename
return M return M

View file

@ -103,9 +103,9 @@ local function compile_generic(language_config, substitutions)
local compile_cmd = substitute_template(language_config.compile, substitutions) local compile_cmd = substitute_template(language_config.compile, substitutions)
logger.log(("compiling: %s"):format(table.concat(compile_cmd, " "))) logger.log(("compiling: %s"):format(table.concat(compile_cmd, " ")))
local start_time = vim.loop.hrtime() local start_time = vim.uv.hrtime()
local result = vim.system(compile_cmd, { text = true }):wait() local result = vim.system(compile_cmd, { text = true }):wait()
local compile_time = (vim.loop.hrtime() - start_time) / 1000000 local compile_time = (vim.uv.hrtime() - start_time) / 1000000
if result.code == 0 then if result.code == 0 then
logger.log(("compilation successful (%.1fms)"):format(compile_time)) logger.log(("compilation successful (%.1fms)"):format(compile_time))
@ -129,7 +129,7 @@ local function execute_command(cmd, input_data, timeout_ms)
logger.log(("executing: %s"):format(table.concat(cmd, " "))) logger.log(("executing: %s"):format(table.concat(cmd, " ")))
local start_time = vim.loop.hrtime() local start_time = vim.uv.hrtime()
local result = vim.system(cmd, { local result = vim.system(cmd, {
stdin = input_data, stdin = input_data,
@ -137,7 +137,7 @@ local function execute_command(cmd, input_data, timeout_ms)
text = true, text = true,
}):wait() }):wait()
local end_time = vim.loop.hrtime() local end_time = vim.uv.hrtime()
local execution_time = (end_time - start_time) / 1000000 local execution_time = (end_time - start_time) / 1000000
local actual_code = result.code or 0 local actual_code = result.code or 0

View file

@ -89,9 +89,9 @@ local function setup_problem(contest_id, problem_id, language)
state.test_cases = cached_test_cases state.test_cases = cached_test_cases
end end
local ctx = problem.create_context(state.platform, contest_id, problem_id, config, language) local scrape_ctx = problem.create_context(state.platform, contest_id, problem_id, config, language)
local scrape_result = scrape.scrape_problem(ctx) local scrape_result = scrape.scrape_problem(scrape_ctx)
if not scrape_result.success then if not scrape_result.success then
logger.log("scraping failed: " .. (scrape_result.error or "unknown error"), vim.log.levels.WARN) logger.log("scraping failed: " .. (scrape_result.error or "unknown error"), vim.log.levels.WARN)
@ -107,7 +107,7 @@ local function setup_problem(contest_id, problem_id, language)
end end
end end
vim.cmd.e(ctx.source_file) vim.cmd.e(scrape_ctx.source_file)
if vim.api.nvim_buf_get_lines(0, 0, -1, true)[1] == "" then if vim.api.nvim_buf_get_lines(0, 0, -1, true)[1] == "" then
local has_luasnip, luasnip = pcall(require, "luasnip") local has_luasnip, luasnip = pcall(require, "luasnip")
@ -135,13 +135,11 @@ local function setup_problem(contest_id, problem_id, language)
end end
end end
vim.api.nvim_set_option_value("winbar", "", { scope = "local" }) local ctx = problem.create_context(state.platform, state.contest_id, state.problem_id, config, language)
vim.api.nvim_set_option_value("foldlevel", 0, { scope = "local" })
vim.api.nvim_set_option_value("foldmethod", "marker", { scope = "local" })
vim.api.nvim_set_option_value("foldmarker", "{{{,}}}", { scope = "local" })
vim.api.nvim_set_option_value("foldtext", "", { scope = "local" })
vim.diagnostic.enable(false) if config.hooks and config.hooks.setup_code then
config.hooks.setup_code(ctx)
end
local source_buf = vim.api.nvim_get_current_buf() local source_buf = vim.api.nvim_get_current_buf()
local input_buf = vim.fn.bufnr(ctx.input_file, true) local input_buf = vim.fn.bufnr(ctx.input_file, true)
@ -179,16 +177,7 @@ local function run_problem()
local ctx = problem.create_context(state.platform, state.contest_id, state.problem_id, config) local ctx = problem.create_context(state.platform, state.contest_id, state.problem_id, config)
if config.hooks and config.hooks.before_run then if config.hooks and config.hooks.before_run then
config.hooks.before_run({ config.hooks.before_run(ctx)
problem_id = problem_id,
platform = state.platform,
contest_id = state.contest_id,
source_file = ctx.source_file,
input_file = ctx.input_file,
output_file = ctx.output_file,
expected_file = ctx.expected_file,
contest_config = contest_config,
})
end end
vim.schedule(function() vim.schedule(function()
@ -212,16 +201,7 @@ local function debug_problem()
local ctx = problem.create_context(state.platform, state.contest_id, state.problem_id, config) local ctx = problem.create_context(state.platform, state.contest_id, state.problem_id, config)
if config.hooks and config.hooks.before_debug then if config.hooks and config.hooks.before_debug then
config.hooks.before_debug({ config.hooks.before_debug(ctx)
problem_id = problem_id,
platform = state.platform,
contest_id = state.contest_id,
source_file = ctx.source_file,
input_file = ctx.input_file,
output_file = ctx.output_file,
expected_file = ctx.expected_file,
contest_config = contest_config,
})
end end
vim.schedule(function() vim.schedule(function()

View file

@ -8,7 +8,6 @@ M.filetype_to_language = {
cc = M.CPP, cc = M.CPP,
cxx = M.CPP, cxx = M.CPP,
cpp = M.CPP, cpp = M.CPP,
c = M.CPP,
py = M.PYTHON, py = M.PYTHON,
py3 = M.PYTHON, py3 = M.PYTHON,
} }

View file

@ -26,9 +26,30 @@ function M.create_context(contest, contest_id, problem_id, config, language)
language = { language, { "string", "nil" }, true }, language = { language, { "string", "nil" }, true },
}) })
local filename_fn = config.filename or require("cp.config").default_filename local contest_config = config.contests[contest]
local source_file = filename_fn(contest, contest_id, problem_id, config, language) if not contest_config then
local base_name = vim.fn.fnamemodify(source_file, ":t:r") error(("No contest config found for '%s'"):format(contest))
end
local target_language = language or contest_config.default_language
local language_config = contest_config[target_language]
if not language_config then
error(("No language config found for '%s' in contest '%s'"):format(target_language, contest))
end
if not language_config.extension then
error(("No extension configured for language '%s' in contest '%s'"):format(target_language, contest))
end
local base_name
if config.filename then
local source_file = config.filename(contest, contest_id, problem_id, config, language)
base_name = vim.fn.fnamemodify(source_file, ":t:r")
else
local default_filename = require("cp.config").default_filename
base_name = default_filename(contest_id, problem_id)
end
local source_file = base_name .. "." .. language_config.extension
return { return {
contest = contest, contest = contest,

View file

@ -10,6 +10,7 @@
---@field height integer ---@field height integer
local M = {} local M = {}
local languages = require("cp.languages")
function M.clearcol() function M.clearcol()
vim.api.nvim_set_option_value("number", false, { scope = "local" }) vim.api.nvim_set_option_value("number", false, { scope = "local" })
@ -78,7 +79,7 @@ function M.restore_layout(state, tile_fn)
local source_file local source_file
if source_files ~= "" then if source_files ~= "" then
local files = vim.split(source_files, "\n") local files = vim.split(source_files, "\n")
local valid_extensions = { "cc", "cpp", "cxx", "c", "py", "py3" } local valid_extensions = vim.tbl_keys(languages.filetype_to_language)
for _, file in ipairs(files) do for _, file in ipairs(files) do
local ext = vim.fn.fnamemodify(file, ":e") local ext = vim.fn.fnamemodify(file, ":e")
if vim.tbl_contains(valid_extensions, ext) then if vim.tbl_contains(valid_extensions, ext) then
@ -87,11 +88,9 @@ function M.restore_layout(state, tile_fn)
end end
end end
source_file = source_file or files[1] source_file = source_file or files[1]
else
source_file = problem_id .. ".cc"
end end
if vim.fn.filereadable(source_file) == 0 then if not source_file or vim.fn.filereadable(source_file) == 0 then
return return
end end

View file

@ -26,8 +26,10 @@ end, {
end, lang_completions) end, lang_completions)
end end
if ArgLead == "--lang" then if ArgLead:match("^%-") and not ArgLead:match("^--lang") then
return { "--lang" } return vim.tbl_filter(function(completion)
return completion:find(ArgLead, 1, true) == 1
end, { "--lang" })
end end
local args = vim.split(vim.trim(CmdLine), "%s+") local args = vim.split(vim.trim(CmdLine), "%s+")
@ -43,7 +45,6 @@ end, {
if num_args == 2 then if num_args == 2 then
local candidates = { "--lang" } local candidates = { "--lang" }
vim.list_extend(candidates, platforms)
vim.list_extend(candidates, actions) vim.list_extend(candidates, actions)
local cp = require("cp") local cp = require("cp")
local context = cp.get_current_context() local context = cp.get_current_context()
@ -56,6 +57,8 @@ end, {
table.insert(candidates, problem.id) table.insert(candidates, problem.id)
end end
end end
else
vim.list_extend(candidates, platforms)
end end
return vim.tbl_filter(function(cmd) return vim.tbl_filter(function(cmd)
return cmd:find(ArgLead, 1, true) == 1 return cmd:find(ArgLead, 1, true) == 1

View file

@ -4,6 +4,8 @@ neovim plugin for competitive programming.
https://private-user-images.githubusercontent.com/62671086/489116291-391976d1-c2f4-49e6-a79d-13ff05e9be86.mp4?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3NTc3NDQ1ODEsIm5iZiI6MTc1Nzc0NDI4MSwicGF0aCI6Ii82MjY3MTA4Ni80ODkxMTYyOTEtMzkxOTc2ZDEtYzJmNC00OWU2LWE3OWQtMTNmZjA1ZTliZTg2Lm1wND9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTA5MTMlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwOTEzVDA2MTgwMVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWI0Zjc0YmQzNWIzNGZkM2VjZjM3NGM0YmZmM2I3MmJkZGQ0YTczYjIxMTFiODc3MjQyMzY3ODc2ZTUxZDRkMzkmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.MBK5q_Zxr0gWuzfjwmSbB7P7dtWrATrT5cDOosdPRuQ https://private-user-images.githubusercontent.com/62671086/489116291-391976d1-c2f4-49e6-a79d-13ff05e9be86.mp4?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3NTc3NDQ1ODEsIm5iZiI6MTc1Nzc0NDI4MSwicGF0aCI6Ii82MjY3MTA4Ni80ODkxMTYyOTEtMzkxOTc2ZDEtYzJmNC00OWU2LWE3OWQtMTNmZjA1ZTliZTg2Lm1wND9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTA5MTMlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwOTEzVDA2MTgwMVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWI0Zjc0YmQzNWIzNGZkM2VjZjM3NGM0YmZmM2I3MmJkZGQ0YTczYjIxMTFiODc3MjQyMzY3ODc2ZTUxZDRkMzkmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.MBK5q_Zxr0gWuzfjwmSbB7P7dtWrATrT5cDOosdPRuQ
[video config](https://github.com/barrett-ruth/dots/blob/main/nvim/lua/plugins/cp.lua)
> Sample test data from [codeforces](https://codeforces.com) is scraped via [cloudscraper](https://github.com/VeNoMouS/cloudscraper). Use at your own risk. > Sample test data from [codeforces](https://codeforces.com) is scraped via [cloudscraper](https://github.com/VeNoMouS/cloudscraper). Use at your own risk.
## Features ## Features

View file

@ -30,7 +30,7 @@ def scrape(url: str) -> list[tuple[str, str]]:
lines = [div.get_text().strip() for div in divs] lines = [div.get_text().strip() for div in divs]
text = "\n".join(lines) text = "\n".join(lines)
else: else:
text = inp_pre.get_text().replace("\r", "") text = inp_pre.get_text().replace("\r", "").strip()
all_inputs.append(text) all_inputs.append(text)
for out_section in output_sections: for out_section in output_sections:
@ -41,7 +41,7 @@ def scrape(url: str) -> list[tuple[str, str]]:
lines = [div.get_text().strip() for div in divs] lines = [div.get_text().strip() for div in divs]
text = "\n".join(lines) text = "\n".join(lines)
else: else:
text = out_pre.get_text().replace("\r", "") text = out_pre.get_text().replace("\r", "").strip()
all_outputs.append(text) all_outputs.append(text)
if all_inputs and all_outputs: if all_inputs and all_outputs:

View file

@ -1,4 +1 @@
std = "vim" std = "lua51+vim"
[config]
lua52 = true