import os
from ranger.shared import FileManagerAware
# -------------------------------- helper classes
class parse(object):
"""Parse commands and extract information"""
def __init__(self, line):
self.line = line
self.chunks = line.split()
try:
self.firstpart = line[:line.rindex(' ') + 1]
except ValueError:
self.firstpart = ''
def chunk(self, n, otherwise=''):
if len(self.chunks) >= n:
return self.chunks[n]
else:
return otherwise
def __add__(self, newpart):
return self.firstpart + newpart
class Command(FileManagerAware):
"""Abstract command class"""
name = None
mode = ':'
line = ''
def __init__(self, line, mode):
self.line = line
self.mode = mode
def execute(self):
pass
def tab(self):
pass
# -------------------------------- definitions
class cd(Command):
"""The cd command changes the directory. The command 'cd -' is
equivalent to typing ``. In the quick console, the directory
will be entered without the need to press enter, as soon as there
is one unambiguous match.
"""
def execute(self):
line = parse(self.line)
try:
destination = line.chunks[1]
except IndexError:
destination = '~'
if destination == '-':
self.fm.enter_bookmark('`')
else:
self.fm.enter_dir(destination)
def tab(self):
from os.path import dirname, basename, expanduser, join, isdir
line = parse(self.line)
pwd = self.fm.env.pwd.path
try:
rel_dest = line.chunks[1]
except IndexError:
rel_dest = ''
if rel_dest.startswith('~'):
return line + expanduser(rel_dest) + '/'
abs_dest = join(pwd, rel_dest)
abs_dirname = dirname(abs_dest)
rel_basename = basename(rel_dest)
rel_dirname = dirname(rel_dest)
try:
if rel_dest.endswith('/') or rel_dest == '':
_, dirnames, _ = os.walk(abs_dest).next()
else:
_, dirnames, _ = os.walk(abs_dirname).next()
dirnames = [dn for dn in dirnames \
if dn.startswith(rel_basename)]
except (OSError, StopIteration):
pass
else:
dirnames.sort()
if len(dirnames) == 0:
return
if len(dirnames) == 1:
return line + join(rel_dirname, dirnames[0]) + '/'
return (line + join(rel_dirname, dirname) for dirname in dirnames)
def quick_open(self):
from os.path import isdir, join, normpath
line = parse(self.line)
pwd = self.fm.env.pwd.path
try:
rel_dest = line.chunks[1]
except IndexError:
return False
abs_dest = normpath(join(pwd, rel_dest))
return rel_dest != '.' and isdir(abs_dest)
class find(Command):
"""The find command will attempt to find a partial, case insensitive
match in the filenames of the current directory. In the quick command
console, once there is one unambiguous match, the file will be run
automatically.
"""
count = 0
def execute(self):
if self.mode != '>':
self._search()
import re
search = parse(self.line).chunk(1)
search = re.escape(search)
self.fm.env.last_search = re.compile(search, re.IGNORECASE)
def quick_open(self):
self._search()
if self.count == 1:
self.fm.move_right()
self.fm.block_input(0.5)
return True
def _search(self):
self.count = 0
line = parse(self.line)
pwd = self.fm.env.pwd
try:
arg = line.chunks[1]
except IndexError:
return False
length = len(pwd.files)
for i in range(length):
actual_index = (pwd.pointed_index + i) % length
filename = pwd.files[actual_index].basename_lower
if arg in filename:
self.count += 1
if self.count == 1:
pwd.move_pointer(absolute=actual_index)
self.fm.env.cf = pwd.pointed_file
if self.count > 1:
return False
return self.count == 1
class quit(Command):
"""Quits the program."""
def execute(self):
raise SystemExit
# -------------------------------- rest
by_name = {}
for varname, var in vars().copy().items():
try:
if issubclass(var, Command) and var != Command:
by_name[var.name or varname] = var
except TypeError:
pass
def alias(**kw):
for key, value in kw.items():
by_name[key] = value
alias(q=quit)