feat: flesh out language support

This commit is contained in:
Barrett Ruth 2025-09-15 11:35:22 -04:00
parent e806b23020
commit 4aa16d2858
7 changed files with 254 additions and 99 deletions

View file

@ -1,13 +1,34 @@
---@class LanguageConfig
---@field compile? string[] Compile command template
---@field run string[] Run command template
---@field debug? string[] Debug command template
---@field executable? string Executable name
---@field version? number Language version
---@field extension string File extension
---@class ContestConfig
---@field cpp LanguageConfig
---@field python LanguageConfig
---@field default_language string
---@field timeout_ms number
---@class cp.Config
---@field contests table
---@field snippets table
---@field contests table<string, ContestConfig>
---@field snippets table[]
---@field hooks table
---@field debug boolean
---@field tile? fun(source_buf: number, input_buf: number, output_buf: number)
---@field filename? fun(contest: string, problem_id: string, problem_letter?: string): string
---@field filename? fun(contest: string, contest_id: string, problem_id?: string, config: cp.Config, language?: string): string
local M = {}
local filetype_to_language = {
cc = "cpp",
c = "cpp",
py = "python",
py3 = "python",
}
---@type cp.Config
M.defaults = {
contests = {
@ -37,13 +58,16 @@ M.defaults = {
},
executable = nil,
version = 20,
extension = "cc",
},
python = {
compile = nil,
run = { "{source}" },
debug = { "{source}" },
executable = "python3",
extension = "py",
},
default_language = "cpp",
timeout_ms = 2000,
},
atcoder = {
@ -74,8 +98,8 @@ local function extend_contest_config(base_config, contest_config)
return result
end
---@param user_config table|nil
---@return table
---@param user_config cp.Config|nil
---@return cp.Config
function M.setup(user_config)
vim.validate({
user_config = { user_config, { "table", "nil" }, true },
@ -97,6 +121,20 @@ function M.setup(user_config)
before_debug = { user_config.hooks.before_debug, { "function", "nil" }, true },
})
end
if user_config.contests then
for contest_name, contest_config in pairs(user_config.contests) do
for lang_name, lang_config in pairs(contest_config) do
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
error(("Invalid extension '%s' for language '%s' in contest '%s'. Valid extensions: %s"):format(
lang_config.extension, lang_name, contest_name, table.concat(vim.tbl_keys(filetype_to_language), ", ")
))
end
end
end
end
end
end
local config = vim.tbl_deep_extend("force", M.defaults, user_config or {})
@ -111,14 +149,32 @@ function M.setup(user_config)
return config
end
local function default_filename(contest, contest_id, problem_id)
---@param contest string
---@param contest_id string
---@param problem_id? string
---@param config cp.Config
---@param language? string
---@return string
local function default_filename(contest, contest_id, problem_id, config, language)
vim.validate({
contest = { contest, "string" },
contest_id = { contest_id, "string" },
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
full_problem_id = full_problem_id .. problem_id:lower()
end
end
return full_problem_id .. ".cc"
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