about summary refs log tree commit diff stats
path: root/ranger/core
diff options
context:
space:
mode:
authorhut <hut@lavabit.com>2010-10-02 05:51:17 +0200
committerhut <hut@lavabit.com>2010-10-02 05:51:17 +0200
commita457053815d72ef5d7ccfedbfda02101665bdec6 (patch)
tree5ea00e015b6488f0874c626e61bc64c62e514b9c /ranger/core
parentba16a2e43a71f3ee1a66ffaf1613bb1cce1665fc (diff)
downloadranger-a457053815d72ef5d7ccfedbfda02101665bdec6.tar.gz
a little restructuration
Diffstat (limited to 'ranger/core')
-rw-r--r--ranger/core/actions.py3
-rw-r--r--ranger/core/environment.py2
-rw-r--r--ranger/core/fm.py21
-rw-r--r--ranger/core/helper.py167
-rw-r--r--ranger/core/loader.py2
-rw-r--r--ranger/core/main.py98
-rw-r--r--ranger/core/shared.py73
7 files changed, 360 insertions, 6 deletions
diff --git a/ranger/core/actions.py b/ranger/core/actions.py
index a19927a4..59902bab 100644
--- a/ranger/core/actions.py
+++ b/ranger/core/actions.py
@@ -26,7 +26,8 @@ from ranger.ext.direction import Direction
 from ranger.ext.relative_symlink import relative_symlink
 from ranger.ext.shell_escape import shell_quote
 from ranger import fsobject
-from ranger.shared import FileManagerAware, EnvironmentAware, SettingsAware
+from ranger.core.shared import FileManagerAware, EnvironmentAware, \
+		SettingsAware
 from ranger.fsobject import File
 from ranger.ext import shutil_generatorized as shutil_g
 from ranger.core.loader import LoadableObject
diff --git a/ranger/core/environment.py b/ranger/core/environment.py
index 8d4c60df..655054d7 100644
--- a/ranger/core/environment.py
+++ b/ranger/core/environment.py
@@ -22,7 +22,7 @@ from os.path import abspath, normpath, join, expanduser, isdir
 from ranger.fsobject import Directory
 from ranger.container import KeyBuffer, KeyManager, History
 from ranger.ext.signal_dispatcher import SignalDispatcher
-from ranger.shared import SettingsAware
+from ranger.core.shared import SettingsAware
 
 ALLOWED_CONTEXTS = ('browser', 'pager', 'embedded_pager', 'taskview',
 		'console')
diff --git a/ranger/core/fm.py b/ranger/core/fm.py
index 05b3e52b..7f655aa6 100644
--- a/ranger/core/fm.py
+++ b/ranger/core/fm.py
@@ -19,6 +19,7 @@ The File Manager, putting the pieces together
 
 from time import time
 from collections import deque
+import mimetypes
 import os
 import sys
 
@@ -28,7 +29,6 @@ from ranger.container.tags import Tags
 from ranger.gui.defaultui import DefaultUI
 from ranger.container import Bookmarks
 from ranger.core.runner import Runner
-from ranger import relpath_conf
 from ranger.ext.get_executables import get_executables
 from ranger.fsobject import Directory
 from ranger.ext.signal_dispatcher import SignalDispatcher
@@ -69,7 +69,7 @@ class FM(Actions, SignalDispatcher):
 			if ranger.arg.clean:
 				bookmarkfile = None
 			else:
-				bookmarkfile = relpath_conf('bookmarks')
+				bookmarkfile = self.confpath('bookmarks')
 			self.bookmarks = Bookmarks(
 					bookmarkfile=bookmarkfile,
 					bookmarktype=Directory,
@@ -80,7 +80,7 @@ class FM(Actions, SignalDispatcher):
 			self.bookmarks = bookmarks
 
 		if not ranger.arg.clean and self.tags is None:
-			self.tags = Tags(relpath_conf('tagged'))
+			self.tags = Tags(self.confpath('tagged'))
 
 		if self.ui is None:
 			self.ui = DefaultUI()
@@ -93,6 +93,10 @@ class FM(Actions, SignalDispatcher):
 
 		self.env.signal_bind('cd', self._update_current_tab)
 
+		mimetypes.knownfiles.append(os.path.expanduser('~/.mime.types'))
+		mimetypes.knownfiles.append(self.relpath('data/mime.types'))
+		self.mimetypes = mimetypes.MimeTypes()
+
 	def block_input(self, sec=0):
 		self.input_blocked = sec != 0
 		self.input_blocked_until = time() + sec
@@ -102,6 +106,17 @@ class FM(Actions, SignalDispatcher):
 			self.input_blocked = False
 		return self.input_blocked
 
+	def confpath(self, *paths):
+		"""returns the path relative to rangers configuration directory"""
+		if ranger.arg.clean:
+			assert 0, "Should not access relpath_conf in clean mode!"
+		else:
+			return os.path.join(ranger.arg.confdir, *paths)
+
+	def relpath(self, *paths):
+		"""returns the path relative to rangers library directory"""
+		return os.path.join(ranger.RANGERDIR, *paths)
+
 	def loop(self):
 		"""
 		The main loop consists of:
diff --git a/ranger/core/helper.py b/ranger/core/helper.py
new file mode 100644
index 00000000..c7ac3702
--- /dev/null
+++ b/ranger/core/helper.py
@@ -0,0 +1,167 @@
+# Copyright (C) 2009, 2010  Roman Zimbelmann <romanz@lavabit.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""Helper functions"""
+
+import os.path
+import sys
+from ranger import *
+
+def parse_arguments():
+	"""Parse the program arguments"""
+	from optparse import OptionParser, SUPPRESS_HELP
+	from ranger import __version__, USAGE, DEFAULT_CONFDIR
+	from ranger.ext.openstruct import OpenStruct
+	from os.path import expanduser
+
+	minor_version = __version__[2:]  # assumes major version number is <10
+	if '.' in minor_version:
+		minor_version = minor_version[:minor_version.find('.')]
+	version_tag = ' (stable)' if int(minor_version) % 2 == 0 else ' (testing)'
+	if __version__.endswith('.0'):
+		version_string = 'ranger ' + __version__[:-2] + version_tag
+	else:
+		version_string = 'ranger ' + __version__ + version_tag
+
+	parser = OptionParser(usage=USAGE, version=version_string)
+
+	parser.add_option('-d', '--debug', action='store_true',
+			help="activate debug mode")
+	parser.add_option('-c', '--clean', action='store_true',
+			help="don't touch/require any config files. ")
+	parser.add_option('--fail-if-run', action='store_true', # COMPAT
+			help=SUPPRESS_HELP)
+	parser.add_option('--fail-unless-cd', action='store_true',
+			help="experimental: return the exit code 1 if ranger is" \
+					"used to run a file (with `ranger filename`)")
+	parser.add_option('-r', '--confdir', type='string',
+			metavar='dir', default=DEFAULT_CONFDIR,
+			help="the configuration directory. (%default)")
+	parser.add_option('-m', '--mode', type='int', default=0, metavar='n',
+			help="if a filename is supplied, run it with this mode")
+	parser.add_option('-f', '--flags', type='string', default='',
+			metavar='string',
+			help="if a filename is supplied, run it with these flags.")
+
+	options, positional = parser.parse_args()
+	arg = OpenStruct(options.__dict__, targets=positional)
+	arg.confdir = expanduser(arg.confdir)
+	if arg.fail_if_run:
+		arg.fail_unless_cd = arg.fail_if_run
+		del arg['fail_if_run']
+
+	return arg
+
+
+def load_settings(fm, clean):
+	import ranger.core.shared
+	import ranger.api.commands
+	import ranger.api.keys
+	if not clean:
+		allow_access_to_confdir(ranger.arg.confdir, True)
+
+		# Load commands
+		comcont = ranger.api.commands.CommandContainer()
+		ranger.api.commands.alias = comcont.alias
+		try:
+			import commands
+			comcont.load_commands_from_module(commands)
+		except ImportError:
+			pass
+		from ranger.defaults import commands
+		comcont.load_commands_from_module(commands)
+		commands = comcont
+
+		# Load apps
+		try:
+			import apps
+		except ImportError:
+			from ranger.defaults import apps
+
+		# Load keys
+		keymanager = ranger.core.shared.EnvironmentAware.env.keymanager
+		ranger.api.keys.keymanager = keymanager
+		from ranger.defaults import keys
+		try:
+			import keys
+		except ImportError:
+			pass
+		allow_access_to_confdir(ranger.arg.confdir, False)
+	else:
+		comcont = ranger.api.commands.CommandContainer()
+		ranger.api.commands.alias = comcont.alias
+		from ranger.api import keys
+		keymanager = ranger.core.shared.EnvironmentAware.env.keymanager
+		ranger.api.keys.keymanager = keymanager
+		from ranger.defaults import commands, keys, apps
+		comcont.load_commands_from_module(commands)
+		commands = comcont
+	fm.commands = commands
+	fm.keys = keys
+	fm.apps = apps.CustomApplications()
+
+
+def load_apps(fm, clean):
+	import ranger
+	if not clean:
+		allow_access_to_confdir(ranger.arg.confdir, True)
+		try:
+			import apps
+		except ImportError:
+			from ranger.defaults import apps
+		allow_access_to_confdir(ranger.arg.confdir, False)
+	else:
+		from ranger.defaults import apps
+	fm.apps = apps.CustomApplications()
+
+
+def allow_access_to_confdir(confdir, allow):
+	if allow:
+		try:
+			os.makedirs(confdir)
+		except OSError as err:
+			if err.errno != 17:  # 17 means it already exists
+				print("This configuration directory could not be created:")
+				print(confdir)
+				print("To run ranger without the need for configuration")
+				print("files, use the --clean option.")
+				raise SystemExit()
+		if not confdir in sys.path:
+			sys.path[0:0] = [confdir]
+	else:
+		if sys.path[0] == confdir:
+			del sys.path[0]
+
+
+# Debugging functions.  These will be activated when run with --debug.
+# Example usage in the code:
+# import ranger; ranger.log("hello world")
+def log(*objects, **keywords):
+	"""
+	Writes objects to a logfile (for the purpose of debugging only.)
+	Has the same arguments as print() in python3.
+	"""
+	if LOGFILE is None or not arg.debug or arg.clean: return
+	start = 'start' in keywords and keywords['start'] or 'ranger:'
+	sep   =   'sep' in keywords and keywords['sep']   or ' '
+	_file =  'file' in keywords and keywords['file']  or open(LOGFILE, 'a')
+	end   =   'end' in keywords and keywords['end']   or '\n'
+	_file.write(sep.join(map(str, (start, ) + objects)) + end)
+
+
+def log_traceback():
+	if LOGFILE is None or not arg.debug or arg.clean: return
+	import traceback
+	traceback.print_stack(file=open(LOGFILE, 'a'))
diff --git a/ranger/core/loader.py b/ranger/core/loader.py
index 4f4424e4..ae6436a1 100644
--- a/ranger/core/loader.py
+++ b/ranger/core/loader.py
@@ -15,7 +15,7 @@
 
 from collections import deque
 from time import time
-from ranger.shared import FileManagerAware
+from ranger.core.shared import FileManagerAware
 import math
 
 def status_generator():
diff --git a/ranger/core/main.py b/ranger/core/main.py
new file mode 100644
index 00000000..42118516
--- /dev/null
+++ b/ranger/core/main.py
@@ -0,0 +1,98 @@
+# Copyright (C) 2009, 2010  Roman Zimbelmann <romanz@lavabit.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""
+The main function responsible to initialize the FM object and stuff.
+"""
+
+from ranger.core.helper import *
+
+def main():
+	"""initialize objects and run the filemanager"""
+	import locale
+	import os.path
+	import ranger
+	from ranger.ext import curses_interrupt_handler
+	from ranger.core.runner import Runner
+	from ranger.core.fm import FM
+	from ranger.core.environment import Environment
+	from ranger.gui.defaultui import DefaultUI as UI
+	from ranger.fsobject import File
+	from ranger.core.shared import (EnvironmentAware, FileManagerAware,
+			SettingsAware)
+
+	try:
+		locale.setlocale(locale.LC_ALL, '')
+	except:
+		print("Warning: Unable to set locale.  Expect encoding problems.")
+
+	if not 'SHELL' in os.environ:
+		os.environ['SHELL'] = 'bash'
+
+	ranger.arg = arg = parse_arguments()
+	SettingsAware._setup(clean=arg.clean)
+
+	targets = arg.targets or ['.']
+	target = targets[0]
+	if arg.targets:
+		if target.startswith('file://'):
+			target = target[7:]
+		if not os.access(target, os.F_OK):
+			print("File or directory doesn't exist: %s" % target)
+			sys.exit(1)
+		elif os.path.isfile(target):
+			def print_function(string):
+				print(string)
+			runner = Runner(logfunc=print_function)
+			load_apps(runner, arg.clean)
+			runner(files=[File(target)], mode=arg.mode, flags=arg.flags)
+			sys.exit(1 if arg.fail_unless_cd else 0)
+
+	crash_traceback = None
+	try:
+		# Initialize objects
+		EnvironmentAware.env = Environment(target)
+		fm = FM()
+		fm.tabs = dict((n+1, os.path.abspath(path)) for n, path \
+				in enumerate(targets[:9]))
+		load_settings(fm, arg.clean)
+		if fm.env.username == 'root':
+			fm.settings.preview_files = False
+		FileManagerAware.fm = fm
+		fm.ui = UI()
+		if not arg.debug:
+			curses_interrupt_handler.install_interrupt_handler()
+
+		# Run the file manager
+		fm.initialize()
+		fm.ui.initialize()
+		fm.loop()
+	except Exception:
+		import traceback
+		crash_traceback = traceback.format_exc()
+	except SystemExit as error:
+		return error.args[0]
+	finally:
+		try:
+			fm.ui.destroy()
+		except (AttributeError, NameError):
+			pass
+		if crash_traceback:
+			print(crash_traceback)
+			print("Ranger crashed.  " \
+					"Please report this (including the traceback) at:")
+			print("http://savannah.nongnu.org/bugs/?group=ranger&func=additem")
+			return 1
+		return 0
diff --git a/ranger/core/shared.py b/ranger/core/shared.py
new file mode 100644
index 00000000..b91445a3
--- /dev/null
+++ b/ranger/core/shared.py
@@ -0,0 +1,73 @@
+# Copyright (C) 2009, 2010  Roman Zimbelmann <romanz@lavabit.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+"""Shared objects contain singleton variables which can be
+inherited, essentially acting like global variables."""
+
+from ranger.ext.lazy_property import lazy_property
+
+class Awareness(object):
+	pass
+
+class EnvironmentAware(Awareness):
+	# This creates an instance implicitly, mainly for unit tests
+	@lazy_property
+	def env(self):
+		from ranger.core.environment import Environment
+		return Environment(".")
+
+class FileManagerAware(Awareness):
+	# This creates an instance implicitly, mainly for unit tests
+	@lazy_property
+	def fm(self):
+		from ranger.core.fm import FM
+		return FM()
+
+class SettingsAware(Awareness):
+	# This creates an instance implicitly, mainly for unit tests
+	@lazy_property
+	def settings(self):
+		from ranger.ext.openstruct import OpenStruct
+		return OpenStruct()
+
+	@staticmethod
+	def _setup(clean=True):
+		from ranger.container.settingobject import SettingObject, \
+				ALLOWED_SETTINGS
+		import ranger
+		import sys
+		settings = SettingObject()
+
+		from ranger.gui.colorscheme import _colorscheme_name_to_class
+		settings.signal_bind('setopt.colorscheme',
+				_colorscheme_name_to_class, priority=1)
+
+		if not clean:
+			# add the custom options to the list of setting sources
+			sys.path[0:0] = [ranger.arg.confdir]
+			try:
+				import options as my_options
+			except ImportError:
+				pass
+			else:
+				settings._setting_sources.append(my_options)
+			del sys.path[0]
+
+		from ranger.defaults import options as default_options
+		settings._setting_sources.append(default_options)
+		assert all(hasattr(default_options, setting) \
+				for setting in ALLOWED_SETTINGS), \
+				"Ensure that all options are defined in the defaults!"
+		SettingsAware.settings = settings