core.main: made --fail-unless-cd deprecated
[ranger.git] / ranger / core / main.py
bloba082b8fb992d0deb4b60025a977b5117feef87a2
1 # Copyright (C) 2009, 2010, 2011 Roman Zimbelmann <romanz@lavabit.com>
2 # This software is distributed under the terms of the GNU GPL version 3.
4 """
5 The main function responsible to initialize the FM object and stuff.
6 """
8 import os.path
9 import sys
11 load_default_config = True
13 def main():
14 """initialize objects and run the filemanager"""
15 import locale
16 import ranger.api
17 from ranger.core.shared import FileManagerAware, SettingsAware
18 from ranger.core.fm import FM
20 if not sys.stdin.isatty():
21 sys.stderr.write("Error: Must run ranger from terminal\n")
22 raise SystemExit(1)
24 try:
25 locale.setlocale(locale.LC_ALL, '')
26 except:
27 print("Warning: Unable to set locale. Expect encoding problems.")
29 # so that programs can know that ranger spawned them:
30 level = 'RANGER_LEVEL'
31 if level in os.environ and os.environ[level].isdigit():
32 os.environ[level] = str(int(os.environ[level]) + 1)
33 else:
34 os.environ[level] = '1'
36 if not 'SHELL' in os.environ:
37 os.environ['SHELL'] = 'bash'
39 ranger.arg = arg = parse_arguments()
40 if arg.copy_config is not None:
41 fm = FM()
42 fm.copy_config_files(arg.copy_config)
43 return 1 if arg.fail_unless_cd else 0 # COMPAT
44 if arg.list_tagged_files:
45 fm = FM()
46 try:
47 f = open(fm.confpath('tagged'), 'r')
48 except:
49 pass
50 else:
51 for line in f.readlines():
52 if len(line) > 2 and line[1] == ':':
53 if line[0] in arg.list_tagged_files:
54 sys.stdout.write(line[2:])
55 elif len(line) > 0 and '*' in arg.list_tagged_files:
56 sys.stdout.write(line)
57 return 1 if arg.fail_unless_cd else 0 # COMPAT
59 SettingsAware._setup(clean=arg.clean)
61 if arg.selectfile:
62 arg.selectfile = os.path.abspath(arg.selectfile)
63 arg.targets.insert(0, os.path.dirname(arg.selectfile))
65 targets = arg.targets or ['.']
66 target = targets[0]
67 if arg.targets:
68 if target.startswith('file://'):
69 target = target[7:]
70 if not os.access(target, os.F_OK):
71 print("File or directory doesn't exist: %s" % target)
72 return 1
73 elif os.path.isfile(target):
74 def print_function(string):
75 print(string)
76 from ranger.ext.rifle import Rifle
77 fm = FM()
78 if not arg.clean and os.path.isfile(fm.confpath('rifle.conf')):
79 rifleconf = fm.confpath('rifle.conf')
80 else:
81 rifleconf = fm.relpath('config/rifle.conf')
82 rifle = Rifle(rifleconf)
83 rifle.reload_config()
84 rifle.execute(targets, number=ranger.arg.mode, flags=ranger.arg.flags)
85 return 1 if arg.fail_unless_cd else 0 # COMPAT
87 crash_traceback = None
88 try:
89 # Initialize objects
90 fm = FM(paths=targets)
91 FileManagerAware.fm = fm
92 load_settings(fm, arg.clean)
94 if arg.list_unused_keys:
95 from ranger.ext.keybinding_parser import (special_keys,
96 reversed_special_keys)
97 maps = fm.ui.keymaps['browser']
98 for key in sorted(special_keys.values(), key=lambda x: str(x)):
99 if key not in maps:
100 print("<%s>" % reversed_special_keys[key])
101 for key in range(33, 127):
102 if key not in maps:
103 print(chr(key))
104 return 1 if arg.fail_unless_cd else 0 # COMPAT
106 if fm.username == 'root':
107 fm.settings.preview_files = False
108 fm.settings.use_preview_script = False
109 if not arg.debug:
110 from ranger.ext import curses_interrupt_handler
111 curses_interrupt_handler.install_interrupt_handler()
113 # Run the file manager
114 fm.initialize()
115 ranger.api.hook_init(fm)
116 fm.ui.initialize()
118 if arg.selectfile:
119 fm.select_file(arg.selectfile)
121 if arg.cmd:
122 for command in arg.cmd:
123 fm.execute_console(command)
125 if ranger.arg.profile:
126 import cProfile
127 import pstats
128 profile = None
129 ranger.__fm = fm
130 cProfile.run('ranger.__fm.loop()', '/tmp/ranger_profile')
131 profile = pstats.Stats('/tmp/ranger_profile', stream=sys.stderr)
132 else:
133 fm.loop()
134 except Exception:
135 import traceback
136 crash_traceback = traceback.format_exc()
137 except SystemExit as error:
138 return error.args[0]
139 finally:
140 if crash_traceback:
141 try:
142 filepath = fm.thisfile.path if fm.thisfile else "None"
143 except:
144 filepath = "None"
145 try:
146 fm.ui.destroy()
147 except (AttributeError, NameError):
148 pass
149 if ranger.arg.profile and profile:
150 profile.strip_dirs().sort_stats('cumulative').print_callees()
151 if crash_traceback:
152 print("ranger version: %s, executed with python %s" %
153 (ranger.__version__, sys.version.split()[0]))
154 print("Locale: %s" % '.'.join(str(s) for s in locale.getlocale()))
155 try:
156 print("Current file: %s" % filepath)
157 except:
158 pass
159 print(crash_traceback)
160 print("ranger crashed. " \
161 "Please report this traceback at:")
162 print("http://savannah.nongnu.org/bugs/?group=ranger&func=additem")
163 return 1
164 return 0
167 def parse_arguments():
168 """Parse the program arguments"""
169 from optparse import OptionParser, SUPPRESS_HELP
170 from os.path import expanduser
171 from ranger import CONFDIR, USAGE, VERSION
172 from ranger.ext.openstruct import OpenStruct
174 if 'XDG_CONFIG_HOME' in os.environ and os.environ['XDG_CONFIG_HOME']:
175 default_confdir = os.environ['XDG_CONFIG_HOME'] + '/ranger'
176 else:
177 default_confdir = CONFDIR
179 parser = OptionParser(usage=USAGE, version=VERSION)
181 parser.add_option('-d', '--debug', action='store_true',
182 help="activate debug mode")
183 parser.add_option('-c', '--clean', action='store_true',
184 help="don't touch/require any config files. ")
185 parser.add_option('--copy-config', type='string', metavar='which',
186 help="copy the default configs to the local config directory. "
187 "Possible values: all, rc, rifle, commands, scope")
188 parser.add_option('--fail-unless-cd', action='store_true',
189 help=SUPPRESS_HELP) # COMPAT
190 parser.add_option('-r', '--confdir', type='string',
191 metavar='dir', default=default_confdir,
192 help="the configuration directory. (%default)")
193 parser.add_option('-m', '--mode', type='int', default=0, metavar='n',
194 help="if a filename is supplied, run it with this mode")
195 parser.add_option('-f', '--flags', type='string', default='',
196 metavar='string',
197 help="if a filename is supplied, run it with these flags.")
198 parser.add_option('--choosefile', type='string', metavar='TARGET',
199 help="Makes ranger act like a file chooser. When opening "
200 "a file, it will quit and write the name of the selected "
201 "file to TARGET.")
202 parser.add_option('--choosefiles', type='string', metavar='TARGET',
203 help="Makes ranger act like a file chooser for multiple files "
204 "at once. When opening a file, it will quit and write the name "
205 "of all selected files to TARGET.")
206 parser.add_option('--choosedir', type='string', metavar='TARGET',
207 help="Makes ranger act like a directory chooser. When ranger quits"
208 ", it will write the name of the last visited directory to TARGET")
209 parser.add_option('--list-unused-keys', action='store_true',
210 help="List common keys which are not bound to any action.")
211 parser.add_option('--selectfile', type='string', metavar='filepath',
212 help="Open ranger with supplied file selected.")
213 parser.add_option('--list-tagged-files', type='string', default=None,
214 metavar='tag',
215 help="List all files which are tagged with the given tag, default: *")
216 parser.add_option('--profile', action='store_true',
217 help="Print statistics of CPU usage on exit.")
218 parser.add_option('--cmd', action='append', type='string', metavar='COMMAND',
219 help="Execute COMMAND after the configuration has been read. "
220 "Use this option multiple times to run multiple commands.")
222 options, positional = parser.parse_args()
223 arg = OpenStruct(options.__dict__, targets=positional)
224 arg.confdir = expanduser(arg.confdir)
226 if arg.fail_unless_cd: # COMPAT
227 sys.stderr.write("Warning: The option --fail-unless-cd is deprecated.\n"
228 "It was used to faciliate using ranger as a file launcher.\n"
229 "Now, please use the standalone file launcher 'rifle' instead.\n")
231 return arg
234 def load_settings(fm, clean):
235 global load_default_config
236 from ranger.core.actions import Actions
237 import ranger.core.shared
238 import ranger.api.commands
239 from ranger.config import commands
241 # Load default commands
242 fm.commands = ranger.api.commands.CommandContainer()
243 exclude = ['settings']
244 include = [name for name in dir(Actions) if name not in exclude]
245 fm.commands.load_commands_from_object(fm, include)
246 fm.commands.load_commands_from_module(commands)
248 if not clean:
249 allow_access_to_confdir(ranger.arg.confdir, True)
251 # Load custom commands
252 if os.path.exists(fm.confpath('commands.py')):
253 try:
254 import commands
255 fm.commands.load_commands_from_module(commands)
256 except ImportError:
257 pass
259 allow_access_to_confdir(ranger.arg.confdir, False)
261 # Load rc.conf
262 custom_conf = fm.confpath('rc.conf')
263 default_conf = fm.relpath('config', 'rc.conf')
265 if load_default_config:
266 fm.source(default_conf)
267 if os.access(custom_conf, os.R_OK):
268 fm.source(custom_conf)
270 allow_access_to_confdir(ranger.arg.confdir, True)
272 # XXX Load plugins (experimental)
273 try:
274 plugindir = fm.confpath('plugins')
275 plugins = [p[:-3] for p in os.listdir(plugindir) \
276 if p.endswith('.py') and not p.startswith('_')]
277 except:
278 pass
279 else:
280 if not os.path.exists(fm.confpath('plugins', '__init__.py')):
281 f = open(fm.confpath('plugins', '__init__.py'), 'w')
282 f.close()
284 ranger.fm = fm
285 for plugin in sorted(plugins):
286 try:
287 module = __import__('plugins', fromlist=[plugin])
288 fm.log.append("Loaded plugin '%s'." % module)
289 except Exception as e:
290 fm.log.append("Error in plugin '%s'" % plugin)
291 import traceback
292 for line in traceback.format_exception_only(type(e), e):
293 fm.log.append(line)
294 ranger.fm = None
296 # COMPAT: Load the outdated options.py
297 # options.py[oc] are deliberately ignored
298 if os.path.exists(fm.confpath("options.py")):
299 module = __import__('options')
300 from ranger.container.settingobject import ALLOWED_SETTINGS
301 for setting in ALLOWED_SETTINGS:
302 if hasattr(module, setting):
303 fm.settings[setting] = getattr(module, setting)
305 sys.stderr.write(
306 """******************************
307 Warning: The configuration file 'options.py' is deprecated.
308 Please move all settings to the file 'rc.conf', converting lines like
309 "preview_files = False"
311 "set preview_files false"
312 If you had python code in the options.py that you'd like to keep, simply
313 copy & paste it to a .py file in ~/.config/ranger/plugins/.
314 Remove the options.py or discard stderr to get rid of this warning.
315 ******************************\n""")
317 allow_access_to_confdir(ranger.arg.confdir, False)
318 else:
319 fm.source(fm.relpath('config', 'rc.conf'))
322 def allow_access_to_confdir(confdir, allow):
323 import sys
324 from errno import EEXIST
326 if allow:
327 try:
328 os.makedirs(confdir)
329 except OSError as err:
330 if err.errno != EEXIST: # EEXIST means it already exists
331 print("This configuration directory could not be created:")
332 print(confdir)
333 print("To run ranger without the need for configuration")
334 print("files, use the --clean option.")
335 raise SystemExit()
336 if not confdir in sys.path:
337 sys.path[0:0] = [confdir]
338 else:
339 if sys.path[0] == confdir:
340 del sys.path[0]