# ============================================================================ # FILE: defx.py # AUTHOR: Shougo Matsushita # License: MIT license # ============================================================================ import typing from defx.base.source import Base as Source from defx.source.file.list import Source as SourceList from defx.source.file import Source as SourceFile from defx.context import Context from defx.sort import sort from defx.util import Nvim from defx.util import cd, error from pathlib import Path Candidate = typing.Dict[str, typing.Any] class Defx(object): def __init__(self, vim: Nvim, context: Context, source_name: str, cwd: str, index: int) -> None: self._vim = vim self._context = context self._cwd = self._vim.call('getcwd') self.cd(cwd) self._source: Source = (SourceList(self._vim) if source_name == 'file/list' else SourceFile(self._vim)) self._index = index self._enabled_ignored_files = not context.show_ignored_files self._filtered_files = context.filtered_files.split(',') self._ignored_files = context.ignored_files.split(',') self._cursor_history: typing.Dict[str, Path] = {} self._sort_method: str = self._context.sort self._mtime: int = -1 self._opened_candidates: typing.Set[str] = set() self._selected_candidates: typing.Set[str] = set() self._nested_candidates: typing.Set[str] = set() self._init_source() def _init_source(self) -> None: custom = self._vim.call('defx#custom#_get')['source'] name = self._source.name if name in custom: self._source.vars.update(custom[name]) def debug(self, expr: typing.Any) -> None: error(self._vim, expr) def cd(self, path: str) -> None: self._cwd = str(Path(self._cwd).joinpath(path)) if self._context.auto_cd and Path(path).is_dir(): cd(self._vim, path) def get_root_candidate(self) -> Candidate: """ Returns root candidate """ if not self._source: return {} root = self._source.get_root_candidate(self._context, Path(self._cwd)) root['is_root'] = True root['is_opened_tree'] = False root['is_selected'] = False root['level'] = 0 root['root_marker'] = self._context.root_marker + ( self._source.name + ':' if self._source.name != 'file' else '') root['word'] = root['root_marker'] + root['word'] return root def tree_candidates( self, path: str, base_level: int, max_level: int ) -> typing.List[Candidate]: gathered_candidates = self.gather_candidates_recursive( path, base_level, max_level) if not self._opened_candidates and not self._nested_candidates: return gathered_candidates candidates = [] for candidate in gathered_candidates: candidates.append(candidate) candidate['level'] = base_level candidate_path = str(candidate['action__path']) if not candidate['is_directory']: continue if (candidate_path not in self._opened_candidates and candidate_path not in self._nested_candidates): continue children = self.tree_candidates( candidate_path, base_level + 1, max_level) candidate['is_opened_tree'] = True candidates += children return candidates def gather_candidates_recursive( self, path: str, base_level: int, max_level: int ) -> typing.List[Candidate]: candidates = self._gather_candidates(path, base_level) if base_level >= max_level: return candidates ret = [] for candidate in candidates: ret.append(candidate) if candidate['is_directory']: candidate['is_opened_tree'] = True ret += self.gather_candidates_recursive( str(candidate['action__path']), base_level + 1, max_level) return ret def _gather_candidates( self, path: str, base_level: int = 0) -> typing.List[Candidate]: """ Returns file candidates """ if not self._source: return [] candidates = self._source.gather_candidates( self._context, Path(path)) if self._filtered_files != ['']: new_candidates = [] for candidate in candidates: matched = False for glob in self._filtered_files: if candidate['action__path'].match(glob): matched = True break if matched or candidate['is_directory']: new_candidates.append(candidate) candidates = new_candidates if self._enabled_ignored_files: for glob in self._ignored_files: candidates = [x for x in candidates if not x['action__path'].match(glob)] for candidate in candidates: candidate['is_opened_tree'] = False candidate['is_root'] = False candidate['is_selected'] = False candidate['level'] = base_level return sort(self._sort_method, candidates)