Skip to content

feat: structured parsers and diagnostic messages #75

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion autoload/ultest/adapter.vim
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ function! ultest#adapter#build_cmd(test, scope) abort
execute 'cd' g:test#project_root
endif
let a:test.file = fnamemodify(a:test.file, get(g:, "test#filename_modifier", ":."))
call ultest#process#pre(a:test)
call ultest#process#pre([a:test])
let runner = test#determine_runner(a:test.file)
let executable = test#base#executable(runner)

Expand Down
176 changes: 100 additions & 76 deletions autoload/ultest/process.vim
Original file line number Diff line number Diff line change
Expand Up @@ -6,105 +6,129 @@ for processor in g:ultest#processors
endif
endfor

function ultest#process#new(test) abort
call ultest#process#pre(a:test)
if index(g:ultest_buffers, a:test.file) == -1
let g:ultest_buffers = add(g:ultest_buffers, a:test.file)
endif
let tests = getbufvar(a:test.file, "ultest_tests", {})
let tests[a:test.id] = a:test
function! s:CallProcessor(event, args) abort
for processor in g:ultest#active_processors
let new = get(processor, "new", "")
if new != ""
call function(new)(a:test)
let func = get(processor, a:event, "")
if func != ""
if get(processor, "lua")
call luaeval(func."(unpack(_A))", a:args)
else
call call(func, a:args)
endif
endif
endfor
endfunction

function ultest#process#start(test) abort
call ultest#process#pre(a:test)
let tests = getbufvar(a:test.file, "ultest_tests", {})
let tests[a:test.id] = a:test
let results = getbufvar(a:test.file, "ultest_results")
if has_key(results, a:test.id)
call remove(results, a:test.id)
endif
for processor in g:ultest#active_processors
let start = get(processor, "start", "")
if start != ""
call function(start)(a:test)
function! s:UpdateBufferTests(tests) abort
let new_tests = {}
for test in a:tests
if index(g:ultest_buffers, test.file) == -1
let g:ultest_buffers = add(g:ultest_buffers, test.file)
endif
if !has_key(new_tests, test.file)
let new_tests[test.file] = {}
endif
let new_tests[test.file][test.id] = test
endfor
for [file, new_file_tests] in items(new_tests)
let tests = getbufvar(file, "ultest_tests", {})
call extend(tests, new_file_tests)
endfor
endfunction

function ultest#process#move(test) abort
call ultest#process#pre(a:test)
let tests = getbufvar(a:test.file, "ultest_tests")
let tests[a:test.id] = a:test
for processor in g:ultest#active_processors
let start = get(processor, "move", "")
if start != ""
call function(start)(a:test)
function! s:UpdateBufferResults(results) abort
let new_results = {}
for result in a:results
if !has_key(new_results, result.file)
let new_results[result.file] = {}
endif
let new_results[result.file][result.id] = result
endfor
for [file, new_file_results] in items(new_results)
let tests = getbufvar(file, "ultest_results", {})
call extend(tests, new_file_results)
endfor
endfunction

function ultest#process#replace(test, result) abort
call ultest#process#pre(a:test)
let tests = getbufvar(a:test.file, "ultest_tests")
let tests[a:test.id] = a:test
let results = getbufvar(a:result.file, "ultest_results")
let results[a:result.id] = a:result
for processor in g:ultest#active_processors
let exit = get(processor, "replace", "")
if exit != ""
call function(exit)(a:result)
function! s:ClearTests(tests) abort
for test in a:tests
let buf_tests = getbufvar(test.file, "ultest_tests")
if has_key(buf_tests, test.id)
call remove(buf_tests, test.id)
endif
endfor
endfunction

function ultest#process#clear(test) abort
call ultest#process#pre(a:test)
let tests = getbufvar(a:test.file, "ultest_tests")
if has_key(tests, a:test.id)
call remove(tests, a:test.id)
endif
let results = getbufvar(a:test.file, "ultest_results")
if has_key(results, a:test.id)
call remove(results, a:test.id)
endif
for processor in g:ultest#active_processors
let clear = get(processor, "clear", "")
if clear != ""
call function(clear)(a:test)
function! s:ClearTestResults(tests) abort
for test in a:tests
let results = getbufvar(test.file, "ultest_results")
if has_key(results, test.id)
call remove(results, test.id)
endif
endfor
endfunction

function ultest#process#exit(test, result) abort
call ultest#process#pre(a:test)
if !has_key(getbufvar(a:result.file, "ultest_tests", {}), a:result.id)
return
endif
let tests = getbufvar(a:test.file, "ultest_tests", {})
let tests[a:test.id] = a:test
let results = getbufvar(a:result.file, "ultest_results")
let results[a:result.id] = a:result
for processor in g:ultest#active_processors
let exit = get(processor, "exit", "")
if exit != ""
call function(exit)(a:result)
endif
function! s:SeparateTestAndResults(combined) abort
let tests = []
let results = []
for [test, result] in a:combined
call add(tests, test)
call add(results, result)
endfor
return [tests, results]
endfunction

function ultest#process#pre(test) abort
if type(a:test.name) == v:t_list
if exists("*list2str")
let newName = list2str(a:test.name)
else
let newName = join(map(a:test.name, {nr, val -> nr2char(val)}), '')
function ultest#process#new(tests) abort
call ultest#process#pre(a:tests)
call s:UpdateBufferTests(a:tests)
call s:CallProcessor("new", [a:tests])
endfunction

function ultest#process#start(tests) abort
call ultest#process#pre(a:tests)
call s:UpdateBufferTests(a:tests)
call s:ClearTestResults(a:tests)
call s:CallProcessor("start", [a:tests])
endfunction

function ultest#process#move(tests) abort
call ultest#process#pre(a:tests)
call s:UpdateBufferTests(a:tests)
call s:CallProcessor("move", [a:tests])
endfunction

function ultest#process#replace(combined) abort
let [tests, results] = s:SeparateTestAndResults(a:combined)
call ultest#process#pre(tests)
call s:UpdateBufferTests(tests)
call s:UpdateBufferResults(results)
call s:CallProcessor("replace", [results])
endfunction

function ultest#process#clear(tests) abort
call ultest#process#pre(a:tests)
call s:ClearTests(a:tests)
call s:ClearTestResults(a:tests)
call s:CallProcessor("clear", [a:tests])
endfunction

function ultest#process#exit(combined) abort
let [tests, results] = s:SeparateTestAndResults(a:combined)
call ultest#process#pre(tests)
call s:UpdateBufferTests(tests)
call s:UpdateBufferResults(results)
call s:CallProcessor("exit", [results])
endfunction

function ultest#process#pre(tests) abort
for test in a:tests
if type(test.name) == v:t_list
if exists("*list2str")
let newName = list2str(test.name)
else
let newName = join(map(test.name, {nr, val -> nr2char(val)}), '')
endif
let test.name = newName
endif
let a:test.name = newName
endif
endfor
endfunction
58 changes: 33 additions & 25 deletions autoload/ultest/signs.vim
Original file line number Diff line number Diff line change
@@ -1,36 +1,42 @@
function! ultest#signs#move(test) abort
if (a:test.type != "test") | return | endif
let result = get(getbufvar(a:test.file, "ultest_results"), a:test.id, {})
if result != {}
call ultest#signs#process(result)
else
call ultest#signs#start(a:test)
endif
function! ultest#signs#move(tests) abort
for test in a:tests
if (test.type != "test") | continue | endif
let result = get(getbufvar(test.file, "ultest_results"), test.id, {})
if result != {}
call ultest#signs#process([result])
else
call ultest#signs#start([test])
endif
endfor
endfunction

function! ultest#signs#start(test) abort
if (a:test.type != "test") | return | endif
call ultest#signs#unplace(a:test)
if !a:test.running | return | endif
function! ultest#signs#start(tests) abort
for test in a:tests
if (test.type != "test") | continue | endif
call ultest#signs#unplace([test])
if !test.running | continue | endif
if s:UseVirtual()
call s:PlaceVirtualText(a:test, g:ultest_running_text, "UltestRunning")
call s:PlaceVirtualText(test, g:ultest_running_text, "UltestRunning")
else
call s:PlaceSign(a:test, "test_running")
call s:PlaceSign(test, "test_running")
endif
endfor
endfunction

function! ultest#signs#process(result) abort
let test = getbufvar(a:result.file, "ultest_tests")[a:result.id]
if (test.type != "test") | return | endif
call ultest#signs#unplace(test)
function! ultest#signs#process(results) abort
for result in a:results
let test = getbufvar(result.file, "ultest_tests")[result.id]
if (test.type != "test") | continue | endif
call ultest#signs#unplace([test])
if s:UseVirtual()
let text_highlight = a:result.code ? "UltestFail" : "UltestPass"
let text = a:result.code ? g:ultest_fail_text : g:ultest_pass_text
let text_highlight = result.code ? "UltestFail" : "UltestPass"
let text = result.code ? g:ultest_fail_text : g:ultest_pass_text
call s:PlaceVirtualText(test, text, text_highlight)
else
let test_icon = a:result.code ? "test_fail" : "test_pass"
let test_icon = result.code ? "test_fail" : "test_pass"
call s:PlaceSign(test, test_icon)
endif
endfor
endfunction

function! s:UseVirtual() abort
Expand All @@ -48,15 +54,17 @@ function! s:PlaceVirtualText(test, text, highlight) abort
call nvim_buf_set_virtual_text(buffer, namespace, str2nr(a:test.line) - 1, [[a:text, a:highlight]], {})
endfunction

function! ultest#signs#unplace(test)
if (a:test.type != "test") | return | endif
function! ultest#signs#unplace(tests)
for test in a:tests
if (test.type != "test") | continue | endif
if s:UseVirtual()
let namespace = s:GetNamespace(a:test)
let namespace = s:GetNamespace(test)
call nvim_buf_clear_namespace(0, namespace, 0, -1)
else
call sign_unplace(a:test.id, {"buffer": a:test.file})
call sign_unplace(test.id, {"buffer": test.file})
redraw
endif
endfor
endfunction

function! s:GetNamespace(test)
Expand Down
17 changes: 0 additions & 17 deletions autoload/ultest/statusline.vim

This file was deleted.

10 changes: 6 additions & 4 deletions autoload/ultest/summary.vim
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,12 @@ function! s:RenderSummary() abort
let structure = getbufvar(test_file, "ultest_file_structure")
let tests = getbufvar(test_file, "ultest_tests", {})
let results = getbufvar(test_file, "ultest_results", {})
let state = {"lines": lines, "matches": matches, "tests": tests, "results": results }
call s:RenderGroup("", structure, 0, state)
if test_file != g:ultest_buffers[-1]
call add(lines, "")
if tests != {}
let state = {"lines": lines, "matches": matches, "tests": tests, "results": results }
call s:RenderGroup("", structure, 0, state)
if test_file != g:ultest_buffers[-1]
call add(lines, "")
endif
endif
endfor
if has("nvim")
Expand Down
43 changes: 20 additions & 23 deletions lua/ultest.lua
Original file line number Diff line number Diff line change
Expand Up @@ -28,37 +28,34 @@ local function dap_run_test(test, build_config)
end

local output_handler = function(_, body)
if vim.tbl_contains({"stdout", "stderr"}, body.category) then
if vim.tbl_contains({ "stdout", "stderr" }, body.category) then
io.write(body.output)
io.flush()
end
end

require("dap").run(
user_config.dap,
{
before = function(config)
local output_file = io.open(output_name, "w")
io.output(output_file)
vim.fn["ultest#handler#external_start"](test.id, test.file, output_name)
dap.listeners.after.event_output[handler_id] = output_handler
dap.listeners.before.event_terminated[handler_id] = terminated_handler
dap.listeners.after.event_exited[handler_id] = exit_handler
return config
end,
after = function()
dap.listeners.after.event_exited[handler_id] = nil
dap.listeners.before.event_terminated[handler_id] = nil
dap.listeners.after.event_output[handler_id] = nil
end
}
)
require("dap").run(user_config.dap, {
before = function(config)
local output_file = io.open(output_name, "w")
io.output(output_file)
vim.fn["ultest#handler#external_start"](test.id, test.file, output_name)
dap.listeners.after.event_output[handler_id] = output_handler
dap.listeners.before.event_terminated[handler_id] = terminated_handler
dap.listeners.after.event_exited[handler_id] = exit_handler
return config
end,
after = function()
dap.listeners.after.event_exited[handler_id] = nil
dap.listeners.before.event_terminated[handler_id] = nil
dap.listeners.after.event_output[handler_id] = nil
end,
})
end

local function get_builder(test, config)
local builder =
config.build_config or builders[vim.fn["ultest#adapter#get_runner"](test.file)] or
builders[vim.fn["getbufvar"](test.file, "&filetype")]
local builder = config.build_config
or builders[vim.fn["ultest#adapter#get_runner"](test.file)]
or builders[vim.fn["getbufvar"](test.file, "&filetype")]

if builder == nil then
print("Unsupported runner, need to provide a customer nvim-dap config builder")
Expand Down
Loading