feat(cache): cache clearing, updating and resetting
This commit is contained in:
parent
a40a53fafa
commit
78fb4f8f4b
10 changed files with 111 additions and 114 deletions
|
|
@ -62,7 +62,3 @@ See [my config](https://github.com/barrett-ruth/dots/blob/main/nvim/lua/plugins/
|
||||||
|
|
||||||
- [competitest.nvim](https://github.com/xeluxee/competitest.nvim)
|
- [competitest.nvim](https://github.com/xeluxee/competitest.nvim)
|
||||||
- [assistant.nvim](https://github.com/A7Lavinraj/assistant.nvim)
|
- [assistant.nvim](https://github.com/A7Lavinraj/assistant.nvim)
|
||||||
|
|
||||||
## TODO
|
|
||||||
|
|
||||||
- Windows support
|
|
||||||
|
|
|
||||||
|
|
@ -342,4 +342,24 @@ function M.clear_contest_list(platform)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function M.clear_all()
|
||||||
|
cache_data = {}
|
||||||
|
M.save()
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param platform string
|
||||||
|
function M.clear_platform(platform)
|
||||||
|
vim.validate({
|
||||||
|
platform = { platform, 'string' },
|
||||||
|
})
|
||||||
|
|
||||||
|
if cache_data[platform] then
|
||||||
|
cache_data[platform] = nil
|
||||||
|
end
|
||||||
|
if cache_data.contest_lists and cache_data.contest_lists[platform] then
|
||||||
|
cache_data.contest_lists[platform] = nil
|
||||||
|
end
|
||||||
|
M.save()
|
||||||
|
end
|
||||||
|
|
||||||
return M
|
return M
|
||||||
|
|
|
||||||
|
|
@ -101,7 +101,7 @@ M.defaults = {
|
||||||
filename = nil,
|
filename = nil,
|
||||||
run_panel = {
|
run_panel = {
|
||||||
ansi = true,
|
ansi = true,
|
||||||
diff_mode = 'vim',
|
diff_mode = 'git',
|
||||||
next_test_key = '<c-n>',
|
next_test_key = '<c-n>',
|
||||||
prev_test_key = '<c-p>',
|
prev_test_key = '<c-p>',
|
||||||
toggle_diff_key = 't',
|
toggle_diff_key = 't',
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
local M = {}
|
local M = {}
|
||||||
|
|
||||||
M.PLATFORMS = { 'atcoder', 'codeforces', 'cses' }
|
M.PLATFORMS = { 'atcoder', 'codeforces', 'cses' }
|
||||||
M.ACTIONS = { 'run', 'next', 'prev', 'pick' }
|
M.ACTIONS = { 'run', 'next', 'prev', 'pick', 'cache' }
|
||||||
|
|
||||||
M.PLATFORM_DISPLAY_NAMES = {
|
M.PLATFORM_DISPLAY_NAMES = {
|
||||||
atcoder = 'AtCoder',
|
atcoder = 'AtCoder',
|
||||||
|
|
|
||||||
|
|
@ -294,6 +294,7 @@ local function toggle_run_panel(is_debug)
|
||||||
|
|
||||||
vim.api.nvim_set_current_win(parent_win)
|
vim.api.nvim_set_current_win(parent_win)
|
||||||
vim.cmd.split()
|
vim.cmd.split()
|
||||||
|
vim.cmd('resize ' .. math.floor(vim.o.lines * 0.35))
|
||||||
local actual_win = vim.api.nvim_get_current_win()
|
local actual_win = vim.api.nvim_get_current_win()
|
||||||
vim.api.nvim_win_set_buf(actual_win, actual_buf)
|
vim.api.nvim_win_set_buf(actual_win, actual_buf)
|
||||||
|
|
||||||
|
|
@ -341,6 +342,7 @@ local function toggle_run_panel(is_debug)
|
||||||
|
|
||||||
vim.api.nvim_set_current_win(parent_win)
|
vim.api.nvim_set_current_win(parent_win)
|
||||||
vim.cmd.split()
|
vim.cmd.split()
|
||||||
|
vim.cmd('resize ' .. math.floor(vim.o.lines * 0.35))
|
||||||
local diff_win = vim.api.nvim_get_current_win()
|
local diff_win = vim.api.nvim_get_current_win()
|
||||||
vim.api.nvim_win_set_buf(diff_win, diff_buf)
|
vim.api.nvim_win_set_buf(diff_win, diff_buf)
|
||||||
|
|
||||||
|
|
@ -375,6 +377,7 @@ local function toggle_run_panel(is_debug)
|
||||||
|
|
||||||
vim.api.nvim_set_current_win(parent_win)
|
vim.api.nvim_set_current_win(parent_win)
|
||||||
vim.cmd.split()
|
vim.cmd.split()
|
||||||
|
vim.cmd('resize ' .. math.floor(vim.o.lines * 0.35))
|
||||||
local win = vim.api.nvim_get_current_win()
|
local win = vim.api.nvim_get_current_win()
|
||||||
vim.api.nvim_win_set_buf(win, buf)
|
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', 'cptest', { buf = buf })
|
||||||
|
|
@ -600,7 +603,7 @@ local function toggle_run_panel(is_debug)
|
||||||
state.test_buffers = test_buffers
|
state.test_buffers = test_buffers
|
||||||
state.test_windows = test_windows
|
state.test_windows = test_windows
|
||||||
local test_state = run.get_run_panel_state()
|
local test_state = run.get_run_panel_state()
|
||||||
logger.log(string.format('test panel opened (%d test cases)', #test_state.test_cases))
|
logger.log(string.format('test panel opened (%d test cases)', #test_state.test_cases), vim.log.levels.INFO)
|
||||||
end
|
end
|
||||||
|
|
||||||
---@param contest_id string
|
---@param contest_id string
|
||||||
|
|
@ -751,6 +754,26 @@ local function handle_pick_action()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function handle_cache_command(cmd)
|
||||||
|
if cmd.subcommand == 'clear' then
|
||||||
|
cache.load()
|
||||||
|
if cmd.platform then
|
||||||
|
if vim.tbl_contains(platforms, cmd.platform) then
|
||||||
|
cache.clear_platform(cmd.platform)
|
||||||
|
logger.log(('cleared cache for %s'):format(cmd.platform), vim.log.levels.INFO, true)
|
||||||
|
else
|
||||||
|
logger.log(
|
||||||
|
('unknown platform: %s. Available: %s'):format(cmd.platform, table.concat(platforms, ', ')),
|
||||||
|
vim.log.levels.ERROR
|
||||||
|
)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
cache.clear_all()
|
||||||
|
logger.log('cleared all cache', vim.log.levels.INFO, true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local function restore_from_current_file()
|
local function restore_from_current_file()
|
||||||
local current_file = vim.fn.expand('%:p')
|
local current_file = vim.fn.expand('%:p')
|
||||||
if current_file == '' then
|
if current_file == '' then
|
||||||
|
|
@ -820,7 +843,24 @@ local function parse_command(args)
|
||||||
local first = filtered_args[1]
|
local first = filtered_args[1]
|
||||||
|
|
||||||
if vim.tbl_contains(actions, first) then
|
if vim.tbl_contains(actions, first) then
|
||||||
return { type = 'action', action = first, language = language, debug = debug }
|
if first == 'cache' then
|
||||||
|
local subcommand = filtered_args[2]
|
||||||
|
if not subcommand then
|
||||||
|
return { type = 'error', message = 'cache command requires subcommand: clear' }
|
||||||
|
end
|
||||||
|
if subcommand == 'clear' then
|
||||||
|
local platform = filtered_args[3]
|
||||||
|
return {
|
||||||
|
type = 'cache',
|
||||||
|
subcommand = 'clear',
|
||||||
|
platform = platform
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return { type = 'error', message = 'unknown cache subcommand: ' .. subcommand }
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return { type = 'action', action = first, language = language, debug = debug }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if vim.tbl_contains(platforms, first) then
|
if vim.tbl_contains(platforms, first) then
|
||||||
|
|
@ -896,6 +936,11 @@ function M.handle_command(opts)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if cmd.type == 'cache' then
|
||||||
|
handle_cache_command(cmd)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
if cmd.type == 'platform_only' then
|
if cmd.type == 'platform_only' then
|
||||||
set_platform(cmd.platform)
|
set_platform(cmd.platform)
|
||||||
return
|
return
|
||||||
|
|
@ -929,7 +974,9 @@ function M.handle_command(opts)
|
||||||
#metadata_result.problems,
|
#metadata_result.problems,
|
||||||
cmd.platform,
|
cmd.platform,
|
||||||
cmd.contest
|
cmd.contest
|
||||||
)
|
),
|
||||||
|
vim.log.levels.INFO,
|
||||||
|
true
|
||||||
)
|
)
|
||||||
problem_ids = vim.tbl_map(function(prob)
|
problem_ids = vim.tbl_map(function(prob)
|
||||||
return prob.id
|
return prob.id
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ function M.compile_generic(language_config, substitutions)
|
||||||
result.stderr = ansi.bytes_to_string(result.stderr or '')
|
result.stderr = ansi.bytes_to_string(result.stderr or '')
|
||||||
|
|
||||||
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), vim.log.levels.INFO)
|
||||||
else
|
else
|
||||||
logger.log(('compilation failed (%.1fms)'):format(compile_time))
|
logger.log(('compilation failed (%.1fms)'):format(compile_time))
|
||||||
end
|
end
|
||||||
|
|
@ -235,7 +235,7 @@ function M.compile_problem(ctx, contest_config, is_debug)
|
||||||
if compile_result.code ~= 0 then
|
if compile_result.code ~= 0 then
|
||||||
return { success = false, output = compile_result.stdout or 'unknown error' }
|
return { success = false, output = compile_result.stdout or 'unknown error' }
|
||||||
end
|
end
|
||||||
logger.log(('compilation successful (%s)'):format(is_debug and 'debug mode' or 'test mode'))
|
logger.log(('compilation successful (%s)'):format(is_debug and 'debug mode' or 'test mode'), vim.log.levels.INFO)
|
||||||
end
|
end
|
||||||
|
|
||||||
return { success = true, output = nil }
|
return { success = true, output = nil }
|
||||||
|
|
|
||||||
|
|
@ -315,7 +315,7 @@ function M.load_test_cases(ctx, state)
|
||||||
run_panel_state.constraints.memory_mb
|
run_panel_state.constraints.memory_mb
|
||||||
)
|
)
|
||||||
or ''
|
or ''
|
||||||
logger.log(('loaded %d test case(s)%s'):format(#test_cases, constraint_info))
|
logger.log(('loaded %d test case(s)%s'):format(#test_cases, constraint_info), vim.log.levels.INFO)
|
||||||
return #test_cases > 0
|
return #test_cases > 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -272,74 +272,8 @@ def scrape_contests() -> list[ContestSummary]:
|
||||||
r"[\uff01-\uff5e]", lambda m: chr(ord(m.group()) - 0xFEE0), name
|
r"[\uff01-\uff5e]", lambda m: chr(ord(m.group()) - 0xFEE0), name
|
||||||
)
|
)
|
||||||
|
|
||||||
def generate_display_name_from_id(contest_id: str) -> str:
|
|
||||||
parts = contest_id.replace("-", " ").replace("_", " ")
|
|
||||||
|
|
||||||
parts = re.sub(
|
|
||||||
r"\b(jsc|JSC)\b",
|
|
||||||
"Japanese Student Championship",
|
|
||||||
parts,
|
|
||||||
flags=re.IGNORECASE,
|
|
||||||
)
|
|
||||||
parts = re.sub(
|
|
||||||
r"\b(wtf|WTF)\b",
|
|
||||||
"World Tour Finals",
|
|
||||||
parts,
|
|
||||||
flags=re.IGNORECASE,
|
|
||||||
)
|
|
||||||
parts = re.sub(
|
|
||||||
r"\b(ahc)(\d+)\b",
|
|
||||||
r"Heuristic Contest \2 (AHC)",
|
|
||||||
parts,
|
|
||||||
flags=re.IGNORECASE,
|
|
||||||
)
|
|
||||||
parts = re.sub(
|
|
||||||
r"\b(arc)(\d+)\b",
|
|
||||||
r"Regular Contest \2 (ARC)",
|
|
||||||
parts,
|
|
||||||
flags=re.IGNORECASE,
|
|
||||||
)
|
|
||||||
parts = re.sub(
|
|
||||||
r"\b(abc)(\d+)\b",
|
|
||||||
r"Beginner Contest \2 (ABC)",
|
|
||||||
parts,
|
|
||||||
flags=re.IGNORECASE,
|
|
||||||
)
|
|
||||||
parts = re.sub(
|
|
||||||
r"\b(agc)(\d+)\b",
|
|
||||||
r"Grand Contest \2 (AGC)",
|
|
||||||
parts,
|
|
||||||
flags=re.IGNORECASE,
|
|
||||||
)
|
|
||||||
|
|
||||||
return parts.title()
|
|
||||||
|
|
||||||
english_chars = sum(1 for c in name if c.isascii() and c.isalpha())
|
|
||||||
total_chars = len(re.sub(r"\s+", "", name))
|
|
||||||
|
|
||||||
if total_chars > 0 and english_chars / total_chars < 0.3:
|
|
||||||
display_name = generate_display_name_from_id(contest_id)
|
|
||||||
else:
|
|
||||||
display_name = name
|
|
||||||
if "AtCoder Beginner Contest" in name:
|
|
||||||
match = re.search(r"AtCoder Beginner Contest (\d+)", name)
|
|
||||||
if match:
|
|
||||||
display_name = f"Beginner Contest {match.group(1)} (ABC)"
|
|
||||||
elif "AtCoder Regular Contest" in name:
|
|
||||||
match = re.search(r"AtCoder Regular Contest (\d+)", name)
|
|
||||||
if match:
|
|
||||||
display_name = f"Regular Contest {match.group(1)} (ARC)"
|
|
||||||
elif "AtCoder Grand Contest" in name:
|
|
||||||
match = re.search(r"AtCoder Grand Contest (\d+)", name)
|
|
||||||
if match:
|
|
||||||
display_name = f"Grand Contest {match.group(1)} (AGC)"
|
|
||||||
elif "AtCoder Heuristic Contest" in name:
|
|
||||||
match = re.search(r"AtCoder Heuristic Contest (\d+)", name)
|
|
||||||
if match:
|
|
||||||
display_name = f"Heuristic Contest {match.group(1)} (AHC)"
|
|
||||||
|
|
||||||
contests.append(
|
contests.append(
|
||||||
ContestSummary(id=contest_id, name=name, display_name=display_name)
|
ContestSummary(id=contest_id, name=name, display_name=name)
|
||||||
)
|
)
|
||||||
|
|
||||||
return contests
|
return contests
|
||||||
|
|
|
||||||
|
|
@ -237,42 +237,8 @@ def scrape_contests() -> list[ContestSummary]:
|
||||||
contest_id = str(contest["id"])
|
contest_id = str(contest["id"])
|
||||||
name = contest["name"]
|
name = contest["name"]
|
||||||
|
|
||||||
display_name = name
|
|
||||||
if "Educational Codeforces Round" in name:
|
|
||||||
match = re.search(r"Educational Codeforces Round (\d+)", name)
|
|
||||||
if match:
|
|
||||||
display_name = f"Educational Round {match.group(1)}"
|
|
||||||
elif "Codeforces Global Round" in name:
|
|
||||||
match = re.search(r"Codeforces Global Round (\d+)", name)
|
|
||||||
if match:
|
|
||||||
display_name = f"Global Round {match.group(1)}"
|
|
||||||
elif "Codeforces Round" in name:
|
|
||||||
div_match = re.search(r"Codeforces Round (\d+) \(Div\. (\d+)\)", name)
|
|
||||||
if div_match:
|
|
||||||
display_name = (
|
|
||||||
f"Round {div_match.group(1)} (Div. {div_match.group(2)})"
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
combined_match = re.search(
|
|
||||||
r"Codeforces Round (\d+) \(Div\. 1 \+ Div\. 2\)", name
|
|
||||||
)
|
|
||||||
if combined_match:
|
|
||||||
display_name = (
|
|
||||||
f"Round {combined_match.group(1)} (Div. 1 + Div. 2)"
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
single_div_match = re.search(
|
|
||||||
r"Codeforces Round (\d+) \(Div\. 1\)", name
|
|
||||||
)
|
|
||||||
if single_div_match:
|
|
||||||
display_name = f"Round {single_div_match.group(1)} (Div. 1)"
|
|
||||||
else:
|
|
||||||
round_match = re.search(r"Codeforces Round (\d+)", name)
|
|
||||||
if round_match:
|
|
||||||
display_name = f"Round {round_match.group(1)}"
|
|
||||||
|
|
||||||
contests.append(
|
contests.append(
|
||||||
ContestSummary(id=contest_id, name=name, display_name=display_name)
|
ContestSummary(id=contest_id, name=name, display_name=name)
|
||||||
)
|
)
|
||||||
|
|
||||||
return contests
|
return contests
|
||||||
|
|
|
||||||
|
|
@ -156,4 +156,38 @@ describe('cp.cache', function()
|
||||||
assert.equals('python', result.language)
|
assert.equals('python', result.language)
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
describe('cache management', function()
|
||||||
|
it('clears all cache data', function()
|
||||||
|
cache.set_contest_data('atcoder', 'test_contest', { { id = 'A' } })
|
||||||
|
cache.set_contest_data('codeforces', 'test_contest', { { id = 'B' } })
|
||||||
|
cache.set_file_state('/tmp/test.cpp', 'atcoder', 'abc123', 'a', 'cpp')
|
||||||
|
|
||||||
|
cache.clear_all()
|
||||||
|
|
||||||
|
assert.is_nil(cache.get_contest_data('atcoder', 'test_contest'))
|
||||||
|
assert.is_nil(cache.get_contest_data('codeforces', 'test_contest'))
|
||||||
|
assert.is_nil(cache.get_file_state('/tmp/test.cpp'))
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('clears cache for specific platform', function()
|
||||||
|
cache.set_contest_data('atcoder', 'test_contest', { { id = 'A' } })
|
||||||
|
cache.set_contest_data('codeforces', 'test_contest', { { id = 'B' } })
|
||||||
|
cache.set_contest_list('atcoder', { { id = '123', name = 'Test' } })
|
||||||
|
cache.set_contest_list('codeforces', { { id = '456', name = 'Test' } })
|
||||||
|
|
||||||
|
cache.clear_platform('atcoder')
|
||||||
|
|
||||||
|
assert.is_nil(cache.get_contest_data('atcoder', 'test_contest'))
|
||||||
|
assert.is_nil(cache.get_contest_list('atcoder'))
|
||||||
|
assert.is_not_nil(cache.get_contest_data('codeforces', 'test_contest'))
|
||||||
|
assert.is_not_nil(cache.get_contest_list('codeforces'))
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('handles clear platform for non-existent platform', function()
|
||||||
|
assert.has_no_errors(function()
|
||||||
|
cache.clear_platform('nonexistent')
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue