def init(self, paths: typing.List[str], context: typing.Dict[str, typing.Any], clipboard: Clipboard) -> None: context['wincol'] = int(context['wincol']) context['winheight'] = int(context['winheight']) context['winrow'] = int(context['winrow']) context['winwidth'] = int(context['winwidth']) context['prev_bufnr'] = int(context['prev_bufnr']) context['prev_winid'] = int(context['prev_winid']) self._context = Context(**context) self._bufname = f'[defx] {self._context.buffer_name}-{self._index}' if not self.init_buffer(paths): self._winid = self._vim.call('win_getid') return self._candidates = [] self._context = Context(**context) self._clipboard = clipboard # Initialize defx self._defxs = [] self._buffer.vars['defx']['paths'] = paths for [index, path] in enumerate(paths): self._defxs.append(Defx(self._vim, self._context, path, index)) self.init_columns(self._context.columns.split(':')) self.redraw(True) for defx in self._defxs: self.init_cursor(defx)
def __init__(self, vim: Nvim, paths: typing.List[str], context: dict) -> None: self._vim: Nvim = vim self._candidates: typing.List[dict] = [] self._selected_candidates: typing.List[int] = [] self._context = Context(**context) # Initialize defx self._defxs: typing.List[Defx] = [] for path in paths: self._defxs.append(Defx(self._vim, path)) # Create new buffer self._vim.call('defx#util#execute_path', 'silent keepalt edit', '[defx]') self._options = self._vim.current.buffer.options self._options['buftype'] = 'nofile' self._options['swapfile'] = False self._options['modeline'] = False self._options['filetype'] = 'defx' self._options['modifiable'] = False self._options['modified'] = False self._vim.command('silent doautocmd FileType defx') self._columns: typing.List[Column] = [] for column in [Mark(self._vim), Filename(self._vim)]: column.syntax_name = 'Defx_' + column.name # type: ignore self._columns.append(column)
def init(self, paths: typing.List[str], context: typing.Dict[str, typing.Any], clipboard: Clipboard) -> None: context['fnamewidth'] = int(context['fnamewidth']) context['winheight'] = int(context['winheight']) context['winwidth'] = int(context['winwidth']) context['prev_bufnr'] = int(context['prev_bufnr']) self._context = Context(**context) self._bufname = f'[defx] {self._context.buffer_name}-{self._index}' if not self.init_buffer(): return self._candidates = [] self._selected_candidates = [] self._context = Context(**context) self._clipboard = clipboard # Initialize defx self._defxs: typing.List[Defx] = [] for [index, path] in enumerate(paths): self._defxs.append(Defx(self._vim, self._context, path, index)) self.init_columns() self.init_syntax() if self._context.search: for defx in self._defxs: if self.search_tree(self._context.search, defx._index): break
def init(self, paths: typing.List[str], context: typing.Dict[str, typing.Any], clipboard: Clipboard) -> None: context['winheight'] = int(context['winheight']) context['winwidth'] = int(context['winwidth']) context['prev_bufnr'] = int(context['prev_bufnr']) context['prev_winid'] = int(context['prev_winid']) self._context = Context(**context) self._bufname = f'[defx] {self._context.buffer_name}-{self._index}' if not self.init_buffer(paths): return self._candidates = [] self._selected_candidates = [] self._context = Context(**context) self._clipboard = clipboard # Initialize defx self._defxs: typing.List[Defx] = [] self._buffer.vars['defx']['paths'] = paths for [index, path] in enumerate(paths): self._defxs.append(Defx(self._vim, self._context, path, index)) self.init_columns(self._context.columns.split(':')) for defx in self._defxs: if self._context.search: self.search_tree(self._context.search, defx._index) else: self.init_cursor(defx)
def _init_context( self, context: typing.Dict[str, typing.Any]) -> Context: # Convert to int for attr in [x[0] for x in Context()._asdict().items() if isinstance(x[1], int) and x[0] in context]: context[attr] = int(context[attr]) return Context(**context)
def init(self, paths: typing.List[str], context: dict, clipboard: Clipboard) -> None: self._candidates = [] self._selected_candidates = [] self._context = Context(**context) self._clipboard = clipboard context['fnamewidth'] = int(context['fnamewidth']) context['winheight'] = int(context['winheight']) context['winwidth'] = int(context['winwidth']) self._context = Context(**context) self._bufname = f'[defx] {self._context.buffer_name}-{self._index}' # Initialize defx self._defxs: typing.List[Defx] = [] for [index, path] in enumerate(paths): self._defxs.append(Defx(self._vim, self._context, path, index)) if not self.init_buffer(): return # Initialize columns self._columns: typing.List[Column] = [] self._all_columns: typing.Dict[str, Column] = { 'mark': Mark(self._vim), 'filename': Filename(self._vim), 'type': Type(self._vim), } self._columns = [ self._all_columns[x] for x in self._context.columns.split(':') if x in self._all_columns ] start = 1 for column in self._columns: column.on_init() column.start = start length = column.length(self._context) column.end = start + length - 1 column.syntax_name = 'Defx_' + column.name start += length self.init_syntax() self.redraw(True) if self._context.search: for defx in self._defxs: if self.search_tree(self._context.search, defx._index): break
def _preview_file(view: View, defx: Defx, context: Context, candidate: Candidate) -> None: previewed_buffers = view._vim.vars['defx#_previewed_buffers'] filepath = str(candidate['action__path']) has_preview = bool(view._vim.call('defx#util#_get_preview_window')) if (has_preview and view._previewed_target and view._previewed_target == candidate): bufnr = str(view._vim.call('bufnr', filepath)) if bufnr in previewed_buffers: previewed_buffers.pop(bufnr) view._vim.vars['defx#_previewed_buffers'] = previewed_buffers view._vim.command('pclose!') return prev_id = view._vim.call('win_getid') listed = view._vim.call('buflisted', filepath) view._previewed_target = candidate view._vim.call('defx#util#preview_file', context._replace(targets=[])._asdict(), filepath) view._vim.current.window.options['foldenable'] = False if not listed: bufnr = str(view._vim.call('bufnr', filepath)) previewed_buffers[bufnr] = 1 view._vim.vars['defx#_previewed_buffers'] = previewed_buffers view._vim.call('win_gotoid', prev_id)
def get_root_candidate(self) -> dict: """ Returns root candidate """ root = self._source.get_root_candidate(Context(), self._cwd) root['is_root'] = True return root
def create_open(self, view: View, defx: Defx, context: Context, path: Path, command: str, isdir: bool, isopen: bool) -> None: if isdir: path.mkdir(parents=True) else: path.parent.mkdir(parents=True, exist_ok=True) path.touch() if not isopen: view.redraw(True) view.search_recursive(path, defx._index) return # Note: Must be redraw before actions view.redraw(True) view.search_recursive(path, defx._index) if isdir: if command == 'open_tree': view.open_tree(path, defx._index, False, 0) else: view.cd(defx, defx._source.name, str(path), context.cursor) else: if command == 'drop': self._drop( view, defx, context._replace(args=[], targets=[{ 'action__path': path }])) else: view._vim.call('defx#util#execute_path', command, self.get_buffer_name(str(path)))
def _multi(self, view: View, defx: Defx, context: Context) -> None: for arg in context.args: args: typing.List[str] if isinstance(arg, list): args = arg else: args = [arg] do_action(view, defx, args[0], context._replace(args=args[1:]))
def __init__(self, vim: Nvim, paths: typing.List[str], context: dict) -> None: self._vim: Nvim = vim self._candidates: typing.List[dict] = [] self._selected_candidates: typing.List[int] = [] context['fnamewidth'] = int(context['fnamewidth']) self._context = Context(**context) # Initialize defx self._defxs: typing.List[Defx] = [] index = 0 for path in paths: self._defxs.append(Defx(self._vim, self._context, path, index)) index += 1 self.init_buffer() # Initialize columns self._columns: typing.List[Column] = [] self._all_columns: typing.List[Column] = [ Mark(self._vim), Filename(self._vim), Type(self._vim) ] columns = self._context.columns.split(':') self._columns = [x for x in self._all_columns if x.name in columns] start = 1 for column in self._columns: column.on_init() column.start = start length = column.length(self._context) column.end = start + length - 1 column.syntax_name = 'Defx_' + column.name start += length self.init_syntax() self.redraw(True) if self._context.search: for defx in self._defxs: self.search_file(self._context.search, defx._index)
def _call(view: View, defx: Defx, context: Context) -> None: """ Call the function. """ function = context.args[0] if context.args else None if not function: return dict_context = context._asdict() dict_context['targets'] = [str(x['action__path']) for x in context.targets] view._vim.call(function, dict_context)
def _multi(self, view: View, defx: Defx, context: Context) -> None: for arg in context.args: args: typing.List[typing.Union[str, typing.List[str]]] if isinstance(arg, list): args = arg else: args = [arg] action_args = ((args[1] if isinstance(args[1], list) else [args[1]]) if len(args) > 1 else []) do_action(view, defx, str(args[0]), context._replace(args=action_args))
def gather_candidates(self) -> typing.List: """ Returns file candidates """ candidates = self._source.gather_candidates(Context(), self._cwd) # Sort dirs = sorted([x for x in candidates if x['is_directory']], key=lambda x: x['abbr']) files = sorted([x for x in candidates if not x['is_directory']], key=lambda x: x['abbr']) return dirs + files
def do_action(view: View, defx: Defx, action_name: str, context: Context) -> bool: """ Do "action_name" action. """ if not defx._source: return True actions: typing.Dict[str, ActionTable] = defx._source.kind.get_actions() if action_name not in actions: return True action = actions[action_name] selected_candidates = [x for x in view._candidates if x['is_selected']] if (selected_candidates and ActionAttr.NO_TAGETS not in action.attr and ActionAttr.TREE not in action.attr): # Clear marks for candidate in selected_candidates: candidate['is_selected'] = False view.redraw() if ActionAttr.CURSOR_TARGET in action.attr: # Use cursor candidate only cursor_candidate = view.get_cursor_candidate(context.cursor) if not cursor_candidate: return True context = context._replace( targets=[cursor_candidate], ) action.func(view, defx, context) if action_name != 'repeat': view._prev_action = action_name if ActionAttr.MARK in action.attr: # Update marks view.update_candidates() view.redraw() elif ActionAttr.TREE in action.attr: view.update_candidates() view.redraw() elif ActionAttr.REDRAW in action.attr: # Redraw view.redraw(True) return False
def _open_tree(view: View, defx: Defx, context: Context) -> None: nested = False recursive_level = 0 toggle = False for arg in context.args: if arg == 'nested': nested = True elif arg == 'recursive': recursive_level = 20 elif re.search(r'recursive:\d+', arg): recursive_level = int(arg.split(':')[1]) elif arg == 'toggle': toggle = True for target in [x for x in context.targets if x['is_directory']]: if toggle and not target['is_directory'] or target['is_opened_tree']: _close_tree(view, defx, context._replace(targets=[target])) else: view.open_tree(target['action__path'], defx._index, nested, recursive_level)
def __init__(self, vim: Nvim) -> None: super().__init__(vim) self.name = 'filename' self.vars = { 'min_width': 40, 'max_width': 100, 'root_marker_highlight': 'Constant', } self.is_stop_variable = True self._current_length = 0 self._syntaxes = [ 'directory', 'directory_marker', 'hidden', 'root', 'root_marker', ] self._context: Context = Context() self._directory_marker = '**' self._file_marker = '||'
def __init__(self, vim: Nvim) -> None: super().__init__(vim) self.name = 'filename' self.vars = { 'directory_icon': '+', 'indent': ' ', 'min_width': 40, 'max_width': 100, 'root_icon': ' ', 'opened_icon': '-', } self._current_length = 0 self._syntaxes = [ 'directory', 'directory_icon', 'hidden', 'marker', 'opened_icon', 'root', 'root_icon', ] self._context: Context = Context()
def _open_or_close_tree(self, view: View, defx: Defx, context: Context) -> None: self._open_tree(view, defx, context._replace(args=context.args + ['toggle']))
def _open_tree_recursive(self, view: View, defx: Defx, context: Context) -> None: level = context.args[0] if context.args else '20' self._open_tree( view, defx, context._replace(args=context.args + ['recursive:' + level]))
class View(object): def __init__(self, vim: Nvim, index: int) -> None: self._vim: Nvim = vim self._candidates: typing.List[dict] = [] self._selected_candidates: typing.List[int] = [] self._clipboard = Clipboard() self._bufnr = -1 self._index = index self._bufname = '[defx]' def init(self, paths: typing.List[str], context: dict, clipboard: Clipboard) -> None: self._candidates = [] self._selected_candidates = [] self._context = Context(**context) self._clipboard = clipboard context['fnamewidth'] = int(context['fnamewidth']) context['winheight'] = int(context['winheight']) context['winwidth'] = int(context['winwidth']) self._context = Context(**context) self._bufname = f'[defx] {self._context.buffer_name}-{self._index}' # Initialize defx self._defxs: typing.List[Defx] = [] for [index, path] in enumerate(paths): self._defxs.append(Defx(self._vim, self._context, path, index)) if not self.init_buffer(): return # Initialize columns self._columns: typing.List[Column] = [] self._all_columns: typing.Dict[str, Column] = { 'mark': Mark(self._vim), 'filename': Filename(self._vim), 'type': Type(self._vim), } self._columns = [ self._all_columns[x] for x in self._context.columns.split(':') if x in self._all_columns ] start = 1 for column in self._columns: column.on_init() column.start = start length = column.length(self._context) column.end = start + length - 1 column.syntax_name = 'Defx_' + column.name start += length self.init_syntax() self.redraw(True) if self._context.search: for defx in self._defxs: if self.search_tree(self._context.search, defx._index): break def init_buffer(self) -> bool: if self._context.split == 'tab': self._vim.command('tabnew') winnr = self._vim.call('bufwinnr', self._bufname) if winnr > 0: self._vim.command(f'{winnr}wincmd w') if self._context.toggle: self.quit() return False return True # Create new buffer self._vim.call( 'defx#util#execute_path', 'silent keepalt %s %s %s ' % ( self._context.direction, ('vertical' if self._context.split == 'vertical' else ''), ('edit' if self._context.split == 'no' or self._context.split == 'tab' else 'new'), ), self._bufname) window_options = self._vim.current.window.options window_options['list'] = False window_options['wrap'] = False if (self._context.split == 'vertical' and self._context.winwidth > 0): window_options['winfixwidth'] = True self._vim.command(f'vertical resize {self._context.winwidth}') elif (self._context.split == 'horizontal' and self._context.winheight > 0): window_options['winfixheight'] = True self._vim.command(f'resize {self._context.winheight}') buffer_options = self._vim.current.buffer.options buffer_options['buftype'] = 'nofile' buffer_options['swapfile'] = False buffer_options['modeline'] = False buffer_options['filetype'] = 'defx' buffer_options['modifiable'] = False buffer_options['modified'] = False self._vim.current.buffer.vars['defx'] = { 'context': self._context._asdict(), } if not self._context.listed: buffer_options['buflisted'] = False buffer_options['bufhidden'] = 'wipe' self._vim.command('silent doautocmd FileType defx') self._vim.command('autocmd! FocusGained <buffer>') self._vim.command('autocmd defx FocusGained <buffer> ' + 'call defx#_do_action("redraw", [])') self._bufnr = self._vim.current.buffer.number return True def init_syntax(self) -> None: for column in self._columns: self._vim.command('silent! syntax clear ' + column.syntax_name) self._vim.command('syntax region ' + column.syntax_name + ' start=/\%' + str(column.start) + 'v/ end=/\%' + str(column.end) + 'v/ keepend oneline') column.highlight() def debug(self, expr: typing.Any) -> None: error(self._vim, expr) def print_msg(self, expr: typing.Any) -> None: self._vim.call('defx#util#print_message', expr) def quit(self) -> None: if self._vim.call('winnr', '$') != 1: self._vim.command('close') else: self._vim.command('enew') def init_candidates(self) -> None: self._candidates = [] for defx in self._defxs: candidates = [defx.get_root_candidate()] candidates += defx.gather_candidates() for candidate in candidates: candidate['_defx_index'] = defx._index self._candidates += candidates def redraw(self, is_force: bool = False) -> None: """ Redraw defx buffer. """ buffer_options = self._vim.current.buffer.options if buffer_options['filetype'] != 'defx': return start = time.time() prev = self.get_cursor_candidate(self._vim.call('line', '.')) if is_force: self._selected_candidates = [] self.init_candidates() is_busy = time.time() - start > 0.5 if is_busy: self.print_msg('Waiting...') # Set is_selected flag for candidate in self._candidates: candidate['is_selected'] = False for index in self._selected_candidates: self._candidates[index]['is_selected'] = True buffer_options['modifiable'] = True self._vim.current.buffer[:] = [ self.get_columns_text(self._context, x) for x in self._candidates ] buffer_options['modifiable'] = False buffer_options['modified'] = False if prev: self.search_file(prev['action__path'], prev['_defx_index']) if is_busy: self._vim.command('redraw') self.print_msg('Done.') if self._context.profile: error(self._vim, f'redraw time = {time.time() - start}') def get_columns_text(self, context: Context, candidate: dict) -> str: text = '' for column in self._columns: text += column.get(context, candidate) return text def get_cursor_candidate(self, cursor: int) -> dict: if len(self._candidates) < cursor: return {} else: return self._candidates[cursor - 1] def get_selected_candidates(self, cursor: int, index: int) -> typing.List[dict]: if not self._selected_candidates: candidates = [self.get_cursor_candidate(cursor)] else: candidates = [ self._candidates[x] for x in self._selected_candidates ] return [x for x in candidates if x['_defx_index'] == index] def cd(self, defx: Defx, path: str, cursor: int) -> None: # Save previous cursor position history = defx._cursor_history history[defx._cwd] = self.get_cursor_candidate(cursor)['action__path'] global_histories = self._vim.vars['defx#_histories'] global_histories.append(defx._cwd) self._vim.vars['defx#_histories'] = global_histories defx.cd(path) self.redraw(True) if path in history: self.search_file(history[path], defx._index) self._selected_candidates = [] def search_tree(self, start: str, index: int) -> bool: path = Path(start) while True: if self.search_file(str(path), index): return True if path.parent == path: break path = path.parent return False def search_file(self, path: str, index: int) -> bool: linenr = 1 for candidate in self._candidates: if (candidate['_defx_index'] == index and str(candidate['action__path']) == path): self._vim.call('cursor', [linenr, 1]) return True linenr += 1 return False def do_action(self, action_name: str, action_args: typing.List[str], new_context: dict) -> None: """ Do "action" action. """ if not self._candidates: return cursor = new_context['cursor'] defx_targets = { x._index: self.get_selected_candidates(cursor, x._index) for x in self._defxs } import defx.action as action for defx in self._defxs: targets = defx_targets[defx._index] if not targets: continue context = self._context._replace(targets=targets, args=action_args, cursor=cursor) ret = action.do_action(self, defx, action_name, context) if ret: error(self._vim, 'Invalid action_name:' + action_name) return
class View(object): def __init__(self, vim: Nvim, index: int) -> None: self._vim: Nvim = vim self._candidates: typing.List[typing.Dict[str, typing.Any]] = [] self._selected_candidates: typing.List[int] = [] self._clipboard = Clipboard() self._bufnr = -1 self._index = index self._bufname = '[defx]' self._buffer: Nvim.buffer = None self._prev_action = '' self._prev_highlight_commands: typing.List[str] = [] def init(self, paths: typing.List[str], context: typing.Dict[str, typing.Any], clipboard: Clipboard) -> None: context['winheight'] = int(context['winheight']) context['winwidth'] = int(context['winwidth']) context['prev_bufnr'] = int(context['prev_bufnr']) context['prev_winid'] = int(context['prev_winid']) self._context = Context(**context) self._bufname = f'[defx] {self._context.buffer_name}-{self._index}' if not self.init_buffer(paths): return self._candidates = [] self._selected_candidates = [] self._context = Context(**context) self._clipboard = clipboard # Initialize defx self._defxs: typing.List[Defx] = [] self._buffer.vars['defx']['paths'] = paths for [index, path] in enumerate(paths): self._defxs.append(Defx(self._vim, self._context, path, index)) self.init_columns(self._context.columns.split(':')) for defx in self._defxs: if self._context.search: self.search_tree(self._context.search, defx._index) else: self.init_cursor(defx) def init_columns(self, columns: typing.List[str]) -> None: # Initialize columns self._columns: typing.List[Column] = [] self._all_columns: typing.Dict[str, Column] = {} for path_column in self.load_custom_columns(): column = import_plugin(path_column, 'column', 'Column') if not column: continue column = column(self._vim) if column.name not in self._all_columns: self._all_columns[column.name] = column custom = self._vim.call('defx#custom#_get')['column'] self._columns = [ self._all_columns[x] for x in columns if x in self._all_columns ] for column in self._columns: if column.name in custom: column.vars.update(custom[column.name]) column.on_init(self._context) column.syntax_name = 'Defx_' + column.name def init_buffer(self, paths: typing.List[str]) -> bool: if self._context.split == 'tab': self._vim.command('tabnew') winnr = self._vim.call('bufwinnr', self._bufname) if winnr > 0: self._vim.command(f'{winnr}wincmd w') if self._context.toggle: self.quit() return False return True if (self._vim.current.buffer.options['modified'] and not self._vim.options['hidden'] and self._context.split == 'no'): self._context = self._context._replace(split='vertical') # Create new buffer vertical = 'vertical' if self._context.split == 'vertical' else '' if self._vim.call('bufexists', self._bufnr): command = ('buffer' if self._context.split in ['no', 'tab'] else 'sbuffer') self._vim.command('silent keepalt %s %s %s %s' % ( self._context.direction, vertical, command, self._bufnr, )) if self._context.resume: return False else: command = ('edit' if self._context.split in ['no', 'tab'] else 'new') self._vim.call( 'defx#util#execute_path', 'silent keepalt %s %s %s ' % ( self._context.direction, vertical, command, ), self._bufname) self._buffer = self._vim.current.buffer self._bufnr = self._buffer.number window_options = self._vim.current.window.options window_options['list'] = False window_options['wrap'] = False if (self._context.split == 'vertical' and self._context.winwidth > 0): window_options['winfixwidth'] = True self._vim.command(f'vertical resize {self._context.winwidth}') elif (self._context.split == 'horizontal' and self._context.winheight > 0): window_options['winfixheight'] = True self._vim.command(f'resize {self._context.winheight}') buffer_options = self._buffer.options buffer_options['buftype'] = 'nofile' buffer_options['swapfile'] = False buffer_options['modeline'] = False buffer_options['filetype'] = 'defx' buffer_options['modifiable'] = False buffer_options['modified'] = False self._buffer.vars['defx'] = { 'context': self._context._asdict(), 'paths': paths, } if not self._context.listed: buffer_options['buflisted'] = False buffer_options['bufhidden'] = 'wipe' self.execute_commands([ 'silent doautocmd FileType defx', 'autocmd! defx * <buffer>', ]) self._vim.command('autocmd defx ' 'CursorHold,WinEnter,FocusGained <buffer> ' 'call defx#call_async_action("check_redraw")') self._prev_highlight_commands = [] return True def init_length(self) -> None: start = 1 for column in self._columns: column.start = start length = column.length( self._context._replace(targets=self._candidates)) column.end = start + length start += length + 1 def update_syntax(self) -> None: highlight_commands: typing.List[str] = [] for column in self._columns: highlight_commands += column.highlight_commands() if highlight_commands == self._prev_highlight_commands: # Skip highlights return self._prev_highlight_commands = highlight_commands commands: typing.List[str] = [] for column in self._columns: commands.append('silent! syntax clear ' + column.syntax_name) for syntax in column.syntaxes(): commands.append('silent! syntax clear ' + syntax) commands.append('syntax region ' + column.syntax_name + r' start=/\%' + str(column.start) + r'v/ end=/\%' + str(column.end) + 'v/ keepend oneline') commands += highlight_commands self.execute_commands(commands) def debug(self, expr: typing.Any) -> None: error(self._vim, expr) def print_msg(self, expr: typing.Any) -> None: self._vim.call('defx#util#print_message', expr) def execute_commands(self, commands: typing.List[str]) -> None: self._vim.command(' | '.join(commands)) def quit(self) -> None: winnr = self._vim.call('bufwinnr', self._bufname) if winnr < 0: return self._vim.command(f'{winnr}wincmd w') if self._context.split in ['no', 'tab']: if self._vim.call('bufexists', self._context.prev_bufnr): self._vim.command('buffer ' + str(self._context.prev_bufnr)) else: self._vim.command('enew') else: if self._vim.call('winnr', '$') != 1: self._vim.command('close') self._vim.call('win_gotoid', self._context.prev_winid) else: self._vim.command('enew') def init_candidates(self) -> None: self._candidates = [] for defx in self._defxs: root = defx.get_root_candidate() defx._mtime = root['action__path'].stat().st_mtime candidates = [root] candidates += defx.gather_candidates() for candidate in candidates: candidate['_defx_index'] = defx._index self._candidates += candidates def redraw(self, is_force: bool = False) -> None: """ Redraw defx buffer. """ if self._buffer != self._vim.current.buffer: return start = time.time() prev_linenr = self._vim.call('line', '.') prev = self.get_cursor_candidate(prev_linenr) if is_force: self._selected_candidates = [] self.init_candidates() self.init_length() self.update_syntax() # Set is_selected flag for candidate in self._candidates: candidate['is_selected'] = False for index in self._selected_candidates: self._candidates[index]['is_selected'] = True for column in self._columns: column.on_redraw(self._context) if self._buffer != self._vim.current.buffer: return self._buffer.options['modifiable'] = True self._buffer[:] = [ self.get_columns_text(self._context, x) for x in self._candidates ] self._buffer.options['modifiable'] = False self._buffer.options['modified'] = False self._vim.call('cursor', [prev_linenr, 0]) if prev: self.search_file(prev['action__path'], prev['_defx_index']) if self._context.profile: error(self._vim, f'redraw time = {time.time() - start}') def get_columns_text(self, context: Context, candidate: typing.Dict[str, typing.Any]) -> str: text = '' for column in self._columns: if text: text += ' ' text += column.get(context, candidate) return text def get_cursor_candidate(self, cursor: int) -> typing.Dict[str, typing.Any]: if len(self._candidates) < cursor: return {} else: return self._candidates[cursor - 1] def get_selected_candidates( self, cursor: int, index: int) -> typing.List[typing.Dict[str, typing.Any]]: if not self._candidates: return [] if not self._selected_candidates: candidates = [self.get_cursor_candidate(cursor)] else: candidates = [ self._candidates[x] for x in self._selected_candidates ] return [x for x in candidates if x.get('_defx_index', -1) == index] def cd(self, defx: Defx, path: str, cursor: int) -> None: # Save previous cursor position history = defx._cursor_history history[defx._cwd] = self.get_cursor_candidate(cursor)['action__path'] global_histories = self._vim.vars['defx#_histories'] global_histories.append(defx._cwd) self._vim.vars['defx#_histories'] = global_histories defx.cd(path) self.redraw(True) self.init_cursor(defx) if path in history: self.search_file(history[path], defx._index) self._selected_candidates = [] self.update_paths(defx._index, path) def update_paths(self, index: int, path: str) -> None: var_defx = self._buffer.vars['defx'] var_defx['paths'][index] = path self._buffer.vars['defx'] = var_defx def search_tree(self, start: str, index: int) -> bool: path = Path(start) while True: if self.search_file(path, index): return True if path.parent == path: break path = path.parent return False def search_file(self, path: Path, index: int) -> bool: linenr = 1 target = str(path) if target and target[-1] == '/': target = target[:-1] for candidate in self._candidates: if (candidate['_defx_index'] == index and str(candidate['action__path']) == target): self._vim.call('cursor', [linenr, 1]) return True linenr += 1 return False def init_cursor(self, defx: Defx) -> None: self.search_file(Path(defx._cwd), defx._index) # Move to next self._vim.call('cursor', [self._vim.call('line', '.') + 1, 1]) def do_action(self, action_name: str, action_args: typing.List[str], new_context: typing.Dict[str, typing.Any]) -> None: """ Do "action" action. """ cursor = new_context['cursor'] defx_targets = { x._index: self.get_selected_candidates(cursor, x._index) for x in self._defxs } all_targets: typing.List[typing.Dict[str, typing.Any]] = [] for targets in defx_targets.values(): all_targets += targets import defx.action as action for defx in [ x for x in self._defxs if not all_targets or defx_targets[x._index] ]: context = self._context._replace(targets=defx_targets[defx._index], args=action_args, cursor=cursor) ret = action.do_action(self, defx, action_name, context) if ret: error(self._vim, 'Invalid action_name:' + action_name) return def load_custom_columns(self) -> typing.List[Path]: rtp_list = self._vim.options['runtimepath'].split(',') result: typing.List[Path] = [] for path in rtp_list: column_path = Path(path).joinpath('rplugin', 'python3', 'defx', 'column') if safe_call(column_path.is_dir): result += column_path.glob('*.py') return result
class View(object): def __init__(self, vim: Nvim, paths: typing.List[str], context: dict) -> None: self._vim: Nvim = vim self._candidates: typing.List[dict] = [] self._selected_candidates: typing.List[int] = [] context['fnamewidth'] = int(context['fnamewidth']) self._context = Context(**context) # Initialize defx self._defxs: typing.List[Defx] = [] index = 0 for path in paths: self._defxs.append(Defx(self._vim, self._context, path, index)) index += 1 self.init_buffer() # Initialize columns self._columns: typing.List[Column] = [] self._all_columns: typing.List[Column] = [ Mark(self._vim), Filename(self._vim), Type(self._vim) ] columns = self._context.columns.split(':') self._columns = [x for x in self._all_columns if x.name in columns] start = 1 for column in self._columns: column.on_init() column.start = start length = column.length(self._context) column.end = start + length - 1 column.syntax_name = 'Defx_' + column.name start += length self.init_syntax() self.redraw(True) if self._context.search: for defx in self._defxs: self.search_file(self._context.search, defx._index) def init_buffer(self) -> None: # Create new buffer self._vim.call('defx#util#execute_path', 'silent keepalt edit', '[defx]') window_options = self._vim.current.window.options window_options['list'] = False window_options['wrap'] = False buffer_options = self._vim.current.buffer.options buffer_options['buftype'] = 'nofile' buffer_options['swapfile'] = False buffer_options['modeline'] = False buffer_options['filetype'] = 'defx' buffer_options['modifiable'] = False buffer_options['modified'] = False buffer_options['buflisted'] = False buffer_options['bufhidden'] = 'wipe' self._vim.command('silent doautocmd FileType defx') self._vim.command('augroup defx | autocmd! | augroup END') self._vim.command('autocmd defx FocusGained <buffer> ' + 'call defx#_do_action("redraw", [])') def init_syntax(self) -> None: for column in self._columns: self._vim.command('silent! syntax clear ' + column.syntax_name) self._vim.command('syntax region ' + column.syntax_name + ' start=/\%' + str(column.start) + 'v/ end=/\%' + str(column.end) + 'v/ keepend oneline') column.highlight() def debug(self, expr: typing.Any) -> None: error(self._vim, expr) def quit(self) -> None: if self._vim.call('winnr', '$') != 1: self._vim.command('close') else: self._vim.command('enew') def init_candidates(self) -> None: self._candidates = [] for defx in self._defxs: candidates = [defx.get_root_candidate()] candidates += defx.gather_candidates() for candidate in candidates: candidate['_defx_index'] = defx._index self._candidates += candidates def redraw(self, is_force: bool = False) -> None: """ Redraw defx buffer. """ buffer_options = self._vim.current.buffer.options if buffer_options['filetype'] != 'defx': return prev = self.get_cursor_candidate(self._vim.call('line', '.')) if is_force: self._selected_candidates = [] self.init_candidates() # Set is_selected flag for candidate in self._candidates: candidate['is_selected'] = False for index in self._selected_candidates: self._candidates[index]['is_selected'] = True buffer_options['modifiable'] = True self._vim.current.buffer[:] = [ self.get_columns_text(self._context, x) for x in self._candidates ] buffer_options['modifiable'] = False buffer_options['modified'] = False if prev: self.search_file(prev['action__path'], prev['_defx_index']) def get_columns_text(self, context: Context, candidate: dict) -> str: text = '' for column in self._columns: text += column.get(context, candidate) return text def get_cursor_candidate(self, cursor: int) -> dict: if len(self._candidates) < cursor: return {} else: return self._candidates[cursor - 1] def get_selected_candidates(self, cursor: int, index: int) -> typing.List[dict]: if not self._selected_candidates: candidates = [self.get_cursor_candidate(cursor)] else: candidates = [ self._candidates[x] for x in self._selected_candidates ] return [x for x in candidates if x['_defx_index'] == index] def cd(self, defx: Defx, path: str, cursor: int) -> None: # Save previous cursor position history = defx._cursor_history history[defx._cwd] = self.get_cursor_candidate(cursor)['action__path'] defx.cd(path) self.redraw(True) if path in history: self.search_file(history[path], defx._index) self._selected_candidates = [] def search_file(self, path: str, index: int) -> None: linenr = 1 for candidate in self._candidates: if (candidate['_defx_index'] == index and candidate['action__path'] == path): self._vim.call('cursor', [linenr, 1]) return linenr += 1 def do_action(self, action_name: str, action_args: typing.List[str], new_context: dict) -> None: """ Do "action" action. """ if not self._candidates: return cursor = new_context['cursor'] import defx.action as action for defx in self._defxs: targets = self.get_selected_candidates(cursor, defx._index) if not targets: continue context = self._context._replace(targets=targets, args=action_args, cursor=cursor) ret = action.do_action(self, defx, action_name, context) if ret: error(self._vim, 'Invalid action_name:' + action_name) return
def _open_or_close_tree(view: View, defx: Defx, context: Context) -> None: for target in context.targets: if not target['is_directory'] or target['is_opened_tree']: _close_tree(view, defx, context._replace(targets=[target])) else: _open_tree(view, defx, context._replace(targets=[target]))
class View(object): def __init__(self, vim: Nvim, paths: typing.List[str], context: dict) -> None: self._vim: Nvim = vim self._candidates: typing.List[dict] = [] self._selected_candidates: typing.List[int] = [] self._context = Context(**context) # Initialize defx self._defxs: typing.List[Defx] = [] for path in paths: self._defxs.append(Defx(self._vim, path)) # Create new buffer self._vim.call('defx#util#execute_path', 'silent keepalt edit', '[defx]') self._options = self._vim.current.buffer.options self._options['buftype'] = 'nofile' self._options['swapfile'] = False self._options['modeline'] = False self._options['filetype'] = 'defx' self._options['modifiable'] = False self._options['modified'] = False self._vim.command('silent doautocmd FileType defx') self._columns: typing.List[Column] = [] for column in [Mark(self._vim), Filename(self._vim)]: column.syntax_name = 'Defx_' + column.name # type: ignore self._columns.append(column) def init_syntax(self): for column in self._columns: if hasattr(column, 'highlight'): self._vim.command('silent! syntax clear ' + column.syntax_name) def redraw(self, is_force: bool = False) -> None: """ Redraw defx buffer. """ if is_force: self._selected_candidates = [] self._candidates = [] for defx in self._defxs: self._candidates.append({ 'word': defx._cwd, 'abbr': defx._cwd + '/', 'kind': 'directory', 'is_directory': True, 'is_root': True, 'action__path': defx._cwd, }) self._candidates += defx.gather_candidates() # Set is_selected flag for index in self._selected_candidates: self._candidates[index]['is_selected'] = True self._options['modifiable'] = True self._vim.current.buffer[:] = [ self.get_columns_text(self._context, x) for x in self._candidates ] self._options['modifiable'] = False self._options['modified'] = False def get_columns_text(self, context: Context, candidate: dict) -> str: text = '' for column in self._columns: text += column.get(context, candidate) return text def get_selected_candidates(self, cursor: int) -> typing.List[dict]: if not self._selected_candidates: return [self._candidates[cursor - 1]] else: return [self._candidates[x] for x in self._selected_candidates] def do_action(self, action_name: str, action_args: typing.List[str], new_context: dict) -> None: """ Do "action" action. """ if not self._candidates: return cursor = new_context['cursor'] context = self._context._replace( targets=self.get_selected_candidates(cursor), args=action_args, cursor=cursor) import defx.action as action for defx in self._defxs: action.do_action(self, defx, action_name, context)