-
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 a9c3bb6
Showing
13 changed files
with
384 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,24 @@ | ||
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" | ||
} | ||
build = { | ||
type = "builtin", | ||
modules = { | ||
["go-to-test-file"] = "lua/go-to-test-file.lua", | ||
["go-to-test-file.dir"] = "lua/go-to-test-file/dir.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,243 @@ | ||
local str = require('go_to_test_file.str') | ||
local matrix = require('go_to_test_file.matrix') | ||
local dir = require('go_to_test_file.dir') | ||
|
||
GoToTestFile = {} | ||
-- requirements fzf, rg, realpath, git, fd | ||
|
||
|
||
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') | ||
vim.api.nvim_set_var('test_folder_prefixes', '^(test/|tests/|spec/)(unit/|integration/)?') | ||
vim.api.nvim_set_var('deep_test_folder_prefixes', '(test|tests|spec)(/unit|/integration)?$') | ||
-- TODO add second level | ||
vim.api.nvim_set_var('lua_test_folder_prefixes', '^test/|^tests/|^spec/') | ||
|
||
local 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 | ||
|
||
GoToTestFile.FindProjectTestDirectory = function(git_root, source_file_folder_abs_path) | ||
local test_dirs = vim.fn.system("cd " .. git_root .. " > /dev/null && fd --type d --hidden --exclude .git | rg '" .. vim.g.deep_test_folder_prefixes .. "'") | ||
if test_dirs == '' then | ||
return '' | ||
end | ||
local git_root_rel_source_file_folder_path = dir.difference_between_ancestor_folder_and_sub_folder(git_root, source_file_folder_abs_path) | ||
local hops = {} | ||
for _k,v in pairs(str.split(test_dirs, '\n')) do | ||
local path = vim.fn.trim(vim.fn.system('cd ' .. git_root .. ' > /dev/null && realpath --relative-to="' .. git_root_rel_source_file_folder_path .. '" "' .. v .. '"')) | ||
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 = dir.difference_between_ancestor_folder_and_sub_folder(git_root, source_file_folder_abs_path) | ||
local full_path = vim.fn.trim(vim.fn.system('realpath ' .. git_root .. '/' .. rel_path_to_pwd_from_git_root .. '/' .. path_with_smallest_hops)) | ||
return full_path | ||
end | ||
|
||
GoToTestFile.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 | ||
|
||
GoToTestFile.DomainlessSourceFolderGoToTestFileatch = function(prefixes, source_folder) | ||
local identifiers = str.split(prefixes, '|') | ||
return 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.GitRootOfFile = function(file_abs_path) | ||
local file_folder_abs_path = vim.fn.fnamemodify(file_abs_path, ":h") | ||
return vim.fn.trim(vim.fn.system('cd ' .. file_folder_abs_path .. ' > /dev/null && git rev-parse --show-toplevel')) | ||
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 = GoToTestFile.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=dir.difference_between_ancestor_folder_and_sub_folder(project_abs_path_root, source_file_folder_abs_path) | ||
local project_source_folder = GoToTestFile.ProjectSourceFolder(project_abs_path_root, source_file_folder_path_rel_to_project_root) | ||
local domainless_source_folder_match = GoToTestFile.DomainlessSourceFolderGoToTestFileatch(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 command = "cd " .. test_folder_abs_path .. " > /dev/null && rg --files | fzf --filter '" .. prefixless_source_file_path .. "' | head -1" | ||
local file_relative_to_root = vim.fn.trim(vim.fn.system(command)) | ||
if file_relative_to_root == '' then | ||
return test_folder_abs_path | ||
else | ||
return test_folder_abs_path .. '/' .. file_relative_to_root | ||
end | ||
end | ||
|
||
vim.cmd('command! FindTestFolderTestFile :lua print(GoToTestFile.FindTestFolderTestFile(GoToTestFile.GitRootOfFile(vim.fn.expand("%:p")), vim.fn.expand("%:p")))') | ||
|
||
GoToTestFile.RemoveTestFileNameIdentifiers = function(test_filename_rel_path_from_project) | ||
local identifiers = str.split(vim.g.lua_test_file_identifiers, '|') | ||
local with_period = match_one(test_filename_rel_path_from_project, identifiers, '%.', '') | ||
local with_underscore = 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 = 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 = GoToTestFile.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=dir.difference_between_ancestor_folder_and_sub_folder(project_abs_path_root, test_file_folder_abs_path) | ||
|
||
local path_without_prefixes = GoToTestFile.RemoveTestFolderPrefixes(vim.g.lua_test_folder_prefixes, test_file_folder_path_rel_to_project_root) | ||
local current_filename_no_ext = vim.fn.fnamemodify(test_file_with_abs_path, ':t:r') | ||
local test_filepath_without_test_identifiers = GoToTestFile.RemoveTestFileNameIdentifiers(path_without_prefixes .. '/' .. current_filename_no_ext) | ||
|
||
-- 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" | ||
return vim.fn.trim(vim.fn.system(command)) | ||
end | ||
vim.cmd('command! FindSrcFolderCodeFile :lua print(GoToTestFile.FindSrcFolderCodeFile(GoToTestFile.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 list = str.split(vim.g.lua_test_file_identifiers, '|') | ||
local matched = match_one(test_filename, list, '%.', '%.') | ||
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 | ||
GoToTestFile.HasPeerSourceCodeFile = function(file_with_path) | ||
local current_file_name = vim.fn.fnamemodify(file_with_path, ':t') | ||
local output = vim.fn.trim(vim.fn.system('printf "' .. current_file_name .. '" | rg "\\.' .. vim.g.test_file_identifiers .. '\\."')) | ||
return output ~= '' | ||
end | ||
|
||
vim.cmd('command! HasPeerSourceCodeFile :lua GoToTestFile.HasPeerSourceCodeFile(vim.fn.expand("%:."))') | ||
|
||
-- TODO cd with abs path | ||
GoToTestFile.FindPeerTestCodeFile = function(file_with_path) | ||
local current_file_name_no_ext = vim.fn.fnamemodify(file_with_path, ':t:r') | ||
local path = vim.fn.fnamemodify(file_with_path, ':p:h') | ||
local output = vim.fn.trim(vim.fn.system("cd " .. path .. " > /dev/null && rg --files | fzf --filter '" .. current_file_name_no_ext .. "' | rg '" .. vim.g.test_file_identifiers .. "' | head -n 1 ")) | ||
if output == '' then | ||
return '' | ||
else | ||
return path .. '/' .. output | ||
end | ||
end | ||
|
||
vim.cmd('command! FindPeerTestCodeFile :lua print(GoToTestFile.FindPeerTestCodeFile(vim.fn.expand("%:p")))') | ||
|
||
GoToTestFile.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 = GoToTestFile.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 | ||
|
||
vim.cmd('command! IsInATestFolder :lua print(IsInATestFolder(GitRootOfFile(vim.fn.expand("%:p")), vim.fn.expand("%:p")))') | ||
|
||
GoToTestFile.FindTestOrSrcCodeFile = function(git_root, current_file_abs_path) | ||
if GoToTestFile.HasPeerSourceCodeFile(current_file_abs_path) then | ||
return GoToTestFile.FindPeerSourceCodeFile(current_file_abs_path) | ||
elseif GoToTestFile.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.GitRootOfFile(vim.fn.expand("%:p")), vim.fn.expand("%:p")))') | ||
|
||
GoToTestFile.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 | ||
|
||
vim.cmd('command! RepoTestFolder :lua print(GoToTestFile.RepoTestFolder())') | ||
|
||
-- 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.GitRootOfFile(current_file_abs_path) | ||
local path = GoToTestFile.FindTestOrSrcCodeFile(git_root, current_file_abs_path) | ||
if path == './' then | ||
local test_path = GoToTestFile.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,25 @@ | ||
-- 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, | ||
-- 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) | ||
return vim.fn.trim(vim.fn.system('realpath --relative-to="' .. ancestor .. '" "' .. sub_folder .. '"')) | ||
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 { | ||
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 | ||
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 @@ | ||
return {} |
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 | ||
} |
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 @@ | ||
local windows_name = 'WIN' | ||
local linux_name = 'NIX' | ||
local function is_win() | ||
return package.config:sub(1, 1) == '\\' | ||
end | ||
|
||
return { | ||
windows_name = windows_name, | ||
linux_name = linux_name, | ||
is_win = is_win, | ||
name = function() | ||
if is_win() then | ||
return windows_name | ||
else | ||
return linux_name | ||
end | ||
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,23 @@ | ||
local assert = require('luassert') | ||
|
||
|
||
local dir = require('go_to_test_file.dir') | ||
local system = require('go_to_test_file.system') | ||
|
||
describe('dir', function() | ||
describe('script_path', function() | ||
it('will print the relative path of the current script directory', function() | ||
local actual = dir.script_path(system.name) | ||
local ps = dir.path_separator(system.name()) | ||
local expected = vim.fn.getcwd() .. ps .. 'spec/go_to_test_file/' | ||
assert.are.equal(expected, actual) | ||
end) | ||
end) | ||
describe('difference_between_ancestor_folder_and_sub_folder', function() | ||
it('will print the relative path from subfolder to ancestor', function() | ||
local ps = dir.path_separator(system.name()) | ||
local this_path = vim.fn.getcwd() .. ps .. 'spec/go_to_test_file' | ||
assert.are.equal(dir.difference_between_ancestor_folder_and_sub_folder(this_path, 'tst'), '../../tst') | ||
end) | ||
end) | ||
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,10 @@ | ||
local matrix = require('go_to_test_file.matrix') | ||
|
||
describe('table', function() | ||
describe('row_with_smallest_first_item', function() | ||
it('finds the index of the row with the smallest first item', function() | ||
local test_table = { {9, '/lib'}, {1, '/etc'}, {2, '/root'} } | ||
assert.are.equal(2, matrix.row_with_smallest_first_item(test_table)) | ||
end) | ||
end) | ||
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,8 @@ | ||
local str = require('go_to_test_file.str') | ||
|
||
describe('str', function() | ||
it('splits a string', function() | ||
|
||
assert(str.split("asdf,zxcv", ',')) | ||
end) | ||
end) |
Empty file.