Merge pull request #218 from barrettruth/fix/scraper-refactor
misc tweaks
This commit is contained in:
commit
6ba51a92c2
6 changed files with 102 additions and 34 deletions
|
|
@ -258,7 +258,7 @@ Here's an example configuration with lazy.nvim:
|
||||||
prev_test_key = '<c-p>', -- or nil to disable
|
prev_test_key = '<c-p>', -- or nil to disable
|
||||||
},
|
},
|
||||||
panel = {
|
panel = {
|
||||||
diff_mode = 'vim',
|
diff_modes = { 'side-by-side', 'git', 'vim' },
|
||||||
max_output_lines = 50,
|
max_output_lines = 50,
|
||||||
},
|
},
|
||||||
diff = {
|
diff = {
|
||||||
|
|
@ -378,8 +378,10 @@ run CSES problems with Rust using the single schema:
|
||||||
|
|
||||||
*cp.PanelConfig*
|
*cp.PanelConfig*
|
||||||
Fields: ~
|
Fields: ~
|
||||||
{diff_mode} (string, default: "none") Diff backend: "none",
|
{diff_modes} (string[], default: {'side-by-side', 'git', 'vim'})
|
||||||
"vim", or "git".
|
List of diff modes to cycle through with 't' key.
|
||||||
|
First element is the default mode.
|
||||||
|
Valid modes: 'side-by-side', 'git', 'vim'.
|
||||||
{max_output_lines} (number, default: 50) Maximum lines of test output.
|
{max_output_lines} (number, default: 50) Maximum lines of test output.
|
||||||
|
|
||||||
*cp.DiffConfig*
|
*cp.DiffConfig*
|
||||||
|
|
@ -851,17 +853,20 @@ PANEL KEYMAPS *cp-panel-keys*
|
||||||
|
|
||||||
<c-n> Navigate to next test case
|
<c-n> Navigate to next test case
|
||||||
<c-p> Navigate to previous test case
|
<c-p> Navigate to previous test case
|
||||||
t Cycle through diff modes: none → git → vim
|
t Cycle through configured diff modes (see |cp.PanelConfig|)
|
||||||
q Exit panel and restore layout
|
q Exit panel and restore layout
|
||||||
<c-q> Exit interactive terminal and restore layout
|
<c-q> Exit interactive terminal and restore layout
|
||||||
|
|
||||||
Diff Modes ~
|
Diff Modes ~
|
||||||
|
|
||||||
Three diff backends are available:
|
Three diff modes are available:
|
||||||
|
|
||||||
none Nothing
|
side-by-side Expected and actual output shown side-by-side (default)
|
||||||
vim Built-in vim diff (default, always available)
|
vim Built-in vim diff (always available)
|
||||||
git Character-level git word-diff (requires git, more precise)
|
git Character-level git word-diff (requires git, more precise)
|
||||||
|
|
||||||
|
Configure which modes to cycle through via |cp.PanelConfig|.diff_modes.
|
||||||
|
The first element is used as the default mode.
|
||||||
|
|
||||||
The git backend shows character-level changes with [-removed-] and {+added+}
|
The git backend shows character-level changes with [-removed-] and {+added+}
|
||||||
markers.
|
markers.
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
---@field overrides? table<string, CpPlatformOverrides>
|
---@field overrides? table<string, CpPlatformOverrides>
|
||||||
|
|
||||||
---@class PanelConfig
|
---@class PanelConfig
|
||||||
---@field diff_mode "none"|"vim"|"git"
|
---@field diff_modes string[]
|
||||||
---@field max_output_lines integer
|
---@field max_output_lines integer
|
||||||
|
|
||||||
---@class DiffGitConfig
|
---@class DiffGitConfig
|
||||||
|
|
@ -173,7 +173,7 @@ M.defaults = {
|
||||||
add_test_key = 'ga',
|
add_test_key = 'ga',
|
||||||
save_and_exit_key = 'q',
|
save_and_exit_key = 'q',
|
||||||
},
|
},
|
||||||
panel = { diff_mode = 'none', max_output_lines = 50 },
|
panel = { diff_modes = { 'side-by-side', 'git', 'vim' }, max_output_lines = 50 },
|
||||||
diff = {
|
diff = {
|
||||||
git = {
|
git = {
|
||||||
args = { 'diff', '--no-index', '--word-diff=plain', '--word-diff-regex=.', '--no-prefix' },
|
args = { 'diff', '--no-index', '--word-diff=plain', '--word-diff-regex=.', '--no-prefix' },
|
||||||
|
|
@ -313,15 +313,26 @@ function M.setup(user_config)
|
||||||
setup_io_output = { cfg.hooks.setup_io_output, { 'function', 'nil' }, true },
|
setup_io_output = { cfg.hooks.setup_io_output, { 'function', 'nil' }, true },
|
||||||
})
|
})
|
||||||
|
|
||||||
|
local layouts = require('cp.ui.layouts')
|
||||||
|
local valid_modes_str = table.concat(vim.tbl_keys(layouts.DIFF_MODES), ',')
|
||||||
|
if type(cfg.ui.panel.diff_modes) == 'table' then
|
||||||
|
local invalid = {}
|
||||||
|
for _, mode in ipairs(cfg.ui.panel.diff_modes) do
|
||||||
|
if not layouts.DIFF_MODES[mode] then
|
||||||
|
table.insert(invalid, mode)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if #invalid > 0 then
|
||||||
|
error(
|
||||||
|
('invalid diff modes [%s] - must be one of: {%s}'):format(
|
||||||
|
table.concat(invalid, ','),
|
||||||
|
valid_modes_str
|
||||||
|
)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
vim.validate({
|
vim.validate({
|
||||||
ansi = { cfg.ui.ansi, 'boolean' },
|
ansi = { cfg.ui.ansi, 'boolean' },
|
||||||
diff_mode = {
|
|
||||||
cfg.ui.panel.diff_mode,
|
|
||||||
function(v)
|
|
||||||
return vim.tbl_contains({ 'none', 'vim', 'git' }, v)
|
|
||||||
end,
|
|
||||||
"diff_mode must be 'none', 'vim', or 'git'",
|
|
||||||
},
|
|
||||||
max_output_lines = {
|
max_output_lines = {
|
||||||
cfg.ui.panel.max_output_lines,
|
cfg.ui.panel.max_output_lines,
|
||||||
function(v)
|
function(v)
|
||||||
|
|
@ -383,6 +394,13 @@ function M.setup(user_config)
|
||||||
end,
|
end,
|
||||||
'nil or non-empty string',
|
'nil or non-empty string',
|
||||||
},
|
},
|
||||||
|
picker = {
|
||||||
|
cfg.ui.picker,
|
||||||
|
function(v)
|
||||||
|
return v == nil or v == 'telescope' or v == 'fzf-lua'
|
||||||
|
end,
|
||||||
|
"nil, 'telescope', or 'fzf-lua'",
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
for id, lang in pairs(cfg.languages) do
|
for id, lang in pairs(cfg.languages) do
|
||||||
|
|
@ -443,7 +461,18 @@ function M.get_language_for_platform(platform_id, language_id)
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
local effective = cfg.runtime.effective[platform_id][language_id]
|
local platform_effective = cfg.runtime.effective[platform_id]
|
||||||
|
if not platform_effective then
|
||||||
|
return {
|
||||||
|
valid = false,
|
||||||
|
error = string.format(
|
||||||
|
'No runtime config for platform %s (plugin not initialized)',
|
||||||
|
platform_id
|
||||||
|
),
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local effective = platform_effective[language_id]
|
||||||
if not effective then
|
if not effective then
|
||||||
return {
|
return {
|
||||||
valid = false,
|
valid = false,
|
||||||
|
|
|
||||||
|
|
@ -177,6 +177,16 @@ function M.compile_problem(debug, on_complete)
|
||||||
local language = state.get_language() or config.platforms[platform].default_language
|
local language = state.get_language() or config.platforms[platform].default_language
|
||||||
local eff = config.runtime.effective[platform][language]
|
local eff = config.runtime.effective[platform][language]
|
||||||
|
|
||||||
|
local source_file = state.get_source_file()
|
||||||
|
if source_file then
|
||||||
|
local buf = vim.fn.bufnr(source_file)
|
||||||
|
if buf ~= -1 and vim.api.nvim_buf_is_loaded(buf) and vim.bo[buf].modified then
|
||||||
|
vim.api.nvim_buf_call(buf, function()
|
||||||
|
vim.cmd.write({ mods = { silent = true, noautocmd = true } })
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local compile_config = (debug and eff.commands.debug) or eff.commands.build
|
local compile_config = (debug and eff.commands.debug) or eff.commands.build
|
||||||
|
|
||||||
if not compile_config then
|
if not compile_config then
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,7 @@ local function start_tests(platform, contest_id, problems)
|
||||||
return not vim.tbl_isempty(cache.get_test_cases(platform, contest_id, p.id))
|
return not vim.tbl_isempty(cache.get_test_cases(platform, contest_id, p.id))
|
||||||
end, problems)
|
end, problems)
|
||||||
if cached_len ~= #problems then
|
if cached_len ~= #problems then
|
||||||
logger.log(('Fetching problem test data... (%d/%d)'):format(cached_len, #problems))
|
logger.log(('Fetching %s/%s problem tests...'):format(cached_len, #problems))
|
||||||
scraper.scrape_all_tests(platform, contest_id, function(ev)
|
scraper.scrape_all_tests(platform, contest_id, function(ev)
|
||||||
local cached_tests = {}
|
local cached_tests = {}
|
||||||
if not ev.interactive and vim.tbl_isempty(ev.tests) then
|
if not ev.interactive and vim.tbl_isempty(ev.tests) then
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,13 @@ local M = {}
|
||||||
local helpers = require('cp.helpers')
|
local helpers = require('cp.helpers')
|
||||||
local utils = require('cp.utils')
|
local utils = require('cp.utils')
|
||||||
|
|
||||||
local function create_none_diff_layout(parent_win, expected_content, actual_content)
|
M.DIFF_MODES = {
|
||||||
|
['side-by-side'] = 'side-by-side',
|
||||||
|
vim = 'vim',
|
||||||
|
git = 'git',
|
||||||
|
}
|
||||||
|
|
||||||
|
local function create_side_by_side_layout(parent_win, expected_content, actual_content)
|
||||||
local expected_buf = utils.create_buffer_with_options()
|
local expected_buf = utils.create_buffer_with_options()
|
||||||
local actual_buf = utils.create_buffer_with_options()
|
local actual_buf = utils.create_buffer_with_options()
|
||||||
helpers.clearcol(expected_buf)
|
helpers.clearcol(expected_buf)
|
||||||
|
|
@ -21,8 +27,13 @@ local function create_none_diff_layout(parent_win, expected_content, actual_cont
|
||||||
|
|
||||||
vim.api.nvim_set_option_value('filetype', 'cp', { buf = expected_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('filetype', 'cp', { buf = actual_buf })
|
||||||
vim.api.nvim_set_option_value('winbar', 'Expected', { win = expected_win })
|
local label = M.DIFF_MODES['side-by-side']
|
||||||
vim.api.nvim_set_option_value('winbar', 'Actual', { win = actual_win })
|
vim.api.nvim_set_option_value(
|
||||||
|
'winbar',
|
||||||
|
('expected (diff: %s)'):format(label),
|
||||||
|
{ win = expected_win }
|
||||||
|
)
|
||||||
|
vim.api.nvim_set_option_value('winbar', ('actual (diff: %s)'):format(label), { win = actual_win })
|
||||||
|
|
||||||
local expected_lines = vim.split(expected_content, '\n', { plain = true, trimempty = true })
|
local expected_lines = vim.split(expected_content, '\n', { plain = true, trimempty = true })
|
||||||
local actual_lines = vim.split(actual_content, '\n', { plain = true })
|
local actual_lines = vim.split(actual_content, '\n', { plain = true })
|
||||||
|
|
@ -33,6 +44,7 @@ local function create_none_diff_layout(parent_win, expected_content, actual_cont
|
||||||
return {
|
return {
|
||||||
buffers = { expected_buf, actual_buf },
|
buffers = { expected_buf, actual_buf },
|
||||||
windows = { expected_win, actual_win },
|
windows = { expected_win, actual_win },
|
||||||
|
mode = 'side-by-side',
|
||||||
cleanup = function()
|
cleanup = function()
|
||||||
pcall(vim.api.nvim_win_close, expected_win, true)
|
pcall(vim.api.nvim_win_close, expected_win, true)
|
||||||
pcall(vim.api.nvim_win_close, actual_win, true)
|
pcall(vim.api.nvim_win_close, actual_win, true)
|
||||||
|
|
@ -60,8 +72,13 @@ local function create_vim_diff_layout(parent_win, expected_content, actual_conte
|
||||||
|
|
||||||
vim.api.nvim_set_option_value('filetype', 'cp', { buf = expected_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('filetype', 'cp', { buf = actual_buf })
|
||||||
vim.api.nvim_set_option_value('winbar', 'Expected', { win = expected_win })
|
local label = M.DIFF_MODES.vim
|
||||||
vim.api.nvim_set_option_value('winbar', 'Actual', { win = actual_win })
|
vim.api.nvim_set_option_value(
|
||||||
|
'winbar',
|
||||||
|
('expected (diff: %s)'):format(label),
|
||||||
|
{ win = expected_win }
|
||||||
|
)
|
||||||
|
vim.api.nvim_set_option_value('winbar', ('actual (diff: %s)'):format(label), { win = actual_win })
|
||||||
|
|
||||||
local expected_lines = vim.split(expected_content, '\n', { plain = true, trimempty = true })
|
local expected_lines = vim.split(expected_content, '\n', { plain = true, trimempty = true })
|
||||||
local actual_lines = vim.split(actual_content, '\n', { plain = true })
|
local actual_lines = vim.split(actual_content, '\n', { plain = true })
|
||||||
|
|
@ -83,6 +100,7 @@ local function create_vim_diff_layout(parent_win, expected_content, actual_conte
|
||||||
return {
|
return {
|
||||||
buffers = { expected_buf, actual_buf },
|
buffers = { expected_buf, actual_buf },
|
||||||
windows = { expected_win, actual_win },
|
windows = { expected_win, actual_win },
|
||||||
|
mode = 'vim',
|
||||||
cleanup = function()
|
cleanup = function()
|
||||||
pcall(vim.api.nvim_win_close, expected_win, true)
|
pcall(vim.api.nvim_win_close, expected_win, true)
|
||||||
pcall(vim.api.nvim_win_close, actual_win, true)
|
pcall(vim.api.nvim_win_close, actual_win, true)
|
||||||
|
|
@ -103,7 +121,8 @@ local function create_git_diff_layout(parent_win, expected_content, actual_conte
|
||||||
vim.api.nvim_win_set_buf(diff_win, diff_buf)
|
vim.api.nvim_win_set_buf(diff_win, diff_buf)
|
||||||
|
|
||||||
vim.api.nvim_set_option_value('filetype', 'cp', { 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 label = M.DIFF_MODES.git
|
||||||
|
vim.api.nvim_set_option_value('winbar', ('diff: %s'):format(label), { win = diff_win })
|
||||||
|
|
||||||
local diff_backend = require('cp.ui.diff')
|
local diff_backend = require('cp.ui.diff')
|
||||||
local backend = diff_backend.get_best_backend('git')
|
local backend = diff_backend.get_best_backend('git')
|
||||||
|
|
@ -121,6 +140,7 @@ local function create_git_diff_layout(parent_win, expected_content, actual_conte
|
||||||
return {
|
return {
|
||||||
buffers = { diff_buf },
|
buffers = { diff_buf },
|
||||||
windows = { diff_win },
|
windows = { diff_win },
|
||||||
|
mode = 'git',
|
||||||
cleanup = function()
|
cleanup = function()
|
||||||
pcall(vim.api.nvim_win_close, diff_win, true)
|
pcall(vim.api.nvim_win_close, diff_win, true)
|
||||||
pcall(vim.api.nvim_buf_delete, diff_buf, { force = true })
|
pcall(vim.api.nvim_buf_delete, diff_buf, { force = true })
|
||||||
|
|
@ -143,6 +163,7 @@ local function create_single_layout(parent_win, content)
|
||||||
return {
|
return {
|
||||||
buffers = { buf },
|
buffers = { buf },
|
||||||
windows = { win },
|
windows = { win },
|
||||||
|
mode = 'single',
|
||||||
cleanup = function()
|
cleanup = function()
|
||||||
pcall(vim.api.nvim_win_close, win, true)
|
pcall(vim.api.nvim_win_close, win, true)
|
||||||
pcall(vim.api.nvim_buf_delete, buf, { force = true })
|
pcall(vim.api.nvim_buf_delete, buf, { force = true })
|
||||||
|
|
@ -153,12 +174,14 @@ end
|
||||||
function M.create_diff_layout(mode, parent_win, expected_content, actual_content)
|
function M.create_diff_layout(mode, parent_win, expected_content, actual_content)
|
||||||
if mode == 'single' then
|
if mode == 'single' then
|
||||||
return create_single_layout(parent_win, actual_content)
|
return create_single_layout(parent_win, actual_content)
|
||||||
elseif mode == 'none' then
|
elseif mode == 'side-by-side' then
|
||||||
return create_none_diff_layout(parent_win, expected_content, actual_content)
|
return create_side_by_side_layout(parent_win, expected_content, actual_content)
|
||||||
elseif mode == 'git' then
|
elseif mode == 'git' then
|
||||||
return create_git_diff_layout(parent_win, expected_content, actual_content)
|
return create_git_diff_layout(parent_win, expected_content, actual_content)
|
||||||
else
|
elseif mode == 'vim' then
|
||||||
return create_vim_diff_layout(parent_win, expected_content, actual_content)
|
return create_vim_diff_layout(parent_win, expected_content, actual_content)
|
||||||
|
else
|
||||||
|
return create_side_by_side_layout(parent_win, expected_content, actual_content)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -191,12 +214,13 @@ function M.update_diff_panes(
|
||||||
actual_content = actual_content
|
actual_content = actual_content
|
||||||
end
|
end
|
||||||
|
|
||||||
local desired_mode = is_compilation_failure and 'single' or config.ui.panel.diff_mode
|
local default_mode = config.ui.panel.diff_modes[1]
|
||||||
|
local desired_mode = is_compilation_failure and 'single' or (current_mode or default_mode)
|
||||||
local highlight = require('cp.ui.highlight')
|
local highlight = require('cp.ui.highlight')
|
||||||
local diff_namespace = highlight.create_namespace()
|
local diff_namespace = highlight.create_namespace()
|
||||||
local ansi_namespace = vim.api.nvim_create_namespace('cp_ansi_highlights')
|
local ansi_namespace = vim.api.nvim_create_namespace('cp_ansi_highlights')
|
||||||
|
|
||||||
if current_diff_layout and current_mode ~= desired_mode then
|
if current_diff_layout and current_diff_layout.mode ~= desired_mode then
|
||||||
local saved_pos = vim.api.nvim_win_get_cursor(0)
|
local saved_pos = vim.api.nvim_win_get_cursor(0)
|
||||||
current_diff_layout.cleanup()
|
current_diff_layout.cleanup()
|
||||||
current_diff_layout = nil
|
current_diff_layout = nil
|
||||||
|
|
@ -251,7 +275,7 @@ function M.update_diff_panes(
|
||||||
ansi_namespace
|
ansi_namespace
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
elseif desired_mode == 'none' then
|
elseif desired_mode == 'side-by-side' then
|
||||||
local expected_lines = vim.split(expected_content, '\n', { plain = true, trimempty = true })
|
local expected_lines = vim.split(expected_content, '\n', { plain = true, trimempty = true })
|
||||||
local actual_lines = vim.split(actual_content, '\n', { plain = true })
|
local actual_lines = vim.split(actual_content, '\n', { plain = true })
|
||||||
utils.update_buffer_content(current_diff_layout.buffers[1], expected_lines, {})
|
utils.update_buffer_content(current_diff_layout.buffers[1], expected_lines, {})
|
||||||
|
|
|
||||||
|
|
@ -900,15 +900,15 @@ function M.toggle_panel(panel_opts)
|
||||||
M.toggle_panel()
|
M.toggle_panel()
|
||||||
end, { buffer = buf, silent = true })
|
end, { buffer = buf, silent = true })
|
||||||
vim.keymap.set('n', 't', function()
|
vim.keymap.set('n', 't', function()
|
||||||
local modes = { 'none', 'git', 'vim' }
|
local modes = config.ui.panel.diff_modes
|
||||||
local current_idx = 1
|
local current_idx = 1
|
||||||
for i, mode in ipairs(modes) do
|
for i, mode in ipairs(modes) do
|
||||||
if config.ui.panel.diff_mode == mode then
|
if current_mode == mode then
|
||||||
current_idx = i
|
current_idx = i
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
config.ui.panel.diff_mode = modes[(current_idx % #modes) + 1]
|
current_mode = modes[(current_idx % #modes) + 1]
|
||||||
refresh_panel()
|
refresh_panel()
|
||||||
end, { buffer = buf, silent = true })
|
end, { buffer = buf, silent = true })
|
||||||
vim.keymap.set('n', '<c-n>', function()
|
vim.keymap.set('n', '<c-n>', function()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue