From 0a37942388174282fa5716a71e7b703795f2d63f Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Mon, 17 May 2021 22:02:33 +0200 Subject: [PATCH 1/3] feat(utils): add neomake#utils#find_nearest_file_upwards --- autoload/neomake/utils.vim | 32 +++++++++++++++++++++++++ tests/utils.vader | 48 +++++++++++++++++++++++++++++++++++++- 2 files changed, 79 insertions(+), 1 deletion(-) diff --git a/autoload/neomake/utils.vim b/autoload/neomake/utils.vim index 69e2ad4738..c0795bceb9 100644 --- a/autoload/neomake/utils.vim +++ b/autoload/neomake/utils.vim @@ -552,6 +552,38 @@ function! neomake#utils#FindGlobFile(glob, ...) abort return '' endfunction +" Find the nearest file of the given filenames (upwards). +" (provides better performance than `neomake#utils#FindGlobFile`). +" a:1: optional start dir, defaulting to "current buffer" ("."). +function! neomake#utils#find_nearest_file_upwards(fnames, ...) abort + if !empty(&suffixesadd) + let saved_suffixesadd = &suffixesadd + let &suffixesadd = '' + endif + let path = (a:0 ? a:1 : '.') . ';' + let found = '' + let found_parts_count = 0 + for fname in a:fnames + let ffname = findfile(fname, path) + if empty(ffname) + continue + endif + + let abs_ffname = fnamemodify(ffname, ':p') + let abs_dir = fnamemodify(ffname, ':h') + let part_count = len(split(abs_dir, neomake#utils#Slash())) + if part_count > found_parts_count + let found = abs_ffname + let found_parts_count = part_count + let path = fnamemodify(found, ':h') . '.' + endif + endfor + if exists('l:saved_suffixesadd') + let &suffixesadd = saved_suffixesadd + endif + return found +endfunction + function! neomake#utils#JSONdecode(json) abort return neomake#compat#json_decode(a:json) endfunction diff --git a/tests/utils.vader b/tests/utils.vader index 3cf5581c72..be84a00f65 100644 --- a/tests/utils.vader +++ b/tests/utils.vader @@ -761,7 +761,7 @@ Execute (neomake#utils#fnamemodify handles empty bufname): AssertEqual neomake#utils#fnamemodify(bufnr('%'), ':p'), '' bwipe -Execute (neomake#utils#FindGlobFile): +Execute (neomake#utils#FindGlobFile / neomake#utils#find_nearest_file_upwards): let tempdir = tempname() let slash = neomake#utils#Slash() let subdir = tempdir . slash . 'sub' @@ -778,6 +778,14 @@ Execute (neomake#utils#FindGlobFile): let anotherfile_in_subdir = subdir.slash.'common-file-2' call writefile([], anotherfile_in_subdir) + " tree: + " ├── common-file + " ├── sub + " │   ├── common-file + " │   ├── common-file-2 + " │   └── sub-file + " └── temp-file + new exe 'lcd' subdir AssertEqual neomake#utils#FindGlobFile('doesnotexist'), '' @@ -785,6 +793,15 @@ Execute (neomake#utils#FindGlobFile): AssertEqual neomake#utils#FindGlobFile('sub-file', tempdir), '' AssertEqual neomake#utils#FindGlobFile('common-file'), file_in_subdir AssertEqual neomake#utils#FindGlobFile('common-file', tempdir), file_in_tempdir + " Behaves the same. + AssertEqual neomake#utils#find_nearest_file_upwards(['doesnotexist']), '' + AssertEqual neomake#utils#find_nearest_file_upwards(['sub-file']), subfile + AssertEqual neomake#utils#find_nearest_file_upwards(['sub-file'], tempdir), '' + AssertEqual neomake#utils#find_nearest_file_upwards(['common-file']), file_in_subdir + AssertEqual neomake#utils#find_nearest_file_upwards(['common-file'], tempdir), file_in_tempdir + + AssertEqual neomake#utils#find_nearest_file_upwards(['sub-file', 'temp-file']), subfile + AssertEqual neomake#utils#find_nearest_file_upwards(['common-file', 'temp-file']), file_in_subdir exe 'lcd' tempdir AssertEqual neomake#utils#FindGlobFile('sub-file'), '' @@ -794,10 +811,39 @@ Execute (neomake#utils#FindGlobFile): AssertEqual neomake#utils#FindGlobFile('common-file'), file_in_tempdir AssertEqual neomake#utils#FindGlobFile('common-file'), file_in_tempdir AssertEqual neomake#utils#FindGlobFile('common-file', subdir), file_in_subdir + " Behaves the same. + AssertEqual neomake#utils#find_nearest_file_upwards(['sub-file']), '' + AssertEqual neomake#utils#find_nearest_file_upwards(['sub-file'], subdir), subfile + AssertEqual neomake#utils#find_nearest_file_upwards(['sub-file'], tempdir), '' + AssertEqual neomake#utils#find_nearest_file_upwards(['sub-file'], tempname()), '' + AssertEqual neomake#utils#find_nearest_file_upwards(['common-file']), file_in_tempdir + AssertEqual neomake#utils#find_nearest_file_upwards(['common-file']), file_in_tempdir + AssertEqual neomake#utils#find_nearest_file_upwards(['common-file'], subdir), file_in_subdir " Only the first found file gets returned. AssertEqual neomake#utils#FindGlobFile('common-file{,-2}', subdir), file_in_subdir AssertEqual neomake#utils#FindGlobFile('common-file{-2,}', subdir), anotherfile_in_subdir + " Behaves the same. + AssertEqual neomake#utils#find_nearest_file_upwards(['common-file', 'common-file-2'], subdir), file_in_subdir + AssertEqual neomake#utils#find_nearest_file_upwards(['common-file-2', 'common-file'], subdir), anotherfile_in_subdir + bwipe + +Execute (neomake#utils#find_nearest_file_upwards handles &suffixesadd): + let tempdir = tempname() + let file_with_ext = tempdir.slash.'file_with_ext.txt' + call writefile([], file_with_ext) + + new + setlocal suffixesadd=.txt + + " Test behavior with used findfile. + AssertEqual findfile('file_with_ext', '.;'), file_with_ext + + AssertEqual neomake#utils#find_nearest_file_upwards(['file_with_ext']), '' + AssertEqual neomake#utils#find_nearest_file_upwards(['file_with_ext.txt']), file_with_ext + + " Gets reset. + AssertEqual findfile('file_with_ext', '.;'), file_with_ext bwipe Execute (neomake#utils#shellescape): From df14c16c8e7441554e2fc25426b88e759bce6bb3 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Mon, 17 May 2021 22:19:53 +0200 Subject: [PATCH 2/3] fixup! feat(utils): add neomake#utils#find_nearest_file_upwards --- tests/utils.vader | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/utils.vader b/tests/utils.vader index be84a00f65..87baa349a2 100644 --- a/tests/utils.vader +++ b/tests/utils.vader @@ -830,20 +830,23 @@ Execute (neomake#utils#FindGlobFile / neomake#utils#find_nearest_file_upwards): Execute (neomake#utils#find_nearest_file_upwards handles &suffixesadd): let tempdir = tempname() + let slash = neomake#utils#Slash() + call mkdir(tempdir, 'p', 0700) let file_with_ext = tempdir.slash.'file_with_ext.txt' call writefile([], file_with_ext) new + exe 'lcd' tempdir setlocal suffixesadd=.txt " Test behavior with used findfile. - AssertEqual findfile('file_with_ext', '.;'), file_with_ext + AssertEqual findfile('file_with_ext', fnameescape(tempdir).';'), 'file_with_ext.txt' AssertEqual neomake#utils#find_nearest_file_upwards(['file_with_ext']), '' AssertEqual neomake#utils#find_nearest_file_upwards(['file_with_ext.txt']), file_with_ext " Gets reset. - AssertEqual findfile('file_with_ext', '.;'), file_with_ext + AssertEqual findfile('file_with_ext', '.;'), 'file_with_ext.txt' bwipe Execute (neomake#utils#shellescape): From f369ef66883fab79c2072e1b2144f041ef9b8572 Mon Sep 17 00:00:00 2001 From: Daniel Hahler Date: Tue, 18 May 2021 22:15:40 +0200 Subject: [PATCH 3/3] Amendments/WIP, to be revisited --- autoload/neomake/utils.vim | 11 ++++++++--- tests/utils.vader | 11 +++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/autoload/neomake/utils.vim b/autoload/neomake/utils.vim index c0795bceb9..c6489834fc 100644 --- a/autoload/neomake/utils.vim +++ b/autoload/neomake/utils.vim @@ -532,7 +532,7 @@ function! neomake#utils#path_sep() abort return neomake#utils#IsRunningWindows() ? ';' : ':' endfunction -" Find a file matching `a:glob` (using `globpath()`) by going up the +" Find a file/dir matching `a:glob` (using `globpath()`) by going up the " directories from the start directory (a:1, defaults to `expand('%:p:h')`, " i.e. the directory of the current buffer's file).) function! neomake#utils#FindGlobFile(glob, ...) abort @@ -560,7 +560,8 @@ function! neomake#utils#find_nearest_file_upwards(fnames, ...) abort let saved_suffixesadd = &suffixesadd let &suffixesadd = '' endif - let path = (a:0 ? a:1 : '.') . ';' + " NOTE: findfile requires an absolute path, except for special '.'. + let path = (a:0 ? fnamemodify(a:1, ':p') : '.') . ';' let found = '' let found_parts_count = 0 for fname in a:fnames @@ -570,7 +571,11 @@ function! neomake#utils#find_nearest_file_upwards(fnames, ...) abort endif let abs_ffname = fnamemodify(ffname, ':p') - let abs_dir = fnamemodify(ffname, ':h') + if isdirectory(abs_ffname) + " Remove trailing slash. + let abs_ffname = fnamemodify(ffname, ':h') + endif + let abs_dir = fnamemodify(abs_ffname, ':h') let part_count = len(split(abs_dir, neomake#utils#Slash())) if part_count > found_parts_count let found = abs_ffname diff --git a/tests/utils.vader b/tests/utils.vader index 87baa349a2..04eda21dc4 100644 --- a/tests/utils.vader +++ b/tests/utils.vader @@ -790,12 +790,14 @@ Execute (neomake#utils#FindGlobFile / neomake#utils#find_nearest_file_upwards): exe 'lcd' subdir AssertEqual neomake#utils#FindGlobFile('doesnotexist'), '' AssertEqual neomake#utils#FindGlobFile('sub-file'), subfile + AssertEqual neomake#utils#FindGlobFile('sub-file', subdir), subfile AssertEqual neomake#utils#FindGlobFile('sub-file', tempdir), '' AssertEqual neomake#utils#FindGlobFile('common-file'), file_in_subdir AssertEqual neomake#utils#FindGlobFile('common-file', tempdir), file_in_tempdir " Behaves the same. AssertEqual neomake#utils#find_nearest_file_upwards(['doesnotexist']), '' AssertEqual neomake#utils#find_nearest_file_upwards(['sub-file']), subfile + AssertEqual neomake#utils#find_nearest_file_upwards(['sub-file'], subdir), subfile AssertEqual neomake#utils#find_nearest_file_upwards(['sub-file'], tempdir), '' AssertEqual neomake#utils#find_nearest_file_upwards(['common-file']), file_in_subdir AssertEqual neomake#utils#find_nearest_file_upwards(['common-file'], tempdir), file_in_tempdir @@ -820,6 +822,15 @@ Execute (neomake#utils#FindGlobFile / neomake#utils#find_nearest_file_upwards): AssertEqual neomake#utils#find_nearest_file_upwards(['common-file']), file_in_tempdir AssertEqual neomake#utils#find_nearest_file_upwards(['common-file'], subdir), file_in_subdir + " Handles relative path/startdir. + AssertEqual neomake#utils#FindGlobFile('sub-file', 'sub'), 'sub'.slash.'sub-file' + AssertEqual neomake#utils#find_nearest_file_upwards(['sub-file'], 'sub'), subfile + + " FindGlobFile handles directories. + AssertEqual neomake#utils#FindGlobFile('sub'), subdir + " find_nearest_file_upwards does not handle directories. + AssertEqual neomake#utils#find_nearest_file_upwards(['sub']), '' + " Only the first found file gets returned. AssertEqual neomake#utils#FindGlobFile('common-file{,-2}', subdir), file_in_subdir AssertEqual neomake#utils#FindGlobFile('common-file{-2,}', subdir), anotherfile_in_subdir