diff options
author | hut <hut@lavabit.com> | 2009-12-22 15:53:15 +0100 |
---|---|---|
committer | hut <hut@lavabit.com> | 2009-12-22 15:53:15 +0100 |
commit | fa704babe536ebd6409a939cfb684d5ac281de8a (patch) | |
tree | c119b7312afcfd858da0f512c2396db3825cf321 | |
parent | 2b82ef62212c9a8d8702523c2720eb10b6b2bb28 (diff) | |
download | ranger-fa704babe536ebd6409a939cfb684d5ac281de8a.tar.gz |
(half-assed) implementation of parallel directory loader
-rw-r--r-- | ranger/actions.py | 14 | ||||
-rw-r--r-- | ranger/fm.py | 4 | ||||
-rw-r--r-- | ranger/fsobject/__init__.py | 7 | ||||
-rw-r--r-- | ranger/fsobject/directory.py | 101 | ||||
-rw-r--r-- | ranger/fsobject/loader.py | 61 | ||||
-rw-r--r-- | ranger/gui/ui.py | 15 | ||||
-rw-r--r-- | ranger/gui/widgets/filelist.py | 36 |
7 files changed, 165 insertions, 73 deletions
diff --git a/ranger/actions.py b/ranger/actions.py index e699053c..d51b2119 100644 --- a/ranger/actions.py +++ b/ranger/actions.py @@ -139,16 +139,10 @@ class Actions(EnvironmentAware, SettingsAware): if isinstance(self.env.settings[string], bool): self.env.settings[string] ^= True - def force_load_preview(self, obj=None): - if not obj: - obj = self.env.cf - - if isinstance(obj, fsobject.Directory): - if not obj.force_load: - obj.force_load = True - else: - obj.load_content() - + def force_load_preview(self): + cf = self.env.cf + if cf is not None: + cf.force_load = True # ------------------------------------ filesystem operations diff --git a/ranger/fm.py b/ranger/fm.py index db09129c..59568e68 100644 --- a/ranger/fm.py +++ b/ranger/fm.py @@ -4,6 +4,7 @@ from ranger.actions import Actions from ranger.container import Bookmarks from ranger.ext.relpath import relpath_conf from ranger import __version__ +from ranger.fsobject import Loader CTRL_C = 3 TICKS_BEFORE_COLLECTING_GARBAGE = 100 @@ -16,6 +17,7 @@ class FM(Actions): Actions.__init__(self) self.ui = ui self.bookmarks = bookmarks + self.loader = Loader() self.apps = self.settings.apps.CustomApplications() from ranger.shared import FileManagerAware @@ -61,6 +63,8 @@ class FM(Actions): try: self.bookmarks.update_if_outdated() self.ui.redraw() + self.loader.work() + self.ui.set_load_mode(self.loader) key = self.ui.get_next_key() diff --git a/ranger/fsobject/__init__.py b/ranger/fsobject/__init__.py index ce765e1e..79645c5e 100644 --- a/ranger/fsobject/__init__.py +++ b/ranger/fsobject/__init__.py @@ -11,6 +11,7 @@ BAD_INFO = None class NotLoadedYet(Exception): pass -from ranger.fsobject.file import File -from ranger.fsobject.directory import Directory, NoDirectoryGiven -from ranger.fsobject.fsobject import FileSystemObject +from .file import File +from .directory import Directory, NoDirectoryGiven +from .fsobject import FileSystemObject +from .loader import Loader diff --git a/ranger/fsobject/directory.py b/ranger/fsobject/directory.py index fea7be34..2478616d 100644 --- a/ranger/fsobject/directory.py +++ b/ranger/fsobject/directory.py @@ -18,6 +18,7 @@ class NoDirectoryGiven(Exception): class Directory(SuperClass, SettingsAware): scheduled = False enterable = False + loading = False filenames = None files = None @@ -41,8 +42,9 @@ class Directory(SuperClass, SettingsAware): # to find out if something has changed: self.old_show_hidden = self.settings.show_hidden self.old_directories_first = self.settings.directories_first - - def load_content(self): + self.load_progress = None + + def load_bit_by_bit(self): """Loads the contents of the directory. Use this sparingly since it takes rather long. """ @@ -50,43 +52,58 @@ class Directory(SuperClass, SettingsAware): from os import listdir self.load_if_outdated() + yield + + if self.exists and self.runnable: + filenames = [] + for fname in listdir(self.path): + if not self.settings.show_hidden and fname[0] == '.': + continue + if isinstance(self.filter, str) and self.filter in fname: + continue + filenames.append(join(self.path, fname)) + self.scroll_offset = 0 + self.filenames = filenames + self.infostring = ' %d' % len(self.filenames) # update the infostring + yield + + files = [] + for name in self.filenames: + if isdir(name): + f = Directory(name) + else: + f = File(name) + f.load() + files.append(f) + yield + + self.files = files + self.old_directories_first = None + + if len(self.files) > 0: + if self.pointed_file is not None: + self.move_pointer_to_file_path(self.pointed_file) + else: + self.filenames = None + self.files = None + self.infostring = BAD_INFO + + self.content_loaded = True + self.loading = False + yield + + def load_content(self, schedule=False): + """Loads the contents of the directory. Use this sparingly since + it takes rather long. + """ - try: - self.stopped = False - if self.exists and self.runnable: - filenames = [] - for fname in listdir(self.path): - if not self.settings.show_hidden and fname[0] == '.': - continue - if isinstance(self.filter, str) and self.filter in fname: - continue - filenames.append(join(self.path, fname)) - self.scroll_offset = 0 - self.filenames = filenames - self.infostring = ' %d' % len(self.filenames) # update the infostring - files = [] - for name in self.filenames: - if isdir(name): - f = Directory(name) - else: - f = File(name) - f.load() - files.append(f) - - self.files = files - self.old_directories_first = None - - if len(self.files) > 0: - if self.pointed_file is not None: - self.move_pointer_to_file_path(self.pointed_file) + if not self.loading: + if schedule and self.fm: + self.loading = True + self.fm.loader.add(self) else: - self.filenames = None - self.files = None - self.infostring = BAD_INFO - self.content_loaded = True - except (KeyboardInterrupt, ValueError): - self.stopped = True - + for _ in self.load_bit_by_bit(): + pass def sort(self): """Sort the containing files""" @@ -192,22 +209,22 @@ class Directory(SuperClass, SettingsAware): self.pointed_index = i self.pointed_file = self[i] - def load_content_once(self): + def load_content_once(self, *a, **k): """Load the contents of the directory if not done yet""" if not self.content_loaded: - self.load_content() + self.load_content(*a, **k) return True return False - def load_content_if_outdated(self): + def load_content_if_outdated(self, *a, **k): """Load the contents of the directory if it's outdated or not done yet """ - if self.load_content_once(): return True + if self.load_content_once(*a, **k): return True if self.old_show_hidden != self.settings.show_hidden: self.old_show_hidden = self.settings.show_hidden - self.load_content() + self.load_content(*a, **k) return True import os diff --git a/ranger/fsobject/loader.py b/ranger/fsobject/loader.py new file mode 100644 index 00000000..a1ebcc97 --- /dev/null +++ b/ranger/fsobject/loader.py @@ -0,0 +1,61 @@ +from collections import deque +from time import time +from ranger import log +import math + +def status_generator(): + while True: + yield '/' + yield '-' + yield '\\' + yield '|' + +def delayfunc(n): + if n < 4: + return 0.05 + else: + return math.log(n-2) * 0.2 + +class Loader(object): + seconds_of_work_time = 0.1 + def __init__(self): + self.queue = deque() + self.item = None + self.load_generator = None + self.status_generator = status_generator() + self.tick = 0 + self.rotate() + + def rotate(self): + self.status = next(self.status_generator) + + def add(self, obj): + self.queue.append(obj) + + def work(self): + if self.item is None: + try: + self.item = self.queue.popleft() + except IndexError: + return + + self.load_generator = self.item.load_bit_by_bit() + self.tick = 0 + + self.rotate() + self.tick += 1 + start_time = time() + end_time = time() + delayfunc(self.tick) + + log(tuple(map(str, self.queue))) + try: +# log("loading " + self.item.basename) + while time() < end_time: + next(self.load_generator) + + except StopIteration: + self.item = None + self.load_generator = None + + def __nonzero__(self): + return bool(self.queue or self.item is not None) diff --git a/ranger/gui/ui.py b/ranger/gui/ui.py index 2cb66f2f..e55b9ba9 100644 --- a/ranger/gui/ui.py +++ b/ranger/gui/ui.py @@ -7,6 +7,7 @@ from ranger.container import CommandList class UI(DisplayableContainer): is_set_up = False mousemask = curses.ALL_MOUSE_EVENTS | curses.REPORT_MOUSE_POSITION + load_mode = False def __init__(self, commandlist=None, env=None, fm=None): import os os.environ['ESCDELAY'] = '25' # don't know a cleaner way @@ -29,6 +30,7 @@ class UI(DisplayableContainer): """initialize curses, then call setup (at the first time) and resize.""" self.win.leaveok(0) self.win.keypad(1) + self.load_mode = False curses.cbreak() curses.noecho() @@ -64,6 +66,19 @@ class UI(DisplayableContainer): curses.mousemask(0) curses.endwin() + def set_load_mode(self, boolean): + from ranger import log + boolean = bool(boolean) + if boolean != self.load_mode: + self.load_mode = boolean + + if boolean: + log('setting halfdelay to 1') + curses.halfdelay(1) + else: + log('setting halfdelay to 20') + curses.halfdelay(20) + def destroy(self): """Destroy all widgets and turn off curses""" DisplayableContainer.destroy(self) diff --git a/ranger/gui/widgets/filelist.py b/ranger/gui/widgets/filelist.py index 58dcd856..b4c756f1 100644 --- a/ranger/gui/widgets/filelist.py +++ b/ranger/gui/widgets/filelist.py @@ -71,12 +71,10 @@ class FileList(Widget): self.draw_file() elif type(self.target) == Directory: self.draw_directory() -# else: -# self.win.addnstr(self.y, self.x, "unknown type.", self.wid) def finalize(self): if self.postpone_drawing: - self.target.load_content_if_outdated() + self.target.load_content_if_outdated(schedule=True) self.draw_directory() self.postpone_drawing = False @@ -111,21 +109,23 @@ class FileList(Widget): self.target.use() if not self.target.content_loaded: - if self.target.force_load: - self.target.stopped = False - - else: - if not self.target.stopped: - maxdirsize = self.settings.max_dirsize_for_autopreview - if maxdirsize is not None and self.target.accessible \ - and self.target.size > maxdirsize: - self.target.stopped = True - - if self.target.stopped: - self.color(base_color, 'error') - self.win.addnstr(self.y, self.x, "no preview", self.wid) - self.color_reset() - return +# if self.target.force_load: +# self.target.stopped = False +# +# else: +# if not self.target.stopped: +# +# if maxdirsize is not None and self.target.accessible \ +# and self.target.size > maxdirsize: +# self.target.stopped = True +# + maxdirsize = self.settings.max_dirsize_for_autopreview + if not self.target.force_load and maxdirsize is not None \ + and self.target.size > maxdirsize: + self.color(base_color, 'error') + self.win.addnstr(self.y, self.x, "no preview", self.wid) + self.color_reset() + return if self.settings.auto_load_preview: self.color(base_color) |