-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit dbdc557
Showing
23 changed files
with
605 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export PATH="${PWD}/lua_modules/bin:${PATH}" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
/luarocks | ||
/lua_modules | ||
/.luarocks |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package = "go-to-test-file.nvim" | ||
version = "test.init-1" | ||
source = { | ||
url = "git+ssh://git@github.com/jtzero/go-to-test-file.nvim.git" | ||
} | ||
description = { | ||
homepage = "*** please enter a project homepage ***", | ||
license = "*** please specify a license ***" | ||
} | ||
dependencies = { | ||
"lua >= 5.1, < 5.2", | ||
"vusted >= 2.3.4-1, < 3", | ||
"plenary.nvim >= scm-1" | ||
} | ||
build = { | ||
type = "builtin", | ||
modules = { | ||
["go-to-test-file"] = "lua/go-to-test-file.lua", | ||
["go-to-test-file.path"] = "lua/go-to-test-file/path.lua", | ||
["go-to-test-file.project"] = "lua/go-to-test-file/project.lua", | ||
["go-to-test-file.str"] = "lua/go-to-test-file/str.lua", | ||
["go-to-test-file.system"] = "lua/go-to-test-file/system.lua", | ||
["go-to-test-file.matrix"] = "lua/go-to-test-file/matrix.lua" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,194 @@ | ||
local str = require('go_to_test_file.str') | ||
local path = require('go_to_test_file.path') | ||
local project = require('go_to_test_file.project') | ||
local git = require('go_to_test_file.git') | ||
local list = require('go_to_test_file.list') | ||
local peer = require('go_to_test_file.peer') | ||
local system = require('go_to_test_file.system') | ||
|
||
GoToTestFile = { | ||
git = git | ||
} | ||
-- requirements fzf, rg, realpath, git, fd | ||
-- TODO remove fzf | ||
|
||
|
||
vim.api.nvim_set_var('src_chomp_prefixes', '^src/|lib/|app/|lua/') | ||
vim.api.nvim_set_var('lua_src_chomp_prefixes', '^src/|^lib/|^app/|^lua/') | ||
vim.api.nvim_set_var('test_file_identifiers', '(test|tests|spec)') | ||
vim.api.nvim_set_var('lua_test_file_identifiers', 'test|tests|spec') | ||
-- fd added end slashes to dirs after 8.4.0 | ||
vim.api.nvim_set_var('test_folder_prefixes', '^(test/|tests/|spec/)(unit/|integration/)?') | ||
-- TODO add second level | ||
vim.api.nvim_set_var('lua_test_folder_prefixes', '^test/|^tests/|^spec/') | ||
|
||
GoToTestFile.DomainlessSourceFolderMatch = function(prefixes, source_folder) | ||
local identifiers = str.split(prefixes, '|') | ||
return list.match_one(source_folder .. "/", identifiers, '', '') | ||
end | ||
|
||
GoToTestFile.RemoveProjectDomainlessPrefix = function(domainless_source_folder_match, git_repo_pwd) | ||
return string.gsub(git_repo_pwd, domainless_source_folder_match, '') | ||
end | ||
|
||
GoToTestFile.FindTestFolderTestFile = function(git_root, source_file_with_abs_path) | ||
local source_file_folder_abs_path = vim.fn.fnamemodify(source_file_with_abs_path, ":h") | ||
local test_folder_abs_path = project.FindProjectTestDirectory(git_root, source_file_folder_abs_path) | ||
local project_abs_path_root = vim.fn.fnamemodify(test_folder_abs_path, ':h') | ||
local source_file_folder_path_rel_to_project_root=path.difference_between_ancestor_folder_and_sub_folder(project_abs_path_root, source_file_folder_abs_path) | ||
local project_source_folder = project.ProjectSourceFolder(project_abs_path_root, source_file_folder_path_rel_to_project_root) | ||
local domainless_source_folder_match = GoToTestFile.DomainlessSourceFolderMatch(vim.g.lua_src_chomp_prefixes, project_source_folder) | ||
|
||
local current_filename_no_ext = vim.fn.fnamemodify(source_file_with_abs_path, ':t:r') | ||
local filepath_relative_to_project_root = source_file_folder_path_rel_to_project_root .. '/' .. current_filename_no_ext | ||
|
||
local prefixless_source_file_path = '' | ||
if domainless_source_folder_match ~= '' then | ||
prefixless_source_file_path = GoToTestFile.RemoveProjectDomainlessPrefix(project_source_folder .. '/', filepath_relative_to_project_root) | ||
else | ||
prefixless_source_file_path = filepath_relative_to_project_root | ||
end | ||
|
||
local cmd = '' | ||
if string.find(prefixless_source_file_path, path.path_separator(system.name)) then | ||
cmd = "cd " .. test_folder_abs_path .. " > /dev/null && fd -t f -p '" .. prefixless_source_file_path .. "' | head -n 1 " | ||
else | ||
cmd = "cd " .. test_folder_abs_path .. " > /dev/null && fd -t f '" .. prefixless_source_file_path .. "' | head -n 1 " | ||
end | ||
local file_relative_to_root = vim.fn.trim(vim.fn.system(cmd)):gsub("^./", "") | ||
if file_relative_to_root == '' then | ||
return test_folder_abs_path | ||
else | ||
return test_folder_abs_path .. '/' .. file_relative_to_root | ||
end | ||
end | ||
|
||
GoToTestFile.RemoveTestFileNameIdentifiers = function(test_filename_rel_path_from_project) | ||
local identifiers = str.split(vim.g.lua_test_file_identifiers, '|') | ||
local with_period = list.match_one(test_filename_rel_path_from_project, identifiers, '%.', '') | ||
local with_underscore = list.match_one(test_filename_rel_path_from_project, identifiers, '_', '') | ||
local path_without_infixes = string.gsub(test_filename_rel_path_from_project, with_period, '') | ||
local path_without_infixes = string.gsub(test_filename_rel_path_from_project, with_underscore, '') | ||
|
||
return path_without_infixes | ||
end | ||
|
||
GoToTestFile.RemoveTestFolderPrefixes = function(test_folder_prefixes, test_file_folder_path_rel_from_project_root) | ||
local identifiers = str.split(test_folder_prefixes, '|') | ||
local prefix_to_chomp = list.match_one(test_file_folder_path_rel_from_project_root, identifiers, '', '') | ||
local path_without_prefixes = string.gsub(test_file_folder_path_rel_from_project_root, prefix_to_chomp, '') | ||
return path_without_prefixes | ||
end | ||
|
||
GoToTestFile.FindSrcFolderCodeFile = function(git_root, test_file_with_abs_path) | ||
local test_file_folder_abs_path = vim.fn.fnamemodify(test_file_with_abs_path, ":h") | ||
local test_file_name = vim.fn.fnamemodify(test_file_with_abs_path, ":t") | ||
local test_folder_abs_path = project.FindProjectTestDirectory(git_root, test_file_folder_abs_path) | ||
local project_abs_path_root = vim.fn.fnamemodify(test_folder_abs_path, ':h') | ||
|
||
local test_file_folder_path_rel_to_project_root=path.difference_between_ancestor_folder_and_sub_folder(project_abs_path_root, test_file_folder_abs_path) | ||
|
||
local sep = path.path_separator(system.name) | ||
local path_without_prefixes = "" | ||
if test_file_folder_path_rel_to_project_root:sub(-#sep) == sep then | ||
path_without_prefixes = GoToTestFile.RemoveTestFolderPrefixes(vim.g.lua_test_folder_prefixes, test_file_folder_path_rel_to_project_root) | ||
else | ||
path_without_prefixes = GoToTestFile.RemoveTestFolderPrefixes(vim.g.lua_test_folder_prefixes, test_file_folder_path_rel_to_project_root .. sep) | ||
end | ||
local current_filename_no_ext = vim.fn.fnamemodify(test_file_with_abs_path, ':t:r') | ||
local test_filepath_without_test_identifiers | ||
if path_without_prefixes == '' then | ||
test_filepath_without_test_identifiers = GoToTestFile.RemoveTestFileNameIdentifiers(current_filename_no_ext) | ||
else | ||
test_filepath_without_test_identifiers = GoToTestFile.RemoveTestFileNameIdentifiers(path_without_prefixes .. '/' .. current_filename_no_ext) | ||
end | ||
-- TODO minimize pathing to make this faster and more precise | ||
local command = "cd " .. project_abs_path_root .. " > /dev/null && rg --files | rg -v '^" .. test_file_name .. "$' | fzf --filter '" .. test_filepath_without_test_identifiers .. "' | head -1" | ||
local relative_path = vim.fn.trim(vim.fn.system(command)) | ||
return path.join(sep, project_abs_path_root, relative_path) | ||
end | ||
vim.cmd('command! FindSrcFolderCodeFile :lua print(GoToTestFile.FindSrcFolderCodeFile(GoToTestFile.git.GitRootOfFile(vim.fn.expand("%:p")), vim.fn.expand("%:p")))') | ||
|
||
-- TODO cd with abs path | ||
GoToTestFile.FindPeerSourceCodeFile = function(file_with_path) | ||
local test_filename = vim.fn.fnamemodify(file_with_path, ':t') | ||
local patterns = str.split(vim.g.lua_test_file_identifiers, '|') | ||
local matched = list.match_one(test_filename, patterns, '%.', '%.') | ||
local expected_source_code_filename = string.gsub(test_filename, matched, '.') | ||
local path = vim.fn.fnamemodify(file_with_path, ':.:h') | ||
local command = "cd " .. path .. " > /dev/null && rg --files | rg -v '^" .. test_filename .. "$' | fzf --filter '" .. expected_source_code_filename .. "' | head -1" | ||
local output = vim.fn.trim(vim.fn.system(command)) | ||
return path .. '/' .. output | ||
end | ||
|
||
vim.cmd('command! FindPeerSourceCodeFile :lua GoToTestFile.FindPeerSourceCodeFile(vim.fn.expand("%:p"))') | ||
|
||
-- TODO cd with abs path | ||
-- TODO filter current_file_name with path | ||
GoToTestFile.FindPeerTestCodeFile = function(file_with_path) | ||
local current_file_name_no_ext = vim.fn.fnamemodify(file_with_path, ':t:r') | ||
local current_file_name = vim.fn.fnamemodify(file_with_path, ':t') | ||
local path = vim.fn.fnamemodify(file_with_path, ':p:h') | ||
local cmd = "cd " .. path .. " > /dev/null && fd -t f '" .. current_file_name_no_ext .. | ||
"' | rg -v '" .. current_file_name .. "' | rg '" .. vim.g.test_file_identifiers .. "' | head -n 1 " | ||
local output = vim.fn.trim(vim.fn.system(cmd)) | ||
if output == '' then | ||
return '' | ||
else | ||
return path .. '/' .. output | ||
end | ||
end | ||
|
||
vim.cmd('command! FindPeerTestCodeFile :lua print(GoToTestFile.FindPeerTestCodeFile(vim.fn.expand("%:p")))') | ||
|
||
GoToTestFile.FindTestOrSrcCodeFile = function(git_root, current_file_abs_path) | ||
if peer.HasPeerSourceCodeFile(current_file_abs_path) then | ||
return GoToTestFile.FindPeerSourceCodeFile(current_file_abs_path) | ||
elseif project.IsInATestFolder(git_root, current_file_abs_path) then | ||
return GoToTestFile.FindSrcFolderCodeFile(git_root, current_file_abs_path) | ||
else | ||
local peer_test_code_file = GoToTestFile.FindPeerTestCodeFile(current_file_abs_path) | ||
if peer_test_code_file ~= '' then | ||
return peer_test_code_file | ||
else | ||
return GoToTestFile.FindTestFolderTestFile(git_root, current_file_abs_path) | ||
end | ||
end | ||
end | ||
|
||
vim.cmd('command! FindTestOrSrcCodeFile :lua print(GoToTestFile.FindTestOrSrcCodeFile(GoToTestFile.git.GitRootOfFile(vim.fn.expand("%:p")), vim.fn.expand("%:p")))') | ||
|
||
-- rename to last resort, the above should provide some sane locations even if it cannot find the file | ||
GoToTestFile.FindTestOrSrcCodeFileFolderOnFailure = function(current_file_abs_path) | ||
local git_root = GoToTestFile.git.GitRootOfFile(current_file_abs_path) | ||
local path = GoToTestFile.FindTestOrSrcCodeFile(git_root, current_file_abs_path) | ||
if path == './' then | ||
local test_path = project.RepoTestFolder() | ||
if test_path ~= '' then | ||
return test_path | ||
else | ||
return git_root | ||
end | ||
else | ||
return path | ||
end | ||
end | ||
|
||
GoToTestFile.setup = function(opts) | ||
opts = opts or {} | ||
|
||
--vim.notify_once("gruvbox.nvim: you must use neovim 0.8 or higher") | ||
|
||
vim.api.nvim_create_user_command("FindTestOrSrcCodeFileFolderOnFailure", | ||
function() | ||
local path = GoToTestFile.FindTestOrSrcCodeFileFolderOnFailure(vim.fn.expand("%:p")) | ||
print(path) | ||
vim.cmd('e ' .. path) | ||
end, | ||
{} | ||
) | ||
--vim.cmd('command! FindTestOrSrcCodeFileFolderOnFailure :exec "e " . :lua FindTestOrSrcCodeFileFolderOnFailure(expand("%:p"))') | ||
vim.keymap.set('n', '<M-T>', '<cmd>FindTestOrSrcCodeFileFolderOnFailure<CR>', {desc = 'Opens a corresponding test file or src file if not found opens the test folder', noremap = true}) | ||
end | ||
|
||
return GoToTestFile |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
return { | ||
GitRootOfFile = function(file_abs_path) | ||
local file_folder_abs_path = vim.fn.fnamemodify(file_abs_path, ":h") | ||
local cmd = 'cd ' .. file_folder_abs_path .. ' > /dev/null && git rev-parse --show-toplevel' | ||
return vim.fn.trim(vim.fn.system(cmd)) | ||
end | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
|
||
return { | ||
match_one = function(test_str, list, prefix, suffix) | ||
local exhausted = false | ||
local i = 1 | ||
local found = '' | ||
while (not found) or (not exhausted) do | ||
if string.match(test_str, prefix .. list[i] .. suffix) then | ||
found = prefix .. list[i] .. suffix | ||
end | ||
i = i + 1 | ||
if #list < i then | ||
exhausted = true | ||
end | ||
end | ||
return found or '' | ||
end | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
return { | ||
row_with_smallest_first_item = function(table_to_search) | ||
local min = math.huge | ||
local idx = -1 | ||
for i = 1, #table_to_search do | ||
local new_min = min < table_to_search[i][1] and min or table_to_search[i][1] | ||
if new_min == 0 then | ||
idx = 1 | ||
return idx | ||
else | ||
if new_min < min then | ||
min = new_min | ||
idx = i | ||
end | ||
end | ||
end | ||
return idx | ||
end | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
-- replace with plenary | ||
local system = require('go_to_test_file.system') | ||
|
||
local function path_separator(system_name) | ||
if system_name == system.windows_name then | ||
return '\\' | ||
end | ||
return '/' | ||
end | ||
|
||
local function script_path(system_name) | ||
local ps = path_separator(system_name) | ||
local str = vim.fn.getcwd() .. ps .. debug.getinfo(2, 'S').source:sub(2) | ||
str = str:gsub('/', ps) -- ?? | ||
return str:match('(.*' .. ps .. ')') | ||
end | ||
|
||
return { | ||
script_path = script_path, | ||
path_separator = path_separator, | ||
join = function(sep, a, ...) | ||
local memo = a | ||
for _key,value in ipairs({...}) do | ||
memo = memo .. sep .. value | ||
end | ||
return memo | ||
end, | ||
-- ancestor has to be relative to PWD or you have to pass in abs | ||
difference_between_ancestor_folder_and_sub_folder = function(ancestor, sub_folder) | ||
local cmd = 'realpath --relative-to="' .. ancestor .. '" "' .. sub_folder .. '"' | ||
return vim.fn.trim(vim.fn.system(cmd)) | ||
end | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
local peer = {} | ||
|
||
vim.api.nvim_set_var('test_file_identifiers', '(test|tests|spec)') | ||
|
||
-- TODO cd with abs path | ||
-- TODO should_have_peer_source_code_file_from_name | ||
peer.HasPeerSourceCodeFile = function(file_with_path) | ||
local current_file_name = vim.fn.fnamemodify(file_with_path, ':t') | ||
local cmd = 'printf "' .. current_file_name .. '" | rg "\\.' .. vim.g.test_file_identifiers .. '\\."' | ||
local output = vim.fn.trim(vim.fn.system(cmd)) | ||
return output ~= '' | ||
end | ||
|
||
return peer |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
vim.api.nvim_set_var('deep_test_folder_prefixes', '(test|tests|spec)(/unit|/integration)?$') | ||
|
||
local str = require('go_to_test_file.str') | ||
local path = require('go_to_test_file.path') | ||
local matrix = require('go_to_test_file.matrix') | ||
local project = {} | ||
|
||
project.RepoTestFolder = function() | ||
local folder_name = vim.fn.trim(vim.fn.system('cd "$(git rev-parse --show-toplevel)" > /dev/null && find . -type d -print -maxdepth 1 | cut -d/ -f2- | rg "^' .. vim.g.test_file_identifiers .. '$"')) | ||
return vim.fn.trim(vim.fn.system('git rev-parse --show-toplevel')) .. '/' .. folder_name | ||
end | ||
|
||
project.ProjectSourceFolder = function(project_abs_path_root, source_file_folder_path_rel_to_project_root) | ||
local project_source_folder = vim.fn.trim(vim.fn.system('realpath --relative-to="' .. project_abs_path_root .. '" "' .. source_file_folder_path_rel_to_project_root .. '"')) | ||
return str.split(project_source_folder, '/')[1] | ||
end | ||
|
||
project.IsInATestFolder = function(git_root, current_file_with_abs_path) | ||
local current_file_folder_abs_path = vim.fn.fnamemodify(current_file_with_abs_path, ":h") | ||
local test_folder_abs_path = project.FindProjectTestDirectory(git_root, current_file_folder_abs_path) | ||
if test_folder_abs_path == '' then | ||
return false | ||
else | ||
-- TODO this is a little niave | ||
return string.find(current_file_folder_abs_path, test_folder_abs_path, 1, true) ~= nil | ||
end | ||
end | ||
|
||
project.FindProjectTestDirectory = function(git_root, source_file_folder_abs_path) | ||
-- fd added end slashes to paths after 8.4.0 | ||
local test_paths = vim.fn.system("cd " .. git_root .. " > /dev/null && fd --type d --hidden --exclude .git | sed 's/\\/$//' | rg '" .. vim.g.deep_test_folder_prefixes .. "'") | ||
if test_paths == '' then | ||
return '' | ||
end | ||
local git_root_rel_source_file_folder_path = path.difference_between_ancestor_folder_and_sub_folder(git_root, source_file_folder_abs_path) | ||
local hops = {} | ||
for _k,v in pairs(str.split(test_paths, '\n')) do | ||
local cmd = 'cd ' .. git_root .. ' > /dev/null && realpath --relative-to="' .. git_root_rel_source_file_folder_path .. '" "' .. v .. '"' | ||
local path = vim.fn.trim(vim.fn.system(cmd)) | ||
if path == '.' then | ||
path = git_root_rel_source_file_folder_path | ||
end | ||
local _, count = string.gsub(path, '/', {}) | ||
table.insert(hops, {count, path}) | ||
end | ||
local idx = matrix.row_with_smallest_first_item(hops) | ||
local path_with_smallest_hops = hops[idx][2] | ||
local rel_path_to_pwd_from_git_root = path.difference_between_ancestor_folder_and_sub_folder(git_root, source_file_folder_abs_path) | ||
local cmd = '' | ||
if rel_path_to_pwd_from_git_root == path_with_smallest_hops then | ||
cmd = 'realpath ' .. git_root .. '/' .. path_with_smallest_hops | ||
else | ||
cmd = 'realpath ' .. git_root .. '/' .. rel_path_to_pwd_from_git_root .. '/' .. path_with_smallest_hops | ||
end | ||
local response = vim.fn.system(cmd) | ||
if vim.v.shell_error ~= 0 then | ||
error(response) | ||
end | ||
return vim.trim(response) | ||
end | ||
|
||
return project |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
return { | ||
split = function(str, sep) | ||
local result = {} | ||
local regex = ("([^%s]+)"):format(sep) | ||
for each in str:gmatch(regex) do | ||
table.insert(result, each) | ||
end | ||
return result | ||
end | ||
} |
Oops, something went wrong.