Beispiel #1
0
    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}')
Beispiel #2
0
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)
Beispiel #3
0
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)
Beispiel #4
0
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)
Beispiel #5
0
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)
Beispiel #6
0
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)
Beispiel #7
0
    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)
Beispiel #8
0
    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')
Beispiel #9
0
    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
Beispiel #10
0
 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
Beispiel #11
0
    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)
Beispiel #12
0
    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}')
Beispiel #13
0
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)
Beispiel #14
0
    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
Beispiel #15
0
    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}')
Beispiel #16
0
    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)
Beispiel #17
0
    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
Beispiel #18
0
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)
Beispiel #19
0
 def debug(self, expr: typing.Any) -> None:
     error(self._vim, expr)
Beispiel #20
0
    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}')