diff --git a/autoload/ale/path.vim b/autoload/ale/path.vim index 5595416859..078fee9753 100644 --- a/autoload/ale/path.vim +++ b/autoload/ale/path.vim @@ -62,6 +62,36 @@ function! ale#path#FindNearestDirectory(buffer, directory_name) abort return '' endfunction +" Given a buffer and a filename, find the nearest file or directory by +" searching upwards through the paths relative to the given buffer. +function! ale#path#FindNearestFileOrDirectory(buffer, filename) abort + let l:buffer_filename = fnamemodify(bufname(a:buffer), ':p') + let l:buffer_filename = fnameescape(l:buffer_filename) + + let l:relative_path_file = findfile(a:filename, l:buffer_filename . ';') + let l:relative_path_dir = finddir(a:filename, l:buffer_filename . ';') + + " If we find both a file and directory, choose the shorter response by + " making the longer one empty instead. + if !empty(l:relative_path_file) && !empty(l:relative_path_dir) + if strlen(l:relative_path_file) > strlen(l:relative_path_dir) + let l:relative_path_dir = '' + else + let l:relative_path_file = '' + endif + endif + + if !empty(l:relative_path_file) + return fnamemodify(l:relative_path_file, ':p') + endif + + if !empty(l:relative_path_dir) + return fnamemodify(l:relative_path_dir, ':p') + endif + + return '' +endfunction + " Given a buffer, a string to search for, and a global fallback for when " the search fails, look for a file in parent paths, and if that fails, " use the global fallback path instead. diff --git a/test/test-files/top/needle_dir/needle b/test/test-files/top/needle_dir/needle new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/test-files/top/needle_dir/target/needle/.gitkeep b/test/test-files/top/needle_dir/target/needle/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/test-files/top/needle_dir/target/query/buffer.txt b/test/test-files/top/needle_dir/target/query/buffer.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/test-files/top/needle_file/needle/.gitkeep b/test/test-files/top/needle_file/needle/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/test-files/top/needle_file/target/needle b/test/test-files/top/needle_file/target/needle new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/test-files/top/needle_file/target/query/buffer.txt b/test/test-files/top/needle_file/target/query/buffer.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test/test_nearest_file_search.vader b/test/test_find_nearest_file.vader similarity index 100% rename from test/test_nearest_file_search.vader rename to test/test_find_nearest_file.vader diff --git a/test/test_find_nearest_file_or_directory.vader b/test/test_find_nearest_file_or_directory.vader new file mode 100644 index 0000000000..fd5e1c30c2 --- /dev/null +++ b/test/test_find_nearest_file_or_directory.vader @@ -0,0 +1,22 @@ +Before: + call ale#test#SetDirectory('/testplugin/test') + +After: + call ale#test#RestoreDirectory() + +Execute(We should find a directory when searching and it is closer): + call ale#test#SetFilename('test-files/top/needle_dir/target/query/buffer.txt') + + AssertEqual + \ ale#path#Simplify(expand('%:p:h:h:h:h:h:h') . '/test-files/top/needle_dir/target/needle/'), + \ ale#path#FindNearestFileOrDirectory(bufnr('%'), 'needle') + +Execute(We should find a file when searching and it is closer): + call ale#test#SetFilename('test-files/top/needle_file/target/query/buffer.txt') + + AssertEqual + \ ale#path#Simplify(expand('%:p:h:h:h:h:h:h') . '/test-files/top/needle_file/target/needle'), + \ ale#path#FindNearestFileOrDirectory(bufnr('%'), 'needle') + +Execute(We shouldn't find anything for files which don't match): + AssertEqual '', ale#path#FindNearestFileOrDirectory(bufnr('%'), 'cantfindthis')