feat: window mgmt
This commit is contained in:
parent
c4a7dc8215
commit
a6abcc3fc3
4 changed files with 421 additions and 42 deletions
333
CLAUDE.md
Normal file
333
CLAUDE.md
Normal file
|
|
@ -0,0 +1,333 @@
|
||||||
|
# CP.nvim Analysis & Modernization Plan
|
||||||
|
|
||||||
|
## Current Architecture Overview
|
||||||
|
|
||||||
|
### Plugin Structure
|
||||||
|
- **Main Logic**: `lua/cp/init.lua` (297 lines) - Core plugin functionality
|
||||||
|
- **Configuration**: `lua/cp/config.lua` (16 lines) - Contest settings and defaults
|
||||||
|
- **Snippets**: `lua/cp/snippets.lua` (21 lines) - LuaSnip integration
|
||||||
|
- **Entry Point**: `plugin/cp.lua` (7 lines) - Plugin initialization
|
||||||
|
- **Vim Integration**: `after/` directory with filetype detection, syntax highlighting, and buffer settings
|
||||||
|
|
||||||
|
### Current Build System (Make/Shell-Based)
|
||||||
|
|
||||||
|
#### Templates Structure
|
||||||
|
```
|
||||||
|
templates/
|
||||||
|
├── makefile # Build orchestration
|
||||||
|
├── compile_flags.txt # Release flags: -O2, -DLOCAL
|
||||||
|
├── debug_flags.txt # Debug flags: -g3, -fsanitize=address,undefined, -DLOCAL
|
||||||
|
├── .clang-format # Code formatting rules (Google style)
|
||||||
|
├── scripts/
|
||||||
|
│ ├── run.sh # Compilation + execution workflow
|
||||||
|
│ ├── debug.sh # Debug compilation + execution
|
||||||
|
│ ├── scrape.sh # Problem scraping orchestration
|
||||||
|
│ └── utils.sh # Core build/execution utilities
|
||||||
|
├── scrapers/ # Python scrapers for each judge
|
||||||
|
│ ├── atcoder.py # AtCoder problem scraping
|
||||||
|
│ ├── codeforces.py # Codeforces problem scraping (with cloudscraper)
|
||||||
|
│ └── cses.py # CSES problem scraping
|
||||||
|
└── io/ # Input/output files directory
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Build Workflow Analysis
|
||||||
|
|
||||||
|
**Compilation Process** (`utils.sh:compile_source`):
|
||||||
|
```bash
|
||||||
|
g++ @compile_flags.txt $flags "$src" -o "$bin" 2>"$output"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Execution Process** (`utils.sh:execute_binary`):
|
||||||
|
- **Timeout**: 2-second hardcoded timeout using `timeout 2s`
|
||||||
|
- **Debug Mode**: LD_PRELOAD with AddressSanitizer when debugging
|
||||||
|
- **Output Processing**:
|
||||||
|
- Truncates to first 1000 lines
|
||||||
|
- Appends metadata: `[code]`, `[time]`, `[debug]`, `[matches]`
|
||||||
|
- Compares with `.expected` file if available
|
||||||
|
- **Signal Handling**: Maps exit codes to signal names (SIGSEGV, SIGFPE, etc.)
|
||||||
|
|
||||||
|
### Current Neovim Integration
|
||||||
|
|
||||||
|
#### Command System
|
||||||
|
- `:CP <contest>` - Setup contest environment
|
||||||
|
- `:CP <contest> <problem_id> [letter]` - Setup problem + scrape
|
||||||
|
- `:CP run` - Compile and execute current problem
|
||||||
|
- `:CP debug` - Compile with debug flags and execute
|
||||||
|
- `:CP diff` - Toggle diff mode between output and expected
|
||||||
|
|
||||||
|
#### Current vim.system Usage
|
||||||
|
```lua
|
||||||
|
-- Only used for async compilation in init.lua:148, 166
|
||||||
|
vim.system({ "make", "run", vim.fn.expand("%:t") }, {}, callback)
|
||||||
|
vim.system({ "make", "debug", vim.fn.expand("%:t") }, {}, callback)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Window Management
|
||||||
|
- **Current Layout**: Code editor | Output window + Input window (vsplit + split)
|
||||||
|
- **Diff Mode**:
|
||||||
|
- Uses `vim.cmd.diffthis()` and `vim.cmd.diffoff()`
|
||||||
|
- Session saving with `mksession!` and restoration
|
||||||
|
- Manual window arrangement with `vim.cmd.only()`, splits, and `wincmd`
|
||||||
|
- **vim-zoom dependency**: Listed as optional for "better diff view" but not used in code
|
||||||
|
|
||||||
|
#### File Type Integration
|
||||||
|
- **Auto-detection**: `*/io/*.in` → `cpinput`, `*/io/*.out` → `cpoutput`
|
||||||
|
- **Buffer Settings**: Disables line numbers, signs, status column for I/O files
|
||||||
|
- **Syntax Highlighting**: Custom syntax for output metadata (`[code]`, `[time]`, etc.)
|
||||||
|
|
||||||
|
### Current Configuration System
|
||||||
|
|
||||||
|
#### Contest-Specific Settings
|
||||||
|
```lua
|
||||||
|
defaults = {
|
||||||
|
contests = {
|
||||||
|
atcoder = { cpp_version = 23 },
|
||||||
|
codeforces = { cpp_version = 23 },
|
||||||
|
cses = { cpp_version = 20 },
|
||||||
|
},
|
||||||
|
snippets = {},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### File-Based Configuration Dependencies
|
||||||
|
- `compile_flags.txt` - Compiler flags for release builds
|
||||||
|
- `debug_flags.txt` - Debug-specific compiler flags
|
||||||
|
- `.clang-format` - Code formatting configuration
|
||||||
|
- **Missing**: `.clangd` file (referenced in makefile but doesn't exist)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Proposed Modernization: Full Lua Migration
|
||||||
|
|
||||||
|
### 1. Replace Make/Shell System with vim.system
|
||||||
|
|
||||||
|
#### Benefits of Native Lua Implementation
|
||||||
|
- **Better Error Handling**: Lua error handling vs shell exit codes
|
||||||
|
- **Timeout Control**: `vim.system` supports timeout parameter directly
|
||||||
|
- **Streaming I/O**: Native stdin/stdout handling without temp files
|
||||||
|
- **Progress Reporting**: Real-time compilation/execution feedback
|
||||||
|
- **Cross-Platform**: Remove shell script dependencies
|
||||||
|
|
||||||
|
#### Proposed Build System
|
||||||
|
```lua
|
||||||
|
local function compile_cpp(src_path, output_path, flags, timeout_ms)
|
||||||
|
local compile_cmd = { "g++", unpack(flags), src_path, "-o", output_path }
|
||||||
|
return vim.system(compile_cmd, { timeout = timeout_ms or 10000 })
|
||||||
|
end
|
||||||
|
|
||||||
|
local function execute_with_timeout(binary_path, input_data, timeout_ms)
|
||||||
|
return vim.system(
|
||||||
|
{ binary_path },
|
||||||
|
{
|
||||||
|
stdin = input_data,
|
||||||
|
timeout = timeout_ms or 2000,
|
||||||
|
stdout = true,
|
||||||
|
stderr = true,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Configuration Migration to Pure Lua
|
||||||
|
|
||||||
|
#### Replace File-Based Config with Lua Tables
|
||||||
|
```lua
|
||||||
|
config = {
|
||||||
|
contests = {
|
||||||
|
atcoder = {
|
||||||
|
cpp_version = 23,
|
||||||
|
compile_flags = { "-std=c++23", "-O2", "-DLOCAL", "-Wall", "-Wextra" },
|
||||||
|
debug_flags = { "-std=c++23", "-g3", "-fsanitize=address,undefined", "-DLOCAL" },
|
||||||
|
timeout_ms = 2000,
|
||||||
|
},
|
||||||
|
-- ... other contests
|
||||||
|
},
|
||||||
|
clangd_config = {
|
||||||
|
CompileFlags = { Add = { "-std=c++23", "-DLOCAL" } },
|
||||||
|
Diagnostics = { ClangTidy = { Add = { "readability-*" } } },
|
||||||
|
},
|
||||||
|
clang_format = {
|
||||||
|
BasedOnStyle = "Google",
|
||||||
|
AllowShortFunctionsOnASingleLine = false,
|
||||||
|
-- ... other formatting options
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Dynamic File Generation
|
||||||
|
- Generate `.clangd` YAML from Lua config
|
||||||
|
- Generate `.clang-format` from Lua config
|
||||||
|
- Eliminate static template files
|
||||||
|
|
||||||
|
### 3. Enhanced Window Management (Remove vim-zoom Dependency)
|
||||||
|
|
||||||
|
#### Current Diff Implementation Issues
|
||||||
|
- Manual session management with temp files
|
||||||
|
- No proper view state restoration
|
||||||
|
- Hardcoded window arrangements
|
||||||
|
|
||||||
|
#### Proposed Native Window Management
|
||||||
|
```lua
|
||||||
|
local function save_window_state()
|
||||||
|
return {
|
||||||
|
layout = vim.fn.winrestcmd(),
|
||||||
|
views = vim.tbl_map(function(win)
|
||||||
|
return {
|
||||||
|
winid = win,
|
||||||
|
view = vim.fn.winsaveview(),
|
||||||
|
bufnr = vim.api.nvim_win_get_buf(win)
|
||||||
|
}
|
||||||
|
end, vim.api.nvim_list_wins())
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local function restore_window_state(state)
|
||||||
|
vim.cmd(state.layout)
|
||||||
|
for _, view_state in ipairs(state.views) do
|
||||||
|
if vim.api.nvim_win_is_valid(view_state.winid) then
|
||||||
|
vim.api.nvim_win_call(view_state.winid, function()
|
||||||
|
vim.fn.winrestview(view_state.view)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Improved Diff Mode
|
||||||
|
- Use `vim.diff()` API for programmatic diff generation
|
||||||
|
- Better window state management with `winsaveview`/`winrestview`
|
||||||
|
- Native zoom functionality without external dependency
|
||||||
|
|
||||||
|
### 4. Enhanced I/O and Timeout Management
|
||||||
|
|
||||||
|
#### Current Limitations
|
||||||
|
- Hardcoded 2-second timeout
|
||||||
|
- Shell-based timeout implementation
|
||||||
|
- Limited output processing
|
||||||
|
|
||||||
|
#### Proposed Improvements
|
||||||
|
```lua
|
||||||
|
local function execute_solution(config)
|
||||||
|
local start_time = vim.loop.hrtime()
|
||||||
|
|
||||||
|
local result = vim.system(
|
||||||
|
{ config.binary_path },
|
||||||
|
{
|
||||||
|
stdin = config.input_data,
|
||||||
|
timeout = config.timeout_ms,
|
||||||
|
stdout = true,
|
||||||
|
stderr = true,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
local end_time = vim.loop.hrtime()
|
||||||
|
local execution_time = (end_time - start_time) / 1000000 -- Convert to ms
|
||||||
|
|
||||||
|
return {
|
||||||
|
stdout = result.stdout,
|
||||||
|
stderr = result.stderr,
|
||||||
|
code = result.code,
|
||||||
|
time_ms = execution_time,
|
||||||
|
timed_out = result.code == 124,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Integrated Problem Scraping
|
||||||
|
|
||||||
|
#### Current Python Integration
|
||||||
|
- Separate uv environment management
|
||||||
|
- Shell script orchestration for scraping
|
||||||
|
- External Python dependencies (requests, beautifulsoup4, cloudscraper)
|
||||||
|
|
||||||
|
#### Proposed Native Integration Options
|
||||||
|
|
||||||
|
**Option A: Keep Python, Improve Integration**
|
||||||
|
```lua
|
||||||
|
local function scrape_problem(contest, problem_id, problem_letter)
|
||||||
|
local scraper_path = get_scraper_path(contest)
|
||||||
|
local args = contest == "cses" and { problem_id } or { problem_id, problem_letter }
|
||||||
|
|
||||||
|
return vim.system(
|
||||||
|
{ "uv", "run", scraper_path, unpack(args) },
|
||||||
|
{ cwd = plugin_path, timeout = 30000 }
|
||||||
|
)
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
**Option B: Native Lua HTTP (Future)**
|
||||||
|
- Wait for Neovim native HTTP client
|
||||||
|
- Eliminate Python dependency entirely
|
||||||
|
- Pure Lua HTML parsing (challenging)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Implementation Challenges & Considerations
|
||||||
|
|
||||||
|
### Technical Feasibility
|
||||||
|
|
||||||
|
#### ✅ **Definitely Possible**
|
||||||
|
- Replace makefile with vim.system calls
|
||||||
|
- Migrate configuration to pure Lua tables
|
||||||
|
- Implement native window state management
|
||||||
|
- Add configurable timeouts
|
||||||
|
- Remove vim-zoom dependency
|
||||||
|
|
||||||
|
#### ⚠️ **Requires Careful Implementation**
|
||||||
|
- **Signal Handling**: Shell scripts handle SIGSEGV, SIGFPE mapping - need Lua equivalent
|
||||||
|
- **AddressSanitizer Integration**: LD_PRELOAD handling in debug mode
|
||||||
|
- **Cross-Platform**: Shell scripts provide some cross-platform abstraction
|
||||||
|
|
||||||
|
#### 🤔 **Complex/Questionable**
|
||||||
|
- **Complete Python Elimination**: Would require native HTTP client + HTML parsing
|
||||||
|
- **Output Truncation Logic**: Currently truncates to 1000 lines efficiently in shell
|
||||||
|
|
||||||
|
### Migration Strategy
|
||||||
|
|
||||||
|
#### Phase 1: Core Build System
|
||||||
|
1. Replace `vim.system({ "make", ... })` with direct `vim.system({ "g++", ... })`
|
||||||
|
2. Migrate compile/debug flags from txt files to Lua config
|
||||||
|
3. Implement native timeout and execution management
|
||||||
|
|
||||||
|
#### Phase 2: Window Management
|
||||||
|
1. Implement native window state saving/restoration
|
||||||
|
2. Remove vim-zoom dependency mention
|
||||||
|
3. Enhance diff mode with better view management
|
||||||
|
|
||||||
|
#### Phase 3: Configuration Integration
|
||||||
|
1. Generate .clangd/.clang-format from Lua config
|
||||||
|
2. Consolidate all configuration in single config table
|
||||||
|
3. Add runtime configuration validation
|
||||||
|
|
||||||
|
#### Phase 4: Enhanced Features
|
||||||
|
1. Configurable timeouts per contest
|
||||||
|
2. Better error reporting and progress feedback
|
||||||
|
3. Enhanced output processing and metadata
|
||||||
|
|
||||||
|
### User Experience Impact
|
||||||
|
|
||||||
|
#### Advantages
|
||||||
|
- **Simpler Dependencies**: No external shell scripts or makefile
|
||||||
|
- **Better Error Messages**: Native Lua error handling
|
||||||
|
- **Configurable Timeouts**: Per-contest timeout settings
|
||||||
|
- **Improved Performance**: Direct system calls vs shell interpretation
|
||||||
|
- **Better Integration**: Native Neovim APIs throughout
|
||||||
|
|
||||||
|
#### Potential Concerns
|
||||||
|
- **Compatibility**: Users relying on current makefile system
|
||||||
|
- **Feature Parity**: Ensuring all current functionality is preserved
|
||||||
|
- **Debugging**: Shell scripts are easier to debug independently
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Recommendation
|
||||||
|
|
||||||
|
**Proceed with modernization** - The proposed changes align well with Neovim 0.9+ capabilities and would significantly improve the plugin's maintainability and user experience. The migration is technically feasible with the main complexity being in preserving exact feature parity during the transition.
|
||||||
|
|
||||||
|
**Priority Order**:
|
||||||
|
1. Build system migration (highest impact, lowest risk)
|
||||||
|
2. Window management improvements (removes external dependency)
|
||||||
|
3. Configuration consolidation (improves user experience)
|
||||||
|
4. Enhanced I/O and timeout management (adds new capabilities)
|
||||||
|
|
||||||
|
The plugin's current architecture is well-designed, making this modernization an enhancement rather than a rewrite.
|
||||||
|
|
@ -2,6 +2,7 @@ local config_module = require("cp.config")
|
||||||
local snippets = require("cp.snippets")
|
local snippets = require("cp.snippets")
|
||||||
local execute = require("cp.execute")
|
local execute = require("cp.execute")
|
||||||
local scrape = require("cp.scrape")
|
local scrape = require("cp.scrape")
|
||||||
|
local window = require("cp.window")
|
||||||
|
|
||||||
local M = {}
|
local M = {}
|
||||||
local config = {}
|
local config = {}
|
||||||
|
|
@ -15,13 +16,6 @@ if not vim.fn.has("nvim-0.10.0") then
|
||||||
return M
|
return M
|
||||||
end
|
end
|
||||||
|
|
||||||
local function clearcol()
|
|
||||||
vim.api.nvim_set_option_value("number", false, { scope = "local" })
|
|
||||||
vim.api.nvim_set_option_value("relativenumber", false, { scope = "local" })
|
|
||||||
vim.api.nvim_set_option_value("statuscolumn", "", { scope = "local" })
|
|
||||||
vim.api.nvim_set_option_value("signcolumn", "no", { scope = "local" })
|
|
||||||
vim.api.nvim_set_option_value("equalalways", false, { scope = "global" })
|
|
||||||
end
|
|
||||||
|
|
||||||
local function get_plugin_path()
|
local function get_plugin_path()
|
||||||
local plugin_path = debug.getinfo(1, "S").source:sub(2)
|
local plugin_path = debug.getinfo(1, "S").source:sub(2)
|
||||||
|
|
@ -129,11 +123,11 @@ local function setup_problem(problem_id, problem_letter)
|
||||||
|
|
||||||
vim.cmd.vsplit(output)
|
vim.cmd.vsplit(output)
|
||||||
vim.cmd.w()
|
vim.cmd.w()
|
||||||
clearcol()
|
window.clearcol()
|
||||||
vim.cmd(("vertical resize %d"):format(math.floor(vim.o.columns * 0.3)))
|
vim.cmd(("vertical resize %d"):format(math.floor(vim.o.columns * 0.3)))
|
||||||
vim.cmd.split(input)
|
vim.cmd.split(input)
|
||||||
vim.cmd.w()
|
vim.cmd.w()
|
||||||
clearcol()
|
window.clearcol()
|
||||||
vim.cmd.wincmd("h")
|
vim.cmd.wincmd("h")
|
||||||
|
|
||||||
log(("switched to problem %s"):format(full_problem_id))
|
log(("switched to problem %s"):format(full_problem_id))
|
||||||
|
|
@ -198,13 +192,9 @@ end
|
||||||
|
|
||||||
local function diff_problem()
|
local function diff_problem()
|
||||||
if vim.g.cp_diff_mode then
|
if vim.g.cp_diff_mode then
|
||||||
vim.cmd.diffoff()
|
window.restore_layout(vim.g.cp_saved_layout)
|
||||||
if vim.g.cp_saved_session then
|
|
||||||
vim.cmd(("silent! source %s"):format(vim.g.cp_saved_session))
|
|
||||||
vim.fn.delete(vim.g.cp_saved_session)
|
|
||||||
vim.g.cp_saved_session = nil
|
|
||||||
end
|
|
||||||
vim.g.cp_diff_mode = false
|
vim.g.cp_diff_mode = false
|
||||||
|
vim.g.cp_saved_layout = nil
|
||||||
log("exited diff mode")
|
log("exited diff mode")
|
||||||
else
|
else
|
||||||
local problem_id = get_current_problem()
|
local problem_id = get_current_problem()
|
||||||
|
|
@ -222,31 +212,14 @@ local function diff_problem()
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local temp_output = vim.fn.tempname()
|
vim.g.cp_saved_layout = window.save_layout()
|
||||||
|
|
||||||
local result = vim.system({ "awk", "/^\\[[^]]*\\]:/ {exit} {print}", output }, { text = true }):wait()
|
local result = vim.system({ "awk", "/^\\[[^]]*\\]:/ {exit} {print}", output }, { text = true }):wait()
|
||||||
vim.fn.writefile(vim.split(result.stdout, "\n"), temp_output)
|
local actual_output = result.stdout
|
||||||
|
|
||||||
local session_file = vim.fn.tempname() .. ".vim"
|
|
||||||
vim.cmd(("silent! mksession! %s"):format(session_file))
|
|
||||||
vim.g.cp_saved_session = session_file
|
|
||||||
|
|
||||||
vim.cmd.diffoff()
|
|
||||||
vim.cmd.only()
|
|
||||||
|
|
||||||
vim.cmd.edit(temp_output)
|
|
||||||
vim.cmd.diffthis()
|
|
||||||
clearcol()
|
|
||||||
|
|
||||||
vim.cmd.vsplit(expected)
|
|
||||||
vim.cmd.diffthis()
|
|
||||||
clearcol()
|
|
||||||
|
|
||||||
vim.cmd(("botright split %s"):format(input))
|
|
||||||
clearcol()
|
|
||||||
vim.cmd.wincmd("k")
|
|
||||||
|
|
||||||
|
window.setup_diff_layout(actual_output, expected, input)
|
||||||
|
|
||||||
vim.g.cp_diff_mode = true
|
vim.g.cp_diff_mode = true
|
||||||
vim.g.cp_temp_output = temp_output
|
|
||||||
log("entered diff mode")
|
log("entered diff mode")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
75
lua/cp/window.lua
Normal file
75
lua/cp/window.lua
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
local M = {}
|
||||||
|
|
||||||
|
function M.clearcol()
|
||||||
|
vim.api.nvim_set_option_value("number", false, { scope = "local" })
|
||||||
|
vim.api.nvim_set_option_value("relativenumber", false, { scope = "local" })
|
||||||
|
vim.api.nvim_set_option_value("statuscolumn", "", { scope = "local" })
|
||||||
|
vim.api.nvim_set_option_value("signcolumn", "no", { scope = "local" })
|
||||||
|
vim.api.nvim_set_option_value("equalalways", false, { scope = "global" })
|
||||||
|
end
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
function M.restore_layout(state)
|
||||||
|
if not state then return end
|
||||||
|
|
||||||
|
vim.cmd.diffoff()
|
||||||
|
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
|
||||||
|
|
||||||
|
function M.setup_diff_layout(actual_output, expected_output, input_file)
|
||||||
|
vim.cmd.diffoff()
|
||||||
|
vim.cmd.only()
|
||||||
|
|
||||||
|
local output_lines = vim.split(actual_output, "\n")
|
||||||
|
local output_buf = vim.api.nvim_create_buf(false, true)
|
||||||
|
vim.api.nvim_buf_set_lines(output_buf, 0, -1, false, output_lines)
|
||||||
|
vim.bo[output_buf].filetype = "cpoutput"
|
||||||
|
|
||||||
|
vim.cmd.edit()
|
||||||
|
vim.api.nvim_set_current_buf(output_buf)
|
||||||
|
vim.cmd.diffthis()
|
||||||
|
M.clearcol()
|
||||||
|
|
||||||
|
vim.cmd.vsplit(expected_output)
|
||||||
|
vim.cmd.diffthis()
|
||||||
|
M.clearcol()
|
||||||
|
|
||||||
|
vim.cmd(("botright split %s"):format(input_file))
|
||||||
|
M.clearcol()
|
||||||
|
vim.cmd.wincmd("k")
|
||||||
|
end
|
||||||
|
|
||||||
|
return M
|
||||||
|
|
@ -15,9 +15,8 @@ neovim plugin for competitive programming.
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
- Neovim 0.9+
|
- Neovim 0.10.0+
|
||||||
- `make`
|
- [uv](https://docs.astral.sh/uv/): problem scraping (optional)
|
||||||
- [uv](https://docs.astral.sh/uv/): problem scraping (optional)
|
|
||||||
- [LuaSnip](https://github.com/L3MON4D3/LuaSnip): contest-specific snippets (optional)
|
- [LuaSnip](https://github.com/L3MON4D3/LuaSnip): contest-specific snippets (optional)
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
@ -42,8 +41,7 @@ Using [lazy.nvim](https://github.com/folke/lazy.nvim):
|
||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
|
|
||||||
- remove vim-zoom dependency
|
- vimdocs
|
||||||
- vimdocs
|
|
||||||
- example video
|
- example video
|
||||||
- more flexible setup (more of a question of philosophy)
|
- more flexible setup (more of a question of philosophy)
|
||||||
- USACO support
|
- USACO support
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue