Search for multiple file/dir names in lsp#utils#find_nearest_parent_file_directory (#373)

* Search for multiple file/dir names in lsp#utils#find_nearest_parent_file_directory

* Add tests for lsp#utils#find_nearest_parent_file_directory

* Document lsp#utils#find_nearest_parent_file_directory
This commit is contained in:
IceNature
2019-05-13 13:33:38 +08:00
committed by Prabir Shrestha
parent a80d617938
commit fe2ec6e040
10 changed files with 98 additions and 4 deletions

View File

@@ -107,13 +107,38 @@ function! lsp#utils#find_nearest_parent_file(path, filename) abort
endfunction
" Find a nearest to a `path` parent filename `filename` by traversing the filesystem upwards
" The filename ending with '/' or '\' will be regarded as directory name,
" otherwith as file name
function! lsp#utils#find_nearest_parent_file_directory(path, filename) abort
let l:path = lsp#utils#find_nearest_parent_file(a:path, a:filename)
if type(a:filename) == 3
let l:matched_paths = {}
for current_name in a:filename
let l:path = lsp#utils#find_nearest_parent_file_directory(a:path, current_name)
if !empty(l:path)
return fnamemodify(l:path, ':p:h')
if !empty(l:path)
if has_key(l:matched_paths, l:path)
let l:matched_paths[l:path] += 1
else
let l:matched_paths[l:path] = 1
endif
endif
endfor
return empty(l:matched_paths) ?
\ '' :
\ keys(l:matched_paths)[index(values(l:matched_paths), max(values(l:matched_paths)))]
elseif type(a:filename) == 1
if a:filename[-1:] ==# '/' || a:filename[-1:] ==# '\'
let l:modify_str = ':p:h:h'
let l:path = lsp#utils#find_nearest_parent_directory(a:path, a:filename[:-2])
else
let l:modify_str = ':p:h'
let l:path = lsp#utils#find_nearest_parent_file(a:path, a:filename)
endif
return empty(l:path) ? '' : fnamemodify(l:path, l:modify_str)
else
return ''
echoerr "The type of argument \"filename\" must be String or List"
endif
endfunction

View File

@@ -24,6 +24,8 @@ CONTENTS *vim-lsp-contents*
disable |vim-lsp-disable|
register_server |vim-lsp-register_server|
stop_server |vim-lsp-stop_server|
utils#find_nearest_parent_file_directory
|vim-lsp-utils-find_nearest_parent_file_directory|
Commands |vim-lsp-commands|
LspCodeAction |LspCodeAction|
LspDocumentDiagnostics |LspDocumentDiagnostics|
@@ -406,6 +408,37 @@ Get the status of a server.
Returns one of "unknown server", " "exited", "starting", "failed",
"running", "not running".
*vim-lsp-utils-find_nearest_parent_file_directory*
utils#find_nearest_parent_file_directory
Find the nearest parent directory which contains the specific files or
diretories. The method has two parameters. The first is the path where
searching starts. The second is the files or directories names which
you want to find. The return value is the directory path which is found
the most times.
This method is mainly used to generate 'root_uri' when registering server.
Example:
if executable('ccls')
au User lsp_setup call lsp#register_server({
\ 'name': 'ccls',
\ 'cmd': {server_info->['ccls']},
\ 'root_uri':{server_info->lsp#utils#path_to_uri(
\ lsp#utils#find_nearest_parent_file_directory(
\ lsp#utils#get_buffer_path(),
\ ['.ccls', 'compile_commands.json', '.git/']
\ ))},
\ 'initialization_options': {},
\ 'whitelist': ['c', 'cpp', 'objc', 'objcpp', 'cc'],
\ })
endif
Note:
* The second parameter can be a |String| or a string |List|.
* For the second parameter, the string ends with '/' or '\' will
be regarded as a directory name, otherwise as a file name.
* If there is not directory with the specific files or diretories
found, the method will return an empty string.
===============================================================================
Commands *vim-lsp-commands*

View File

@@ -45,4 +45,40 @@ Describe lsp#utils
endfor
End
End
Describe lsp#utils#find_nearest_parent_file_directory
It should return the root directory if it is found
let tests = [
\ {'from': './test/testproject/src/main.cpp', 'target': ['.ccls', 'compile_commands.json', 'README.md', 'git/'], 'root': './test/testproject'},
\ {'from': './test/testproject/src/main.cpp', 'target': ['.ccls', 'build/', 'CMakeLists.txt', 'git/'], 'root': './test/testproject'},
\ {'from': './test/testproject/src/main.cpp', 'target': '.ccls', 'root': './test/testproject'},
\ {'from': './test/testproject/src/main.cpp', 'target': 'git/', 'root': './test/testproject'},
\ {'from': './test/testproject/src/main.cpp', 'target': 'CMakeLists.txt', 'root': './test/testproject/src'},
\ {'from': './test/testproject/README.md', 'target': ['.ccls', 'compile_commands.json', 'README.md', 'git/'], 'root': './test/testproject'},
\ {'from': './test/testproject/README.md', 'target': ['.ccls', 'build/', 'CMakeLists.txt', 'git/'], 'root': './test/testproject'},
\ {'from': './test/testproject/README.md', 'target': '.ccls', 'root': './test/testproject'},
\ {'from': './test/testproject/README.md', 'target': 'git/', 'root': './test/testproject'},
\ {'from': './test/testproject/README.md', 'target': 'CMakeLists.txt', 'root': './test/testproject'},
\]
for test in tests
let path = lsp#utils#find_nearest_parent_file_directory(fnamemodify(test.from, ':p:h'), test.target)
Assert Equals(path, fnamemodify(test.root, ':p:h'))
endfor
End
It should return an empty string if not target has been found
let tests = [
\ {'from': './test/testproject/src/main.cpp', 'target': ['fdrvbws/', 'asbr/', 'bgdf/', 'abfrb.txt', 'ngo.c']},
\ {'from': './test/testproject/src/main.cpp', 'target': 'asbr/'},
\ {'from': './test/testproject/src/main.cpp', 'target': 'btr.c'},
\ {'from': './test/testproject/.gitignore', 'target': ['fdrvbws/', 'asbr/', 'bgdf/', 'abfrb.txt', 'ngo.c']},
\ {'from': './test/testproject/.gitignore', 'target': 'asbr/'},
\ {'from': './test/testproject/.gitignore', 'target': 'btr.c'},
\]
for test in tests
let path = lsp#utils#find_nearest_parent_file_directory(fnamemodify(test.from, ':p:h'), test.target)
Assert Empty(path)
endfor
End
End
End

0
test/testproject/.ccls Normal file
View File

View File

View File

View File

0
test/testproject/git/.gitignore vendored Normal file
View File

View File

View File