summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--ranger/core/actions.py56
-rw-r--r--ranger/core/fm.py1
-rw-r--r--ranger/fsobject/file.py27
3 files changed, 58 insertions, 26 deletions
diff --git a/ranger/core/actions.py b/ranger/core/actions.py
index 59eef2be..d0ccfe2b 100644
--- a/ranger/core/actions.py
+++ b/ranger/core/actions.py
@@ -51,6 +51,7 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware):
 	def reset(self):
 		"""Reset the filemanager, clearing the directory buffer"""
 		old_path = self.env.cwd.path
+		self.previews = {}
 		self.env.garbage_collect(-1)
 		self.enter_dir(old_path)
 
@@ -572,6 +573,61 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware):
 		pager.set_source(self.env.cf.get_preview_source(pager.wid, pager.hei))
 
 	# --------------------------
+	# -- Previews
+	# --------------------------
+	def get_preview(self, path, width, height):
+		if self.settings.preview_script:
+			# self.previews is a 2 dimensional dict:
+			# self.previews['/tmp/foo.jpg'][(80, 24)] = "the content..."
+			# self.previews['/tmp/foo.jpg']['loading'] = False
+			# A -1 in tuples means "any"; (80, -1) = wid. of 80 and any hei.
+			try:
+				data = self.previews[path]
+			except:
+				data = self.previews[path] = {'loading': False}
+			else:
+				if data['loading']:
+					return None
+
+			found = data.get((-1, -1), data.get((width, -1),
+				data.get((-1, height), data.get((width, height), False))))
+			if found == False:
+				data['loading'] = True
+				loadable = CommandLoader(args=[self.settings.preview_script,
+					path, str(width), str(height)],
+					silent=True, descr="Getting preview of %s" % path)
+				def on_after(signal):
+					exit = signal.process.poll()
+					content = signal.process.stdout.read()
+					if exit == 0:
+						data[(width, height)] = content
+					elif exit == 3:
+						data[(-1, height)] = content
+					elif exit == 4:
+						data[(width, -1)] = content
+					elif exit == 5:
+						data[(-1, -1)] = content
+					else:
+						data[(-1, -1)] = None # XXX
+					if self.env.cf.path == path:
+						self.ui.browser.pager.need_redraw = True
+						self.ui.browser.need_redraw = True
+					data['loading'] = False
+				def on_destroy(signal):
+					try:
+						del self.previews[path]
+					except:
+						pass
+				loadable.signal_bind('after', on_after)
+				loadable.signal_bind('destroy', on_destroy)
+				self.loader.add(loadable)
+				return None
+			else:
+				return found
+		else:
+			return open(path, 'r')
+
+	# --------------------------
 	# -- Tabs
 	# --------------------------
 	# This implementation of tabs is very simple and keeps track of
diff --git a/ranger/core/fm.py b/ranger/core/fm.py
index 84fea956..bfcebb92 100644
--- a/ranger/core/fm.py
+++ b/ranger/core/fm.py
@@ -50,6 +50,7 @@ class FM(Actions, SignalDispatcher):
 		self.bookmarks = bookmarks
 		self.tags = tags
 		self.tabs = {}
+		self.previews = {}
 		self.current_tab = 1
 		self.loader = Loader()
 
diff --git a/ranger/fsobject/file.py b/ranger/fsobject/file.py
index d7e667a2..33b4e3d3 100644
--- a/ranger/fsobject/file.py
+++ b/ranger/fsobject/file.py
@@ -95,30 +95,5 @@ class File(FileSystemObject):
 			return False
 		return True
 
-	def _loader_after(self, signal):
-		self.preview_known = True
-		self.preview_data = None
-		if not signal.process.poll():
-			self.preview_data = signal.process.stdout.read()
-		if self.fm.env.cf.path == self.path:
-			self.fm.ui.browser.pager.need_redraw = True
-			self.fm.ui.browser.need_redraw = True
-
-	def _loader_destroy(self, signal):
-		self.preview_known = False
-		self.preview_loading = False
-		self.preview_data = None
-
 	def get_preview_source(self, width, height):
-		if self.fm.settings.preview_script:
-			if self.preview_known or self.preview_loading:
-				return self.preview_data
-			self.preview_loading = True
-			loadable = CommandLoader(args=[self.fm.settings.preview_script,
-				self.path, str(width), str(height)],
-				silent=True, descr="Getting preview of %s" % self.path)
-			loadable.signal_bind('after', self._loader_after, weak=True)
-			loadable.signal_bind('destroy', self._loader_destroy, weak=True)
-			self.fm.loader.add(loadable)
-			return None
-		return open(self.path, 'r')
+		return self.fm.get_preview(self.realpath, width, height)