summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--ranger/actions.py8
-rw-r--r--ranger/container/bookmarks.py186
-rw-r--r--ranger/fm.py41
3 files changed, 143 insertions, 92 deletions
diff --git a/ranger/actions.py b/ranger/actions.py
index 2435480b..cc013401 100644
--- a/ranger/actions.py
+++ b/ranger/actions.py
@@ -40,16 +40,16 @@ If CTRL+C is pressed while waiting, the program will be exited"""
 		from ranger.container.bookmarks import NonexistantBookmark
 		try:
 			destination = self.bookmarks[key]
-			current_path = self.env.pwd.path
-			if destination != current_path:
+			pwd = self.env.pwd
+			if destination.path != pwd.path:
 				self.bookmarks.enter(key)
-				self.bookmarks.remember(current_path)
+				self.bookmarks.remember(pwd)
 		except NonexistantBookmark:
 			pass
 
 	def set_bookmark(self, key):
 		"""Set the bookmark with the name <key> to the current directory"""
-		self.bookmarks[key] = self.env.pwd.path
+		self.bookmarks[key] = self.env.pwd
 
 	def unset_bookmark(self, key):
 		"""Delete the bookmark with the name <key>"""
diff --git a/ranger/container/bookmarks.py b/ranger/container/bookmarks.py
index da54e8eb..bf41150c 100644
--- a/ranger/container/bookmarks.py
+++ b/ranger/container/bookmarks.py
@@ -1,63 +1,98 @@
-from string import ascii_letters, digits
-ALLOWED_KEYS = ascii_letters + digits + "`'"
+from ranger import log, trace
+import string
+import re
+import os
+ALLOWED_KEYS = string.ascii_letters + string.digits + "`'"
 
 class NonexistantBookmark(Exception):
 	pass
 
 class Bookmarks(object):
-	def __init__(self, path = None):
-		import string, re, os
-		self.dct = {}
-		if path is None:
-			self.path = os.path.expanduser("~/.ranger/bookmarks")
-		self.load_pattern = re.compile(r"^[\d\w`']:.")
-		self.enter_dir_function = None
-		self.last_mtime = None
+	"""Bookmarks is a container which associates keys with bookmarks.
 
-	def load_dict(self):
-		import os
-		dct = {}
-		if os.access(self.path, os.R_OK):
-			f = open(self.path, 'r')
-			for line in f:
-				if self.load_pattern.match(line):
-					key, value = line[0], line[2:-1]
-					if key in ALLOWED_KEYS: 
-						dct[key] = value
-			f.close()
-			return dct
-		else:
-			raise OSError('Cannot read the given path')
-	
-	def set_dict(self, dct):
-		self.dct.clear()
-		self.dct.update(dct)
-		self.original_dict = self.dct.copy()
-		self.last_mtime = self.get_mtime()
+A key is a string with: len(key) == 1 and key in ALLOWED_KEYS.
 
-	def get_mtime(self):
-		import os
-		try:
-			return os.stat(self.path).st_mtime
-		except OSError:
-			return None
+A bookmark is an object with: bookmark == bookmarktype(str(instance))
+Which is true for str or FileSystemObject. This condition is required
+so bookmark-objects can be saved to and loaded from a file.
+
+Optionally, a bookmark.go() method is used for entering a bookmark.
+"""
+
+	last_mtime = None
+	autosave = True
+	load_pattern = re.compile(r"^[\d\w`']:.")
+
+	def __init__(self, bookmarkfile, bookmarktype=str, autosave=False):
+		"""<bookmarkfile> specifies the path to the file where
+bookmarks are saved in.
+"""
+		self.autosave = autosave
+		self.dct = {}
+		self.path = bookmarkfile
+		self.bookmarktype = bookmarktype
 
 	def load(self):
+		"""Load the bookmarks from path/bookmarks"""
 		try:
-			new_dict = self.load_dict()
+			new_dict = self._load_dict()
 		except OSError:
 			return
 
-		self.set_dict(new_dict)
-	
+		self._set_dict(new_dict)
+
 	def delete(self, key):
+		"""Delete the bookmark with the given key"""
 		if key in self.dct:
 			del self.dct[key]
-			self.save()
+			if self.autosave: self.save()
+
+	def enter(self, key):
+		"""Enter the bookmark with the given key.
+Requires the bookmark instance to have a go() method.
+"""
+
+		try:
+			return self[key].go()
+		except (IndexError, KeyError, AttributeError):
+			return False
+
+	def update_if_outdated(self):
+		if self.last_mtime != self._get_mtime():
+			self.update()
+
+	def remember(self, value):
+		"""Bookmarks <value> to the keys ` and '"""
+		self["`"] = value
+		self["'"] = value
+		if self.autosave: self.save()
+
+	def __getitem__(self, key):
+		"""Get the bookmark associated with the key"""
+		if key in self.dct:
+			return self.dct[key]
+		else:
+			raise NonexistantBookmark()
+
+	def __setitem__(self, key, value):
+		"""Bookmark <value> to the key <key>.
+key is expected to be a 1-character string and element of ALLOWED_KEYS.
+value is expected to be a filesystemobject."""
+		if key in ALLOWED_KEYS:
+			self.dct[key] = value
+			if self.autosave: self.save()
+
+	def __contains__(self, key):
+		"""Test whether a bookmark-key is defined"""
+		return key in self.dct
 
 	def update(self):
+		"""Update the bookmarks from the bookmark file.
+Useful if two instances are running which define different bookmarks.
+"""
+		
 		try:
-			real_dict = self.load_dict()
+			real_dict = self._load_dict()
 		except OSError:
 			return
 
@@ -77,6 +112,9 @@ class Bookmarks(object):
 			else:
 				real = None
 
+			log(key, current, original, real)
+#			trace()
+
 			if current == original and current != real:
 				continue
 
@@ -85,46 +123,50 @@ class Bookmarks(object):
 			else:
 				real_dict[key] = current
 
-		self.set_dict(real_dict)
-
-	def reload_if_outdated(self):
-		if self.last_mtime != self.get_mtime():
-			self.update()
-
-	def enter(self, key):
-		if self.enter_dir_function is not None:
-			self.enter_dir_function(self[key])
-		else:
-			raise RuntimeError('Not specified how to enter a directory')
-
-	def remember(self, value):
-		self["`"] = value
-		self["'"] = value
-
-	def __getitem__(self, key):
-		if key in self.dct:
-			return self.dct[key]
-		else:
-			raise NonexistantBookmark()
-
-	def __setitem__(self, key, value):
-		if key in ALLOWED_KEYS:
-			self.dct[key] = value
-			self.save()
-
-	def __contains__(self, key):
-		return key in self.dct
+		self._set_dict(real_dict)
 
 	def save(self):
+		"""Save the bookmarks to the bookmarkfile.
+This is done automatically after every modification if autosave is True."""
 		import os
 		self.update()
 		if os.access(self.path, os.W_OK):
 			f = open(self.path, 'w')
-
 			for key, value in self.dct.items():
 				if type(key) == str\
-						and type(value) == str \
 						and key in ALLOWED_KEYS:
 					f.write("{0}:{1}\n".format(str(key), str(value)))
 
 			f.close()
+		self._update_mtime()
+
+	def _load_dict(self):
+		import os
+		dct = {}
+		if os.access(self.path, os.R_OK):
+			f = open(self.path, 'r')
+			for line in f:
+				if self.load_pattern.match(line):
+					key, value = line[0], line[2:-1]
+					if key in ALLOWED_KEYS: 
+						dct[key] = self.bookmarktype(value)
+			f.close()
+			return dct
+		else:
+			raise OSError('Cannot read the given path')
+	
+	def _set_dict(self, dct):
+		self.dct.clear()
+		self.dct.update(dct)
+		self.original_dict = self.dct.copy()
+		self._update_mtime()
+
+	def _get_mtime(self):
+		import os
+		try:
+			return os.stat(self.path).st_mtime
+		except OSError:
+			return None
+	
+	def _update_mtime(self):
+		self.last_mtime = self._get_mtime()
diff --git a/ranger/fm.py b/ranger/fm.py
index 43319836..b661efcc 100644
--- a/ranger/fm.py
+++ b/ranger/fm.py
@@ -1,5 +1,6 @@
 from ranger.actions import Actions
 from ranger.container import Bookmarks
+from ranger.ext.relpath import relpath_conf
 from ranger import __version__
 
 CTRL_C = 3
@@ -18,14 +19,17 @@ class FM(Actions):
 
 	def initialize(self):
 		"""If ui/bookmarks are None, they will be initialized here."""
+		from ranger.fsobject.directory import Directory
 
 		if self.bookmarks is None:
-			self.bookmarks = Bookmarks()
+			self.bookmarks = Bookmarks(
+					bookmarkfile=relpath_conf('bookmarks'),
+					bookmarktype=Directory,
+					autosave=False)
 			self.bookmarks.load()
 
 		else:
 			self.bookmarks = bookmarks
-		self.bookmarks.enter_dir_function = self.enter_dir
 
 		if self.ui is None:
 			from ranger.gui.defaultui import DefaultUI
@@ -37,25 +41,30 @@ class FM(Actions):
 1. reloading bookmarks if outdated
 2. drawing and finalizing ui
 3. reading and handling user input
-4. after X loops: collecting unused directory objects"""
+4. after X loops: collecting unused directory objects
+"""
 
 		self.env.enter_dir(self.env.path)
 
 		gc_tick = 0
 
-		while True:
-			try:
-				self.bookmarks.reload_if_outdated()
-				self.ui.draw()
-				self.ui.finalize()
+		try:
+			while True:
+				try:
+					self.bookmarks.update_if_outdated()
+					self.ui.draw()
+					self.ui.finalize()
 
-				key = self.ui.get_next_key()
-				self.ui.handle_key(key)
+					key = self.ui.get_next_key()
+					self.ui.handle_key(key)
 
-				gc_tick += 1
-				if gc_tick > TICKS_BEFORE_COLLECTING_GARBAGE:
-					gc_tick = 0
-					self.env.garbage_collect()
+					gc_tick += 1
+					if gc_tick > TICKS_BEFORE_COLLECTING_GARBAGE:
+						gc_tick = 0
+						self.env.garbage_collect()
 
-			except KeyboardInterrupt:
-				self.ui.handle_key(CTRL_C)
+				except KeyboardInterrupt:
+					self.ui.handle_key(CTRL_C)
+		finally:
+			self.bookmarks.remember(self.env.pwd)
+			self.bookmarks.save()