Skip to content

Commit b42c06c

Browse files
committed
feat: open viewer popup showing compilation errors when compilation fails
1 parent c9be46f commit b42c06c

4 files changed

Lines changed: 38 additions & 14 deletions

File tree

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,7 @@ require('competitest').setup {
256256
height = 0.5,
257257
show_nu = true,
258258
show_rnu = false,
259+
open_when_compilation_fails = true,
259260
},
260261
},
261262
popup_ui = {
@@ -370,6 +371,7 @@ require('competitest').setup {
370371
- `height`: a value from 0 to 1, representing the ratio between viewer window height and Neovim height
371372
- `show_nu`: whether to show line numbers or not in viewer window
372373
- `show_rnu`: whether to show relative line numbers or not in viewer window
374+
- `open_when_compilation_fails`: open viewer popup showing compilation errors when compilation fails
373375
- `popup_ui`: settings related to testcase runner popup interface
374376
- `total_width`: a value from 0 to 1, representing the ratio between total interface width and Neovim width
375377
- `total_height`: a value from 0 to 1, representing the ratio between total interface height and Neovim height

lua/competitest/config.lua

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
---@field height number ratio between viewer popup height and Neovim height (between 0 and 1)
2626
---@field show_nu boolean show lines number
2727
---@field show_rnu boolean show lines relative number
28+
---@field open_when_compilation_fails boolean open viewer popup showing compilation errors when compilation fails
2829

2930
---Runner UI options
3031
---@class (exact) competitest.Config.runner_ui
@@ -150,6 +151,7 @@ local default_config = {
150151
height = 0.5,
151152
show_nu = true,
152153
show_rnu = false,
154+
open_when_compilation_fails = true,
153155
},
154156
},
155157
popup_ui = {

lua/competitest/runner.lua

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
local api = vim.api
22
local luv = vim.uv and vim.uv or vim.loop
3-
local config = require("competitest.config")
43
local utils = require("competitest.utils")
5-
local ui = require("competitest.runner_ui")
64

75
---System command with arguments
86
---@class (exact) competitest.SystemCommand
@@ -11,7 +9,6 @@ local ui = require("competitest.runner_ui")
119

1210
---Running testcase process status
1311
---@class (exact) competitest.TCRunner.testcase_status.process
14-
---@field cmd competitest.SystemCommand
1512
---@field stdin uv.uv_pipe_t
1613
---@field stdout uv.uv_pipe_t
1714
---@field stderr uv.uv_pipe_t
@@ -25,7 +22,7 @@ local ui = require("competitest.runner_ui")
2522
---@field expout string[]? expected output lines
2623
---@field stdout string[] stdout lines
2724
---@field stderr string[] stderr lines
28-
---@field tcnum integer | string testcase number or identifier
25+
---@field tcnum integer | "Compile" testcase number or identifier
2926
---@field status "" | "RUNNING" | "TIMEOUT" | "KILLED" | "SIG x" | "RET x" | "FAILED" | "CORRECT" | "WRONG" | "DONE"
3027
---@field hlgroup string testcase status highlight group
3128
---@field timelimit integer? maximum execution time in milliseconds, or `nil` if there's no time limit
@@ -48,7 +45,7 @@ local ui = require("competitest.runner_ui")
4845
---@field tcdata table<integer, competitest.TCRunner.testcase_status> testcases status, data and results
4946
---@field private compile boolean whether compilation is needed in the current run or not
5047
---@field private next_tc integer index of next unprocessed testcase to run
51-
---@field restore_winid integer? bring the cursor to the given window when testcases runner UI is closed
48+
---@field ui_restore_winid integer? bring the cursor to the given window when testcases runner UI is closed
5249
---@field private ui competitest.RunnerUI?
5350
local TCRunner = {}
5451
TCRunner.__index = TCRunner ---@diagnostic disable-line: inject-field
@@ -81,7 +78,7 @@ function TCRunner:new(bufnr)
8178
return { exec = exec, args = args }
8279
end
8380

84-
local buf_cfg = config.get_buffer_config(bufnr)
81+
local buf_cfg = require("competitest.config").get_buffer_config(bufnr)
8582
local compile_command = nil
8683
if buf_cfg.compile_command[filetype] then
8784
compile_command = eval_command(buf_cfg.compile_command[filetype])
@@ -228,7 +225,6 @@ function TCRunner:execute_testcase(tcindex, cmd, dir, callback)
228225
---@type competitest.TCRunner.testcase_status.process
229226
---@diagnostic disable-next-line: missing-fields
230227
local process = {
231-
cmd = cmd,
232228
stdin = assert(luv.new_pipe(false), "CompetiTest.nvim: TCRunner:execute_testcase: process stdin pipe creation failed"),
233229
stdout = assert(luv.new_pipe(false), "CompetiTest.nvim: TCRunner:execute_testcase: process stdout pipe creation failed"),
234230
stderr = assert(luv.new_pipe(false), "CompetiTest.nvim: TCRunner:execute_testcase: process stderr pipe creation failed"),
@@ -237,8 +233,8 @@ function TCRunner:execute_testcase(tcindex, cmd, dir, callback)
237233

238234
utils.create_directory(dir)
239235
---@diagnostic disable-next-line: missing-fields
240-
process.handle, process.pid = luv.spawn(process.cmd.exec, {
241-
args = process.cmd.args,
236+
process.handle, process.pid = luv.spawn(cmd.exec, {
237+
args = cmd.args,
242238
cwd = dir,
243239
stdio = { process.stdin, process.stdout, process.stderr },
244240
}, function(code, signal)
@@ -279,7 +275,7 @@ function TCRunner:execute_testcase(tcindex, cmd, dir, callback)
279275
end
280276
end)
281277
if not process.handle then
282-
utils.notify("TCRunner:execute_testcase: failed to spawn process using '" .. process.cmd.exec .. "' (" .. process.pid .. ").")
278+
utils.notify("TCRunner:execute_testcase: failed to spawn process using '" .. cmd.exec .. "' (" .. process.pid .. ").")
283279
tc.status = "FAILED"
284280
tc.hlgroup = "CompetiTestWarning"
285281
tc.time = -1
@@ -358,6 +354,8 @@ function TCRunner:execute_testcase(tcindex, cmd, dir, callback)
358354
tc.hlgroup = "CompetiTestRunning"
359355
tc.running = true
360356
tc.killed = false
357+
tc.exit_code = nil
358+
tc.exit_signal = nil
361359
self:update_ui(true)
362360
end
363361

@@ -392,7 +390,7 @@ function TCRunner:show_ui()
392390
return
393391
end
394392
if not self.ui then
395-
self.ui = ui:new(self)
393+
self.ui = require("competitest.runner_ui"):new(self)
396394
end
397395
self.ui:show_ui()
398396
self.ui:update_ui()
@@ -401,7 +399,7 @@ end
401399
---Set or update `restore_winid`
402400
---@param restore_winid integer bring the cursor to the given window after runner is closed
403401
function TCRunner:set_restore_winid(restore_winid)
404-
self.restore_winid = restore_winid
402+
self.ui_restore_winid = restore_winid
405403
if self.ui then
406404
self.ui.restore_winid = restore_winid
407405
end

lua/competitest/runner_ui/init.lua

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ local utils = require("competitest.utils")
5858
---@field private windows competitest.RunnerUI.windows_table
5959
---@field private interface competitest.RunnerUI.interface
6060
---@field private make_viewer_visible boolean one-time request for `self:update_ui()` to open viewer after updating details
61+
---@field private latest_compilation_timestamp integer? latest failed compilation process start timestamp, used to decide whether to automatically show compilation errors in viewer popup or not
6162
local RunnerUI = {}
6263
RunnerUI.__index = RunnerUI ---@diagnostic disable-line: inject-field
6364

@@ -85,7 +86,7 @@ function RunnerUI:new(runner)
8586
viewer_visible = false,
8687
viewer_content = nil,
8788
diff_view = runner.config.view_output_diff,
88-
restore_winid = runner.restore_winid,
89+
restore_winid = runner.ui_restore_winid,
8990
update_details = false,
9091
update_windows = false,
9192
update_testcase = nil,
@@ -432,8 +433,29 @@ function RunnerUI:update_ui()
432433

433434
for tcindex, data in ipairs(self.runner.tcdata) do
434435
local l = { header = "TC " .. data.tcnum, status = data.status, time = "" }
435-
if type(data.tcnum) == "string" then
436+
if data.tcnum == "Compile" then
436437
l.header = data.tcnum
438+
-- open viewer popup showing compilation errors when compilation fails
439+
if
440+
self.runner.config.runner_ui.viewer.open_when_compilation_fails
441+
and not data.killed
442+
and data.exit_code
443+
and data.exit_code ~= 0
444+
and data.process.starting_time ~= self.latest_compilation_timestamp
445+
then
446+
if api.nvim_win_get_cursor(self.windows.tc.winid)[1] == 1 then
447+
self.update_testcase = 1
448+
self.viewer_content = "se"
449+
self.make_viewer_visible = true
450+
self.latest_compilation_timestamp = data.process.starting_time
451+
else
452+
-- move cursor to "Compile" line if not already there, then self:update_ui() will be triggered by CursorMoved event
453+
self.update_testcase = nil
454+
self.update_windows = true
455+
api.nvim_win_set_cursor(self.windows.tc.winid, { 1, 0 })
456+
return
457+
end
458+
end
437459
end
438460
if data.time and data.time ~= -1 then
439461
l.time = string.format("%.3f seconds", data.time / 1000)

0 commit comments

Comments
 (0)