summary refs log tree commit diff stats
path: root/ranger/applications.py
diff options
context:
space:
mode:
Diffstat (limited to 'ranger/applications.py')
-rw-r--r--ranger/applications.py102
1 files changed, 90 insertions, 12 deletions
diff --git a/ranger/applications.py b/ranger/applications.py
index 499e8b2c..a3e3aeea 100644
--- a/ranger/applications.py
+++ b/ranger/applications.py
@@ -1,12 +1,3 @@
-"""
-List of allowed flags:
-s: silent mode. output will be discarded.
-d: detach the process.
-p: redirect output to the pager
-
-An uppercase key ensures that a certain flag will not be used.
-"""
-
 import os, sys
 from ranger.ext.waitpid_no_intr import waitpid_no_intr
 from subprocess import Popen, PIPE
@@ -16,6 +7,39 @@ devnull = open(os.devnull, 'a')
 ALLOWED_FLAGS = 'sdpSDP'
 
 class Applications(object):
+	"""
+	This class contains definitions on how to run programs.
+
+	The user can decide what program to run, and if he uses eg. 'vim', the
+	function app_vim() will be called.  However, usually the user
+	simply wants to "start" the file without specific instructions.
+	In such a case, app_default() is called, where you should examine
+	the context and decide which program to use.
+
+	All app functions have a name starting with app_ and return a string
+	containing the whole command or a tuple containing a list of the
+	arguments.
+	It has one argument, which is the AppContext instance.
+
+	You should define app_default, app_pager and app_editor since
+	internal functions depend on those.  Here are sample implementations:
+
+	def app_default(self, context):
+		if context.file.media:
+			if context.file.video:
+				# detach videos from the filemanager
+				context.flags += 'd'
+			return self.app_mplayer(context)
+		else:
+			return self.app_editor(context)
+	
+	def app_pager(self, context):
+		return ('less', ) + tuple(context)
+
+	def app_editor(self, context):
+		return ('vim', ) + tuple(context)
+	"""
+
 	def get(self, app):
 		"""Looks for an application, returns app_default if it doesn't exist"""
 		try:
@@ -32,10 +56,48 @@ class Applications(object):
 		methods = self.__class__.__dict__
 		return [meth[4:] for meth in methods if meth.startswith('app_')]
 
+
 class AppContext(object):
+	"""
+	An AppContext object abstracts the spawning of processes.
+
+	At initialization of the object you can define many high-level options.
+	When you call the run() function, those options are evaluated and
+	translated into Popen() calls.
+
+	An instances of this class is passed as the only argument to
+	app_xyz calls of the Applications object.
+	
+	Attributes:
+	action -- a string with a command or a list of arguments for
+		the Popen call.
+	app -- the name of the app function. ("vim" for app_vim.)
+		app is used to get an action if the user didn't specify one.
+	mode -- a number, mainly used in determining the action in app_xyz()
+	flags -- a string with flags which change the way programs are run
+	files -- a list containing files, mainly used in app_xyz
+	file -- an arbitrary file from that list (or None)
+	fm -- the filemanager instance
+	wait -- boolean, wait for the end or execute programs in parallel?
+	stdout -- directly passed to Popen
+	stderr -- directly passed to Popen
+	stdin -- directly passed to Popen
+	shell -- directly passed to Popen. Should the string be shell-interpreted?
+
+	List of allowed flags:
+	s: silent mode. output will be discarded.
+	d: detach the process.
+	p: redirect output to the pager
+
+	An uppercase key ensures that a certain flag will not be used.
+	"""
+
 	def __init__(self, app='default', files=None, mode=0, flags='', fm=None,
 			stdout=None, stderr=None, stdin=None, shell=None,
 			wait=True, action=None):
+		"""
+		The necessary parameters are fm and action or app.
+		"""
 
 		if files is None:
 			self.files = []
@@ -62,21 +124,21 @@ class AppContext(object):
 		else:
 			self.shell = shell
 	
-	def __getitem__(self, key):
-		return self.files[key]
-	
 	def __iter__(self):
+		"""Iterates over all file paths"""
 		if self.files:
 			for f in self.files:
 				yield f.path
 	
 	def squash_flags(self):
+		"""Remove duplicates and lowercase counterparts of uppercase flags"""
 		for flag in self.flags:
 			if ord(flag) <= 90:
 				bad = flag + flag.lower()
 				self.flags = ''.join(c for c in self.flags if c not in bad)
 
 	def get_action(self, apps=None):
+		"""Get the action from app_xyz"""		
 		if apps is None and self.fm:
 			apps = self.fm.apps
 
@@ -88,6 +150,11 @@ class AppContext(object):
 		self.shell = isinstance(self.action, str)
 	
 	def run(self):
+		"""
+		Run the application in the way specified by the options.
+
+		This function ensures that there is an action.
+		"""
 		self.squash_flags()
 		if self.action is None:
 			self.get_action()
@@ -99,6 +166,9 @@ class AppContext(object):
 		kw['stderr'] = sys.stderr
 		kw['args'] = self.action
 
+		if kw['args'] is None:
+			return None
+
 		for word in ('shell', 'stdout', 'stdin', 'stderr'):
 			if getattr(self, word) is not None:
 				kw[word] = getattr(self, word)
@@ -135,8 +205,16 @@ class AppContext(object):
 				self.fm.ui.suspend()
 
 def run(action=None, **kw):
+	"""Shortcut for creating and immediately running an AppContext."""
 	app = AppContext(action=action, **kw)
 	return app.run()
 
 def tup(*args):
+	"""
+	This helper function creates a tuple out of the arguments.
+
+	('a', ) + tuple(some_iterator)
+	is equivalent to:
+	tup('a', *some_iterator)
+	"""
 	return tuple(args)
id='n343' href='#n343'>343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478