Skip to content

Commit fe2ec6e

Browse files
IceNatureprabirshrestha
authored andcommitted
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
1 parent a80d617 commit fe2ec6e

File tree

10 files changed

+98
-4
lines changed

10 files changed

+98
-4
lines changed

autoload/lsp/utils.vim

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -107,13 +107,38 @@ function! lsp#utils#find_nearest_parent_file(path, filename) abort
107107
endfunction
108108

109109
" Find a nearest to a `path` parent filename `filename` by traversing the filesystem upwards
110+
" The filename ending with '/' or '\' will be regarded as directory name,
111+
" otherwith as file name
110112
function! lsp#utils#find_nearest_parent_file_directory(path, filename) abort
111-
let l:path = lsp#utils#find_nearest_parent_file(a:path, a:filename)
113+
if type(a:filename) == 3
114+
let l:matched_paths = {}
115+
for current_name in a:filename
116+
let l:path = lsp#utils#find_nearest_parent_file_directory(a:path, current_name)
117+
118+
if !empty(l:path)
119+
if has_key(l:matched_paths, l:path)
120+
let l:matched_paths[l:path] += 1
121+
else
122+
let l:matched_paths[l:path] = 1
123+
endif
124+
endif
125+
endfor
126+
return empty(l:matched_paths) ?
127+
\ '' :
128+
\ keys(l:matched_paths)[index(values(l:matched_paths), max(values(l:matched_paths)))]
129+
130+
elseif type(a:filename) == 1
131+
if a:filename[-1:] ==# '/' || a:filename[-1:] ==# '\'
132+
let l:modify_str = ':p:h:h'
133+
let l:path = lsp#utils#find_nearest_parent_directory(a:path, a:filename[:-2])
134+
else
135+
let l:modify_str = ':p:h'
136+
let l:path = lsp#utils#find_nearest_parent_file(a:path, a:filename)
137+
endif
112138

113-
if !empty(l:path)
114-
return fnamemodify(l:path, ':p:h')
139+
return empty(l:path) ? '' : fnamemodify(l:path, l:modify_str)
115140
else
116-
return ''
141+
echoerr "The type of argument \"filename\" must be String or List"
117142
endif
118143
endfunction
119144

doc/vim-lsp.txt

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ CONTENTS *vim-lsp-contents*
2424
disable |vim-lsp-disable|
2525
register_server |vim-lsp-register_server|
2626
stop_server |vim-lsp-stop_server|
27+
utils#find_nearest_parent_file_directory
28+
|vim-lsp-utils-find_nearest_parent_file_directory|
2729
Commands |vim-lsp-commands|
2830
LspCodeAction |LspCodeAction|
2931
LspDocumentDiagnostics |LspDocumentDiagnostics|
@@ -406,6 +408,37 @@ Get the status of a server.
406408
Returns one of "unknown server", " "exited", "starting", "failed",
407409
"running", "not running".
408410

411+
*vim-lsp-utils-find_nearest_parent_file_directory*
412+
utils#find_nearest_parent_file_directory
413+
414+
Find the nearest parent directory which contains the specific files or
415+
diretories. The method has two parameters. The first is the path where
416+
searching starts. The second is the files or directories names which
417+
you want to find. The return value is the directory path which is found
418+
the most times.
419+
This method is mainly used to generate 'root_uri' when registering server.
420+
421+
Example:
422+
if executable('ccls')
423+
au User lsp_setup call lsp#register_server({
424+
\ 'name': 'ccls',
425+
\ 'cmd': {server_info->['ccls']},
426+
\ 'root_uri':{server_info->lsp#utils#path_to_uri(
427+
\ lsp#utils#find_nearest_parent_file_directory(
428+
\ lsp#utils#get_buffer_path(),
429+
\ ['.ccls', 'compile_commands.json', '.git/']
430+
\ ))},
431+
\ 'initialization_options': {},
432+
\ 'whitelist': ['c', 'cpp', 'objc', 'objcpp', 'cc'],
433+
\ })
434+
endif
435+
Note:
436+
* The second parameter can be a |String| or a string |List|.
437+
* For the second parameter, the string ends with '/' or '\' will
438+
be regarded as a directory name, otherwise as a file name.
439+
* If there is not directory with the specific files or diretories
440+
found, the method will return an empty string.
441+
409442
===============================================================================
410443
Commands *vim-lsp-commands*
411444

test/lsp/utils.vimspec

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,40 @@ Describe lsp#utils
4545
endfor
4646
End
4747
End
48+
49+
Describe lsp#utils#find_nearest_parent_file_directory
50+
It should return the root directory if it is found
51+
let tests = [
52+
\ {'from': './test/testproject/src/main.cpp', 'target': ['.ccls', 'compile_commands.json', 'README.md', 'git/'], 'root': './test/testproject'},
53+
\ {'from': './test/testproject/src/main.cpp', 'target': ['.ccls', 'build/', 'CMakeLists.txt', 'git/'], 'root': './test/testproject'},
54+
\ {'from': './test/testproject/src/main.cpp', 'target': '.ccls', 'root': './test/testproject'},
55+
\ {'from': './test/testproject/src/main.cpp', 'target': 'git/', 'root': './test/testproject'},
56+
\ {'from': './test/testproject/src/main.cpp', 'target': 'CMakeLists.txt', 'root': './test/testproject/src'},
57+
\ {'from': './test/testproject/README.md', 'target': ['.ccls', 'compile_commands.json', 'README.md', 'git/'], 'root': './test/testproject'},
58+
\ {'from': './test/testproject/README.md', 'target': ['.ccls', 'build/', 'CMakeLists.txt', 'git/'], 'root': './test/testproject'},
59+
\ {'from': './test/testproject/README.md', 'target': '.ccls', 'root': './test/testproject'},
60+
\ {'from': './test/testproject/README.md', 'target': 'git/', 'root': './test/testproject'},
61+
\ {'from': './test/testproject/README.md', 'target': 'CMakeLists.txt', 'root': './test/testproject'},
62+
\]
63+
for test in tests
64+
let path = lsp#utils#find_nearest_parent_file_directory(fnamemodify(test.from, ':p:h'), test.target)
65+
Assert Equals(path, fnamemodify(test.root, ':p:h'))
66+
endfor
67+
End
68+
69+
It should return an empty string if not target has been found
70+
let tests = [
71+
\ {'from': './test/testproject/src/main.cpp', 'target': ['fdrvbws/', 'asbr/', 'bgdf/', 'abfrb.txt', 'ngo.c']},
72+
\ {'from': './test/testproject/src/main.cpp', 'target': 'asbr/'},
73+
\ {'from': './test/testproject/src/main.cpp', 'target': 'btr.c'},
74+
\ {'from': './test/testproject/.gitignore', 'target': ['fdrvbws/', 'asbr/', 'bgdf/', 'abfrb.txt', 'ngo.c']},
75+
\ {'from': './test/testproject/.gitignore', 'target': 'asbr/'},
76+
\ {'from': './test/testproject/.gitignore', 'target': 'btr.c'},
77+
\]
78+
for test in tests
79+
let path = lsp#utils#find_nearest_parent_file_directory(fnamemodify(test.from, ':p:h'), test.target)
80+
Assert Empty(path)
81+
endfor
82+
End
83+
End
4884
End

test/testproject/.ccls

Whitespace-only changes.

test/testproject/CMakeLists.txt

Whitespace-only changes.

test/testproject/README.md

Whitespace-only changes.

test/testproject/compile_commands.json

Whitespace-only changes.

test/testproject/git/.gitignore

Whitespace-only changes.

test/testproject/src/CMakeLists.txt

Whitespace-only changes.

test/testproject/src/main.cpp

Whitespace-only changes.

0 commit comments

Comments
 (0)