feat: refactor file structure
This commit is contained in:
parent
9761cded88
commit
965e47a1df
17 changed files with 19 additions and 22 deletions
236
lua/cp/ui/ansi.lua
Normal file
236
lua/cp/ui/ansi.lua
Normal file
|
|
@ -0,0 +1,236 @@
|
|||
---@class AnsiParseResult
|
||||
---@field lines string[]
|
||||
---@field highlights table[]
|
||||
|
||||
local M = {}
|
||||
|
||||
local logger = require('cp.log')
|
||||
|
||||
---@param raw_output string|table
|
||||
---@return string
|
||||
function M.bytes_to_string(raw_output)
|
||||
if type(raw_output) == 'string' then
|
||||
return raw_output
|
||||
end
|
||||
return table.concat(vim.tbl_map(string.char, raw_output))
|
||||
end
|
||||
|
||||
---@param text string
|
||||
---@return AnsiParseResult
|
||||
function M.parse_ansi_text(text)
|
||||
local clean_text = text:gsub('\027%[[%d;]*[a-zA-Z]', '')
|
||||
local lines = vim.split(clean_text, '\n', { plain = true, trimempty = false })
|
||||
|
||||
local highlights = {}
|
||||
local line_num = 0
|
||||
local col_pos = 0
|
||||
|
||||
local ansi_state = {
|
||||
bold = false,
|
||||
italic = false,
|
||||
foreground = nil,
|
||||
}
|
||||
|
||||
local function get_highlight_group()
|
||||
if not ansi_state.bold and not ansi_state.italic and not ansi_state.foreground then
|
||||
return nil
|
||||
end
|
||||
|
||||
local parts = { 'CpAnsi' }
|
||||
if ansi_state.bold then
|
||||
table.insert(parts, 'Bold')
|
||||
end
|
||||
if ansi_state.italic then
|
||||
table.insert(parts, 'Italic')
|
||||
end
|
||||
if ansi_state.foreground then
|
||||
table.insert(parts, ansi_state.foreground)
|
||||
end
|
||||
|
||||
return table.concat(parts)
|
||||
end
|
||||
|
||||
local function apply_highlight(start_line, start_col, end_col)
|
||||
local hl_group = get_highlight_group()
|
||||
if hl_group then
|
||||
table.insert(highlights, {
|
||||
line = start_line,
|
||||
col_start = start_col,
|
||||
col_end = end_col,
|
||||
highlight_group = hl_group,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
local i = 1
|
||||
while i <= #text do
|
||||
local ansi_start, ansi_end, code, cmd = text:find('\027%[([%d;]*)([a-zA-Z])', i)
|
||||
|
||||
if ansi_start then
|
||||
if ansi_start > i then
|
||||
local segment = text:sub(i, ansi_start - 1)
|
||||
local start_line = line_num
|
||||
local start_col = col_pos
|
||||
|
||||
for char in segment:gmatch('.') do
|
||||
if char == '\n' then
|
||||
if col_pos > start_col then
|
||||
apply_highlight(start_line, start_col, col_pos)
|
||||
end
|
||||
line_num = line_num + 1
|
||||
start_line = line_num
|
||||
col_pos = 0
|
||||
start_col = 0
|
||||
else
|
||||
col_pos = col_pos + 1
|
||||
end
|
||||
end
|
||||
|
||||
if col_pos > start_col then
|
||||
apply_highlight(start_line, start_col, col_pos)
|
||||
end
|
||||
end
|
||||
|
||||
if cmd == 'm' then
|
||||
M.update_ansi_state(ansi_state, code)
|
||||
end
|
||||
i = ansi_end + 1
|
||||
else
|
||||
local segment = text:sub(i)
|
||||
if segment ~= '' then
|
||||
local start_line = line_num
|
||||
local start_col = col_pos
|
||||
|
||||
for char in segment:gmatch('.') do
|
||||
if char == '\n' then
|
||||
if col_pos > start_col then
|
||||
apply_highlight(start_line, start_col, col_pos)
|
||||
end
|
||||
line_num = line_num + 1
|
||||
start_line = line_num
|
||||
col_pos = 0
|
||||
start_col = 0
|
||||
else
|
||||
col_pos = col_pos + 1
|
||||
end
|
||||
end
|
||||
|
||||
if col_pos > start_col then
|
||||
apply_highlight(start_line, start_col, col_pos)
|
||||
end
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
return {
|
||||
lines = lines,
|
||||
highlights = highlights,
|
||||
}
|
||||
end
|
||||
|
||||
---@param ansi_state table
|
||||
---@param code_string string
|
||||
function M.update_ansi_state(ansi_state, code_string)
|
||||
if code_string == '' or code_string == '0' then
|
||||
ansi_state.bold = false
|
||||
ansi_state.italic = false
|
||||
ansi_state.foreground = nil
|
||||
return
|
||||
end
|
||||
|
||||
local codes = vim.split(code_string, ';', { plain = true })
|
||||
|
||||
for _, code in ipairs(codes) do
|
||||
local num = tonumber(code)
|
||||
if num then
|
||||
if num == 1 then
|
||||
ansi_state.bold = true
|
||||
elseif num == 3 then
|
||||
ansi_state.italic = true
|
||||
elseif num == 22 then
|
||||
ansi_state.bold = false
|
||||
elseif num == 23 then
|
||||
ansi_state.italic = false
|
||||
elseif num >= 30 and num <= 37 then
|
||||
local colors = { 'Black', 'Red', 'Green', 'Yellow', 'Blue', 'Magenta', 'Cyan', 'White' }
|
||||
ansi_state.foreground = colors[num - 29]
|
||||
elseif num >= 90 and num <= 97 then
|
||||
local colors = {
|
||||
'BrightBlack',
|
||||
'BrightRed',
|
||||
'BrightGreen',
|
||||
'BrightYellow',
|
||||
'BrightBlue',
|
||||
'BrightMagenta',
|
||||
'BrightCyan',
|
||||
'BrightWhite',
|
||||
}
|
||||
ansi_state.foreground = colors[num - 89]
|
||||
elseif num == 39 then
|
||||
ansi_state.foreground = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function M.setup_highlight_groups()
|
||||
local color_map = {
|
||||
Black = vim.g.terminal_color_0,
|
||||
Red = vim.g.terminal_color_1,
|
||||
Green = vim.g.terminal_color_2,
|
||||
Yellow = vim.g.terminal_color_3,
|
||||
Blue = vim.g.terminal_color_4,
|
||||
Magenta = vim.g.terminal_color_5,
|
||||
Cyan = vim.g.terminal_color_6,
|
||||
White = vim.g.terminal_color_7,
|
||||
BrightBlack = vim.g.terminal_color_8,
|
||||
BrightRed = vim.g.terminal_color_9,
|
||||
BrightGreen = vim.g.terminal_color_10,
|
||||
BrightYellow = vim.g.terminal_color_11,
|
||||
BrightBlue = vim.g.terminal_color_12,
|
||||
BrightMagenta = vim.g.terminal_color_13,
|
||||
BrightCyan = vim.g.terminal_color_14,
|
||||
BrightWhite = vim.g.terminal_color_15,
|
||||
}
|
||||
|
||||
if vim.tbl_count(color_map) < 16 then
|
||||
logger.log(
|
||||
'ansi terminal colors (vim.g.terminal_color_*) not configured. ANSI colors will not display properly. ',
|
||||
vim.log.levels.WARN
|
||||
)
|
||||
end
|
||||
|
||||
local combinations = {
|
||||
{ bold = false, italic = false },
|
||||
{ bold = true, italic = false },
|
||||
{ bold = false, italic = true },
|
||||
{ bold = true, italic = true },
|
||||
}
|
||||
|
||||
for _, combo in ipairs(combinations) do
|
||||
for color_name, terminal_color in pairs(color_map) do
|
||||
local parts = { 'CpAnsi' }
|
||||
local opts = { fg = terminal_color or 'NONE' }
|
||||
|
||||
if combo.bold then
|
||||
table.insert(parts, 'Bold')
|
||||
opts.bold = true
|
||||
end
|
||||
if combo.italic then
|
||||
table.insert(parts, 'Italic')
|
||||
opts.italic = true
|
||||
end
|
||||
table.insert(parts, color_name)
|
||||
|
||||
local hl_name = table.concat(parts)
|
||||
vim.api.nvim_set_hl(0, hl_name, opts)
|
||||
end
|
||||
end
|
||||
|
||||
vim.api.nvim_set_hl(0, 'CpAnsiBold', { bold = true })
|
||||
vim.api.nvim_set_hl(0, 'CpAnsiItalic', { italic = true })
|
||||
vim.api.nvim_set_hl(0, 'CpAnsiBoldItalic', { bold = true, italic = true })
|
||||
end
|
||||
|
||||
return M
|
||||
189
lua/cp/ui/diff.lua
Normal file
189
lua/cp/ui/diff.lua
Normal file
|
|
@ -0,0 +1,189 @@
|
|||
---@class DiffResult
|
||||
---@field content string[]
|
||||
---@field highlights table[]?
|
||||
---@field raw_diff string?
|
||||
|
||||
---@class DiffBackend
|
||||
---@field name string
|
||||
---@field render fun(expected: string, actual: string): DiffResult
|
||||
|
||||
local M = {}
|
||||
|
||||
---@type DiffBackend
|
||||
local vim_backend = {
|
||||
name = 'vim',
|
||||
render = function(_, actual)
|
||||
local actual_lines = vim.split(actual, '\n', { plain = true, trimempty = true })
|
||||
|
||||
return {
|
||||
content = actual_lines,
|
||||
highlights = nil,
|
||||
}
|
||||
end,
|
||||
}
|
||||
|
||||
---@type DiffBackend
|
||||
local git_backend = {
|
||||
name = 'git',
|
||||
render = function(expected, actual)
|
||||
local tmp_expected = vim.fn.tempname()
|
||||
local tmp_actual = vim.fn.tempname()
|
||||
|
||||
vim.fn.writefile(vim.split(expected, '\n', { plain = true }), tmp_expected)
|
||||
vim.fn.writefile(vim.split(actual, '\n', { plain = true }), tmp_actual)
|
||||
|
||||
local cmd = {
|
||||
'git',
|
||||
'diff',
|
||||
'--no-index',
|
||||
'--word-diff=plain',
|
||||
'--word-diff-regex=.',
|
||||
'--no-prefix',
|
||||
tmp_expected,
|
||||
tmp_actual,
|
||||
}
|
||||
|
||||
local result = vim.system(cmd, { text = true }):wait()
|
||||
|
||||
vim.fn.delete(tmp_expected)
|
||||
vim.fn.delete(tmp_actual)
|
||||
|
||||
if result.code == 0 then
|
||||
return {
|
||||
content = vim.split(actual, '\n', { plain = true, trimempty = true }),
|
||||
highlights = {},
|
||||
}
|
||||
else
|
||||
local diff_content = result.stdout or ''
|
||||
local lines = {}
|
||||
local highlights = {}
|
||||
local line_num = 0
|
||||
|
||||
for line in diff_content:gmatch('[^\n]*') do
|
||||
if
|
||||
line:match('^[%s%+%-]')
|
||||
or (not line:match('^[@%-+]') and not line:match('^index') and not line:match('^diff'))
|
||||
then
|
||||
local clean_line = line
|
||||
if line:match('^[%+%-]') then
|
||||
clean_line = line:sub(2)
|
||||
end
|
||||
|
||||
local col_pos = 0
|
||||
local processed_line = ''
|
||||
local i = 1
|
||||
|
||||
while i <= #clean_line do
|
||||
local removed_start, removed_end = clean_line:find('%[%-[^%-]*%-]', i)
|
||||
local added_start, added_end = clean_line:find('{%+[^%+]*%+}', i)
|
||||
|
||||
local next_marker_start = nil
|
||||
local marker_type = nil
|
||||
|
||||
if removed_start and (not added_start or removed_start < added_start) then
|
||||
next_marker_start = removed_start
|
||||
marker_type = 'removed'
|
||||
elseif added_start then
|
||||
next_marker_start = added_start
|
||||
marker_type = 'added'
|
||||
end
|
||||
|
||||
if next_marker_start then
|
||||
if next_marker_start > i then
|
||||
local before_text = clean_line:sub(i, next_marker_start - 1)
|
||||
processed_line = processed_line .. before_text
|
||||
col_pos = col_pos + #before_text
|
||||
end
|
||||
|
||||
local marker_end = (marker_type == 'removed') and removed_end or added_end
|
||||
local marker_text = clean_line:sub(next_marker_start, marker_end)
|
||||
local content_text
|
||||
|
||||
if marker_type == 'removed' then
|
||||
content_text = marker_text:sub(3, -3)
|
||||
table.insert(highlights, {
|
||||
line = line_num,
|
||||
col_start = col_pos,
|
||||
col_end = col_pos + #content_text,
|
||||
highlight_group = 'DiffDelete',
|
||||
})
|
||||
else
|
||||
content_text = marker_text:sub(3, -3)
|
||||
table.insert(highlights, {
|
||||
line = line_num,
|
||||
col_start = col_pos,
|
||||
col_end = col_pos + #content_text,
|
||||
highlight_group = 'DiffAdd',
|
||||
})
|
||||
end
|
||||
|
||||
processed_line = processed_line .. content_text
|
||||
col_pos = col_pos + #content_text
|
||||
i = marker_end + 1
|
||||
else
|
||||
local rest = clean_line:sub(i)
|
||||
processed_line = processed_line .. rest
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
table.insert(lines, processed_line)
|
||||
line_num = line_num + 1
|
||||
end
|
||||
end
|
||||
|
||||
return {
|
||||
content = lines,
|
||||
highlights = highlights,
|
||||
raw_diff = diff_content,
|
||||
}
|
||||
end
|
||||
end,
|
||||
}
|
||||
|
||||
---@type table<string, DiffBackend>
|
||||
local backends = {
|
||||
vim = vim_backend,
|
||||
git = git_backend,
|
||||
}
|
||||
|
||||
---@return string[]
|
||||
function M.get_available_backends()
|
||||
return vim.tbl_keys(backends)
|
||||
end
|
||||
|
||||
---@param name string
|
||||
---@return DiffBackend?
|
||||
function M.get_backend(name)
|
||||
return backends[name]
|
||||
end
|
||||
|
||||
---@return boolean
|
||||
function M.is_git_available()
|
||||
local result = vim.system({ 'git', '--version' }, { text = true }):wait()
|
||||
return result.code == 0
|
||||
end
|
||||
|
||||
---@param preferred_backend? string
|
||||
---@return DiffBackend
|
||||
function M.get_best_backend(preferred_backend)
|
||||
if preferred_backend and backends[preferred_backend] then
|
||||
if preferred_backend == 'git' and not M.is_git_available() then
|
||||
return backends.vim
|
||||
end
|
||||
return backends[preferred_backend]
|
||||
end
|
||||
|
||||
return backends.vim
|
||||
end
|
||||
|
||||
---@param expected string
|
||||
---@param actual string
|
||||
---@param backend_name? string
|
||||
---@return DiffResult
|
||||
function M.render_diff(expected, actual, backend_name)
|
||||
local backend = M.get_best_backend(backend_name)
|
||||
return backend.render(expected, actual)
|
||||
end
|
||||
|
||||
return M
|
||||
156
lua/cp/ui/highlight.lua
Normal file
156
lua/cp/ui/highlight.lua
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
---@class DiffHighlight
|
||||
---@field line number
|
||||
---@field col_start number
|
||||
---@field col_end number
|
||||
---@field highlight_group string
|
||||
|
||||
---@class ParsedDiff
|
||||
---@field content string[]
|
||||
---@field highlights DiffHighlight[]
|
||||
|
||||
local M = {}
|
||||
|
||||
---@param text string Raw git diff output line
|
||||
---@return string cleaned_text, DiffHighlight[]
|
||||
local function parse_diff_line(text)
|
||||
local result_text = ''
|
||||
local highlights = {}
|
||||
local pos = 1
|
||||
|
||||
while pos <= #text do
|
||||
local removed_start, removed_end, removed_content = text:find('%[%-(.-)%-%]', pos)
|
||||
if removed_start and removed_start == pos then
|
||||
local highlight_start = #result_text
|
||||
result_text = result_text .. removed_content
|
||||
table.insert(highlights, {
|
||||
line = 0,
|
||||
col_start = highlight_start,
|
||||
col_end = #result_text,
|
||||
highlight_group = 'CpDiffRemoved',
|
||||
})
|
||||
pos = removed_end + 1
|
||||
else
|
||||
local added_start, added_end, added_content = text:find('{%+(.-)%+}', pos)
|
||||
if added_start and added_start == pos then
|
||||
local highlight_start = #result_text
|
||||
result_text = result_text .. added_content
|
||||
table.insert(highlights, {
|
||||
line = 0,
|
||||
col_start = highlight_start,
|
||||
col_end = #result_text,
|
||||
highlight_group = 'CpDiffAdded',
|
||||
})
|
||||
pos = added_end + 1
|
||||
else
|
||||
result_text = result_text .. text:sub(pos, pos)
|
||||
pos = pos + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return result_text, highlights
|
||||
end
|
||||
|
||||
---@param diff_output string
|
||||
---@return ParsedDiff
|
||||
function M.parse_git_diff(diff_output)
|
||||
if diff_output == '' then
|
||||
return { content = {}, highlights = {} }
|
||||
end
|
||||
|
||||
local lines = vim.split(diff_output, '\n', { plain = true })
|
||||
local content_lines = {}
|
||||
local all_highlights = {}
|
||||
|
||||
local content_started = false
|
||||
for _, line in ipairs(lines) do
|
||||
if
|
||||
content_started
|
||||
or (
|
||||
not line:match('^@@')
|
||||
and not line:match('^%+%+%+')
|
||||
and not line:match('^%-%-%-')
|
||||
and not line:match('^index')
|
||||
and not line:match('^diff %-%-git')
|
||||
)
|
||||
then
|
||||
content_started = true
|
||||
|
||||
if line:match('^%+') then
|
||||
local clean_line = line:sub(2)
|
||||
local parsed_line, line_highlights = parse_diff_line(clean_line)
|
||||
|
||||
table.insert(content_lines, parsed_line)
|
||||
|
||||
local line_num = #content_lines
|
||||
for _, highlight in ipairs(line_highlights) do
|
||||
highlight.line = line_num - 1
|
||||
table.insert(all_highlights, highlight)
|
||||
end
|
||||
elseif not line:match('^%-') and not line:match('^\\') then
|
||||
local clean_line = line:match('^%s') and line:sub(2) or line
|
||||
local parsed_line, line_highlights = parse_diff_line(clean_line)
|
||||
|
||||
if parsed_line ~= '' then
|
||||
table.insert(content_lines, parsed_line)
|
||||
|
||||
local line_num = #content_lines
|
||||
for _, highlight in ipairs(line_highlights) do
|
||||
highlight.line = line_num - 1
|
||||
table.insert(all_highlights, highlight)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return {
|
||||
content = content_lines,
|
||||
highlights = all_highlights,
|
||||
}
|
||||
end
|
||||
|
||||
---@param bufnr number
|
||||
---@param highlights DiffHighlight[]
|
||||
---@param namespace number
|
||||
function M.apply_highlights(bufnr, highlights, namespace)
|
||||
vim.api.nvim_buf_clear_namespace(bufnr, namespace, 0, -1)
|
||||
|
||||
for _, highlight in ipairs(highlights) do
|
||||
if highlight.col_start < highlight.col_end then
|
||||
vim.api.nvim_buf_set_extmark(bufnr, namespace, highlight.line, highlight.col_start, {
|
||||
end_col = highlight.col_end,
|
||||
hl_group = highlight.highlight_group,
|
||||
priority = 100,
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---@return number
|
||||
function M.create_namespace()
|
||||
return vim.api.nvim_create_namespace('cp_diff_highlights')
|
||||
end
|
||||
|
||||
---@param bufnr number
|
||||
---@param diff_output string
|
||||
---@param namespace number
|
||||
---@return string[] content_lines
|
||||
function M.parse_and_apply_diff(bufnr, diff_output, namespace)
|
||||
local parsed = M.parse_git_diff(diff_output)
|
||||
|
||||
local was_modifiable = vim.api.nvim_get_option_value('modifiable', { buf = bufnr })
|
||||
local was_readonly = vim.api.nvim_get_option_value('readonly', { buf = bufnr })
|
||||
|
||||
vim.api.nvim_set_option_value('readonly', false, { buf = bufnr })
|
||||
vim.api.nvim_set_option_value('modifiable', true, { buf = bufnr })
|
||||
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, parsed.content)
|
||||
vim.api.nvim_set_option_value('modifiable', was_modifiable, { buf = bufnr })
|
||||
vim.api.nvim_set_option_value('readonly', was_readonly, { buf = bufnr })
|
||||
|
||||
M.apply_highlights(bufnr, parsed.highlights, namespace)
|
||||
|
||||
return parsed.content
|
||||
end
|
||||
|
||||
return M
|
||||
144
lua/cp/ui/window.lua
Normal file
144
lua/cp/ui/window.lua
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
---@class WindowState
|
||||
---@field windows table<integer, WindowData>
|
||||
---@field current_win integer
|
||||
---@field layout string
|
||||
|
||||
---@class WindowData
|
||||
---@field bufnr integer
|
||||
---@field view table
|
||||
---@field width integer
|
||||
---@field height integer
|
||||
|
||||
local M = {}
|
||||
local constants = require('cp.constants')
|
||||
|
||||
---@return WindowState
|
||||
function M.save_layout()
|
||||
local windows = {}
|
||||
for _, win in ipairs(vim.api.nvim_list_wins()) do
|
||||
if vim.api.nvim_win_is_valid(win) then
|
||||
local bufnr = vim.api.nvim_win_get_buf(win)
|
||||
windows[win] = {
|
||||
bufnr = bufnr,
|
||||
view = vim.fn.winsaveview(),
|
||||
width = vim.api.nvim_win_get_width(win),
|
||||
height = vim.api.nvim_win_get_height(win),
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
return {
|
||||
windows = windows,
|
||||
current_win = vim.api.nvim_get_current_win(),
|
||||
layout = vim.fn.winrestcmd(),
|
||||
}
|
||||
end
|
||||
|
||||
---@param state? WindowState
|
||||
---@param tile_fn? fun(source_buf: integer, input_buf: integer, output_buf: integer)
|
||||
function M.restore_layout(state, tile_fn)
|
||||
vim.validate({
|
||||
state = { state, { 'table', 'nil' }, true },
|
||||
tile_fn = { tile_fn, { 'function', 'nil' }, true },
|
||||
})
|
||||
|
||||
if not state then
|
||||
return
|
||||
end
|
||||
|
||||
vim.cmd.diffoff()
|
||||
|
||||
local problem_id = vim.fn.expand('%:t:r')
|
||||
if problem_id == '' then
|
||||
for win, win_state in pairs(state.windows) do
|
||||
if vim.api.nvim_win_is_valid(win) and vim.api.nvim_buf_is_valid(win_state.bufnr) then
|
||||
local bufname = vim.api.nvim_buf_get_name(win_state.bufnr)
|
||||
if
|
||||
not bufname:match('%.in$')
|
||||
and not bufname:match('%.out$')
|
||||
and not bufname:match('%.expected$')
|
||||
then
|
||||
problem_id = vim.fn.fnamemodify(bufname, ':t:r')
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if problem_id ~= '' then
|
||||
vim.cmd('silent only')
|
||||
|
||||
local base_fp = vim.fn.getcwd()
|
||||
local input_file = ('%s/io/%s.in'):format(base_fp, problem_id)
|
||||
local output_file = ('%s/io/%s.out'):format(base_fp, problem_id)
|
||||
local source_files = vim.fn.glob(problem_id .. '.*')
|
||||
local source_file
|
||||
if source_files ~= '' then
|
||||
local files = vim.split(source_files, '\n')
|
||||
local known_extensions = vim.tbl_keys(constants.filetype_to_language)
|
||||
for _, file in ipairs(files) do
|
||||
local ext = vim.fn.fnamemodify(file, ':e')
|
||||
if vim.tbl_contains(known_extensions, ext) then
|
||||
source_file = file
|
||||
break
|
||||
end
|
||||
end
|
||||
source_file = source_file or files[1]
|
||||
end
|
||||
|
||||
if not source_file or vim.fn.filereadable(source_file) == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
vim.cmd.edit(source_file)
|
||||
local source_buf = vim.api.nvim_get_current_buf()
|
||||
local input_buf = vim.fn.bufnr(input_file, true)
|
||||
local output_buf = vim.fn.bufnr(output_file, true)
|
||||
|
||||
if tile_fn then
|
||||
tile_fn(source_buf, input_buf, output_buf)
|
||||
else
|
||||
M.default_tile(source_buf, input_buf, output_buf)
|
||||
end
|
||||
else
|
||||
vim.cmd(state.layout)
|
||||
|
||||
for win, win_state in pairs(state.windows) do
|
||||
if vim.api.nvim_win_is_valid(win) then
|
||||
vim.api.nvim_set_current_win(win)
|
||||
if vim.api.nvim_get_current_buf() == win_state.bufnr then
|
||||
vim.fn.winrestview(win_state.view)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if vim.api.nvim_win_is_valid(state.current_win) then
|
||||
vim.api.nvim_set_current_win(state.current_win)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---@param source_buf integer
|
||||
---@param input_buf integer
|
||||
---@param output_buf integer
|
||||
local function default_tile(source_buf, input_buf, output_buf)
|
||||
vim.validate({
|
||||
source_buf = { source_buf, 'number' },
|
||||
input_buf = { input_buf, 'number' },
|
||||
output_buf = { output_buf, 'number' },
|
||||
})
|
||||
|
||||
vim.api.nvim_set_current_buf(source_buf)
|
||||
vim.cmd.vsplit()
|
||||
vim.api.nvim_set_current_buf(output_buf)
|
||||
vim.bo.filetype = 'cp'
|
||||
vim.cmd(('vertical resize %d'):format(math.floor(vim.o.columns * 0.3)))
|
||||
vim.cmd.split()
|
||||
vim.api.nvim_set_current_buf(input_buf)
|
||||
vim.bo.filetype = 'cp'
|
||||
vim.cmd.wincmd('h')
|
||||
end
|
||||
|
||||
M.default_tile = default_tile
|
||||
|
||||
return M
|
||||
Loading…
Add table
Add a link
Reference in a new issue