diff --git a/lua/cp/cache.lua b/lua/cp/cache.lua index 7279b20..06c4c0d 100644 --- a/lua/cp/cache.lua +++ b/lua/cp/cache.lua @@ -209,30 +209,27 @@ function M.get_constraints(platform, contest_id, problem_id) end ---@param file_path string ----@return FileState? +---@return FileState|nil function M.get_file_state(file_path) - if not cache_data.file_states then - return nil - end - + M.load() + cache_data.file_states = cache_data.file_states or {} return cache_data.file_states[file_path] end ----@param file_path string +---@param path string ---@param platform string ---@param contest_id string ----@param problem_id? string -function M.set_file_state(file_path, platform, contest_id, problem_id) - if not cache_data.file_states then - cache_data.file_states = {} - end - - cache_data.file_states[file_path] = { +---@param problem_id string +---@param language string|nil +function M.set_file_state(path, platform, contest_id, problem_id, language) + M.load() + cache_data.file_states = cache_data.file_states or {} + cache_data.file_states[path] = { platform = platform, contest_id = contest_id, problem_id = problem_id, + language = language, } - M.save() end @@ -255,7 +252,7 @@ end function M.set_contest_summaries(platform, contests) cache_data[platform] = cache_data[platform] or {} for _, contest in ipairs(contests) do - cache_data[platform][contest.id] = cache_data[platform][contest] or {} + cache_data[platform][contest.id] = cache_data[platform][contest.id] or {} cache_data[platform][contest.id].display_name = contest.display_name cache_data[platform][contest.id].name = contest.name end @@ -284,4 +281,6 @@ function M.get_data_pretty() return vim.inspect(cache_data) end +M._cache = cache_data + return M diff --git a/lua/cp/commands/picker.lua b/lua/cp/commands/picker.lua index f41c9b3..a733b58 100644 --- a/lua/cp/commands/picker.lua +++ b/lua/cp/commands/picker.lua @@ -8,9 +8,9 @@ local logger = require('cp.log') function M.handle_pick_action() local config = config_module.get_config() - if not config.picker then + if not (config.ui and config.ui.picker) then logger.log( - 'No picker configured. Set picker = "{telescope,fzf-lua}" in your config.', + 'No picker configured. Set ui.picker = "{telescope,fzf-lua}" in your config.', vim.log.levels.ERROR ) return @@ -18,7 +18,8 @@ function M.handle_pick_action() local picker - if config.picker == 'telescope' then + local picker_name = config.ui.picker + if picker_name == 'telescope' then local ok = pcall(require, 'telescope') if not ok then logger.log( @@ -34,7 +35,7 @@ function M.handle_pick_action() end picker = telescope_picker - elseif config.picker == 'fzf-lua' then + elseif picker_name == 'fzf-lua' then local ok, _ = pcall(require, 'fzf-lua') if not ok then logger.log( diff --git a/lua/cp/config.lua b/lua/cp/config.lua index 738f1a6..f58c369 100644 --- a/lua/cp/config.lua +++ b/lua/cp/config.lua @@ -121,7 +121,7 @@ local function is_string_list(t) if type(t) ~= 'table' then return false end - for i, v in ipairs(t) do + for _, v in ipairs(t) do if type(v) ~= 'string' then return false end @@ -263,7 +263,6 @@ function M.setup(user_config) error('[cp.nvim] ' .. err) end - current_config = cfg return cfg end @@ -272,6 +271,7 @@ local current_config = nil function M.set_current_config(config) current_config = config end + function M.get_config() return current_config or M.defaults end diff --git a/lua/cp/init.lua b/lua/cp/init.lua index a6f70a1..88467ee 100644 --- a/lua/cp/init.lua +++ b/lua/cp/init.lua @@ -4,14 +4,15 @@ local config_module = require('cp.config') local logger = require('cp.log') local snippets = require('cp.snippets') -if not vim.fn.has('nvim-0.10.0') then +if vim.fn.has('nvim-0.10.0') == 0 then logger.log('Requires nvim-0.10.0+', vim.log.levels.ERROR) return {} end local user_config = {} -local config = config_module.setup(user_config) +local config = nil local snippets_initialized = false +local initialized = false --- Root handler for all `:CP ...` commands ---@return nil @@ -30,10 +31,11 @@ function M.setup(opts) snippets.setup(config) snippets_initialized = true end + initialized = true end function M.is_initialized() - return true + return initialized end return M diff --git a/lua/cp/pickers/init.lua b/lua/cp/pickers/init.lua index 2659027..c634c64 100644 --- a/lua/cp/pickers/init.lua +++ b/lua/cp/pickers/init.lua @@ -1,7 +1,6 @@ local M = {} local cache = require('cp.cache') -local config = require('cp.config').get_config() local constants = require('cp.constants') local logger = require('cp.log') local scraper = require('cp.scraper') @@ -22,8 +21,8 @@ local scraper = require('cp.scraper') ---@return cp.PlatformItem[] function M.get_platforms() + local config = require('cp.config').get_config() local result = {} - for _, platform in ipairs(constants.PLATFORMS) do if config.platforms[platform] then table.insert(result, { @@ -32,7 +31,6 @@ function M.get_platforms() }) end end - return result end diff --git a/lua/cp/restore.lua b/lua/cp/restore.lua index ba2f075..875e733 100644 --- a/lua/cp/restore.lua +++ b/lua/cp/restore.lua @@ -4,29 +4,27 @@ local cache = require('cp.cache') local logger = require('cp.log') local state = require('cp.state') +---@return boolean function M.restore_from_current_file() cache.load() - local current_file = vim.fn.expand('%:p') + local current_file = (vim.uv.fs_realpath(vim.fn.expand('%:p')) or vim.fn.expand('%:p')) local file_state = cache.get_file_state(current_file) - if current_file or not file_state then + if not file_state then logger.log('No cached state found for current file.', vim.log.levels.ERROR) return false end - logger.log( - ('Restoring from cached state: %s %s %s'):format( - file_state.platform, - file_state.contest_id, - file_state.problem_id - ) - ) - local setup = require('cp.setup') - local _ = setup.set_platform(file_state.platform) + setup.set_platform(file_state.platform) state.set_contest_id(file_state.contest_id) state.set_problem_id(file_state.problem_id) - setup.setup_contest(file_state.platform, file_state.contest_id, file_state.problem_id) + setup.setup_contest( + file_state.platform, + file_state.contest_id, + file_state.problem_id, + file_state.language + ) return true end diff --git a/lua/cp/runner/execute.lua b/lua/cp/runner/execute.lua index ffd428a..bfe0178 100644 --- a/lua/cp/runner/execute.lua +++ b/lua/cp/runner/execute.lua @@ -33,12 +33,8 @@ local function substitute_template(cmd_template, substitutions) return out end -function M.build_command(cmd_template, executable, substitutions) - local cmd = substitute_template(cmd_template, substitutions) - if executable then - table.insert(cmd, 1, executable) - end - return cmd +function M.build_command(cmd_template, substitutions) + return substitute_template(cmd_template, substitutions) end ---@param compile_cmd string[] @@ -166,11 +162,12 @@ end function M.compile_problem() local state = require('cp.state') - local config = require('cp.config').get_config() local platform = state.get_platform() or '' local language = config.platforms[platform].default_language - local compile_config = config.platforms[platform][language].compile + local eff = config.runtime.effective[platform][language] + local compile_config = eff and eff.commands and eff.commands.build + if not compile_config then return { success = true, output = nil } end diff --git a/lua/cp/runner/run.lua b/lua/cp/runner/run.lua index 21d0d55..16ae696 100644 --- a/lua/cp/runner/run.lua +++ b/lua/cp/runner/run.lua @@ -94,10 +94,9 @@ local function create_sentinal_panel_data(test_cases) end ---@param cmd string[] ----@param executable string ---@return string[] -local function build_command(cmd, executable, substitutions) - return execute.build_command(cmd, executable, substitutions) +local function build_command(cmd, substitutions) + return execute.build_command(cmd, substitutions) end ---@param test_case RanTestCase @@ -109,8 +108,10 @@ local function run_single_test_case(test_case) local substitutions = { source = source_file, binary = binary_file } local platform_config = config.platforms[state.get_platform() or ''] - local language_config = platform_config[platform_config.default_language] - local cmd = build_command(language_config.test, language_config.executable, substitutions) + local language = platform_config.default_language + local eff = config.runtime.effective[state.get_platform() or ''][language] + local run_template = eff and eff.commands and eff.commands.run or {} + local cmd = build_command(run_template, substitutions) local stdin_content = (test_case.input or '') .. '\n' local timeout_ms = (run_panel_state.constraints and run_panel_state.constraints.timeout_ms) or 0 local memory_mb = run_panel_state.constraints and run_panel_state.constraints.memory_mb or 0 @@ -121,7 +122,7 @@ local function run_single_test_case(test_case) local out = r.stdout or '' local highlights = {} if out ~= '' then - if config.run_panel.ansi then + if config.ui.run_panel.ansi then local parsed = ansi.parse_ansi_text(out) out = table.concat(parsed.lines, '\n') highlights = parsed.highlights @@ -130,7 +131,7 @@ local function run_single_test_case(test_case) end end - local max_lines = config.run_panel.max_output_lines + local max_lines = config.ui.run_panel.max_output_lines local lines = vim.split(out, '\n') if #lines > max_lines then local trimmed = {} @@ -246,7 +247,7 @@ function M.handle_compilation_failure(output) local txt local hl = {} - if config.run_panel.ansi then + if config.ui.run_panel.ansi then local p = ansi.parse_ansi_text(output or '') txt = table.concat(p.lines, '\n') hl = p.highlights diff --git a/lua/cp/setup.lua b/lua/cp/setup.lua index fa6b8b0..0e7c8f4 100644 --- a/lua/cp/setup.lua +++ b/lua/cp/setup.lua @@ -1,4 +1,3 @@ --- lua/cp/setup.lua local M = {} local cache = require('cp.cache') @@ -40,14 +39,15 @@ end ---@param platform string ---@param contest_id string ---@param problem_id string|nil -function M.setup_contest(platform, contest_id, problem_id) +---@param language? string|nil +function M.setup_contest(platform, contest_id, problem_id, language) state.set_contest_id(contest_id) cache.load() local function proceed(contest_data) local problems = contest_data.problems local pid = problems[(problem_id and contest_data.index_map[problem_id] or 1)].id - M.setup_problem(pid) + M.setup_problem(pid, language) local cached_len = #vim.tbl_filter(function(p) return not vim.tbl_isempty(cache.get_test_cases(platform, contest_id, p.id)) @@ -89,7 +89,8 @@ function M.setup_contest(platform, contest_id, problem_id) end ---@param problem_id string -function M.setup_problem(problem_id) +---@param language? string +function M.setup_problem(problem_id, language) local platform = state.get_platform() if not platform then logger.log('No platform set.', vim.log.levels.ERROR) @@ -103,17 +104,17 @@ function M.setup_problem(problem_id) vim.schedule(function() vim.cmd.only({ mods = { silent = true } }) - local language = config.platforms[platform].default_language - local source_file = state.get_source_file(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 has_luasnip, luasnip = pcall(require, 'luasnip') - if has_luasnip then - local prefixed_trigger = ('cp.nvim/%s.%s'):format(platform, language) - vim.api.nvim_buf_set_lines(0, 0, -1, false, { prefixed_trigger }) - vim.api.nvim_win_set_cursor(0, { 1, #prefixed_trigger }) + 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 @@ -135,7 +136,8 @@ function M.setup_problem(problem_id) vim.fn.expand('%:p'), platform, state.get_contest_id() or '', - state.get_problem_id() + state.get_problem_id() or '', + lang ) end) end diff --git a/lua/cp/state.lua b/lua/cp/state.lua index a99de8f..c90396c 100644 --- a/lua/cp/state.lua +++ b/lua/cp/state.lua @@ -72,18 +72,18 @@ function M.get_source_file(language) end local config = require('cp.config').get_config() - local contest_config = config.platforms[M.get_platform()] - if not contest_config then + local plat = M.get_platform() + local platform_cfg = config.platforms[plat] + if not platform_cfg then return nil end - - local target_language = language or contest_config.default_language - local language_config = contest_config[target_language] - if not language_config or not language_config.extension then + local target_language = language or platform_cfg.default_language + local eff = config.runtime.effective[plat] and config.runtime.effective[plat][target_language] + or nil + if not eff or not eff.extension then return nil end - - return base_name .. '.' .. language_config.extension + return base_name .. '.' .. eff.extension end function M.get_binary_file() diff --git a/lua/cp/ui/layouts.lua b/lua/cp/ui/layouts.lua index 3d12a21..c2613a5 100644 --- a/lua/cp/ui/layouts.lua +++ b/lua/cp/ui/layouts.lua @@ -185,7 +185,7 @@ function M.update_diff_panes( actual_content = actual_content end - local desired_mode = is_compilation_failure and 'single' or config.run_panel.diff_mode + local desired_mode = is_compilation_failure and 'single' or config.ui.run_panel.diff_mode local highlight = require('cp.ui.highlight') local diff_namespace = highlight.create_namespace() local ansi_namespace = vim.api.nvim_create_namespace('cp_ansi_highlights') diff --git a/lua/cp/ui/panel.lua b/lua/cp/ui/panel.lua index 7b7ee6a..4467f0e 100644 --- a/lua/cp/ui/panel.lua +++ b/lua/cp/ui/panel.lua @@ -263,13 +263,13 @@ function M.toggle_run_panel(debug) local modes = { 'none', 'git', 'vim' } local current_idx = nil for i, mode in ipairs(modes) do - if config.run_panel.diff_mode == mode then + if config.ui.run_panel.diff_mode == mode then current_idx = i break end end current_idx = current_idx or 1 - config.run_panel.diff_mode = modes[(current_idx % #modes) + 1] + config.ui.run_panel.diff_mode = modes[(current_idx % #modes) + 1] refresh_run_panel() end, { buffer = buf, silent = true }) vim.keymap.set('n', '', function() @@ -293,7 +293,7 @@ function M.toggle_run_panel(debug) refresh_run_panel() vim.schedule(function() - if config.run_panel.ansi then + if config.ui.run_panel.ansi then local ansi = require('cp.ui.ansi') ansi.setup_highlight_groups() end