From 777b163e394ba658ef288292efb533b25610ef9d Mon Sep 17 00:00:00 2001 From: Jit Yao Yap Date: Sat, 23 Apr 2022 14:37:28 +0800 Subject: [PATCH] Update python file_in_path completion --- autoload/wilder/cmdline.vim | 21 +++++++ rplugin/python3/wilder/__init__.py | 89 ++++++++++++++++-------------- 2 files changed, 70 insertions(+), 40 deletions(-) diff --git a/autoload/wilder/cmdline.vim b/autoload/wilder/cmdline.vim index 23f0d0f..e9fa5bf 100644 --- a/autoload/wilder/cmdline.vim +++ b/autoload/wilder/cmdline.vim @@ -102,6 +102,14 @@ function! wilder#cmdline#prepare_file_completion(ctx, res, fuzzy) let l:res = copy(a:res) let l:arg = l:res.arg + if l:res.expand ==# 'file_in_path' + let l:res.fuzzy_char = '' + let l:res.expand_arg = l:arg + let l:res.match_arg = l:arg + + return l:res + endif + " Remove backslash preceding spaces. let l:arg = substitute(l:arg, '\\ ', ' ', 'g') @@ -1123,6 +1131,10 @@ function! wilder#cmdline#getcompletion_pipeline(opts) abort \ wilder#subpipeline({ctx, res -> [ \ {ctx, res -> s:getcompletion(ctx, res, l:fuzzy, l:use_python)}, \ wilder#result({ + \ 'value': {ctx, xs, data -> l:fuzzy == 0 ? + \ s:filter_file_in_path(ctx, xs, data) : xs}, + \ }), + \ wilder#result({ \ 'value': {ctx, xs -> get(res, 'relative_to_home_dir', 0) ? \ map(xs, {i, x -> fnamemodify(x, ':~')}) : xs}, \ }), @@ -1190,6 +1202,15 @@ function! wilder#cmdline#getcompletion_pipeline(opts) abort \ ] endfunction +function! s:filter_file_in_path(ctx, xs, data) abort + if get(a:data, 'cmdline.expand', '') !=# 'file_in_path' + return a:xs + endif + + let l:arg = get(a:data, 'cmdline.arg', '') + return filter(a:xs, {_, x -> stridx(x, l:arg) != -1}) +endfunction + function! s:get_lua_completion(ctx, res, fuzzy) abort let l:last_char = a:res.arg[-1 :] if !empty(l:last_char) && diff --git a/rplugin/python3/wilder/__init__.py b/rplugin/python3/wilder/__init__.py index 7e9f1ad..efeda06 100644 --- a/rplugin/python3/wilder/__init__.py +++ b/rplugin/python3/wilder/__init__.py @@ -344,26 +344,13 @@ def _get_file_completion(self, args): cwd = self.nvim.eval('getcwd()') wildignore_opt = self.nvim.eval('&wildignore') + current_file_dir = self.nvim.eval('expand("%:p:h")') add_dot = False if expand_type == 'file_in_path': - directories = [] - if expand_arg: - if expand_arg[0:2] == './': - directories = [cwd] - else: - relpath = os.path.relpath(expand_arg, cwd) - if relpath[0:2] == '..': - add_dot = True - directories = [cwd] - - if not directories: - path_opt = self.nvim.eval('&path') - directories = path_opt.split(',') - - directories = list(map(lambda d: self.nvim.eval('expand("%:p:h")') if d == '.' else d, directories)) - directories = list(map(lambda d: cwd if d == '' else d, directories)) + path_opt = self.nvim.eval('&path') + directories = path_opt.split(',') elif expand_type == 'shellcmd': directories = [] if expand_arg: @@ -382,7 +369,7 @@ def _get_file_completion(self, args): else: directories = [cwd] - self.run_in_background(self.get_file_completion_handler, args + [wildignore_opt, directories, add_dot, cwd]) + self.run_in_background(self.get_file_completion_handler, args + [wildignore_opt, directories, add_dot, cwd, current_file_dir]) def get_file_completion_handler(self, event, @@ -394,22 +381,30 @@ def get_file_completion_handler(self, wildignore_opt, directories, add_dot, - cwd): + cwd, + current_file_dir): if event.is_set(): return try: - res = set() + original_has_wildcard = has_wildcard + res = list() + seen_files = set() wildignore_list = wildignore_opt.split(',') is_file_in_path = expand_type == 'file_in_path' - if is_file_in_path: - seen_file_names = set() visited_directories = set() checker = EventChecker(event) for directory in directories: if checker.check(): return + + if is_file_in_path: + if not directory: + directory = cwd + elif directory == '.': + directory = current_file_dir + if not directory: continue @@ -418,13 +413,16 @@ def get_file_completion_handler(self, visited_directories.add(directory) - has_wildcard = has_wildcard or '*' in directory + has_wildcard = original_has_wildcard or '*' in directory if has_wildcard: tail = os.path.basename(expand_arg) show_hidden = tail.startswith('.') pattern = '' - if is_file_in_path and directory == '**': - wildcard = os.path.join(cwd, '**') + if is_file_in_path: + if directory == '**': + wildcard = os.path.join(cwd, '**') + else: + wildcard = directory elif expand_arg: wildcard = os.path.join(directory, expand_arg) else: @@ -439,7 +437,10 @@ def get_file_completion_handler(self, path = os.path.join(directory, expand_arg) head, tail = os.path.split(path) show_hidden = tail.startswith('.') - pattern = tail + '*' + if is_file_in_path: + pattern = '' + else: + pattern = tail + '*' try: it = os.scandir(head) @@ -482,26 +483,25 @@ def get_file_completion_handler(self, if is_file_in_path and directory == '**' and Path(entry) == Path(cwd): continue - # iglob and scandir return different types - entry_name = str(entry) if has_wildcard else entry.name - if is_file_in_path: - file_name = os.path.basename(entry_name) - # add the base file name if not added already, otherwise add the full path - if file_name in seen_file_names: - entry_name = str(entry) if has_wildcard else entry.path - else: - entry_name = file_name - seen_file_names.add(file_name) + # iglob and scandir return different types + entry_name = str(entry) if has_wildcard else entry.path + entry_name = self.get_path_relative_to_cwd(entry_name, cwd) + else: + entry_name = str(entry) if has_wildcard else entry.name if entry.is_dir(): entry_name += os.sep - res.add(entry_name) + if entry_name in seen_files: + continue + seen_files.add(entry_name) + + res.append(entry_name) except OSError: pass res = sorted(res) - if not has_wildcard: + if not original_has_wildcard and not is_file_in_path: head = os.path.dirname(expand_arg) res = list(map(lambda f: os.path.join(head, f) if head else f, res)) @@ -519,11 +519,20 @@ def get_file_completion_handler(self, def is_descendant_path(self, p1, p2): return os.path.relpath(p2, p1)[0:2] != '..' - def get_basename(self, f): - if f.endswith(os.sep) or f.endswith('/'): - return os.path.basename(f[:-1]) + def get_basename(self, f, is_dir): + if is_dir: + return os.path.basename(f[:-1]) + os.sep return os.path.basename(f) + def get_path_relative_to_cwd(self, p, cwd): + if not self.is_descendant_path(cwd, p): + return p + + p = os.path.relpath(p, cwd) + if not p.startswith('/'): + p = os.path.join('.', p) + return p + @neovim.function('_wilder_python_get_help_tags', sync=False, allow_nested=True) def _get_help_tags(self, args): self.run_in_background(self.get_help_tags_handler, args)