summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--ranger/core/environment.py2
-rw-r--r--ranger/ext/keybinding_parser.py224
-rw-r--r--ranger/ext/keybindings.py150
3 files changed, 176 insertions, 200 deletions
diff --git a/ranger/core/environment.py b/ranger/core/environment.py
index c5279f0d..8ea8fd65 100644
--- a/ranger/core/environment.py
+++ b/ranger/core/environment.py
@@ -20,7 +20,7 @@ import socket
 from os.path import abspath, normpath, join, expanduser, isdir
 
 from ranger.fsobject import Directory
-from ranger.ext.keybindings import KeyBuffer, KeyMaps
+from ranger.ext.keybinding_parser import KeyBuffer, KeyMaps
 from ranger.container import History
 from ranger.ext.signals import SignalDispatcher
 from ranger.core.shared import SettingsAware
diff --git a/ranger/ext/keybinding_parser.py b/ranger/ext/keybinding_parser.py
index 7dbf8c25..27600a4e 100644
--- a/ranger/ext/keybinding_parser.py
+++ b/ranger/ext/keybinding_parser.py
@@ -13,8 +13,59 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
+import sys
+import copy
 import curses.ascii
-from string import ascii_lowercase
+
+PY3 = sys.version > '3'
+digits = set(range(ord('0'), ord('9')+1))
+
+# Arbitrary numbers which are not used with curses.KEY_XYZ
+ANYKEY, PASSIVE_ACTION, ALT_KEY, QUANT_KEY = range(9001, 9005)
+
+special_keys = {
+	'bs': curses.KEY_BACKSPACE,
+	'backspace': curses.KEY_BACKSPACE,
+	'backspace2': curses.ascii.DEL,
+	'delete': curses.KEY_DC,
+	'cr': ord("\n"),
+	'enter': ord("\n"),
+	'return': ord("\n"),
+	'space': ord(" "),
+	'esc': curses.ascii.ESC,
+	'escape': curses.ascii.ESC,
+	'down': curses.KEY_DOWN,
+	'up': curses.KEY_UP,
+	'left': curses.KEY_LEFT,
+	'right': curses.KEY_RIGHT,
+	'pagedown': curses.KEY_NPAGE,
+	'pageup': curses.KEY_PPAGE,
+	'home': curses.KEY_HOME,
+	'end': curses.KEY_END,
+	'tab': ord('\t'),
+	's-tab': curses.KEY_BTAB,
+}
+
+very_special_keys = {
+	'any': ANYKEY,
+	'bg': PASSIVE_ACTION,
+	'allow_quantifiers': QUANT_KEY,
+}
+
+for key, val in tuple(special_keys.items()):
+	special_keys['a-' + key] = (ALT_KEY, val)
+
+for char in 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789':
+	special_keys['a-' + char] = (ALT_KEY, ord(char))
+
+for char in 'abcdefghijklmnopqrstuvwxyz':
+	special_keys['c-' + char] = ord(char) - 96
+
+for n in range(64):
+	special_keys['f' + str(n)] = curses.KEY_F0 + n
+
+special_keys.update(very_special_keys)
+
 
 def parse_keybinding(obj):
 	"""
@@ -63,6 +114,7 @@ def parse_keybinding(obj):
 			for c in bracket_content:
 				yield ord(c)
 
+
 def construct_keybinding(iterable):
 	"""
 	Does the reverse of parse_keybinding
@@ -72,60 +124,134 @@ def construct_keybinding(iterable):
 		result.append(key_to_string(c))
 	return ''.join(result)
 
+
 def key_to_string(key):
-	try:
-		return chr(key)
-	except:
-		return '?'
+	return chr(key) if key in range(32, 127) else '?'
 
-# Arbitrary numbers which are not used with curses.KEY_XYZ
-DIRKEY = 9001
-ANYKEY = 9002
-PASSIVE_ACTION = 9003
-ALT_KEY = 9004
-QUANT_KEY = 9005
-HINT_KEY = 9006
 
-very_special_keys = {
-	'dir': DIRKEY,
-	'any': ANYKEY,
-	'bg': PASSIVE_ACTION,
-	'allow_quantifiers': QUANT_KEY,
-}
+def _unbind_traverse(pointer, keys, pos=0):
+	if keys[pos] not in pointer:
+		return
+	if len(keys) > pos+1 and isinstance(pointer, dict):
+		_unbind_traverse(pointer[keys[pos]], keys, pos=pos+1)
+		if not pointer[keys[pos]]:
+			del pointer[keys[pos]]
+	elif len(keys) == pos+1:
+		try:
+			del pointer[keys[pos]]
+			keys.pop()
+		except:
+			pass
 
-special_keys = {
-	'bs': curses.KEY_BACKSPACE,
-	'backspace': curses.KEY_BACKSPACE,
-	'backspace2': curses.ascii.DEL,
-	'delete': curses.KEY_DC,
-	'cr': ord("\n"),
-	'enter': ord("\n"),
-	'return': ord("\n"),
-	'space': ord(" "),
-	'esc': curses.ascii.ESC,
-	'escape': curses.ascii.ESC,
-	'down': curses.KEY_DOWN,
-	'up': curses.KEY_UP,
-	'left': curses.KEY_LEFT,
-	'right': curses.KEY_RIGHT,
-	'pagedown': curses.KEY_NPAGE,
-	'pageup': curses.KEY_PPAGE,
-	'home': curses.KEY_HOME,
-	'end': curses.KEY_END,
-	'tab': ord('\t'),
-	's-tab': curses.KEY_BTAB,
-}
+class KeyMaps(dict):
+	def __init__(self, keybuffer=None):
+		dict.__init__(self)
+		self.keybuffer = keybuffer
+		self.used_keymap = None
 
-for key, val in tuple(special_keys.items()):
-	special_keys['a-' + key] = (ALT_KEY, val)
+	def use_keymap(self, keymap_name):
+		self.keybuffer.keymap = self.get(keymap_name, dict())
+		if self.used_keymap != keymap_name:
+			self.used_keymap = keymap_name
+			self.keybuffer.clear()
 
-for char in ascii_lowercase + '0123456789':
-	special_keys['a-' + char] = (ALT_KEY, ord(char))
+	def _clean_input(self, context, keys):
+		try:
+			pointer = self[context]
+		except:
+			self[context] = pointer = dict()
+		if PY3:
+			keys = keys.encode('utf-8').decode('latin-1')
+		return list(parse_keybinding(keys)), pointer
 
-for char in ascii_lowercase:
-	special_keys['c-' + char] = ord(char) - 96
+	def bind(self, context, keys, leaf):
+		keys, pointer = self._clean_input(context, keys)
+		if not keys:
+			return
+		last_key = keys[-1]
+		for key in keys[:-1]:
+			try:
+				if isinstance(pointer[key], dict):
+					pointer = pointer[key]
+				else:
+					pointer[key] = pointer = dict()
+			except:
+				pointer[key] = pointer = dict()
+		pointer[last_key] = leaf
 
-for n in range(64):
-	special_keys['f' + str(n)] = curses.KEY_F0 + n
+	def copy(self, context, source, target):
+		clean_source, pointer = self._clean_input(context, source)
+		if not source:
+			return
+		for key in clean_source:
+			try:
+				pointer = pointer[key]
+			except:
+				raise KeyError("Tried to copy the keybinding `%s',"
+						" but it was not found." % source)
+		self.bind(context, target, copy.deepcopy(pointer))
 
-special_keys.update(very_special_keys)
+	def unbind(self, context, keys):
+		keys, pointer = self._clean_input(context, keys)
+		if not keys:
+			return
+		_unbind_traverse(pointer, keys)
+
+
+class KeyBuffer(object):
+	any_key             = ANYKEY
+	passive_key         = PASSIVE_ACTION
+	quantifier_key      = QUANT_KEY
+	exclude_from_anykey = [27]
+
+	def __init__(self, keymap=None):
+		self.keymap = keymap
+		self.clear()
+
+	def clear(self):
+		self.keys = []
+		self.wildcards = []
+		self.pointer = self.keymap
+		self.result = None
+		self.quantifier = None
+		self.finished_parsing_quantifier = False
+		self.finished_parsing = False
+		self.parse_error = False
+
+		if self.keymap and self.quantifier_key in self.keymap:
+			if self.keymap[self.quantifier_key] == 'false':
+				self.finished_parsing_quantifier = True
+
+	def add(self, key):
+		self.keys.append(key)
+		self.result = None
+		if not self.finished_parsing_quantifier and key in digits:
+			if self.quantifier is None:
+				self.quantifier = 0
+			self.quantifier = self.quantifier * 10 + key - 48 # (48 = ord(0))
+		else:
+			self.finished_parsing_quantifier = True
+
+			moved = True
+			if key in self.pointer:
+				self.pointer = self.pointer[key]
+			elif self.any_key in self.pointer and \
+					key not in self.exclude_from_anykey:
+				self.wildcards.append(key)
+				self.pointer = self.pointer[self.any_key]
+			else:
+				moved = False
+
+			if moved:
+				if isinstance(self.pointer, dict):
+					if self.passive_key in self.pointer:
+						self.result = self.pointer[self.passive_key]
+				else:
+					self.result = self.pointer
+					self.finished_parsing = True
+			else:
+				self.finished_parsing = True
+				self.parse_error = True
+
+	def __str__(self):
+		return "".join("{0:c}".format(c) for c in self.keys)
diff --git a/ranger/ext/keybindings.py b/ranger/ext/keybindings.py
deleted file mode 100644
index de08f26f..00000000
--- a/ranger/ext/keybindings.py
+++ /dev/null
@@ -1,150 +0,0 @@
-# Copyright (C) 2009, 2010  Roman Zimbelmann <romanz@lavabit.com>
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-from ranger.ext.keybinding_parser import (parse_keybinding,
-	ANYKEY, PASSIVE_ACTION, QUANT_KEY)
-import sys
-import copy
-
-PY3 = sys.version > '3'
-
-digits = set(range(ord('0'), ord('9')+1))
-
-def _unbind_traverse(pointer, keys, pos=0):
-	if keys[pos] not in pointer:
-		return
-	if len(keys) > pos+1 and isinstance(pointer, dict):
-		_unbind_traverse(pointer[keys[pos]], keys, pos=pos+1)
-		if not pointer[keys[pos]]:
-			del pointer[keys[pos]]
-	elif len(keys) == pos+1:
-		try:
-			del pointer[keys[pos]]
-			keys.pop()
-		except:
-			pass
-
-class KeyMaps(dict):
-	def __init__(self, keybuffer=None):
-		dict.__init__(self)
-		self.keybuffer = keybuffer
-		self.used_keymap = None
-
-	def use_keymap(self, keymap_name):
-		self.keybuffer.keymap = self.get(keymap_name, dict())
-		if self.used_keymap != keymap_name:
-			self.used_keymap = keymap_name
-			self.keybuffer.clear()
-
-	def _clean_input(self, context, keys):
-		try:
-			pointer = self[context]
-		except:
-			self[context] = pointer = dict()
-		if PY3:
-			keys = keys.encode('utf-8').decode('latin-1')
-		return list(parse_keybinding(keys)), pointer
-
-	def bind(self, context, keys, leaf):
-		keys, pointer = self._clean_input(context, keys)
-		if not keys:
-			return
-		last_key = keys[-1]
-		for key in keys[:-1]:
-			try:
-				if isinstance(pointer[key], dict):
-					pointer = pointer[key]
-				else:
-					pointer[key] = pointer = dict()
-			except:
-				pointer[key] = pointer = dict()
-		pointer[last_key] = leaf
-
-	def copy(self, context, source, target):
-		clean_source, pointer = self._clean_input(context, source)
-		if not source:
-			return
-		for key in clean_source:
-			try:
-				pointer = pointer[key]
-			except:
-				raise KeyError("Tried to copy the keybinding `%s',"
-						" but it was not found." % source)
-		self.bind(context, target, copy.deepcopy(pointer))
-
-	def unbind(self, context, keys):
-		keys, pointer = self._clean_input(context, keys)
-		if not keys:
-			return
-		_unbind_traverse(pointer, keys)
-
-
-class KeyBuffer(object):
-	any_key             = ANYKEY
-	passive_key         = PASSIVE_ACTION
-	quantifier_key      = QUANT_KEY
-	exclude_from_anykey = [27]
-
-	def __init__(self, keymap=None):
-		self.keymap = keymap
-		self.clear()
-
-	def clear(self):
-		self.keys = []
-		self.wildcards = []
-		self.pointer = self.keymap
-		self.result = None
-		self.quantifier = None
-		self.finished_parsing_quantifier = False
-		self.finished_parsing = False
-		self.parse_error = False
-
-		if self.keymap and self.quantifier_key in self.keymap:
-			if self.keymap[self.quantifier_key] == 'false':
-				self.finished_parsing_quantifier = True
-
-	def add(self, key):
-		self.keys.append(key)
-		self.result = None
-		if not self.finished_parsing_quantifier and key in digits:
-			if self.quantifier is None:
-				self.quantifier = 0
-			self.quantifier = self.quantifier * 10 + key - 48 # (48 = ord(0))
-		else:
-			self.finished_parsing_quantifier = True
-
-			moved = True
-			if key in self.pointer:
-				self.pointer = self.pointer[key]
-			elif self.any_key in self.pointer and \
-					key not in self.exclude_from_anykey:
-				self.wildcards.append(key)
-				self.pointer = self.pointer[self.any_key]
-			else:
-				moved = False
-
-			if moved:
-				if isinstance(self.pointer, dict):
-					if self.passive_key in self.pointer:
-						self.result = self.pointer[self.passive_key]
-				else:
-					self.result = self.pointer
-					self.finished_parsing = True
-			else:
-				self.finished_parsing = True
-				self.parse_error = True
-
-	def __str__(self):
-		return "".join("{0:c}".format(c) for c in self.keys)