def redraw(self, is_force: bool = False) -> None: """ Redraw defx buffer. """ start = time.time() [info] = self._vim.call('getbufinfo', self._bufnr) prev_linenr = info['lnum'] prev = self.get_cursor_candidate(prev_linenr) if is_force: self._init_candidates() self._init_column_length() for column in self._columns: column.on_redraw(self._context) self._buffer.options['modifiable'] = True lines = [ self._get_columns_text(self._context, x) for x in self._candidates ] # NOTE: Different len of buffer line replacement cause cursor jump if len(lines) >= len(self._buffer): self._buffer[:] = lines[:len(self._buffer)] self._buffer.append(lines[len(self._buffer):]) else: self._buffer[len(lines):] = [] self._buffer[:] = lines self._buffer.options['modifiable'] = False self._buffer.options['modified'] = False # TODO: How to set cursor position for other buffer when # stay in current buffer if self._buffer == self._vim.current.buffer: self._vim.call('cursor', [prev_linenr, 0]) if prev: self.search_file(prev['action__path'], prev['_defx_index']) if is_force: self._init_column_syntax() if self._context.profile: error(self._vim, f'redraw time = {time.time() - start}')
def _new_file(view: View, defx: Defx, context: Context) -> None: """ Create a new file and it's parent directories. """ filename = cwd_input(view._vim, defx._cwd, 'Please input a new filename: ', '', 'file') if not filename: return if filename.exists(): error(view._vim, '{filename} already exists') return if not filename.parent.exists(): filename.parent.mkdir(parents=True) Path(filename).touch() view.redraw(True) view.search_file(str(filename), defx._index)
def _rename(view: View, defx: Defx, context: Context) -> None: """ Rename the file or directory. """ for target in context.targets: path = target['action__path'] filename = cwd_input( view._vim, defx._cwd, ('New name: {} -> '.format(path)), path, 'file') if not filename or filename == path: continue if os.path.exists(filename): error(view._vim, '{} is already exists'.format(filename)) continue os.rename(path, filename) view.redraw(True) view.search_file(filename, defx._index)
def _remove_trash(view: View, defx: Defx, context: Context) -> None: """ Delete the file or directory. """ if not importlib.find_loader('send2trash'): error(view._vim, '"Send2Trash" is not installed') return message = 'Are you sure you want to delete {}?'.format( context.targets[0]['action__path'] if len(context.targets) == 1 else str(len(context.targets)) + ' files') if not confirm(view._vim, message): return import send2trash for target in context.targets: send2trash.send2trash(target['action__path']) view.redraw(True)
def _new_directory(view: View, defx: Defx, context: Context) -> None: """ Create a new directory. """ candidate = view.get_cursor_candidate(context.cursor) if not candidate: return filename = cwd_input(view._vim, str(Path(candidate['action__path']).parent), 'Please input a new filename: ', '', 'file') if not filename: return if filename.exists(): error(view._vim, f'{filename} already exists') return filename.mkdir(parents=True) view.redraw(True) view.search_file(filename, defx._index)
def _new_multiple_files(view: View, defx: Defx, context: Context) -> None: """ Create multiple files. """ candidate = view.get_cursor_candidate(context.cursor) if not candidate: return if candidate['is_opened_tree'] or candidate['is_root']: cwd = str(candidate['action__path']) else: cwd = str(Path(candidate['action__path']).parent) save_cwd = view._vim.call('getcwd') cd(view._vim, cwd) str_filenames: str = view._vim.call('input', 'Please input new filenames: ', '', 'file') cd(view._vim, save_cwd) if not str_filenames: return None for name in str_filenames.split(): is_dir = name[-1] == '/' filename = Path(cwd).joinpath(name) if filename.exists(): error(view._vim, f'{filename} already exists') continue if is_dir: filename.mkdir(parents=True) else: if not filename.parent.exists(): filename.parent.mkdir(parents=True) filename.touch() view.redraw(True) view.search_recursive(filename, defx._index)
def _rename(self, view: View, defx: Defx, context: Context) -> None: """ Rename the file or directory. """ if len(context.targets) > 1: # ex rename view._vim.call('defx#exrename#create_buffer', [{ 'action__path': str(x['action__path']) } for x in context.targets], {'buffer_name': 'defx'}) return for target in context.targets: old = target['action__path'] new_filename = self.input(view, defx, defx._cwd, f'Old name: {old}\nNew name: ', str(old), 'file') view._vim.command('redraw') if not new_filename: return new = self.path_maker(defx._cwd).joinpath(new_filename) if not new or new == old: continue if str(new).lower() != str(old).lower() and new.exists(): error(view._vim, f'{new} already exists') continue if not new.parent.exists(): new.parent.mkdir(parents=True) old.rename(new) # Check rename # The old is directory, the path may be matched opened file if not new.is_dir(): view._vim.call('defx#util#buffer_rename', view._vim.call('bufnr', str(old)), str(new)) view.redraw(True) view.search_recursive(new, defx._index)
def cd(self, defx: Defx, source_name: str, path: str, cursor: int, save_history: bool = True) -> None: history = defx._cursor_history # Save previous cursor position candidate = self.get_cursor_candidate(cursor) if candidate: history[defx._cwd] = candidate['action__path'] if save_history: global_histories = self._vim.vars['defx#_histories'] global_histories.append([defx._source.name, defx._cwd]) self._vim.vars['defx#_histories'] = global_histories if source_name != defx._source.name: if source_name not in self._all_sources: error(self._vim, 'Invalid source_name:' + source_name) return # Replace with new defx self._defxs[defx._index] = Defx(self._vim, self._context, self._all_sources[source_name], path, defx._index) defx = self._defxs[defx._index] defx.cd(path) self.redraw(True) self._check_session(defx._index, path) self._init_cursor(defx) if path in history: self.search_file(history[path], defx._index) self._update_paths(defx._index, path) self._vim.command('silent doautocmd <nomodeline> User DefxDirChanged')
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 } import defx.action as action for defx in self._defxs: 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 gather_candidates( self, context: Context, path: Path) -> typing.List[typing.Dict[str, typing.Any]]: candidates = [] if not readable(path) or not path.is_dir(): error(self.vim, f'"{path}" is not readable directory.') return [] try: for entry in path.iterdir(): candidates.append({ 'word': entry.name.replace('\n', '\\n') + ('/' if safe_call(entry.is_dir, False) else ''), 'is_directory': safe_call(entry.is_dir, False), 'action__path': entry, }) except OSError: pass return candidates
def _cd(self, view: View, defx: Defx, context: Context) -> None: """ Change the current directory. """ source_name = defx._source.name is_parent = context.args and context.args[0] == '..' open = len(context.args) > 1 and context.args[1] == 'open' save_history = len(context.args) < 3 or context.args[2] != 'nohist' prev_cwd = self.path_maker(defx._cwd) if open: # Don't close current directory defx._opened_candidates.add(defx._cwd) if is_parent: path = prev_cwd.parent else: if context.args: if len(context.args) > 1: source_name = context.args[0] path = self.path_maker(context.args[1]) else: path = self.path_maker(context.args[0]) else: path = self.get_home() path = prev_cwd.joinpath(path) if not self.is_readable(path): error(view._vim, f'{path} is invalid.') path = path.resolve() if source_name == 'file' and not path.is_dir(): error(view._vim, f'{path} is invalid.') return view.cd(defx, source_name, str(path), context.cursor, save_history=save_history) if is_parent: view.search_file(prev_cwd, defx._index)
def redraw(self, is_force: bool = False) -> None: """ Redraw defx buffer. """ if self._buffer != self._vim.current.buffer: return start = time.time() 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 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 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 _cd(view: View, defx: Defx, context: Context) -> None: """ Change the current directory. """ source_name = defx._source.name if context.args: if len(context.args) > 1: source_name = context.args[0] path = Path(context.args[1]) else: path = Path(context.args[0]) else: path = Path.home() path = Path(defx._cwd).joinpath(path).resolve() if not readable(path) or (source_name == 'file' and not path.is_dir()): error(view._vim, f'{path} is invalid.') return prev_cwd = defx._cwd view.cd(defx, source_name, str(path), context.cursor) if context.args and context.args[0] == '..': view.search_file(Path(prev_cwd), defx._index)
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 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._init_candidates() self._init_column_length() self._init_column_syntax() 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 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'] visual_start = new_context['visual_start'] visual_end = new_context['visual_end'] 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( args=action_args, cursor=cursor, targets=defx_targets[defx._index], visual_start=visual_start, visual_end=visual_end, ) ret = action.do_action(self, defx, action_name, context) if ret: error(self._vim, 'Invalid action_name:' + action_name) return # Jump to the defx window if context.post_action == 'jump': self._vim.call('win_gotoid', self._winid)
def gather_candidates( self, context: Context, path: Path ) -> typing.List[typing.Dict[str, typing.Any]]: if not readable(path): error(self.vim, f'"{path}" is not readable file.') return [] if path.is_dir(): # Fallback to file source return File(self.vim).gather_candidates(context, path) candidates = [] with path.open() as f: for line in f: entry = Path(line.rstrip('\n')) if not entry.exists(): continue candidates.append({ 'word': str(entry) + ( '/' if safe_call(entry.is_dir, False) else ''), 'is_directory': safe_call(entry.is_dir, False), 'action__path': entry, }) return candidates
def _rename(view: View, defx: Defx, context: Context) -> None: """ Rename the file or directory. """ if len(context.targets) > 1: # ex rename view._vim.call('defx#exrename#create_buffer', [{ 'action__path': str(x['action__path']) } for x in context.targets], {'buffer_name': 'defx'}) return for target in context.targets: old = target['action__path'] new_filename = cwd_input(view._vim, defx._cwd, f'Old name: {old}\nNew name: ', str(old), 'file') view._vim.command('redraw') if not new_filename: return new = Path(defx._cwd).joinpath(new_filename) if not new or new == old: continue if str(new).lower() != str(old).lower() and new.exists(): error(view._vim, f'{new} already exists') continue old.rename(new) # Check rename view._vim.call('defx#util#buffer_rename', view._vim.call('bufnr', str(old)), str(new)) view.redraw(True) view.search_file(new, defx._index)
def debug(self, expr: typing.Any) -> None: error(self._vim, expr)
def redraw(self, is_force: bool = False) -> None: """ Redraw defx buffer. """ start = time.time() [info] = self._vim.call('getbufinfo', self._bufnr) prev_linenr = info['lnum'] prev = self.get_cursor_candidate(prev_linenr) if is_force: self._init_candidates() self._init_column_length() for column in self._columns: column.on_redraw(self, self._context) lines = [] columns_highlights = [] self._context = self._context._replace(with_highlights=self._ns > 0) for (i, candidate) in enumerate(self._candidates): (text, highlights) = self._get_columns_text(self._context, candidate) lines.append(text) columns_highlights += ([(x[0], i, x[1], x[1] + x[2]) for x in highlights]) self._buffer.options['modifiable'] = True # NOTE: Different len of buffer line replacement cause cursor jump if len(lines) >= len(self._buffer): self._buffer[:] = lines[:len(self._buffer)] self._buffer.append(lines[len(self._buffer):]) else: self._buffer[len(lines):] = [] self._buffer[:] = lines # Update highlights if self._ns > 0 and columns_highlights: commands = [[ 'nvim_buf_clear_namespace', [self._bufnr, self._ns, 0, -1] ]] commands += [[ 'nvim_buf_add_highlight', [self._bufnr, self._ns, x[0], x[1], x[2], x[3]] ] for x in columns_highlights] self._vim.call('defx#util#call_atomic', commands) self._buffer.options['modifiable'] = False self._buffer.options['modified'] = False # TODO: How to set cursor position for other buffer when # stay in current buffer if self._buffer == self._vim.current.buffer: self._vim.call('cursor', [prev_linenr, 0]) if prev: self.search_file(prev['action__path'], prev['_defx_index']) if is_force: self._init_column_syntax() if self._context.profile: error(self._vim, f'redraw time = {time.time() - start}')