<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html><head><title>Python: package ranger.container</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head><body bgcolor="#f0f0f8">
<table width="100%" cellspacing=0 cellpadding=2 border=0 summary="heading">
<tr bgcolor="#7799ee">
<td valign=bottom> <br>
<font color="#ffffff" face="helvetica, arial"> <br><big><big><strong><a href="ranger.html"><font color="#ffffff">ranger</font></a>.container</strong></big></big></font></td
><td align=right valign=bottom
><font color="#ffffff" face="helvetica, arial"><a href=".">index</a><br><a href="file:/home/hut/code/ranger/ranger/container/__init__.py">/home/hut/code/ranger/ranger/container/__init__.py</a></font></tdpre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */# Copyright (c) 2009, 2010 hut <hut@lavabit.com>
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
from string import ascii_lowercase
from inspect import isfunction, getargspec
from ranger.ext.tree import Tree
MAX_ALIAS_RECURSION = 20
DIRKEY = 9001
ANYKEY = 9002
FUNC = 'func'
DIRECTION = 'direction'
DIRARG = 'dir'
ALIASARG = 'alias'
class Direction(object):
"""An object with a down and right method"""
def __init__(self, down=0, right=0):
self.down = down
self.right = right
def copy(self):
new = type(self)()
new.__dict__.update(self.__dict__)
return new
def __mul__(self, other):
copy = self.copy()
if other is not None:
copy.down *= other
copy.right *= other
return copy
__rmul__ = __mul__
def to_string(i):
"""convert a ord'd integer to a string"""
try:
return chr(i)
except ValueError:
return '?'
def is_ascii_digit(n):
return n >= 48 and n <= 57
class CommandArgs(object):
"""The arguments which are passed to a keybinding function"""
def __init__(self, fm, widget, keybuffer):
self.fm = fm
self.wdg = widget
self.keybuffer = keybuffer
self.n = keybuffer.quant
self.direction = keybuffer.directions and keybuffer.directions[0] or None
self.directions = keybuffer.directions
self.keys = str(keybuffer)
self.matches = keybuffer.matches
self.binding = keybuffer.command
@staticmethod
def from_widget(widget):
return CommandArgs(widget.fm, \
widget, widget.env.keybuffer)
class KeyMap(Tree):
"""Contains a tree with all the keybindings"""
def add(self, *args, **keywords):
if keywords:
return self.add_binding(*args, **keywords)
firstarg = args[0]
if isfunction(firstarg):
keywords[FUNC] = firstarg
return self.add_binding(*args[1:], **keywords)
def decorator_function(func):
keywords = {FUNC:func}
self.add(*args, **keywords)
return func
return decorator_function
def add_binding(self, *keys, **actions):
assert keys
bind = Binding(keys, actions)
for key in keys:
self.set(translate_keys(key), bind)
def __getitem__(self, key):
return self.traverse(translate_keys(key))
class Binding(object):
"""The keybinding object"""
def __init__(self, keys, actions):
assert hasattr(keys, '__iter__')
assert isinstance(actions, dict)
self.actions = actions
try:
self.function = self.actions[FUNC]
except KeyError:
self.function = None
self.has_direction = False
else:
argnames = getargspec(self.function)[0]
try:
self.has_direction = actions['with_direction']
except KeyError:
self.has_direction = DIRECTION in argnames
try:
self.direction = self.actions[DIRARG]
except KeyError:
self.direction = None
try:
alias = self.actions[ALIASARG]
except KeyError:
self.alias = None
else:
self.alias = translate_keys(alias)
class KeyBuffer(object):
"""The evaluator and storage for pressed keys"""
def __init__(self, keymap, direction_keys):
self.assign(keymap, direction_keys)
def assign(self, keymap, direction_keys):
self.keymap = keymap
self.direction_keys = direction_keys
def add(self, key):
if self.failure:
return None
assert isinstance(key, int)
assert key >= 0
# evaluate quantifiers
if self.eval_quantifier and self._do_eval_quantifier(key):
return
# evaluate the command
if self.eval_command and self._do_eval_command(key):
return
# evaluate (the first number of) the direction-quantifier
if self.eval_quantifier and self._do_eval_quantifier(key):
return
# evaluate direction keys {j,k,gg,pagedown,...}
if not self.eval_command:
self._do_eval_direction(key)
def _do_eval_direction(self, key):
# swap quant and direction_quant in bindings like '<dir>'
if self.quant is not None and self.command is None \
and self.direction_quant is None:
self.direction_quant = self.quant
self.quant = None
try:
assert isinstance(self.dir_tree_pointer, dict)
self.dir_tree_pointer = self.dir_tree_pointer[key]
except KeyError:
self.failure = True
else:
self._direction_try_to_finish()
def _direction_try_to_finish(self, rec=MAX_ALIAS_RECURSION):
if rec <= 0:
self.failure = True
return None
if not isinstance(self.dir_tree_pointer, dict):
match = self.dir_tree_pointer
assert isinstance(match, Binding)
if 'alias' in match.actions:
self.dir_tree_pointer = self.direction_keys.traverse(
match.alias)
self._direction_try_to_finish(rec - 1)
else:
direction = match.actions['dir'] * self.direction_quant
self.directions.append(direction)
self.direction_quant = None
self.eval_command = True
self._try_to_finish()
def _do_eval_quantifier(self, key):
if self.eval_command:
tree = self.tree_pointer
else:
tree = self.dir_tree_pointer
if is_ascii_digit(key) and ANYKEY not in tree:
attr = self.eval_command and 'quant' or 'direction_quant'
if getattr(self, attr) is None:
setattr(self, attr, 0)
setattr(self, attr, getattr(self, attr) * 10 + key - 48)
else:
self.eval_quantifier = False
return None
return True
def _do_eval_command(self, key):
try:
assert isinstance(self.tree_pointer, dict)
self.tree_pointer = self.tree_pointer[key]
except TypeError:
print(self.tree_pointer)
self.failure = True
return None
except KeyError:
if DIRKEY in self.tree_pointer:
self.eval_command = False
self.eval_quantifier = True
self.tree_pointer = self.tree_pointer[DIRKEY]
assert isinstance(self.tree_pointer, (Binding, dict))
self.dir_tree_pointer = self.direction_keys._tree
elif ANYKEY in self.tree_pointer:
self.matches.append(key)
self.tree_pointer = self.tree_pointer[ANYKEY]
assert isinstance(self.tree_pointer, (Binding, dict))
self._try_to_finish()
else:
self.failure = True
return None
else:
self._try_to_finish()
def _try_to_finish(self, rec=MAX_ALIAS_RECURSION):
if rec <= 0:
self.failure = True
return None
assert isinstance(self.tree_pointer, (Binding, dict, KeyMap))
if isinstance(self.tree_pointer, KeyMap):
self.tree_pointer = self.tree_pointer._tree
if isinstance(self.tree_pointer, Binding):
if 'alias' in self.tree_pointer.actions:
self.tree_pointer = self.keymap.traverse(
translate_keys(self.tree_pointer.actions['alias']))
self._try_to_finish(rec - 1)
else:
self.command = self.tree_pointer
self.done = True
def clear(self):
self.failure = False
self.done = False
self.quant = None
self.matches = []
self.command = None
self.direction_quant = None
self.directions = []
self.all_keys = []
self.tree_pointer = self.keymap._tree
self.dir_tree_pointer = self.direction_keys._tree
self.eval_quantifier = True
self.eval_command = True
def __str__(self):
"""returns a concatenation of all characters"""
return "".join(to_string(c) for c in self.all_keys)
def simulate_press(self, string):
for char in translate_keys(string):
self.add(char)
if self.done:
return self.command
if self.failure:
break
key_map = {
'dir': DIRKEY,
'any': ANYKEY,
'cr': ord("\n"),
'enter': ord("\n"),
'space': ord(" "),
'space': ord(" "),
'tab': ord('\t'),
}
for char in ascii_lowercase:
key_map['c-' + char] = ord(char) - 96
def translate_keys(obj):
"""
Translate a keybinding to a sequence of integers
Example:
lol<CR> => (108, 111, 108, 10)
"""
assert isinstance(obj, (tuple, int, str))
if isinstance(obj, tuple):
for char in obj:
yield char
elif isinstance(obj, int):
yield obj
elif isinstance(obj, str):
in_brackets = False
bracket_content = None
for char in obj:
if in_brackets:
if char == '>':
in_brackets = False
string = ''.join(bracket_content).lower()
try:
yield key_map[string]
except KeyError:
yield ord('<')
for c in bracket_content:
yield ord(c)
yield ord('>')
else:
bracket_content.append(char)
else:
if char == '<':
in_brackets = True
bracket_content = []
else:
yield ord(char)
if in_brackets:
yield ord('<')
for c in bracket_content:
yield ord(c)