about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--TODO2
-rw-r--r--ranger/actions.py56
-rw-r--r--ranger/defaults/keys.py18
-rw-r--r--ranger/fsobject/directory.py32
-rw-r--r--ranger/gui/widgets/console.py2
5 files changed, 85 insertions, 25 deletions
diff --git a/TODO b/TODO
index 206f0445..bfd80a4d 100644
--- a/TODO
+++ b/TODO
@@ -17,4 +17,4 @@ General
    (X) #9   09/12/24  add a widget for managing running operations
    (X) #10  09/12/24  sorting
    (X) #11  09/12/27  filter
-   ( ) #12  09/12/27  jump through the list in a specific order
+   (X) #12  09/12/27  jump through the list in a specific order
diff --git a/ranger/actions.py b/ranger/actions.py
index e1005201..968aae4f 100644
--- a/ranger/actions.py
+++ b/ranger/actions.py
@@ -5,15 +5,53 @@ from ranger.shared import EnvironmentAware, SettingsAware
 from ranger import fsobject
 
 class Actions(EnvironmentAware, SettingsAware):
-	def search_forward(self):
-		"""Search forward for the regexp in self.env.last_search"""
-		if self.env.pwd:
-			self.env.pwd.search(self.env.last_search)
-
-	def search_backward(self):
-		"""Search backward for the regexp in self.env.last_search"""
-		if self.env.pwd:
-			self.env.pwd.search(self.env.last_search, -1)
+	search_method = 'ctime'
+	search_forward = False
+
+	def search(self, order=None, forward=True):
+		if self.search_forward:
+			direction = bool(forward)
+		else:
+			direction = not bool(forward)
+
+		if order is None:
+			order = self.search_method
+		else:
+			self.set_search_method(order=order)
+
+		if order in ('search', 'tag'):
+			if order == 'search':
+				arg = self.env.last_search
+				if arg is None:
+					return False
+				if hasattr(arg, 'search'):
+					fnc = lambda x: arg.search(x.basename)
+				else:
+					fnc = lambda x: arg in x.basename
+			elif order == 'tag':
+				fnc = lambda x: x.realpath in self.tags
+
+			return self.env.pwd.search_fnc(fnc=fnc, forward=forward)
+
+		elif order in ('size', 'mimetype', 'ctime'):
+			pwd = self.env.pwd
+			if not pwd.cycle_list:
+				lst = list(pwd.files)
+				if order == 'size':
+					fnc = lambda item: item.size
+				elif order == 'mimetype':
+					fnc = lambda item: item.mimetype
+				elif order == 'ctime':
+					fnc = lambda item: -int(item.stat and item.stat.st_ctime)
+				lst.sort(key=fnc)
+				pwd.set_cycle_list(lst)
+
+			return pwd.cycle(forward=forward)
+
+	def set_search_method(self, order, forward=True):
+		if order in ('search', 'tag', 'size', 'mimetype', 'ctime'):
+			self.search_method = order
+			self.search_forward = forward
 
 	def interrupt(self):
 		"""
diff --git a/ranger/defaults/keys.py b/ranger/defaults/keys.py
index 75956b7a..c3490c4a 100644
--- a/ranger/defaults/keys.py
+++ b/ranger/defaults/keys.py
@@ -39,12 +39,14 @@ def initialize_commands(command_list):
 	bind('v', do('mark', all=True, toggle=True))
 	bind('V', do('mark', all=True, val=False))
 
-	bind('yy', 'cp', do('copy'))
-	bind('cut', do('cut'))
+	bind('yy', do('copy'))
+	bind('dd', do('cut'))
 	bind('p', do('paste'))
 
 	bind('s', do('spawn', 'bash'))
 
+	bind(TAB, do('search', order='tag'))
+
 	t_hint = "show_//h//idden //p//review_files //d//irectories_first //a//uto_load_preview //c//ollapse_preview"
 	command_list.hint(t_hint, 't')
 	bind('th', do('toggle_boolean_option', 'show_hidden'))
@@ -83,6 +85,8 @@ def initialize_commands(command_list):
 	bind('term', do('spawn', 'x-terminal-emulator'))
 	bind('du', do('runcmd', 'du --max-depth=1 -h | less'))
 	bind('tf', do('open_console', cmode.COMMAND, 'filter '))
+	d_hint = 'd//u// (disk usage) d//d// (cut)'
+	command_list.hint(d_hint, 'd')
 
 	# key combinations which change the current directory
 	def cd(path):
@@ -98,8 +102,14 @@ def initialize_commands(command_list):
 	bind('gs', do('cd', '/srv'))
 	bind('gR', do('cd', RANGERDIR))
 
-	bind('n', do('search_forward'))
-	bind('N', do('search_backward'))
+	bind('n', do('search', forward=True))
+	bind('N', do('search', forward=False))
+
+	bind('cc', do('search', forward=True, order='ctime'))
+	bind('cm', do('search', forward=True, order='mimetype'))
+	bind('cs', do('search', forward=True, order='size'))
+	c_hint = '//c//time //m//imetype //s//ize'
+	command_list.hint(c_hint, 'c')
 
 	# bookmarks
 	for key in ALLOWED_BOOKMARK_KEYS:
diff --git a/ranger/fsobject/directory.py b/ranger/fsobject/directory.py
index f263aa74..6c9ab7b1 100644
--- a/ranger/fsobject/directory.py
+++ b/ranger/fsobject/directory.py
@@ -1,6 +1,7 @@
 from ranger.fsobject import BAD_INFO, File, FileSystemObject
 from ranger.shared import SettingsAware
 from ranger.ext.accumulator import Accumulator
+from collections import deque
 from ranger import log
 import ranger.fsobject
 
@@ -18,6 +19,7 @@ class NoDirectoryGiven(Exception):
 class Directory(FileSystemObject, Accumulator, SettingsAware):
 	enterable = False
 	load_generator = None
+	cycle_list = None
 	loading = False
 
 	filenames = None
@@ -171,6 +173,7 @@ class Directory(FileSystemObject, Accumulator, SettingsAware):
 			self.files = None
 			self.infostring = BAD_INFO
 
+		self.cycle_list = None
 		self.content_loaded = True
 		self.loading = False
 
@@ -251,21 +254,18 @@ class Directory(FileSystemObject, Accumulator, SettingsAware):
 
 		Accumulator.move_to_obj(self, arg, attr='path')
 
-	def search(self, arg, direction = 1):
-		"""Search for a regular expression"""
-		if self.empty() or arg is None:
+	def search_fnc(self, fnc, forward=True):
+		if not hasattr(fnc, '__call__'):
 			return False
-		elif hasattr(arg, 'search'):
-			fnc = lambda x: arg.search(x.basename)
-		else:
-			fnc = lambda x: arg in x.basename
 
 		length = len(self)
 
-		if direction > 0:
-			generator = ((self.pointer + (x + 1)) % length for x in range(length-1))
+		if forward:
+			generator = ((self.pointer + (x + 1)) % length \
+					for x in range(length-1))
 		else:
-			generator = ((self.pointer - (x + 1)) % length for x in range(length-1))
+			generator = ((self.pointer - (x + 1)) % length \
+					for x in range(length-1))
 
 		for i in generator:
 			_file = self.files[i]
@@ -276,6 +276,18 @@ class Directory(FileSystemObject, Accumulator, SettingsAware):
 				return True
 		return False
 
+	def set_cycle_list(self, lst):
+		self.cycle_list = deque(lst)
+
+	def cycle(self, forward=True):
+		if self.cycle_list:
+			if forward:
+				self.cycle_list.rotate(-1)
+			else:
+				self.cycle_list.rotate(1)
+
+			self.move_to_obj(self.cycle_list[0])
+
 	def correct_pointer(self):
 		"""Make sure the pointer is in the valid range"""
 		Accumulator.correct_pointer(self)
diff --git a/ranger/gui/widgets/console.py b/ranger/gui/widgets/console.py
index 2d6df2a7..92c57a46 100644
--- a/ranger/gui/widgets/console.py
+++ b/ranger/gui/widgets/console.py
@@ -296,7 +296,7 @@ class SearchConsole(Console):
 		if self.fm.env.pwd:
 			regexp = re.compile(self.line, re.L | re.U | re.I)
 			self.fm.env.last_search = regexp
-			if self.fm.env.pwd.search(regexp):
+			if self.fm.search(order='search'):
 				self.fm.env.cf = self.fm.env.pwd.pointed_obj
 		Console.execute(self)