about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorhut <hut@lavabit.com>2010-01-23 01:47:15 +0100
committerhut <hut@lavabit.com>2010-01-23 01:47:15 +0100
commitd46a05a856c417140e3fc2a9481fc67d6c8a66ba (patch)
tree39a02dac0cc5140c26264f07bec777c7b9cc9ad0
parent2dc35a085a285a274a960c8a029d4e7bc8026aee (diff)
downloadranger-d46a05a856c417140e3fc2a9481fc67d6c8a66ba.tar.gz
apps: more intelligent application choosing
ranger can now check whether an application is installed
on the system and choose the best available application out of
a list. ("either" method)
-rw-r--r--ranger/applications.py37
-rw-r--r--ranger/defaults/apps.py33
-rw-r--r--ranger/fm.py9
3 files changed, 73 insertions, 6 deletions
diff --git a/ranger/applications.py b/ranger/applications.py
index 5f267a42..e5a5fc4e 100644
--- a/ranger/applications.py
+++ b/ranger/applications.py
@@ -19,12 +19,14 @@ This module faciliates starting of new processes.
 import os, sys
 from ranger.ext.waitpid_no_intr import waitpid_no_intr
 from subprocess import Popen, PIPE
+from ranger.ext.iter_tools import flatten
+from ranger.shared import FileManagerAware
 
 devnull = open(os.devnull, 'a')
 
 ALLOWED_FLAGS = 'sdpSDP'
 
-class Applications(object):
+class Applications(FileManagerAware):
 	"""
 	This class contains definitions on how to run programs and should
 	be extended in ranger.defaults.apps
@@ -59,6 +61,30 @@ class Applications(object):
 		return ('vim', ) + tuple(context)
 	"""
 
+	def _meets_dependencies(self, fnc):
+		try:
+			deps = fnc.dependencies
+		except AttributeError:
+			return True
+
+		for dep in deps:
+			if hasattr(dep, 'dependencies') \
+			and not self._meets_dependencies(dep):
+				return False
+			if dep not in self.fm.executables:
+				return False
+
+		return True
+
+	def either(self, context, *args):
+		for app in args:
+			try:
+				application_handler = getattr(self, 'app_' + app)
+			except AttributeError:
+				continue
+			if self._meets_dependencies(application_handler):
+				return application_handler(context)
+
 	def app_self(self, context):
 		"""Run the file itself"""
 		return "./" + context.file.basename
@@ -268,4 +294,11 @@ def tup(*args):
 	is equivalent to:
 	tup('a', *some_iterator)
 	"""
-	return tuple(args)
+	return args
+
+def depends_on(*args):
+	args = tuple(flatten(args))
+	def decorator(fnc):
+		fnc.dependencies = args
+		return fnc
+	return decorator
diff --git a/ranger/defaults/apps.py b/ranger/defaults/apps.py
index 5117a027..5c4174ab 100644
--- a/ranger/defaults/apps.py
+++ b/ranger/defaults/apps.py
@@ -12,6 +12,7 @@
 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
+import os
 from re import compile, VERBOSE
 from ranger.applications import *
 
@@ -27,7 +28,7 @@ class CustomApplications(Applications):
 
 		if f.extension is not None:
 			if f.extension in ('pdf'):
-				return self.app_apvlv(c)
+				return self.either(c, 'evince', 'apvlv')
 			if f.extension in ('swc', 'smc'):
 				return self.app_zsnes(c)
 
@@ -41,7 +42,7 @@ class CustomApplications(Applications):
 		if f.video or f.audio:
 			if f.video:
 				c.flags += 'd'
-			return self.app_mplayer(c)
+			return self.either(c, 'mplayer', 'totem')
 		
 		if f.image:
 			return self.app_feh(c)
@@ -53,22 +54,35 @@ class CustomApplications(Applications):
 	def app_pager(self, c):
 		return tup('less', *c)
 
+	@depends_on('vim')
 	def app_vim(self, c):
 		return tup('vim', *c)
 
-	app_editor = app_vim
+	def app_editor(self, c):
+		default_editor = os.environ['EDITOR']
+		parts = default_editor.split()
+		exe_name = os.path.basename(parts[0])
+		log(exe_name)
 
+		if exe_name in self.fm.executables:
+			return tuple(parts) + tuple(c)
+
+		else:
+			return self.either(c, 'vim', 'emacs', 'nano')
+
+	@depends_on(app_editor, Applications.app_self)
 	def app_edit_or_run(self, c):
 		if c.mode is 1:
 			return self.app_self(c)
 		return self.app_editor(c)
 
+	@depends_on('mplayer')
 	def app_mplayer(self, c):
 		if c.mode is 1:
 			return tup('mplayer', *c)
 
 		elif c.mode is 2:
-			args = "mplayer -fs -sid 0 -vfm ffmpeg -lavdopts" \
+			args = "mplayer -fs -sid 0 -vfm ffmpeg -lavdopts " \
 					"lowres=1:fast:skiploopfilter=all:threads=8".split()
 			args.extend(c)
 			return tup(*args)
@@ -79,6 +93,7 @@ class CustomApplications(Applications):
 		else:
 			return tup('mplayer', '-fs', *c)
 
+	@depends_on('feh')
 	def app_feh(self, c):
 		arg = {1: '--bg-scale', 2: '--bg-tile', 3: '--bg-center'}
 
@@ -90,16 +105,19 @@ class CustomApplications(Applications):
 			return tup('gimp', *c)
 		return tup('feh', *c)
 
+	@depends_on('aunpack')
 	def app_aunpack(self, c):
 		if c.mode is 0:
 			c.flags += 'p'
 			return tup('aunpack', '-l', c.file.path)
 		return tup('aunpack', c.file.path)
 	
+	@depends_on('apvlv')
 	def app_apvlv(self, c):
 		c.flags += 'd'
 		return tup('apvlv', *c)
 
+	@depends_on('make')
 	def app_make(self, c):
 		if c.mode is 0:
 			return tup("make")
@@ -108,12 +126,15 @@ class CustomApplications(Applications):
 		if c.mode is 2:
 			return tup("make", "clear")
 	
+	@depends_on('firefox')
 	def app_firefox(self, c):
 		return tup("firefox")
 
+	@depends_on('javac')
 	def app_javac(self, c):
 		return tup("javac", *c)
 	
+	@depends_on('java')
 	def app_java(self, c):
 		def strip_extensions(file):
 			if '.' in file.basename:
@@ -122,15 +143,19 @@ class CustomApplications(Applications):
 		files_without_extensions = map(strip_extensions, c.files)
 		return tup("java", files_without_extensions)
 	
+	@depends_on('zsnes')
 	def app_zsnes(self, c):
 		return tup("zsnes", c.file)
 	
+	@depends_on('evince')
 	def app_evince(self, c):
 		return tup("evince", *c)
 	
+	@depends_on('wine')
 	def app_wine(self, c):
 		return tup("wine", c.file)
 
+	@depends_on('totem')
 	def app_totem(self, c):
 		if c.mode is 0:
 			return tup("totem", "--fullscreen", *c)
diff --git a/ranger/fm.py b/ranger/fm.py
index 3471dcd4..7993a207 100644
--- a/ranger/fm.py
+++ b/ranger/fm.py
@@ -18,6 +18,7 @@ from collections import deque
 from ranger.actions import Actions
 from ranger.container import Bookmarks
 from ranger.ext.relpath import relpath_conf
+from ranger.ext.get_executables import get_executables
 from ranger import __version__
 from ranger.fsobject import Loader
 
@@ -36,11 +37,19 @@ class FM(Actions):
 		self.bookmarks = bookmarks
 		self.tags = tags
 		self.loader = Loader()
+		self._executables = None
 		self.apps = self.settings.apps.CustomApplications()
 
 		from ranger.shared import FileManagerAware
 		FileManagerAware.fm = self
 
+	def get_executables(self):
+		if self._executables is None:
+			self._executables = get_executables()
+		return self._executables
+
+	executables = property(get_executables)
+
 	def initialize(self):
 		"""If ui/bookmarks are None, they will be initialized here."""
 		from ranger.fsobject.directory import Directory
b9dcafcb52bbdcd92aed0c'>^
c9383c72 ^


f07bb12f ^
















































c9383c72 ^










f07bb12f ^




c9383c72 ^
f07bb12f ^
c9383c72 ^


f07bb12f ^




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221