from __future__ import (absolute_import, division, print_function) # You can import any python module as needed. import os from collections import deque from ranger.api.commands import Command fd_deq = deque() class fd_search(Command): """:fd_search [-d] Executes "fd -d " in the current directory and focuses the first match. defaults to 1, i.e. only the contents of the current directory. """ def execute(self): import subprocess from ranger.ext.get_executables import get_executables if not 'fd' in get_executables(): self.fm.notify("Couldn't find fd on the PATH.", bad=True) return if self.arg(1): if self.arg(1)[:2] == '-d': depth = self.arg(1) target = self.rest(2) else: depth = '-d1' target = self.rest(1) else: self.fm.notify(":fd_search needs a query.", bad=True) return # For convenience, change which dict is used as result_sep to change # fd's behavior from splitting results by \0, which allows for newlines # in your filenames to splitting results by \n, which allows for \0 in # filenames. null_sep = {'arg': '-0', 'split': '\0'} nl_sep = {'arg': '', 'split': '\n'} result_sep = null_sep process = subprocess.Popen(['fd', result_sep['arg'], depth, target], universal_newlines=True, stdout=subprocess.PIPE) (search_results, _err) = process.communicate() global fd_deq fd_deq = deque((self.fm.thisdir.path + os.sep + rel for rel in sorted(search_results.split(result_sep['split']), key=str.lower) if rel != '')) if len(fd_deq) > 0: self.fm.select_file(fd_deq[0]) class fd_next(Command): """:fd_next Selects the next match from the last :fd_search. """ def execute(self): if len(fd_deq) > 1: fd_deq.rotate(-1) # rotate left self.fm.select_file(fd_deq[0]) elif len(fd_deq) == 1: self.fm.select_file(fd_deq[0]) class fd_prev(Command): """:fd_prev Selects the next match from the last :fd_search. """ def execute(self): if len(fd_deq) > 1: fd_deq.rotate(1) # rotate right self.fm.select_file(fd_deq[0]) elif len(fd_deq) == 1: self.fm.select_file(fd_deq[0]) class fzf_select(Command): """ :fzf_select Find a file using fzf. With a prefix argument select only directories. See: https://github.com/junegunn/fzf """ def execute(self): import subprocess import os.path if self.quantifier: # match only directories command="find -L . \( -path '*/\.*' -o -fstype 'dev' -o -fstype 'proc' \) -prune \ -o -type d -print 2> /dev/null | sed 1d | cut -b3- | fzf +m" else: # match files and directories command="find -L . \( -path '*/\.*' -o -fstype 'dev' -o -fstype 'proc' \) -prune \ -o -print 2> /dev/null | sed 1d | cut -b3- | fzf +m" fzf = self.fm.execute_command(command, universal_newlines=True, stdout=subprocess.PIPE) stdout, stderr = fzf.communicate() if fzf.returncode == 0: fzf_file = os.path.abspath(stdout.rstrip('\n')) if os.path.isdir(fzf_file): self.fm.cd(fzf_file) else: self.fm.select_file(fzf_file)