diff options
-rw-r--r-- | ranger/actions.py | 8 | ||||
-rw-r--r-- | ranger/container/bookmarks.py | 186 | ||||
-rw-r--r-- | ranger/fm.py | 41 |
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() |