diff options
author | hut <hut@lavabit.com> | 2010-03-24 14:05:08 +0100 |
---|---|---|
committer | hut <hut@lavabit.com> | 2010-03-24 14:05:08 +0100 |
commit | 55435343b142c424619e3072475ca8b3366d109c (patch) | |
tree | 55c5ba8d815bd2d4cfca2086dba998eaebb83067 /ranger | |
parent | efbde17048b14d43895e4cf91e798fb97702b68f (diff) | |
parent | 0a16f0da970ae344f0094767c08995dd63f616cb (diff) | |
download | ranger-55435343b142c424619e3072475ca8b3366d109c.tar.gz |
Merge branch 'master' into newkey
Conflicts: ranger/api/keys.py ranger/container/commandlist.py ranger/core/actions.py ranger/defaults/keys.py ranger/gui/ui.py ranger/gui/widgets/browserview.py
Diffstat (limited to 'ranger')
45 files changed, 1012 insertions, 3181 deletions
diff --git a/ranger/__init__.py b/ranger/__init__.py index 61df678d..e2a4983d 100644 --- a/ranger/__init__.py +++ b/ranger/__init__.py @@ -17,28 +17,53 @@ import os import sys - -# for easier access -from ranger.ext.debug import log, trace - -__copyright__ = """ -Copyright (C) 2009, 2010 Roman Zimbelmann <romanz@lavabit.com> -""" +from ranger.ext.openstruct import OpenStruct __license__ = 'GPL3' -__version__ = '1.0.3' +__version__ = '1.0.4' __credits__ = 'Roman Zimbelmann' __author__ = 'Roman Zimbelmann' __maintainer__ = 'Roman Zimbelmann' __email__ = 'romanz@lavabit.com' -debug = False +__copyright__ = """ +Copyright (C) 2009, 2010 Roman Zimbelmann <romanz@lavabit.com> +""" -CONFDIR = os.path.expanduser('~/.ranger') +USAGE = '%prog [options] [path/filename]' +DEFAULT_CONFDIR = '~/.ranger' RANGERDIR = os.path.dirname(__file__) +LOGFILE = '/tmp/errorlog' +arg = OpenStruct(cd_after_exit=False, + debug=False, clean=False, confdir=DEFAULT_CONFDIR, + mode=0, flags='', targets=[]) -sys.path.append(CONFDIR) +#for python3-only versions, this could be replaced with: +#def log(*objects, start='ranger:', sep=' ', end='\n'): +# print(start, *objects, end=end, sep=sep, file=open(LOGFILE, 'a')) +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 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 relpath_conf(*paths): + """returns the path relative to rangers configuration directory""" + if arg.clean: + assert 0, "Should not access relpath_conf in clean mode!" + else: + return os.path.join(arg.confdir, *paths) + +def relpath(*paths): + """returns the path relative to rangers library directory""" + return os.path.join(RANGERDIR, *paths) -USAGE = '%prog [options] [path/filename]' from ranger.__main__ import main diff --git a/ranger/__main__.py b/ranger/__main__.py index 72b4adf8..bd01bf4a 100644 --- a/ranger/__main__.py +++ b/ranger/__main__.py @@ -19,40 +19,14 @@ import os import sys -def main(): - """initialize objects and run the filemanager""" - try: - import curses - except ImportError as errormessage: - print(errormessage) - print('ranger requires the python curses module. Aborting.') - sys.exit(1) - - from signal import signal, SIGINT - from locale import setlocale, LC_ALL - from optparse import OptionParser, SUPPRESS_HELP - - import ranger - from ranger.ext import curses_interrupt_handler - from ranger import __version__, USAGE, CONFDIR - from ranger.fm import FM - from ranger.container.environment import Environment - from ranger.shared.settings import SettingsAware - from ranger.gui.defaultui import DefaultUI as UI - from ranger.fsobject.file import File - try: - setlocale(LC_ALL, 'en_US.utf8') - except: - pass - os.stat_float_times(True) - curses_interrupt_handler.install_interrupt_handler() - - if not os.path.exists(CONFDIR): - os.mkdir(CONFDIR) +def parse_arguments(): + """Parse the program arguments""" + from optparse import OptionParser, SUPPRESS_HELP + from ranger.ext.openstruct import OpenStruct + from ranger import __version__, USAGE, DEFAULT_CONFDIR - # Parse options parser = OptionParser(usage=USAGE, version='ranger ' + __version__) # Instead of using this directly, use the embedded @@ -62,33 +36,91 @@ def main(): action='store_true', help=SUPPRESS_HELP) - parser.add_option('-m', type='int', dest='mode', default=0, + 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('-r', '--confdir', dest='confdir', type='string', + default=DEFAULT_CONFDIR, + help="the configuration directory. (%default)") + + parser.add_option('-m', '--mode', type='int', dest='mode', default=0, help="if a filename is supplied, run it with this mode") - parser.add_option('-f', type='string', dest='flags', default='', + parser.add_option('-f', '--flags', type='string', dest='flags', default='', help="if a filename is supplied, run it with these flags.") - parser.add_option('-d', '--debug', action='store_true', - help="activate debug mode") + options, positional = parser.parse_args() + + arg = OpenStruct(options.__dict__, targets=positional) - args, rest = parser.parse_args() + arg.confdir = os.path.expanduser(arg.confdir) - if args.cd_after_exit: + if arg.cd_after_exit: sys.stderr = sys.__stdout__ - ranger.debug = args.debug + if not arg.clean: + try: + os.makedirs(arg.confdir) + except OSError as err: + if err.errno != 17: # 17 means it already exists + print("This configuration directory could not be created:") + print(arg.confdir) + print("To run ranger without the need for configuration files") + print("use the --clean option.") + raise SystemExit() + + sys.path.append(arg.confdir) + + return arg + +def main(): + """initialize objects and run the filemanager""" + try: + import curses + except ImportError as errormessage: + print(errormessage) + print('ranger requires the python curses module. Aborting.') + sys.exit(1) + + from signal import signal, SIGINT + from locale import getdefaultlocale, setlocale, LC_ALL + + import ranger + from ranger.ext import curses_interrupt_handler + from ranger.core.fm import FM + from ranger.core.environment import Environment + from ranger.shared.settings import SettingsAware + from ranger.gui.defaultui import DefaultUI as UI + from ranger.fsobject.file import File + + # Ensure that a utf8 locale is set. + if getdefaultlocale()[1] not in ('utf8', 'UTF-8'): + for locale in ('en_US.utf8', 'en_US.UTF-8'): + try: setlocale(LC_ALL, locale) + except: pass #sometimes there is none available though... + else: + setlocale(LC_ALL, '') + + arg = parse_arguments() + ranger.arg = arg + + if not ranger.arg.debug: + curses_interrupt_handler.install_interrupt_handler() SettingsAware._setup() # Initialize objects - target = ' '.join(rest) - if target: + if arg.targets: + target = arg.targets[0] 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): thefile = File(target) - FM().execute_file(thefile, mode=args.mode, flags=args.flags) + FM().execute_file(thefile, mode=arg.mode, flags=arg.flags) sys.exit(0) else: path = target @@ -100,7 +132,7 @@ def main(): try: my_ui = UI() my_fm = FM(ui=my_ui) - my_fm.stderr_to_out = args.cd_after_exit + my_fm.stderr_to_out = arg.cd_after_exit # Run the file manager my_fm.initialize() @@ -110,8 +142,8 @@ def main(): # Finish, clean up if 'my_ui' in vars(): my_ui.destroy() - if args.cd_after_exit: - try: sys.__stderr__.write(my_fm.env.pwd.path) + if arg.cd_after_exit: + try: sys.__stderr__.write(my_fm.env.cwd.path) except: pass if __name__ == '__main__': diff --git a/ranger/api/apps.py b/ranger/api/apps.py index 743fa248..a17a6601 100644 --- a/ranger/api/apps.py +++ b/ranger/api/apps.py @@ -14,7 +14,7 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. """ -This module provides helper functions/classes for ranger.defaults.apps. +This module provides helper functions/classes for ranger.apps. """ import os, sys, re @@ -26,7 +26,7 @@ from ranger.shared import FileManagerAware class Applications(FileManagerAware): """ This class contains definitions on how to run programs and should - be extended in ranger.defaults.apps + be extended in ranger.apps 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 @@ -78,6 +78,8 @@ class Applications(FileManagerAware): try: application_handler = getattr(self, 'app_' + app) except AttributeError: + if app in self.fm.executables: + return tup(app, *context) continue if self._meets_dependencies(application_handler): return application_handler(context) @@ -99,6 +101,8 @@ class Applications(FileManagerAware): try: handler = getattr(self, 'app_' + app) except AttributeError: + if app in self.fm.executables: + return tup(app, *context) # generic app handler = self.app_default return handler(context) @@ -108,8 +112,12 @@ class Applications(FileManagerAware): def all(self): """Returns a list with all application functions""" - methods = self.__class__.__dict__ - return [meth[4:] for meth in methods if meth.startswith('app_')] + result = set() + # go through all the classes in the mro (method resolution order) + # so subclasses will return the apps of their superclasses. + for cls in self.__class__.__mro__: + result |= set(m[4:] for m in cls.__dict__ if m.startswith('app_')) + return sorted(result) def tup(*args): diff --git a/ranger/api/options.py b/ranger/api/options.py index 10778379..7ead8c90 100644 --- a/ranger/api/options.py +++ b/ranger/api/options.py @@ -15,4 +15,16 @@ import re from re import compile as regexp -from ranger import colorschemes +from ranger import colorschemes as allschemes + +class AttrToString(object): + """ + Purely for compatibility to 1.0.3. + """ + def __getattr__(self, attr): + print("NOTE: your configuration is out of date.") + print("instead of this: colorscheme = colorschemes." + attr) + print("please use a string: colorscheme = \"" + attr + "\"") + return attr + +colorschemes = AttrToString() diff --git a/ranger/colorschemes/__init__.py b/ranger/colorschemes/__init__.py index b685a191..8b7a21a9 100644 --- a/ranger/colorschemes/__init__.py +++ b/ranger/colorschemes/__init__.py @@ -13,30 +13,6 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. -"""Colorschemes are required to be located here, -or in the CONFDIR/colorschemes/ directory""" -from ranger.ext.get_all_modules import get_all_modules -from os.path import expanduser, dirname, exists, join - -__all__ = get_all_modules(dirname(__file__)) - -from ranger.colorschemes import * - -confpath = expanduser('~/.ranger') -if exists(join(confpath, 'colorschemes')): - initpy = join(confpath, 'colorschemes/__init__.py') - if not exists(initpy): - open(initpy, 'w').write("""# Automatically generated: -from ranger.ext.get_all_modules import get_all_modules -from os.path import dirname - -__all__ = get_all_modules(dirname(__file__)) -""") - - try: - import sys - sys.path[0:0] = [confpath] - from colorschemes import * - except ImportError: - pass - +""" +Colorschemes are required to be located here or in CONFDIR/colorschemes/ +""" diff --git a/ranger/colorschemes/default.py b/ranger/colorschemes/default.py index f5c5d763..d1a7e820 100644 --- a/ranger/colorschemes/default.py +++ b/ranger/colorschemes/default.py @@ -30,6 +30,8 @@ class Default(ColorScheme): attr = normal if context.empty or context.error: bg = red + if context.border: + fg = default if context.media: if context.image: fg = yellow diff --git a/ranger/colorschemes/default88.py b/ranger/colorschemes/default88.py new file mode 100644 index 00000000..9af6dca7 --- /dev/null +++ b/ranger/colorschemes/default88.py @@ -0,0 +1,59 @@ +# 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 default colorscheme, using 88 colors. + +For now, just map each of the 8 base colors to new ones +for brighter blue, etc. and do some minor modifications. +""" + +from ranger.gui.colorscheme import ColorScheme +from ranger.gui.color import * + +from ranger.colorschemes.default import Default +import curses + +class Scheme(Default): + def use(self, context): + fg, bg, attr = Default.use(self, context) + + if curses.COLORS < 88: + return fg, bg, attr + + try: + translate = { + blue: 22, + yellow: 72, + green: 20, + cyan: 21, + white: 79, + red: 32, + magenta: magenta, + } + fg = translate[fg] + except KeyError: + pass + + if context.in_browser: + if context.main_column and context.marked: + if context.selected: + fg = 77 + else: + fg = 68 + attr |= reverse + + return fg, bg, attr + diff --git a/ranger/colorschemes/texas.py b/ranger/colorschemes/texas.py new file mode 100644 index 00000000..93fd4791 --- /dev/null +++ b/ranger/colorschemes/texas.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/>. + +""" +Some experimental colorscheme. +""" + +from ranger.gui.colorscheme import ColorScheme +from ranger.gui.color import * + +from ranger.colorschemes.default import Default +import curses + +class Scheme(Default): + def use(self, context): + fg, bg, attr = Default.use(self, context) + + if curses.COLORS < 88: + return fg, bg, attr + + dircolor = 77 + dircolor_selected = {True: 79, False: 78} + linkcolor = {True: 21, False: 48} + + if context.in_browser: + if context.media: + if context.image: + fg = 20 + elif context.video: + fg = 22 + elif context.audio: + fg = 23 + + if context.container: + fg = 32 + if context.directory: + fg = dircolor + if context.selected: + fg = dircolor_selected[context.main_column] + elif context.executable and not \ + any((context.media, context.container)): + fg = 82 + if context.link: + fg = linkcolor[context.good] + + if context.main_column: + if context.selected: + attr |= bold + if context.marked: + attr |= bold + fg = 53 + + if context.in_titlebar: + if context.hostname: + fg = context.bad and 48 or 82 + elif context.directory: + fg = dircolor + elif context.link: + fg = linkcolor[True] + + return fg, bg, attr diff --git a/ranger/container/bookmarks.py b/ranger/container/bookmarks.py index a0c757ca..d4e12f62 100644 --- a/ranger/container/bookmarks.py +++ b/ranger/container/bookmarks.py @@ -150,6 +150,8 @@ class Bookmarks(object): This is done automatically after every modification if autosave is True.""" import os self.update() + if self.path is None: + return if os.access(self.path, os.W_OK): f = open(self.path, 'w') for key, value in self.dct.items(): @@ -163,6 +165,10 @@ class Bookmarks(object): def _load_dict(self): import os dct = {} + + if self.path is None: + return dct + if not os.path.exists(self.path): try: f = open(self.path, 'w') @@ -193,6 +199,8 @@ class Bookmarks(object): def _get_mtime(self): import os + if self.path is None: + return None try: return os.stat(self.path).st_mtime except OSError: diff --git a/ranger/container/tags.py b/ranger/container/tags.py index 70a4aa3d..11ac3a5d 100644 --- a/ranger/container/tags.py +++ b/ranger/container/tags.py @@ -81,3 +81,7 @@ class Tags(object): for line in f: result.add(line.strip()) return result + + def __nonzero__(self): + return True + __bool__ = __nonzero__ diff --git a/ranger/core/__init__.py b/ranger/core/__init__.py new file mode 100644 index 00000000..93c483f2 --- /dev/null +++ b/ranger/core/__init__.py @@ -0,0 +1 @@ +"""Core components""" diff --git a/ranger/actions.py b/ranger/core/actions.py index 754fd857..e55d65b1 100644 --- a/ranger/actions.py +++ b/ranger/core/actions.py @@ -51,12 +51,12 @@ class Actions(EnvironmentAware, SettingsAware): elif order == 'tag': fnc = lambda x: x.realpath in self.tags - return self.env.pwd.search_fnc(fnc=fnc, forward=forward) + return self.env.cwd.search_fnc(fnc=fnc, forward=forward) elif order in ('size', 'mimetype', 'ctime'): - pwd = self.env.pwd - if original_order is not None or not pwd.cycle_list: - lst = list(pwd.files) + cwd = self.env.cwd + if original_order is not None or not cwd.cycle_list: + lst = list(cwd.files) if order == 'size': fnc = lambda item: -item.size elif order == 'mimetype': @@ -64,10 +64,10 @@ class Actions(EnvironmentAware, SettingsAware): elif order == 'ctime': fnc = lambda item: -int(item.stat and item.stat.st_ctime) lst.sort(key=fnc) - pwd.set_cycle_list(lst) - return pwd.cycle(forward=None) + cwd.set_cycle_list(lst) + return cwd.cycle(forward=None) - return pwd.cycle(forward=forward) + return cwd.cycle(forward=forward) def set_search_method(self, order, forward=True): if order in ('search', 'tag', 'size', 'mimetype', 'ctime'): @@ -85,9 +85,9 @@ class Actions(EnvironmentAware, SettingsAware): def enter_dir(self, path, remember=False): """Enter the directory at the given path""" if remember: - pwd = self.env.pwd + cwd = self.env.cwd result = self.env.enter_dir(path) - self.bookmarks.remember(pwd) + self.bookmarks.remember(cwd) return result return self.env.enter_dir(path) @@ -133,16 +133,16 @@ class Actions(EnvironmentAware, SettingsAware): """Enter the bookmark with the name <key>""" try: destination = self.bookmarks[key] - pwd = self.env.pwd - if destination.path != pwd.path: + cwd = self.env.cwd + if destination.path != cwd.path: self.bookmarks.enter(key) - self.bookmarks.remember(pwd) + self.bookmarks.remember(cwd) except KeyError: pass def set_bookmark(self, key): """Set the bookmark with the name <key> to the current directory""" - self.bookmarks[key] = self.env.pwd + self.bookmarks[key] = self.env.cwd def unset_bookmark(self, key): """Delete the bookmark with the name <key>""" @@ -273,7 +273,7 @@ class Actions(EnvironmentAware, SettingsAware): def move_pointer(self, relative = 0, absolute = None, narg=None): """Move the pointer down by <relative> or to <absolute>""" - self.env.pwd.move(relative=relative, + self.env.cwd.move(relative=relative, absolute=absolute, narg=narg) def move(self, dir, narg=None): @@ -316,12 +316,12 @@ class Actions(EnvironmentAware, SettingsAware): def move_pointer_by_pages(self, relative): """Move the pointer down by <relative> pages""" - self.env.pwd.move(relative=int(relative * self.env.termsize[0])) + self.env.cwd.move(relative=int(relative * self.env.termsize[0])) def move_pointer_by_percentage(self, relative=0, absolute=None, narg=None): """Move the pointer down by <relative>% or to <absolute>%""" try: - factor = len(self.env.pwd) / 100.0 + factor = len(self.env.cwd) / 100.0 except: return @@ -331,7 +331,7 @@ class Actions(EnvironmentAware, SettingsAware): if absolute is not None: absolute = int(absolute * factor) - self.env.pwd.move( + self.env.cwd.move( relative=int(relative * factor), absolute=absolute) @@ -339,7 +339,7 @@ class Actions(EnvironmentAware, SettingsAware): """Scroll down by <relative> lines""" if hasattr(self.ui, 'scroll'): self.ui.scroll(relative) - self.env.cf = self.env.pwd.pointed_obj + self.env.cf = self.env.cwd.pointed_obj def redraw_window(self): """Redraw the window""" @@ -347,7 +347,7 @@ class Actions(EnvironmentAware, SettingsAware): def reset(self): """Reset the filemanager, clearing the directory buffer""" - old_path = self.env.pwd.path + old_path = self.env.cwd.path self.env.directories = {} self.enter_dir(old_path) @@ -371,7 +371,7 @@ class Actions(EnvironmentAware, SettingsAware): def reload_cwd(self): try: - cwd = self.env.pwd + cwd = self.env.cwd except: pass cwd.unload() @@ -379,13 +379,13 @@ class Actions(EnvironmentAware, SettingsAware): def traverse(self): cf = self.env.cf - cwd = self.env.pwd + cwd = self.env.cwd if cf is not None and cf.is_directory: self.enter_dir(cf.path) elif cwd.pointer >= len(cwd) - 1: while True: self.enter_dir('..') - cwd = self.env.pwd + cwd = self.env.cwd if cwd.pointer < len(cwd) - 1: break if cwd.path == '/': @@ -398,13 +398,13 @@ class Actions(EnvironmentAware, SettingsAware): def set_filter(self, fltr): try: - self.env.pwd.filter = fltr + self.env.cwd.filter = fltr except: pass def notify(self, text, duration=4, bad=False): if isinstance(text, Exception): - if ranger.debug: + if ranger.arg.debug: raise bad = True text = str(text) @@ -425,12 +425,12 @@ class Actions(EnvironmentAware, SettingsAware): val - mark or unmark? """ - if self.env.pwd is None: + if self.env.cwd is None: return - pwd = self.env.pwd + cwd = self.env.cwd - if not pwd.accessible: + if not cwd.accessible: return if movedown is None: @@ -441,17 +441,17 @@ class Actions(EnvironmentAware, SettingsAware): if all: if toggle: - pwd.toggle_all_marks() + cwd.toggle_all_marks() else: - pwd.mark_all(val) + cwd.mark_all(val) else: - for i in range(pwd.pointer, min(pwd.pointer + narg, len(pwd))): - item = pwd.files[i] + for i in range(cwd.pointer, min(cwd.pointer + narg, len(cwd))): + item = cwd.files[i] if item is not None: if toggle: - pwd.toggle_mark(item) + cwd.toggle_mark(item) else: - pwd.mark_item(item, val) + cwd.mark_item(item, val) if movedown: self.move_pointer(relative=narg) @@ -467,7 +467,7 @@ class Actions(EnvironmentAware, SettingsAware): """Copy the selected items""" selected = self.env.get_selection() - self.env.copy = set(f for f in selected if f in self.env.pwd.files) + self.env.copy = set(f for f in selected if f in self.env.cwd.files) self.env.cut = False def cut(self): @@ -499,7 +499,7 @@ class Actions(EnvironmentAware, SettingsAware): if not copied_files: return - original_path = self.env.pwd.path + original_path = self.env.cwd.path try: one_file = copied_files[0] except: @@ -518,8 +518,8 @@ class Actions(EnvironmentAware, SettingsAware): dst=original_path, overwrite=overwrite): yield - pwd = self.env.get_directory(original_path) - pwd.load_content() + cwd = self.env.get_directory(original_path) + cwd.load_content() else: if len(copied_files) == 1: descr = "copying: " + one_file.path @@ -529,7 +529,7 @@ class Actions(EnvironmentAware, SettingsAware): for f in self.env.copy: if isdir(f.path): for _ in shutil_g.copytree(src=f.path, - dst=join(self.env.pwd.path, f.basename), + dst=join(self.env.cwd.path, f.basename), symlinks=True, overwrite=overwrite): yield @@ -538,8 +538,8 @@ class Actions(EnvironmentAware, SettingsAware): symlinks=True, overwrite=overwrite): yield - pwd = self.env.get_directory(original_path) - pwd.load_content() + cwd = self.env.get_directory(original_path) + cwd.load_content() self.loader.add(LoadableObject(generate(), descr)) @@ -559,10 +559,11 @@ class Actions(EnvironmentAware, SettingsAware): os.remove(f.path) except OSError as err: self.notify(err) + self.env.ensure_correct_pointer() def mkdir(self, name): try: - os.mkdir(os.path.join(self.env.pwd.path, name)) + os.mkdir(os.path.join(self.env.cwd.path, name)) except OSError as err: self.notify(err) diff --git a/ranger/container/environment.py b/ranger/core/environment.py index b08b357f..4301d237 100644 --- a/ranger/container/environment.py +++ b/ranger/core/environment.py @@ -13,19 +13,22 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. -from os.path import abspath, normpath, join, expanduser, isdir +import curses import os +import pwd +import socket +from os.path import abspath, normpath, join, expanduser, isdir + from ranger.fsobject.directory import Directory, NoDirectoryGiven from ranger.container import KeyBuffer, History from ranger.shared import SettingsAware -import curses class Environment(SettingsAware): """A collection of data which is relevant for more than one class. """ - pwd = None # current directory + cwd = None # current directory cf = None # current file copy = None cmd = None @@ -46,6 +49,13 @@ class Environment(SettingsAware): self.copy = set() self.history = History(self.settings.max_history_size) + try: + self.username = pwd.getpwuid(os.geteuid()).pw_name + except: + self.username = 'uid:' + str(os.geteuid()) + self.hostname = socket.gethostname() + self.home_path = os.path.expanduser('~') + from ranger.shared import EnvironmentAware EnvironmentAware.env = self @@ -63,22 +73,32 @@ class Environment(SettingsAware): self.keybuffer.clear() def at_level(self, level): - """Returns the FileSystemObject at the given level. - level 1 => preview + """ + Returns the FileSystemObject at the given level. + level >0 => previews level 0 => current file/directory - level <0 => parent directories""" + level <0 => parent directories + """ if level <= 0: try: return self.pathway[level - 1] except IndexError: return None else: + directory = self.cf + for i in range(level - 1): + if directory is None: + return None + if directory.is_directory: + directory = directory.pointed_obj + else: + return None try: - return self.directories[self.cf.path] + return self.directories[directory.path] except AttributeError: return None except KeyError: - return self.cf + return directory def garbage_collect(self): """Delete unused directory objects""" @@ -90,8 +110,8 @@ class Environment(SettingsAware): del self.directories[key] def get_selection(self): - if self.pwd: - return self.pwd.get_selection() + if self.cwd: + return self.cwd.get_selection() return set() def get_directory(self, path): @@ -109,7 +129,7 @@ class Environment(SettingsAware): stat = statvfs(path) return stat.f_bavail * stat.f_bsize - def assign_correct_cursor_positions(self): + def assign_cursor_positions_for_subdirs(self): """Assign correct cursor positions for subdirectories""" last_path = None for path in reversed(self.pathway): @@ -120,6 +140,10 @@ class Environment(SettingsAware): path.move_to_obj(last_path) last_path = path + def ensure_correct_pointer(self): + if self.cwd: + self.cwd.correct_pointer() + def history_go(self, relative): """Move relative in history""" if self.history: @@ -137,15 +161,15 @@ class Environment(SettingsAware): return try: - new_pwd = self.get_directory(path) + new_cwd = self.get_directory(path) except NoDirectoryGiven: return False self.path = path - self.pwd = new_pwd + self.cwd = new_cwd os.chdir(path) - self.pwd.load_content_if_outdated() + self.cwd.load_content_if_outdated() # build the pathway, a tuple of directory objects which lie # on the path to the current directory. @@ -159,14 +183,14 @@ class Environment(SettingsAware): pathway.append(self.get_directory(currentpath)) self.pathway = tuple(pathway) - self.assign_correct_cursor_positions() + self.assign_cursor_positions_for_subdirs() # set the current file. - self.pwd.directories_first = self.settings.directories_first - self.pwd.sort_if_outdated() - self.cf = self.pwd.pointed_obj + self.cwd.directories_first = self.settings.directories_first + self.cwd.sort_if_outdated() + self.cf = self.cwd.pointed_obj if history: - self.history.add(new_pwd) + self.history.add(new_cwd) return True diff --git a/ranger/fm.py b/ranger/core/fm.py index aa1f0493..994447b0 100644 --- a/ranger/fm.py +++ b/ranger/core/fm.py @@ -13,13 +13,18 @@ # 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 File Manager, putting the pieces together +""" + from time import time from collections import deque -from ranger.actions import Actions +import ranger +from ranger.core.actions import Actions from ranger.container import Bookmarks -from ranger.runner import Runner -from ranger.ext.relpath import relpath_conf +from ranger.core.runner import Runner +from ranger import relpath_conf from ranger.ext.get_executables import get_executables from ranger import __version__ from ranger.fsobject import Loader @@ -61,8 +66,12 @@ class FM(Actions): from ranger.fsobject.directory import Directory if self.bookmarks is None: + if ranger.arg.clean: + bookmarkfile = None + else: + bookmarkfile = relpath_conf('bookmarks') self.bookmarks = Bookmarks( - bookmarkfile=relpath_conf('bookmarks'), + bookmarkfile=bookmarkfile, bookmarktype=Directory, autosave=self.settings.autosave_bookmarks) self.bookmarks.load() @@ -71,8 +80,8 @@ class FM(Actions): self.bookmarks = bookmarks from ranger.container.tags import Tags - if self.tags is None: - self.tags = Tags('~/.ranger/tagged') + if not ranger.arg.clean and self.tags is None: + self.tags = Tags(relpath_conf('tagged')) if self.ui is None: from ranger.gui.defaultui import DefaultUI @@ -97,34 +106,47 @@ class FM(Actions): gc_tick = 0 + # for faster lookup: + ui = self.ui + throbber = ui.throbber + bookmarks = self.bookmarks + loader = self.loader + env = self.env + has_throbber = hasattr(ui, 'throbber') + try: while True: - self.bookmarks.update_if_outdated() - self.loader.work() - if hasattr(self.ui, 'throbber'): - if self.loader.has_work(): - self.ui.throbber(self.loader.status) + bookmarks.update_if_outdated() + loader.work() + if has_throbber: + if loader.has_work(): + throbber(loader.status) else: - self.ui.throbber(remove=True) + throbber(remove=True) - self.ui.redraw() + ui.redraw() - self.ui.set_load_mode(self.loader.has_work()) + ui.set_load_mode(loader.has_work()) - key = self.ui.get_next_key() + key = ui.get_next_key() if key > 0: if self.input_blocked and \ time() > self.input_blocked_until: self.input_blocked = False if not self.input_blocked: - self.ui.handle_key(key) + ui.handle_key(key) gc_tick += 1 if gc_tick > TICKS_BEFORE_COLLECTING_GARBAGE: gc_tick = 0 - self.env.garbage_collect() + env.garbage_collect() + + except KeyboardInterrupt: + # this only happens in --debug mode. By default, interrupts + # are caught in curses_interrupt_handler + raise SystemExit finally: - self.bookmarks.remember(self.env.pwd) - self.bookmarks.save() + bookmarks.remember(env.cwd) + bookmarks.save() diff --git a/ranger/runner.py b/ranger/core/runner.py index 26424881..26424881 100644 --- a/ranger/runner.py +++ b/ranger/core/runner.py diff --git a/ranger/data/generate.py b/ranger/data/generate.py deleted file mode 100755 index a0ed2b9b..00000000 --- a/ranger/data/generate.py +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/python -# coding=utf-8 -# -# 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/>. - -if __name__ == '__main__': - import sys, pickle - - protocol = 0 - table = {} - - for line in open(len(sys.argv) > 1 and sys.argv[1] or "mime.types"): - if len(line) > 3 and line[0] != '#' and ('\t' in line or ' ' in line): - name, *extensions = line.split() - for ext in extensions: - table[ext] = name - - pickle.dump(table, open('mime.dat', 'wb'), protocol) diff --git a/ranger/data/mime.dat b/ranger/data/mime.dat deleted file mode 100644 index ddfca976..00000000 --- a/ranger/data/mime.dat +++ /dev/null @@ -1,1752 +0,0 @@ -(dp0 -Valc -p1 -Vchemical/x-alchemy -p2 -sVgf -p3 -Vapplication/x-tex-gf -p4 -sVmp4 -p5 -Vvideo/mp4 -p6 -sVmp2 -p7 -Vaudio/mpeg -p8 -sVmp3 -p9 -g8 -sVnwc -p10 -Vapplication/x-nwc -p11 -sVsct -p12 -Vtext/scriptlet -p13 -sVros -p14 -Vchemical/x-rosdal -p15 -sVmng -p16 -Vvideo/x-mng -p17 -sVwmz -p18 -Vapplication/x-ms-wmz -p19 -sVwmx -p20 -Vvideo/x-ms-wmx -p21 -sVgcd -p22 -Vtext/x-pcs-gcd -p23 -sVtr -p24 -Vapplication/x-troff -p25 -sVts -p26 -Vtext/texmacs -p27 -sVtm -p28 -g27 -sVtk -p29 -Vtext/x-tcl -p30 -sVwml -p31 -Vtext/vnd.wap.wml -p32 -sVwma -p33 -Vaudio/x-ms-wma -p34 -sVfchk -p35 -Vchemical/x-gaussian-checkpoint -p36 -sVwmd -p37 -Vapplication/x-ms-wmd -p38 -sVmpg -p39 -Vvideo/mpeg -p40 -sVcascii -p41 -Vchemical/x-cactvs-binary -p42 -sVmpe -p43 -g40 -sVsmi -p44 -Vapplication/smil -p45 -sVmpv -p46 -Vvideo/x-matroska -p47 -sVwsc -p48 -g13 -sVcml -p49 -Vchemical/x-cml -p50 -sVdif -p51 -Vvideo/dv -p52 -sVp -p53 -Vtext/x-pascal -p54 -sVpbm -p55 -Vimage/x-portable-bitmap -p56 -sVdir -p57 -Vapplication/x-director -p58 -sVhtc -p59 -Vtext/x-component -p60 -sVhta -p61 -Vapplication/hta -p62 -sVodp -p63 -Vapplication/vnd.oasis.opendocument.presentation -p64 -sVhtm -p65 -Vtext/html -p66 -sVnbp -p67 -Vapplication/mathematica -p68 -sVodt -p69 -Vapplication/vnd.oasis.opendocument.text -p70 -sVtex -p71 -Vtext/x-tex -p72 -sVodi -p73 -Vapplication/vnd.oasis.opendocument.image -p74 -sVodm -p75 -Vapplication/vnd.oasis.opendocument.text-master -p76 -sVoda -p77 -Vapplication/oda -p78 -sVodb -p79 -Vapplication/vnd.oasis.opendocument.database -p80 -sVodc -p81 -Vapplication/vnd.oasis.opendocument.chart -p82 -sVodf -p83 -Vapplication/vnd.oasis.opendocument.formula -p84 -sVodg -p85 -Vapplication/vnd.oasis.opendocument.graphics -p86 -sVgl -p87 -Vvideo/gl -p88 -sVrtx -p89 -Vtext/richtext -p90 -sVabw -p91 -Vapplication/x-abiword -p92 -sVoza -p93 -Vapplication/x-oz-application -p94 -sVasc -p95 -Vtext/plain -p96 -sVm3u -p97 -Vaudio/x-mpegurl -p98 -sVctx -p99 -Vchemical/x-ctx -p100 -sVcbin -p101 -g42 -sVrdf -p102 -Vapplication/rdf+xml -p103 -sVboo -p104 -Vtext/x-boo -p105 -sVm3g -p106 -Vapplication/m3g -p107 -sVmaker -p108 -Vapplication/x-maker -p109 -sVwmv -p110 -Vvideo/x-ms-wmv -p111 -sVsgl -p112 -Vapplication/vnd.stardivision.writer-global -p113 -sVbrf -p114 -g96 -sVtxt -p115 -g96 -sVwbmp -p116 -Vimage/vnd.wap.wbmp -p117 -sVsgf -p118 -Vapplication/x-go-sgf -p119 -sVzip -p120 -Vapplication/zip -p121 -sVepsf -p122 -Vapplication/postscript -p123 -sVchm -p124 -Vchemical/x-chemdraw -p125 -sVmsi -p126 -Vapplication/x-msi -p127 -sVmsh -p128 -Vmodel/mesh -p129 -sVjmz -p130 -Vapplication/x-jmol -p131 -sVwvx -p132 -Vvideo/x-ms-wvx -p133 -sVpfb -p134 -Vapplication/x-font -p135 -sVflv -p136 -Vvideo/x-flv -p137 -sVflac -p138 -Vaudio/flac -p139 -sVwbxml -p140 -Vapplication/vnd.wap.wbxml -p141 -sViii -p142 -Vapplication/x-iphone -p143 -sVme -p144 -Vapplication/x-troff-me -p145 -sVmm -p146 -Vapplication/x-freemind -p147 -sVuls -p148 -Vtext/iuls -p149 -sVcap -p150 -Vapplication/cap -p151 -sVcat -p152 -Vapplication/vnd.ms-pki.seccat -p153 -sVfli -p154 -Vvideo/fli -p155 -sVjdx -p156 -Vchemical/x-jcamp-dx -p157 -sVms -p158 -Vapplication/x-troff-ms -p159 -sVxht -p160 -Vapplication/xhtml+xml -p161 -sVcac -p162 -Vchemical/x-cache -p163 -sVcab -p164 -Vapplication/x-cab -p165 -sVdeb -p166 -Vapplication/x-debian-package -p167 -sVeps2 -p168 -g123 -sVeps3 -p169 -g123 -sVspx -p170 -Vaudio/ogg -p171 -sVltx -p172 -g72 -sVxcf -p173 -Vapplication/x-xcf -p174 -sVtar -p175 -Vapplication/x-tar -p176 -sVdxr -p177 -g58 -sVtaz -p178 -Vapplication/x-gtar -p179 -sVspl -p180 -Vapplication/x-futuresplash -p181 -sVspc -p182 -Vchemical/x-galactic-spc -p183 -sVmpc -p184 -Vchemical/x-mopac-input -p185 -sVcsm -p186 -Vchemical/x-csml -p187 -sVchrt -p188 -Vapplication/x-kchart -p189 -sVcsh -p190 -Vtext/x-csh -p191 -sVgcg -p192 -Vchemical/x-gcg8-sequence -p193 -sVsit -p194 -Vapplication/x-stuffit -p195 -sVcsf -p196 -Vchemical/x-cache-csf -p197 -sVent -p198 -Vchemical/x-pdb -p199 -sVsid -p200 -Vaudio/prs.sid -p201 -sVsik -p202 -Vapplication/x-trash -p203 -sVxhtml -p204 -g161 -sVcsv -p205 -Vtext/csv -p206 -sVcss -p207 -Vtext/css -p208 -sVsis -p209 -Vapplication/vnd.symbian.install -p210 -sVsnd -p211 -Vaudio/basic -p212 -sVmpega -p213 -g8 -sVfb -p214 -g109 -sVmesh -p215 -g129 -sVfm -p216 -g109 -sVman -p217 -Vapplication/x-troff-man -p218 -sVlha -p219 -Vapplication/x-lha -p220 -sVgcf -p221 -Vapplication/x-graphing-calculator -p222 -sVsw -p223 -Vchemical/x-swissprot -p224 -sVsh -p225 -Vtext/x-sh -p226 -sVlhs -p227 -Vtext/x-literate-haskell -p228 -sVsd -p229 -Vchemical/x-mdl-sdfile -p230 -sVlsf -p231 -Vvideo/x-la-asf -p232 -sVvmd -p233 -Vchemical/x-vmd -p234 -sVjpeg -p235 -Vimage/jpeg -p236 -sVjng -p237 -Vimage/x-jng -p238 -sVvms -p239 -Vchemical/x-vamas-iso14976 -p240 -sVlsx -p241 -g232 -sVpcx -p242 -Vimage/pcx -p243 -sVdjv -p244 -Vimage/vnd.djvu -p245 -sVwrl -p246 -Vx-world/x-vrml -p247 -sVqgs -p248 -Vapplication/x-qgis -p249 -sVhtml -p250 -g66 -sVfig -p251 -Vapplication/x-xfig -p252 -sVtsv -p253 -Vtext/tab-separated-values -p254 -sVpcf -p255 -g135 -sVtsp -p256 -Vapplication/dsptype -p257 -sVcls -p258 -g72 -sVlzx -p259 -Vapplication/x-lzx -p260 -sVmxu -p261 -Vvideo/vnd.mpegurl -p262 -sVdat -p263 -Vapplication/x-ns-proxy-autoconfig -p264 -sVlzh -p265 -Vapplication/x-lzh -p266 -sVcer -p267 -Vchemical/x-cerius -p268 -sVhqx -p269 -Vapplication/mac-binhex40 -p270 -sVkpr -p271 -Vapplication/x-kpresenter -p272 -sVkpt -p273 -g272 -sVxlb -p274 -Vapplication/vnd.ms-excel -p275 -sVh -p276 -Vtext/x-chdr -p277 -sVxlt -p278 -g275 -sVxls -p279 -g275 -sVatomcat -p280 -Vapplication/atomcat+xml -p281 -sVmdb -p282 -Vapplication/msaccess -p283 -sVgtar -p284 -g179 -sVez -p285 -Vapplication/andrew-inset -p286 -sVes -p287 -Vapplication/ecmascript -p288 -sVvcd -p289 -Vapplication/x-cdlink -p290 -sVvcf -p291 -Vtext/x-vcard -p292 -sVrd -p293 -Vchemical/x-mdl-rdfile -p294 -sVvcs -p295 -Vtext/x-vcalendar -p296 -sVra -p297 -Vaudio/x-realaudio -p298 -sVrb -p299 -Vapplication/x-ruby -p300 -sVrm -p301 -Vaudio/x-pn-realaudio -p302 -sVasx -p303 -Vvideo/x-ms-asf -p304 -sVgnumeric -p305 -Vapplication/x-gnumeric -p306 -sVmml -p307 -Vtext/mathml -p308 -sVasf -p309 -g304 -sVmmd -p310 -Vchemical/x-macromodel-input -p311 -sVmmf -p312 -Vapplication/vnd.smaf -p313 -sVaso -p314 -Vchemical/x-ncbi-asn1-binary -p315 -sVasn -p316 -Vchemical/x-ncbi-asn1-spec -p317 -sVcxx -p318 -Vtext/x-c++src -p319 -sVxpm -p320 -Vimage/x-xpixmap -p321 -sVmidi -p322 -Vaudio/midi -p323 -sVc3d -p324 -Vchemical/x-chem3d -p325 -sVisp -p326 -Vapplication/x-internet-signup -p327 -sVswfl -p328 -Vapplication/x-shockwave-flash -p329 -sVist -p330 -Vchemical/x-isostar -p331 -sVmvb -p332 -Vchemical/x-mopac-vib -p333 -sViso -p334 -Vapplication/x-iso9660-image -p335 -sVxul -p336 -Vapplication/vnd.mozilla.xul+xml -p337 -sVpgn -p338 -Vapplication/x-chess-pgn -p339 -sVpgm -p340 -Vimage/x-portable-graymap -p341 -sVpgp -p342 -Vapplication/pgp-signature -p343 -sVmkv -p344 -Vvideo/mkv -p345 -sVgpt -p346 -Vchemical/x-mopac-graph -p347 -sVphtml -p348 -Vapplication/x-httpd-php -p349 -sVods -p350 -Vapplication/vnd.oasis.opendocument.spreadsheet -p351 -sVogx -p352 -Vapplication/ogg -p353 -sVwax -p354 -Vaudio/x-ms-wax -p355 -sVpnm -p356 -Vimage/x-portable-anymap -p357 -sVcmdf -p358 -Vchemical/x-cmdf -p359 -sVoga -p360 -g171 -sVpng -p361 -Vimage/png -p362 -sVrss -p363 -Vapplication/rss+xml -p364 -sVstd -p365 -Vapplication/vnd.sun.xml.draw.template -p366 -sVb -p367 -Vchemical/x-molconn-Z -p368 -sVstc -p369 -Vapplication/vnd.sun.xml.calc.template -p370 -sVstl -p371 -Vapplication/vnd.ms-pki.stl -p372 -sVogg -p373 -g171 -sVmcif -p374 -Vchemical/x-mmcif -p375 -sVstw -p376 -Vapplication/vnd.sun.xml.writer.template -p377 -sVtorrent -p378 -Vapplication/x-bittorrent -p379 -sVprf -p380 -Vapplication/pics-rules -p381 -sVphp3p -p382 -Vapplication/x-httpd-php3-preprocessed -p383 -sVram -p384 -g302 -sVprt -p385 -Vchemical/x-ncbi-asn1-ascii -p386 -sVrar -p387 -Vapplication/rar -p388 -sVras -p389 -Vimage/x-cmu-raster -p390 -sVanx -p391 -Vapplication/annodex -p392 -sV7z -p393 -Vapplication/x-7z-compressed -p394 -sVshtml -p395 -g66 -sVlin -p396 -Vapplication/bbolin -p397 -sVmid -p398 -g323 -sVmif -p399 -Vapplication/x-mif -p400 -sV323 -p401 -Vtext/h323 -p402 -sVistr -p403 -g331 -sVcsml -p404 -g187 -sVogv -p405 -Vvideo/ogg -p406 -sVzmt -p407 -g185 -sVkar -p408 -g323 -sVmpeg -p409 -g40 -sVsisx -p410 -Vx-epoc/x-sisx-app -p411 -sVpyo -p412 -Vapplication/x-python-code -p413 -sVfch -p414 -g36 -sVpyc -p415 -g413 -sVawb -p416 -Vaudio/amr-wb -p417 -sVcc -p418 -g319 -sVfbdoc -p419 -g109 -sVlatex -p420 -Vapplication/x-latex -p421 -sVexe -p422 -Vapplication/x-msdos-program -p423 -sVaxv -p424 -Vvideo/annodex -p425 -sVdoc -p426 -Vapplication/msword -p427 -sVwmlsc -p428 -Vapplication/vnd.wap.wmlscriptc -p429 -sVhh -p430 -Vtext/x-c++hdr -p431 -sVaxa -p432 -Vaudio/annodex -p433 -sVdot -p434 -g427 -sVcdf -p435 -Vapplication/x-cdf -p436 -sVrtf -p437 -Vapplication/rtf -p438 -sVctab -p439 -g42 -sVcda -p440 -g436 -sVtext -p441 -g96 -sVsdc -p442 -Vapplication/vnd.stardivision.calc -p443 -sVcdt -p444 -Vimage/x-coreldrawtemplate -p445 -sVtexi -p446 -Vapplication/x-texinfo -p447 -sVcdr -p448 -Vimage/x-coreldraw -p449 -sVcdx -p450 -Vchemical/x-cdx -p451 -sVcdy -p452 -Vapplication/vnd.cinderella -p453 -sVxml -p454 -Vapplication/xml -p455 -sVksp -p456 -Vapplication/x-kspread -p457 -sVcache -p458 -g163 -sVjar -p459 -Vapplication/java-archive -p460 -sVjam -p461 -Vapplication/x-jam -p462 -sVjad -p463 -Vtext/vnd.sun.j2me.app-descriptor -p464 -sVief -p465 -Vimage/ief -p466 -sVdl -p467 -Vvideo/dl -p468 -sVcpio -p469 -Vapplication/x-cpio -p470 -sVdx -p471 -g157 -sVdv -p472 -g52 -sVgen -p473 -Vchemical/x-genbank -p474 -sVhin -p475 -Vchemical/x-hin -p476 -sVsilo -p477 -g129 -sVshp -p478 -g249 -sVbat -p479 -g423 -sVqt -p480 -Vvideo/quicktime -p481 -sVcrt -p482 -Vapplication/x-x509-ca-cert -p483 -sVemb -p484 -Vchemical/x-embl-dl-nucleotide -p485 -sVshx -p486 -g249 -sVeml -p487 -Vmessage/rfc822 -p488 -sVc++ -p489 -g319 -sVpatch -p490 -Vtext/x-diff -p491 -sVbak -p492 -g203 -sVcrl -p493 -Vapplication/x-pkcs7-crl -p494 -sVespi -p495 -g123 -sVart -p496 -Vimage/x-jg -p497 -sVser -p498 -Vapplication/java-serialized-object -p499 -sVframe -p500 -g109 -sVsti -p501 -Vapplication/vnd.sun.xml.impress.template -p502 -sVqtl -p503 -Vapplication/x-quicktimeplayer -p504 -sVmovie -p505 -Vvideo/x-sgi-movie -p506 -sVdll -p507 -g423 -sVwm -p508 -Vvideo/x-ms-wm -p509 -sVwk -p510 -Vapplication/x-123 -p511 -sVjs -p512 -Vapplication/javascript -p513 -sVkey -p514 -Vapplication/pgp-keys -p515 -sVsv4crc -p516 -Vapplication/x-sv4crc -p517 -sVpcap -p518 -g151 -sVwz -p519 -Vapplication/x-wingz -p520 -sVvrm -p521 -g247 -sVc -p522 -Vtext/x-csrc -p523 -sVetx -p524 -Vtext/x-setext -p525 -sVsty -p526 -g72 -sVcod -p527 -Vapplication/vnd.rim.cod -p528 -sVpdf -p529 -Vapplication/pdf -p530 -sVcom -p531 -g423 -sVpdb -p532 -g199 -sVxspf -p533 -Vapplication/xspf+xml -p534 -sVroff -p535 -g25 -sVtgz -p536 -g179 -sVpot -p537 -g96 -sVtgf -p538 -Vchemical/x-mdl-tgf -p539 -sVkwt -p540 -Vapplication/x-kword -p541 -sVcxf -p542 -Vchemical/x-cxf -p543 -sVsxd -p544 -Vapplication/vnd.sun.xml.draw -p545 -sVrpm -p546 -Vapplication/x-redhat-package-manager -p547 -sVcu -p548 -Vapplication/cu-seeme -p549 -sVjnlp -p550 -Vapplication/x-java-jnlp-file -p551 -sVps -p552 -g123 -sVmpga -p553 -g8 -sViges -p554 -Vmodel/iges -p555 -sVpy -p556 -Vtext/x-python -p557 -sVfrm -p558 -g109 -sVswf -p559 -g329 -sVpk -p560 -Vapplication/x-tex-pk -p561 -sVpl -p562 -Vtext/x-perl -p563 -sVpm -p564 -g563 -sVoth -p565 -Vapplication/vnd.oasis.opendocument.text-web -p566 -sVmcm -p567 -Vchemical/x-macmolecule -p568 -sVlyx -p569 -Vapplication/x-lyx -p570 -sVgau -p571 -Vchemical/x-gaussian-input -p572 -sVotg -p573 -Vapplication/vnd.oasis.opendocument.graphics-template -p574 -sVgam -p575 -Vchemical/x-gamess-input -p576 -sVgal -p577 -Vchemical/x-gaussian-log -p578 -sVotp -p579 -Vapplication/vnd.oasis.opendocument.presentation-template -p580 -sVots -p581 -Vapplication/vnd.oasis.opendocument.spreadsheet-template -p582 -sVott -p583 -Vapplication/vnd.oasis.opendocument.text-template -p584 -sVmopcrt -p585 -g185 -sVhdf -p586 -Vapplication/x-hdf -p587 -sVatomsrv -p588 -Vapplication/atomserv+xml -p589 -sVaif -p590 -Vaudio/x-aiff -p591 -sV~ -p592 -g203 -sVsvgz -p593 -Vimage/svg+xml -p594 -sVcef -p595 -g543 -sVwp5 -p596 -Vapplication/vnd.wordperfect5.1 -p597 -sVjpe -p598 -g236 -sVjpg -p599 -g236 -sVsitx -p600 -g195 -sVavi -p601 -Vvideo/x-msvideo -p602 -sVtexinfo -p603 -g447 -sVshar -p604 -Vapplication/x-shar -p605 -sVpas -p606 -g54 -sVpat -p607 -Vimage/x-coreldrawpattern -p608 -sVpac -p609 -g264 -sVhxx -p610 -g431 -sV3gp -p611 -Vvideo/3gpp -p612 -sVkin -p613 -Vchemical/x-kinemage -p614 -sVkil -p615 -Vapplication/x-killustrator -p616 -sVwpd -p617 -Vapplication/vnd.wordperfect -p618 -sVigs -p619 -g555 -sVphp -p620 -g349 -sVpht -p621 -g349 -sVgamin -p622 -g576 -sVwmls -p623 -Vtext/vnd.wap.wmlscript -p624 -sVeps -p625 -g123 -sVgsf -p626 -g135 -sVwmlc -p627 -Vapplication/vnd.wap.wmlc -p628 -sVgsm -p629 -Vaudio/x-gsm -p630 -sVhpp -p631 -g431 -sVaiff -p632 -g591 -sVdavmount -p633 -Vapplication/davmount+xml -p634 -sVaifc -p635 -g591 -sVtcl -p636 -g30 -sVbcpio -p637 -Vapplication/x-bcpio -p638 -sVkwd -p639 -g541 -sVskt -p640 -Vapplication/x-koan -p641 -sVskp -p642 -g641 -sVskd -p643 -g641 -sVrgb -p644 -Vimage/x-rgb -p645 -sVcub -p646 -Vchemical/x-gaussian-cube -p647 -sVskm -p648 -g641 -sVm4a -p649 -g8 -sVbin -p650 -Vapplication/octet-stream -p651 -sVembl -p652 -g485 -sVmop -p653 -g185 -sVbib -p654 -Vtext/x-bibtex -p655 -sVmov -p656 -g481 -sVpsd -p657 -Vimage/x-photoshop -p658 -sVmoo -p659 -Vchemical/x-mopac-out -p660 -sVmol -p661 -Vchemical/x-mdl-molfile -p662 -sVmoc -p663 -Vtext/x-moc -p664 -sVamr -p665 -Vaudio/amr -p666 -sVustar -p667 -Vapplication/x-ustar -p668 -sVd -p669 -Vtext/x-dsrc -p670 -sVt -p671 -g25 -sVxsd -p672 -g455 -sVgjf -p673 -g572 -sVvrml -p674 -g247 -sVgjc -p675 -g572 -sVxsl -p676 -g455 -sVold -p677 -g203 -sVvsd -p678 -Vapplication/vnd.visio -p679 -sVdiff -p680 -g491 -sVudeb -p681 -g167 -sVico -p682 -Vimage/x-icon -p683 -sVscala -p684 -Vtext/x-scala -p685 -sVica -p686 -Vapplication/x-ica -p687 -sVkml -p688 -Vapplication/vnd.google-earth.kml+xml -p689 -sVice -p690 -Vx-conference/x-cooltalk -p691 -sVicz -p692 -Vtext/calendar -p693 -sVics -p694 -g693 -sVxtel -p695 -Vchemical/x-xtel -p696 -sVkmz -p697 -Vapplication/vnd.google-earth.kmz -p698 -sVpls -p699 -Vaudio/x-scpls -p700 -sVmmod -p701 -g311 -sVjava -p702 -Vtext/x-java -p703 -sVdcr -p704 -g58 -sVsrc -p705 -Vapplication/x-wais-source -p706 -sVo -p707 -Vapplication/x-object -p708 -sVsd2 -p709 -Vaudio/x-sd2 -p710 -sVtiff -p711 -Vimage/tiff -p712 -sVxyz -p713 -Vchemical/x-xyz -p714 -sVppm -p715 -Vimage/x-portable-pixmap -p716 -sVpps -p717 -Vapplication/vnd.ms-powerpoint -p718 -sVbsd -p719 -Vchemical/x-crossfire -p720 -sVppt -p721 -g718 -sVdjvu -p722 -g245 -sVxpi -p723 -Vapplication/x-xpinstall -p724 -sVval -p725 -g315 -sVwad -p726 -Vapplication/x-doom -p727 -sVclass -p728 -Vapplication/java-vm -p729 -sVgif -p730 -Vimage/gif -p731 -sVsmil -p732 -g45 -sVwav -p733 -Vaudio/x-wav -p734 -sVrhtml -p735 -Vapplication/x-httpd-eruby -p736 -sVsdw -p737 -Vapplication/vnd.stardivision.writer -p738 -sVsds -p739 -Vapplication/vnd.stardivision.chart -p740 -sVhs -p741 -Vtext/x-haskell -p742 -sVsdd -p743 -Vapplication/vnd.stardivision.impress -p744 -sVsdf -p745 -g230 -sVsda -p746 -Vapplication/vnd.stardivision.draw -p747 -sVatom -p748 -Vapplication/atom+xml -p749 -sVsv4cpio -p750 -Vapplication/x-sv4cpio -p751 -sVinfo -p752 -Vapplication/x-info -p753 -sVcif -p754 -Vchemical/x-cif -p755 -sVdmg -p756 -Vapplication/x-apple-diskimage -p757 -sVdms -p758 -Vapplication/x-dms -p759 -sVsvg -p760 -g594 -sVxwd -p761 -Vimage/x-xwindowdump -p762 -sVpfa -p763 -g135 -sVsxc -p764 -Vapplication/vnd.sun.xml.calc -p765 -sVp7r -p766 -Vapplication/x-pkcs7-certreqresp -p767 -sVsxg -p768 -Vapplication/vnd.sun.xml.writer.global -p769 -sVai -p770 -g123 -sVsxi -p771 -Vapplication/vnd.sun.xml.impress -p772 -sVinp -p773 -g576 -sVsxm -p774 -Vapplication/vnd.sun.xml.math -p775 -sVins -p776 -g327 -sVcbr -p777 -Vapplication/x-cbr -p778 -sVau -p779 -g212 -sVsxw -p780 -Vapplication/vnd.sun.xml.writer -p781 -sVcbz -p782 -Vapplication/x-cbz -p783 -sV% -p784 -g203 -sVnb -p785 -g68 -sVnc -p786 -Vapplication/x-netcdf -p787 -sVbook -p788 -g109 -sVphp4 -p789 -Vapplication/x-httpd-php4 -p790 -sVtif -p791 -g712 -sVphp3 -p792 -Vapplication/x-httpd-php3 -p793 -sVmol2 -p794 -Vchemical/x-mol2 -p795 -sVh++ -p796 -g431 -sVdvi -p797 -Vapplication/x-dvi -p798 -sVpcf.Z -p799 -g135 -sVrxn -p800 -Vchemical/x-mdl-rxnfile -p801 -sVcpa -p802 -Vchemical/x-compass -p803 -sVbmp -p804 -Vimage/x-ms-bmp -p805 -sVxbm -p806 -Vimage/x-xbitmap -p807 -sVcpp -p808 -g319 -sVcpt -p809 -Vimage/x-corelphotopaint -p810 -sVphps -p811 -Vapplication/x-httpd-php-source -p812 -s. \ No newline at end of file diff --git a/ranger/data/mime.types b/ranger/data/mime.types index 866db2c2..c8fa5243 100644 --- a/ranger/data/mime.types +++ b/ranger/data/mime.types @@ -2,768 +2,19 @@ # # MIME-TYPES and the extensions that represent them # -# This file is part of the "mime-support" package. Please send email (not a -# bug report) to mime-support@packages.debian.org if you would like new types -# and/or extensions to be added. -# -# The reason that all types are managed by the mime-support package instead -# allowing individual packages to install types in much the same way as they -# add entries in to the mailcap file is so these types can be referenced by -# other programs (such as a web server) even if the specific support package -# for that type is not installed. -# -# Users can add their own types if they wish by creating a ".mime.types" -# file in their home directory. Definitions included there will take -# precedence over those listed here. -# -# Note: Compression schemes like "gzip", "bzip", and "compress" are not -# actually "mime-types". They are "encodings" and hence must _not_ have -# entries in this file to map their extensions. The "mime-type" of an -# encoded file refers to the type of data that has been encoded, not the -# type of encoding. +# This file contains additional mimetypes which I think ranger should have +# by default. You can also use ~/.mime.types to add own types. # +# Mimetypes are used for colorschemes and the builtin filetype detection +# to execute files with the right program. +# ############################################################################### - -application/activemessage -application/andrew-inset ez -application/annodex anx -application/applefile -application/atom+xml atom -application/atomcat+xml atomcat -application/atomserv+xml atomsrv -application/atomicmail -application/batch-SMTP -application/beep+xml -application/bbolin lin -application/cals-1840 -application/cap cap pcap -application/commonground -application/cu-seeme cu -application/cybercash -application/davmount+xml davmount -application/dca-rft -application/dec-dx -application/docbook+xml -application/dsptype tsp -application/dvcs -application/ecmascript es -application/edi-consent -application/edi-x12 -application/edifact -application/eshop -application/font-tdpfr -application/futuresplash spl -application/ghostview -application/hta hta -application/http -application/hyperstudio -application/iges -application/index -application/index.cmd -application/index.obj -application/index.response -application/index.vnd -application/iotp -application/ipp -application/isup -application/java-archive jar -application/java-serialized-object ser -application/java-vm class -application/javascript js -application/m3g m3g -application/mac-binhex40 hqx -application/mac-compactpro cpt -application/macwriteii -application/marc -application/mathematica nb nbp -application/ms-tnef -application/msaccess mdb -application/msword doc dot -application/news-message-id -application/news-transmission -application/ocsp-request -application/ocsp-response -application/octet-stream bin -application/oda oda -application/ogg ogx -application/parityfec -application/pdf pdf -application/pgp-encrypted -application/pgp-keys key -application/pgp-signature pgp -application/pics-rules prf -application/pkcs10 -application/pkcs7-mime -application/pkcs7-signature -application/pkix-cert -application/pkix-crl -application/pkixcmp -application/postscript ps ai eps espi epsf eps2 eps3 -application/prs.alvestrand.titrax-sheet -application/prs.cww -application/prs.nprend -application/qsig -application/rar rar -application/rdf+xml rdf -application/remote-printing -application/riscos -application/rss+xml rss -application/rtf rtf -application/sdp -application/set-payment -application/set-payment-initiation -application/set-registration -application/set-registration-initiation -application/sgml -application/sgml-open-catalog -application/sieve -application/slate -application/smil smi smil -application/timestamp-query -application/timestamp-reply -application/vemmi -application/whoispp-query -application/whoispp-response -application/wita -application/x400-bp -application/xhtml+xml xhtml xht -application/xml xml xsl xsd -application/xml-dtd -application/xml-external-parsed-entity -application/xspf+xml xspf -application/zip zip -application/vnd.3M.Post-it-Notes -application/vnd.accpac.simply.aso -application/vnd.accpac.simply.imp -application/vnd.acucobol -application/vnd.aether.imp -application/vnd.anser-web-certificate-issue-initiation -application/vnd.anser-web-funds-transfer-initiation -application/vnd.audiograph -application/vnd.bmi -application/vnd.businessobjects -application/vnd.canon-cpdl -application/vnd.canon-lips -application/vnd.cinderella cdy -application/vnd.claymore -application/vnd.commerce-battelle -application/vnd.commonspace -application/vnd.comsocaller -application/vnd.contact.cmsg -application/vnd.cosmocaller -application/vnd.ctc-posml -application/vnd.cups-postscript -application/vnd.cups-raster -application/vnd.cups-raw -application/vnd.cybank -application/vnd.dna -application/vnd.dpgraph -application/vnd.dxr -application/vnd.ecdis-update -application/vnd.ecowin.chart -application/vnd.ecowin.filerequest -application/vnd.ecowin.fileupdate -application/vnd.ecowin.series -application/vnd.ecowin.seriesrequest -application/vnd.ecowin.seriesupdate -application/vnd.enliven -application/vnd.epson.esf -application/vnd.epson.msf -application/vnd.epson.quickanime -application/vnd.epson.salt -application/vnd.epson.ssf -application/vnd.ericsson.quickcall -application/vnd.eudora.data -application/vnd.fdf -application/vnd.ffsns -application/vnd.flographit -application/vnd.framemaker -application/vnd.fsc.weblaunch -application/vnd.fujitsu.oasys -application/vnd.fujitsu.oasys2 -application/vnd.fujitsu.oasys3 -application/vnd.fujitsu.oasysgp -application/vnd.fujitsu.oasysprs -application/vnd.fujixerox.ddd -application/vnd.fujixerox.docuworks -application/vnd.fujixerox.docuworks.binder -application/vnd.fut-misnet -application/vnd.google-earth.kml+xml kml -application/vnd.google-earth.kmz kmz -application/vnd.grafeq -application/vnd.groove-account -application/vnd.groove-identity-message -application/vnd.groove-injector -application/vnd.groove-tool-message -application/vnd.groove-tool-template -application/vnd.groove-vcard -application/vnd.hhe.lesson-player -application/vnd.hp-HPGL -application/vnd.hp-PCL -application/vnd.hp-PCLXL -application/vnd.hp-hpid -application/vnd.hp-hps -application/vnd.httphone -application/vnd.hzn-3d-crossword -application/vnd.ibm.MiniPay -application/vnd.ibm.afplinedata -application/vnd.ibm.modcap -application/vnd.informix-visionary -application/vnd.intercon.formnet -application/vnd.intertrust.digibox -application/vnd.intertrust.nncp -application/vnd.intu.qbo -application/vnd.intu.qfx -application/vnd.irepository.package+xml -application/vnd.is-xpr -application/vnd.japannet-directory-service -application/vnd.japannet-jpnstore-wakeup -application/vnd.japannet-payment-wakeup -application/vnd.japannet-registration -application/vnd.japannet-registration-wakeup -application/vnd.japannet-setstore-wakeup -application/vnd.japannet-verification -application/vnd.japannet-verification-wakeup -application/vnd.koan -application/vnd.lotus-1-2-3 -application/vnd.lotus-approach -application/vnd.lotus-freelance -application/vnd.lotus-notes -application/vnd.lotus-organizer -application/vnd.lotus-screencam -application/vnd.lotus-wordpro -application/vnd.mcd -application/vnd.mediastation.cdkey -application/vnd.meridian-slingshot -application/vnd.mif -application/vnd.minisoft-hp3000-save -application/vnd.mitsubishi.misty-guard.trustweb -application/vnd.mobius.daf -application/vnd.mobius.dis -application/vnd.mobius.msl -application/vnd.mobius.plc -application/vnd.mobius.txf -application/vnd.motorola.flexsuite -application/vnd.motorola.flexsuite.adsi -application/vnd.motorola.flexsuite.fis -application/vnd.motorola.flexsuite.gotap -application/vnd.motorola.flexsuite.kmr -application/vnd.motorola.flexsuite.ttc -application/vnd.motorola.flexsuite.wem -application/vnd.mozilla.xul+xml xul -application/vnd.ms-artgalry -application/vnd.ms-asf -application/vnd.ms-excel xls xlb xlt -application/vnd.ms-lrm -application/vnd.ms-pki.seccat cat -application/vnd.ms-pki.stl stl -application/vnd.ms-powerpoint ppt pps -application/vnd.ms-project -application/vnd.ms-tnef -application/vnd.ms-works -application/vnd.mseq -application/vnd.msign -application/vnd.music-niff -application/vnd.musician -application/vnd.netfpx -application/vnd.noblenet-directory -application/vnd.noblenet-sealer -application/vnd.noblenet-web -application/vnd.novadigm.EDM -application/vnd.novadigm.EDX -application/vnd.novadigm.EXT -application/vnd.oasis.opendocument.chart odc -application/vnd.oasis.opendocument.database odb -application/vnd.oasis.opendocument.formula odf -application/vnd.oasis.opendocument.graphics odg -application/vnd.oasis.opendocument.graphics-template otg -application/vnd.oasis.opendocument.image odi -application/vnd.oasis.opendocument.presentation odp -application/vnd.oasis.opendocument.presentation-template otp -application/vnd.oasis.opendocument.spreadsheet ods -application/vnd.oasis.opendocument.spreadsheet-template ots -application/vnd.oasis.opendocument.text odt -application/vnd.oasis.opendocument.text-master odm -application/vnd.oasis.opendocument.text-template ott -application/vnd.oasis.opendocument.text-web oth -application/vnd.osa.netdeploy -application/vnd.palm -application/vnd.pg.format -application/vnd.pg.osasli -application/vnd.powerbuilder6 -application/vnd.powerbuilder6-s -application/vnd.powerbuilder7 -application/vnd.powerbuilder7-s -application/vnd.powerbuilder75 -application/vnd.powerbuilder75-s -application/vnd.previewsystems.box -application/vnd.publishare-delta-tree -application/vnd.pvi.ptid1 -application/vnd.pwg-xhtml-print+xml -application/vnd.rapid -application/vnd.rim.cod cod -application/vnd.s3sms -application/vnd.seemail -application/vnd.shana.informed.formdata -application/vnd.shana.informed.formtemplate -application/vnd.shana.informed.interchange -application/vnd.shana.informed.package -application/vnd.smaf mmf -application/vnd.sss-cod -application/vnd.sss-dtf -application/vnd.sss-ntf -application/vnd.stardivision.calc sdc -application/vnd.stardivision.chart sds -application/vnd.stardivision.draw sda -application/vnd.stardivision.impress sdd -application/vnd.stardivision.math sdf -application/vnd.stardivision.writer sdw -application/vnd.stardivision.writer-global sgl -application/vnd.street-stream -application/vnd.sun.xml.calc sxc -application/vnd.sun.xml.calc.template stc -application/vnd.sun.xml.draw sxd -application/vnd.sun.xml.draw.template std -application/vnd.sun.xml.impress sxi -application/vnd.sun.xml.impress.template sti -application/vnd.sun.xml.math sxm -application/vnd.sun.xml.writer sxw -application/vnd.sun.xml.writer.global sxg -application/vnd.sun.xml.writer.template stw -application/vnd.svd -application/vnd.swiftview-ics -application/vnd.symbian.install sis -application/vnd.triscape.mxs -application/vnd.trueapp -application/vnd.truedoc -application/vnd.tve-trigger -application/vnd.ufdl -application/vnd.uplanet.alert -application/vnd.uplanet.alert-wbxml -application/vnd.uplanet.bearer-choice -application/vnd.uplanet.bearer-choice-wbxml -application/vnd.uplanet.cacheop -application/vnd.uplanet.cacheop-wbxml -application/vnd.uplanet.channel -application/vnd.uplanet.channel-wbxml -application/vnd.uplanet.list -application/vnd.uplanet.list-wbxml -application/vnd.uplanet.listcmd -application/vnd.uplanet.listcmd-wbxml -application/vnd.uplanet.signal -application/vnd.vcx -application/vnd.vectorworks -application/vnd.vidsoft.vidconference -application/vnd.visio vsd -application/vnd.vividence.scriptfile -application/vnd.wap.sic -application/vnd.wap.slc -application/vnd.wap.wbxml wbxml -application/vnd.wap.wmlc wmlc -application/vnd.wap.wmlscriptc wmlsc -application/vnd.webturbo -application/vnd.wordperfect wpd -application/vnd.wordperfect5.1 wp5 -application/vnd.wrq-hp3000-labelled -application/vnd.wt.stf -application/vnd.xara -application/vnd.xfdl -application/vnd.yellowriver-custom-menu -application/x-123 wk -application/x-7z-compressed 7z -application/x-abiword abw -application/x-apple-diskimage dmg -application/x-bcpio bcpio -application/x-bittorrent torrent -application/x-cab cab -application/x-cbr cbr -application/x-cbz cbz -application/x-cdf cdf cda -application/x-cdlink vcd -application/x-chess-pgn pgn -application/x-core -application/x-cpio cpio -application/x-csh csh -application/x-debian-package deb udeb -application/x-director dcr dir dxr -application/x-dms dms -application/x-doom wad -application/x-dvi dvi -application/x-httpd-eruby rhtml -application/x-executable -application/x-font pfa pfb gsf pcf pcf.Z -application/x-freemind mm -application/x-futuresplash spl -application/x-gnumeric gnumeric -application/x-go-sgf sgf -application/x-graphing-calculator gcf -application/x-gtar gtar tgz taz -application/x-hdf hdf -application/x-httpd-php phtml pht php -application/x-httpd-php-source phps -application/x-httpd-php3 php3 -application/x-httpd-php3-preprocessed php3p -application/x-httpd-php4 php4 -application/x-ica ica -application/x-info info -application/x-internet-signup ins isp -application/x-iphone iii -application/x-iso9660-image iso -application/x-jam jam -application/x-java-applet -application/x-java-bean -application/x-java-jnlp-file jnlp -application/x-jmol jmz -application/x-kchart chrt -application/x-kdelnk -application/x-killustrator kil -application/x-koan skp skd skt skm -application/x-kpresenter kpr kpt -application/x-kspread ksp -application/x-kword kwd kwt -application/x-latex latex -application/x-lha lha -application/x-lyx lyx -application/x-lzh lzh -application/x-lzx lzx -application/x-maker frm maker frame fm fb book fbdoc -application/x-mif mif -application/x-ms-wmd wmd -application/x-ms-wmz wmz -application/x-msdos-program com exe bat dll -application/x-msi msi -application/x-netcdf nc -application/x-ns-proxy-autoconfig pac dat -application/x-nwc nwc -application/x-object o -application/x-oz-application oza -application/x-pkcs7-certreqresp p7r -application/x-pkcs7-crl crl -application/x-python-code pyc pyo -application/x-qgis qgs shp shx -application/x-quicktimeplayer qtl -application/x-redhat-package-manager rpm -application/x-ruby rb -application/x-rx -application/x-sh sh -application/x-shar shar -application/x-shellscript -application/x-shockwave-flash swf swfl -application/x-stuffit sit sitx -application/x-sv4cpio sv4cpio -application/x-sv4crc sv4crc -application/x-tar tar -application/x-tcl tcl -application/x-tex-gf gf -application/x-tex-pk pk -application/x-texinfo texinfo texi -application/x-trash ~ % bak old sik -application/x-troff t tr roff -application/x-troff-man man -application/x-troff-me me -application/x-troff-ms ms -application/x-ustar ustar -application/x-videolan -application/x-wais-source src -application/x-wingz wz -application/x-x509-ca-cert crt -application/x-xcf xcf -application/x-xfig fig -application/x-xpinstall xpi - -audio/32kadpcm -audio/3gpp -audio/amr amr -audio/amr-wb awb -audio/amr amr -audio/amr-wb awb -audio/annodex axa -audio/basic au snd audio/flac flac -audio/g.722.1 -audio/l16 -audio/midi mid midi kar -audio/mp4a-latm -audio/mpa-robust -audio/mpeg mpga mpega mp2 mp3 m4a -audio/mpegurl m3u +audio/musepack mpc mpp mp+ audio/ogg oga ogg spx -audio/parityfec -audio/prs.sid sid -audio/telephone-event -audio/tone -audio/vnd.cisco.nse -audio/vnd.cns.anp1 -audio/vnd.cns.inf1 -audio/vnd.digital-winds -audio/vnd.everad.plj -audio/vnd.lucent.voice -audio/vnd.nortel.vbk -audio/vnd.nuera.ecelp4800 -audio/vnd.nuera.ecelp7470 -audio/vnd.nuera.ecelp9600 -audio/vnd.octel.sbc -audio/vnd.qcelp -audio/vnd.rhetorex.32kadpcm -audio/vnd.vmx.cvsd -audio/x-aiff aif aiff aifc -audio/x-gsm gsm -audio/x-mpegurl m3u -audio/x-ms-wma wma -audio/x-ms-wax wax -audio/x-pn-realaudio-plugin -audio/x-pn-realaudio ra rm ram -audio/x-realaudio ra -audio/x-scpls pls -audio/x-sd2 sd2 -audio/x-wav wav - -chemical/x-alchemy alc -chemical/x-cache cac cache -chemical/x-cache-csf csf -chemical/x-cactvs-binary cbin cascii ctab -chemical/x-cdx cdx -chemical/x-cerius cer -chemical/x-chem3d c3d -chemical/x-chemdraw chm -chemical/x-cif cif -chemical/x-cmdf cmdf -chemical/x-cml cml -chemical/x-compass cpa -chemical/x-crossfire bsd -chemical/x-csml csml csm -chemical/x-ctx ctx -chemical/x-cxf cxf cef -#chemical/x-daylight-smiles smi -chemical/x-embl-dl-nucleotide emb embl -chemical/x-galactic-spc spc -chemical/x-gamess-input inp gam gamin -chemical/x-gaussian-checkpoint fch fchk -chemical/x-gaussian-cube cub -chemical/x-gaussian-input gau gjc gjf -chemical/x-gaussian-log gal -chemical/x-gcg8-sequence gcg -chemical/x-genbank gen -chemical/x-hin hin -chemical/x-isostar istr ist -chemical/x-jcamp-dx jdx dx -chemical/x-kinemage kin -chemical/x-macmolecule mcm -chemical/x-macromodel-input mmd mmod -chemical/x-mdl-molfile mol -chemical/x-mdl-rdfile rd -chemical/x-mdl-rxnfile rxn -chemical/x-mdl-sdfile sd sdf -chemical/x-mdl-tgf tgf -#chemical/x-mif mif -chemical/x-mmcif mcif -chemical/x-mol2 mol2 -chemical/x-molconn-Z b -chemical/x-mopac-graph gpt -chemical/x-mopac-input mop mopcrt mpc zmt -chemical/x-mopac-out moo -chemical/x-mopac-vib mvb -chemical/x-ncbi-asn1 asn -chemical/x-ncbi-asn1-ascii prt ent -chemical/x-ncbi-asn1-binary val aso -chemical/x-ncbi-asn1-spec asn -chemical/x-pdb pdb ent -chemical/x-rosdal ros -chemical/x-swissprot sw -chemical/x-vamas-iso14976 vms -chemical/x-vmd vmd -chemical/x-xtel xtel -chemical/x-xyz xyz - -image/cgm -image/g3fax -image/gif gif -image/ief ief -image/jpeg jpeg jpg jpe -image/naplps -image/pcx pcx -image/png png -image/prs.btif -image/prs.pti -image/svg+xml svg svgz -image/tiff tiff tif -image/vnd.cns.inf2 -image/vnd.djvu djvu djv -image/vnd.dwg -image/vnd.dxf -image/vnd.fastbidsheet -image/vnd.fpx -image/vnd.fst -image/vnd.fujixerox.edmics-mmr -image/vnd.fujixerox.edmics-rlc -image/vnd.mix -image/vnd.net-fpx -image/vnd.svf -image/vnd.wap.wbmp wbmp -image/vnd.xiff -image/x-cmu-raster ras -image/x-coreldraw cdr -image/x-coreldrawpattern pat -image/x-coreldrawtemplate cdt -image/x-corelphotopaint cpt -image/x-icon ico -image/x-jg art -image/x-jng jng -image/x-ms-bmp bmp -image/x-photoshop psd -image/x-portable-anymap pnm -image/x-portable-bitmap pbm -image/x-portable-graymap pgm -image/x-portable-pixmap ppm -image/x-rgb rgb -image/x-xbitmap xbm -image/x-xpixmap xpm -image/x-xwindowdump xwd -inode/chardevice -inode/blockdevice -inode/directory-locked -inode/directory -inode/fifo -inode/socket - -message/delivery-status -message/disposition-notification -message/external-body -message/http -message/s-http -message/news -message/partial -message/rfc822 eml - -model/iges igs iges -model/mesh msh mesh silo -model/vnd.dwf -model/vnd.flatland.3dml -model/vnd.gdl -model/vnd.gs-gdl -model/vnd.gtw -model/vnd.mts -model/vnd.vtu -model/vrml wrl vrml - -multipart/alternative -multipart/appledouble -multipart/byteranges -multipart/digest -multipart/encrypted -multipart/form-data -multipart/header-set -multipart/mixed -multipart/parallel -multipart/related -multipart/report -multipart/signed -multipart/voice-message - -text/calendar ics icz -text/css css -text/csv csv -text/directory -text/english -text/enriched -text/h323 323 -text/html html htm shtml -text/iuls uls -text/mathml mml -text/parityfec -text/plain asc txt text pot brf -text/prs.lines.tag -text/rfc822-headers -text/richtext rtx -text/rtf -text/scriptlet sct wsc -text/t140 -text/texmacs tm ts -text/tab-separated-values tsv -text/uri-list -text/vnd.abc -text/vnd.curl -text/vnd.DMClientScript -text/vnd.flatland.3dml -text/vnd.fly -text/vnd.fmi.flexstor -text/vnd.in3d.3dml -text/vnd.in3d.spot -text/vnd.IPTC.NewsML -text/vnd.IPTC.NITF -text/vnd.latex-z -text/vnd.motorola.reflex -text/vnd.ms-mediapackage -text/vnd.sun.j2me.app-descriptor jad -text/vnd.wap.si -text/vnd.wap.sl -text/vnd.wap.wml wml -text/vnd.wap.wmlscript wmls -text/x-bibtex bib -text/x-boo boo -text/x-c++hdr h++ hpp hxx hh -text/x-c++src c++ cpp cxx cc -text/x-chdr h -text/x-component htc -text/x-crontab -text/x-csh csh -text/x-csrc c -text/x-dsrc d -text/x-diff diff patch -text/x-haskell hs -text/x-java java -text/x-literate-haskell lhs -text/x-makefile -text/x-moc moc -text/x-pascal p pas -text/x-pcs-gcd gcd -text/x-perl pl pm -text/x-python py -text/x-scala scala -text/x-server-parsed-html -text/x-setext etx -text/x-sh sh -text/x-tcl tcl tk -text/x-tex tex ltx sty cls -text/x-vcalendar vcs -text/x-vcard vcf - -video/3gpp 3gp -video/annodex axv -video/dl dl -video/dv dif dv -video/fli fli -video/gl gl -video/mpeg mpeg mpg mpe video/mkv mkv -video/mp4 mp4 -video/quicktime qt mov -video/mp4v-es -video/ogg ogv -video/parityfec -video/pointer -video/vnd.fvt -video/vnd.motorola.video -video/vnd.motorola.videop -video/vnd.mpegurl mxu -video/vnd.mts -video/vnd.nokia.interleaved-multimedia -video/vnd.vivo -video/x-flv flv -video/x-la-asf lsf lsx -video/x-mng mng -video/x-ms-asf asf asx -video/x-ms-wm wm -video/x-ms-wmv wmv -video/x-ms-wmx wmx -video/x-ms-wvx wvx -video/x-msvideo avi -video/x-sgi-movie movie -video/x-matroska mpv - -x-conference/x-cooltalk ice - -x-epoc/x-sisx-app sisx -x-world/x-vrml vrm vrml wrl +video/flash flv +video/ogg ogv ogm +video/divx div divx diff --git a/ranger/defaults/__init__.py b/ranger/defaults/__init__.py index ee680432..71df3cb3 100644 --- a/ranger/defaults/__init__.py +++ b/ranger/defaults/__init__.py @@ -1,16 +1 @@ -# 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/>. - """Default options and configration files""" diff --git a/ranger/defaults/apps.py b/ranger/defaults/apps.py index a19df7a9..347b9ce2 100644 --- a/ranger/defaults/apps.py +++ b/ranger/defaults/apps.py @@ -59,7 +59,7 @@ class CustomApplications(Applications): if f.extension is not None: if f.extension in ('pdf'): - return self.either(c, 'evince', 'apvlv') + return self.either(c, 'evince', 'zathura', 'apvlv') if f.extension in ('html', 'htm', 'xhtml', 'swf'): return self.either(c, 'firefox', 'opera', 'elinks') if f.extension in ('swc', 'smc'): @@ -78,11 +78,12 @@ class CustomApplications(Applications): return self.either(c, 'mplayer', 'totem') if f.image: - return self.app_feh(c) + return self.either(c, 'feh', 'eye_of_gnome', 'mirage') - if f.document: + if f.document or f.filetype.startswith('text'): return self.app_editor(c) + # ----------------------------------------- application definitions def app_pager(self, c): return tup('less', *c) @@ -127,10 +128,14 @@ class CustomApplications(Applications): else: return tup('mplayer', '-fs', *c) + @depends_on("eog") + def app_eye_of_gnome(self, c): + c.flags += 'd' + return tup('eog', *c) + @depends_on('mirage') def app_mirage(self, c): c.flags += 'd' - return tup('mirage', *c) @depends_on('feh') @@ -142,7 +147,7 @@ class CustomApplications(Applications): if c.mode in arg: return tup('feh', arg[c.mode], c.file.path) if c.mode is 4: - return tup('gimp', *c) + return self.app_gimp(c) if len(c.files) > 1: return tup('feh', *c) @@ -156,6 +161,10 @@ class CustomApplications(Applications): return tup('feh', *deq) + @depends_on("gimp") + def app_gimp(self, c): + return tup('gimp', *c) + @depends_on('aunpack') def app_aunpack(self, c): if c.mode is 0: @@ -211,6 +220,10 @@ class CustomApplications(Applications): def app_evince(self, c): return tup("evince", *c) + @depends_on('zathura') + def app_zathura(self, c): + return tup("zathura", *c) + @depends_on('wine') def app_wine(self, c): return tup("wine", c.file.path) diff --git a/ranger/commands.py b/ranger/defaults/commands.py index ddd8ba07..b1518013 100644 --- a/ranger/commands.py +++ b/ranger/defaults/commands.py @@ -40,7 +40,7 @@ class Command(FileManagerAware): from os.path import dirname, basename, expanduser, join, isdir line = parse(self.line) - pwd = self.fm.env.pwd.path + cwd = self.fm.env.cwd.path try: rel_dest = line.rest(1) @@ -52,7 +52,7 @@ class Command(FileManagerAware): rel_dest = expanduser(rel_dest) # define some shortcuts - abs_dest = join(pwd, rel_dest) + abs_dest = join(cwd, rel_dest) abs_dirname = dirname(abs_dest) rel_basename = basename(rel_dest) rel_dirname = dirname(rel_dest) @@ -89,7 +89,7 @@ class Command(FileManagerAware): from os.path import dirname, basename, expanduser, join, isdir line = parse(self.line) - pwd = self.fm.env.pwd.path + cwd = self.fm.env.cwd.path try: rel_dest = line.rest(1) @@ -101,7 +101,7 @@ class Command(FileManagerAware): rel_dest = expanduser(rel_dest) # define some shortcuts - abs_dest = join(pwd, rel_dest) + abs_dest = join(cwd, rel_dest) abs_dirname = dirname(abs_dest) rel_basename = basename(rel_dest) rel_dirname = dirname(rel_dest) @@ -167,13 +167,13 @@ class cd(Command): def quick_open(self): from os.path import isdir, join, normpath line = parse(self.line) - pwd = self.fm.env.pwd.path + cwd = self.fm.env.cwd.path rel_dest = line.rest(1) if not rel_dest: return False - abs_dest = normpath(join(pwd, rel_dest)) + abs_dest = normpath(join(cwd, rel_dest)) return rel_dest != '.' and isdir(abs_dest) @@ -212,22 +212,22 @@ class find(Command): def _search(self): self.count = 0 line = parse(self.line) - pwd = self.fm.env.pwd + cwd = self.fm.env.cwd try: arg = line.rest(1) except IndexError: return False - deq = deque(pwd.files) - deq.rotate(-pwd.pointer) + deq = deque(cwd.files) + deq.rotate(-cwd.pointer) i = 0 for fsobj in deq: filename = fsobj.basename_lower if arg in filename: self.count += 1 if self.count == 1: - pwd.move(absolute=(pwd.pointer + i) % len(pwd.files)) - self.fm.env.cf = pwd.pointed_obj + cwd.move(absolute=(cwd.pointer + i) % len(cwd.files)) + self.fm.env.cf = cwd.pointed_obj if self.count > 1: return False i += 1 @@ -255,13 +255,36 @@ class delete(Command): "Selection" is defined as all the "marked files" (by default, you can mark files with space or v). If there are no marked files, use the "current file" (where the cursor is) + + When attempting to delete non-empty directories or multiple + marked files, it will require a confirmation: The last word in + the line has to start with a 'y'. This may look like: + :delete yes + :delete seriously? yeah! """ allow_abbrev = False + WARNING = 'delete seriously? ' def execute(self): - self.fm.delete() + line = parse(self.line) + lastword = line.chunk(-1) + + if lastword.startswith('y'): + # user confirmed deletion! + return self.fm.delete() + elif self.line.startswith(delete.WARNING): + # user did not confirm deletion + return + + if self.fm.env.cwd.marked_items \ + or (self.fm.env.cf.is_directory and not self.fm.env.cf.empty()): + # better ask for a confirmation, when attempting to + # delete multiple files or a non-empty directory. + return self.fm.open_console(self.mode, delete.WARNING) + # no need for a confirmation, just delete + self.fm.delete() class mkdir(Command): """ @@ -275,7 +298,7 @@ class mkdir(Command): from os import mkdir line = parse(self.line) - dirname = join(self.fm.env.pwd.path, expanduser(line.rest(1))) + dirname = join(self.fm.env.cwd.path, expanduser(line.rest(1))) if not lexists(dirname): mkdir(dirname) else: @@ -294,7 +317,7 @@ class touch(Command): from os import mkdir line = parse(self.line) - fname = join(self.fm.env.pwd.path, expanduser(line.rest(1))) + fname = join(self.fm.env.cwd.path, expanduser(line.rest(1))) if not lexists(fname): open(fname, 'a') else: @@ -357,9 +380,11 @@ class rename(Command): def execute(self): from ranger.fsobject.file import File line = parse(self.line) + if not line.rest(1): + return self.fm.notify('Syntax: rename <newname>', bad=True) self.fm.rename(self.fm.env.cf, line.rest(1)) f = File(line.rest(1)) - self.fm.env.pwd.pointed_obj = f + self.fm.env.cwd.pointed_obj = f self.fm.env.cf = f def tab(self): @@ -400,7 +425,7 @@ class chmod(Command): try: # reloading directory. maybe its better to reload the selected # files only. - self.fm.env.pwd.load_content() + self.fm.env.cwd.load_content() except: pass @@ -458,7 +483,7 @@ def get_command(name, abbrev=True): or cmd == name] if len(lst) == 0: raise KeyError - if len(lst) == 1: + if len(lst) == 1 or by_name[name] in lst: return lst[0] raise ValueError("Ambiguous command") else: @@ -470,3 +495,5 @@ def get_command(name, abbrev=True): def command_generator(start): return (cmd + ' ' for cmd in by_name if cmd.startswith(start)) +alias(e=edit) # to make :e unambiguous. + diff --git a/ranger/defaults/keys.py b/ranger/defaults/keys.py index 7a17c831..f48c7012 100644 --- a/ranger/defaults/keys.py +++ b/ranger/defaults/keys.py @@ -15,7 +15,7 @@ """ This is the default key configuration file of ranger. -Syntax for binding keys: bind(*keys, fnc) +Syntax for binding keys: map(*keys, fnc) keys are one or more key-combinations which are either: * a string @@ -34,11 +34,13 @@ arg.keybuffer: the keybuffer instance Check ranger.keyapi for more information """ -from ranger.api.keys import * +# NOTE: The "map" object used below is a callable CommandList +# object and NOT the builtin python map function! +from ranger.api.keys import * -def _vimlike_aliases(command_list): - bind, alias = make_abbreviations(command_list) +def _vimlike_aliases(map): + alias = map.alias # the key 'k' will always do the same as KEY_UP, etc. alias(KEY_UP, 'k') @@ -51,76 +53,71 @@ def _vimlike_aliases(command_list): alias(KEY_HOME, 'gg') alias(KEY_END, 'G') - # I like to move quickly with J/K - alias(ctrl('d'), 'J') - alias(ctrl('u'), 'K') - -def initialize_commands(command_list): +def initialize_commands(map): """Initialize the commands for the main user interface""" - bind, alias = make_abbreviations(command_list) - # -------------------------------------------------------- movement - _vimlike_aliases(command_list) - command_list.alias(KEY_LEFT, KEY_BACKSPACE, DEL) + _vimlike_aliases(map) + map.alias(KEY_LEFT, KEY_BACKSPACE, DEL) - bind(KEY_DOWN, fm.move_pointer(relative=1)) - bind(KEY_UP, fm.move_pointer(relative=-1)) - bind(KEY_RIGHT, KEY_ENTER, ctrl('j'), fm.move_right()) - bind(KEY_LEFT, KEY_BACKSPACE, DEL, fm.move_left(1)) - bind(KEY_HOME, fm.move_pointer(absolute=0)) - bind(KEY_END, fm.move_pointer(absolute=-1)) + map(KEY_DOWN, fm.move_pointer(relative=1)) + map(KEY_UP, fm.move_pointer(relative=-1)) + map(KEY_RIGHT, KEY_ENTER, ctrl('j'), fm.move_right()) + map(KEY_LEFT, KEY_BACKSPACE, DEL, fm.move_left(1)) + map(KEY_HOME, fm.move_pointer(absolute=0)) + map(KEY_END, fm.move_pointer(absolute=-1)) - bind(KEY_HOME, fm.move_pointer(absolute=0)) - bind(KEY_END, fm.move_pointer(absolute=-1)) + map(KEY_HOME, fm.move_pointer(absolute=0)) + map(KEY_END, fm.move_pointer(absolute=-1)) - bind('%', fm.move_pointer_by_percentage(absolute=50)) - bind(KEY_NPAGE, fm.move_pointer_by_pages(1)) - bind(KEY_PPAGE, fm.move_pointer_by_pages(-1)) - bind(ctrl('d'), fm.move_pointer_by_pages(0.5)) - bind(ctrl('u'), fm.move_pointer_by_pages(-0.5)) + map('%', fm.move_pointer_by_percentage(absolute=50)) + map(KEY_NPAGE, fm.move_pointer_by_pages(1)) + map(KEY_PPAGE, fm.move_pointer_by_pages(-1)) + map(ctrl('d'), 'J', fm.move_pointer_by_pages(0.5)) + map(ctrl('u'), 'K', fm.move_pointer_by_pages(-0.5)) - bind(']', fm.traverse()) - bind('[', fm.history_go(-1)) + map(']', fm.traverse()) + map('[', fm.history_go(-1)) # --------------------------------------------------------- history - bind('H', fm.history_go(-1)) - bind('L', fm.history_go(1)) + map('H', fm.history_go(-1)) + map('L', fm.history_go(1)) # ----------------------------------------------- tagging / marking - bind('t', fm.tag_toggle()) - bind('T', fm.tag_remove()) + map('t', fm.tag_toggle()) + map('T', fm.tag_remove()) - bind(' ', fm.mark(toggle=True)) - bind('v', fm.mark(all=True, toggle=True)) - bind('V', fm.mark(all=True, val=False)) + map(' ', fm.mark(toggle=True)) + map('v', fm.mark(all=True, toggle=True)) + map('V', fm.mark(all=True, val=False)) # ------------------------------------------ file system operations - bind('yy', fm.copy()) - bind('dd', fm.cut()) - bind('pp', fm.paste()) - bind('po', fm.paste(overwrite=True)) - bind('pl', fm.paste_symlink()) - bind('p', hint='press //p// once again to confirm pasting' \ + map('yy', fm.copy()) + map('dd', fm.cut()) + map('pp', fm.paste()) + map('po', fm.paste(overwrite=True)) + map('pl', fm.paste_symlink()) + map('p', hint='press //p// once again to confirm pasting' \ ', or //l// to create symlinks') # ---------------------------------------------------- run programs - bind('s', fm.execute_command(os.environ['SHELL'])) - bind('E', fm.edit_file()) - bind(',term', fm.execute_command('x-terminal-emulator', flags='d')) - bind('du', fm.execute_command('du --max-depth=1 -h | less')) + map('s', fm.execute_command(os.environ['SHELL'])) + map('E', fm.edit_file()) + map(',term', fm.execute_command('x-terminal-emulator', flags='d')) + map('du', fm.execute_command('du --max-depth=1 -h | less')) # -------------------------------------------------- toggle options - bind('b', hint="bind_//h//idden //p//review_files //d//irectories_first " \ - "//c//ollapse_preview flush//i//nput") - bind('bh', fm.toggle_boolean_option('show_hidden')) - bind('bp', fm.toggle_boolean_option('preview_files')) - bind('bi', fm.toggle_boolean_option('flushinput')) - bind('bd', fm.toggle_boolean_option('directories_first')) - bind('bc', fm.toggle_boolean_option('collapse_preview')) + map('b', hint="show_//h//idden //p//review_files //d//irectories_first " \ + "//c//ollapse_preview flush//i//nput") + map('bh', fm.toggle_boolean_option('show_hidden')) + map('bp', fm.toggle_boolean_option('preview_files')) + map('bP', fm.toggle_boolean_option('preview_directories')) + map('bi', fm.toggle_boolean_option('flushinput')) + map('bd', fm.toggle_boolean_option('directories_first')) + map('bc', fm.toggle_boolean_option('collapse_preview')) # ------------------------------------------------------------ sort - bind('o', 'O', hint="//s//ize //b//ase//n//ame //m//time //t//ype //r//everse") + map('o', 'O', hint="//s//ize //b//ase//n//ame //m//time //t//ype //r//everse") sort_dict = { 's': 'size', 'b': 'basename', @@ -132,63 +129,63 @@ def initialize_commands(command_list): for key, val in sort_dict.items(): for key, is_capital in ((key, False), (key.upper(), True)): # reverse if any of the two letters is capital - bind('o' + key, fm.sort(func=val, reverse=is_capital)) - bind('O' + key, fm.sort(func=val, reverse=True)) + map('o' + key, fm.sort(func=val, reverse=is_capital)) + map('O' + key, fm.sort(func=val, reverse=True)) - bind('or', 'Or', 'oR', 'OR', lambda arg: \ + map('or', 'Or', 'oR', 'OR', lambda arg: \ arg.fm.sort(reverse=not arg.fm.settings.reverse)) # ----------------------------------------------- console shortcuts - @bind("A") + @map("A") def append_to_filename(arg): command = 'rename ' + arg.fm.env.cf.basename arg.fm.open_console(cmode.COMMAND, command) - bind('cw', fm.open_console(cmode.COMMAND, 'rename ')) - bind('cd', fm.open_console(cmode.COMMAND, 'cd ')) - bind('f', fm.open_console(cmode.COMMAND_QUICK, 'find ')) - bind('tf', fm.open_console(cmode.COMMAND, 'filter ')) - bind('d', hint='d//u// (disk usage) d//d// (cut)') + map('cw', fm.open_console(cmode.COMMAND, 'rename ')) + map('cd', fm.open_console(cmode.COMMAND, 'cd ')) + map('f', fm.open_console(cmode.COMMAND_QUICK, 'find ')) + map('tf', fm.open_console(cmode.COMMAND, 'filter ')) + map('d', hint='d//u// (disk usage) d//d// (cut)') # --------------------------------------------- jump to directories - bind('gh', fm.cd('~')) - bind('ge', fm.cd('/etc')) - bind('gu', fm.cd('/usr')) - bind('gd', fm.cd('/dev')) - bind('gl', fm.cd('/lib')) - bind('go', fm.cd('/opt')) - bind('gv', fm.cd('/var')) - bind('gr', 'g/', fm.cd('/')) - bind('gm', fm.cd('/media')) - bind('gn', fm.cd('/mnt')) - bind('gt', fm.cd('/tmp')) - bind('gs', fm.cd('/srv')) - bind('gR', fm.cd(RANGERDIR)) + map('gh', fm.cd('~')) + map('ge', fm.cd('/etc')) + map('gu', fm.cd('/usr')) + map('gd', fm.cd('/dev')) + map('gl', fm.cd('/lib')) + map('go', fm.cd('/opt')) + map('gv', fm.cd('/var')) + map('gr', 'g/', fm.cd('/')) + map('gm', fm.cd('/media')) + map('gn', fm.cd('/mnt')) + map('gt', fm.cd('/tmp')) + map('gs', fm.cd('/srv')) + map('gR', fm.cd(RANGERDIR)) # ------------------------------------------------------- searching - bind('/', fm.open_console(cmode.SEARCH)) + map('/', fm.open_console(cmode.SEARCH)) - bind('n', fm.search()) - bind('N', fm.search(forward=False)) + map('n', fm.search()) + map('N', fm.search(forward=False)) - bind(TAB, fm.search(order='tag')) - bind('cc', fm.search(order='ctime')) - bind('cm', fm.search(order='mimetype')) - bind('cs', fm.search(order='size')) - bind('c', hint='//c//time //m//imetype //s//ize') + map(TAB, fm.search(order='tag')) + map('cc', fm.search(order='ctime')) + map('cm', fm.search(order='mimetype')) + map('cs', fm.search(order='size')) + map('c', hint='//c//time //m//imetype //s//ize') # ------------------------------------------------------- bookmarks for key in ALLOWED_BOOKMARK_KEYS: - bind("`" + key, "'" + key, fm.enter_bookmark(key)) - bind("m" + key, fm.set_bookmark(key)) - bind("um" + key, fm.unset_bookmark(key)) - bind("`", "'", "m", draw_bookmarks=True) + map("`" + key, "'" + key, fm.enter_bookmark(key)) + map("m" + key, fm.set_bookmark(key)) + map("um" + key, fm.unset_bookmark(key)) + map("`", "'", "m", draw_bookmarks=True) # ---------------------------------------------------- change views - bind('i', fm.display_file()) - bind(ctrl('p'), fm.display_log()) - bind('?', KEY_F1, fm.display_help()) - bind('w', lambda arg: arg.fm.ui.open_taskview()) + map('i', fm.display_file()) + map(ctrl('p'), fm.display_log()) + map('?', KEY_F1, fm.display_help()) + map('w', lambda arg: arg.fm.ui.open_taskview()) # ---------------------------------------------------------- custom # This is useful to track watched episode of a series. @@ -206,134 +203,129 @@ def initialize_commands(command_list): bind(KEY_ENTER, ctrl('j'), fm.move_right(mode=1)) # ------------------------------------------------ system functions - _system_functions(command_list) - bind('ZZ', fm.exit()) - bind(ctrl('R'), fm.reset()) - bind('R', fm.reload_cwd()) - bind(ctrl('C'), fm.exit()) + _system_functions(map) + map('ZZ', fm.exit()) + map(ctrl('R'), fm.reset()) + map('R', fm.reload_cwd()) + map(ctrl('C'), fm.exit()) - bind(':', ';', fm.open_console(cmode.COMMAND)) - bind('>', fm.open_console(cmode.COMMAND_QUICK)) - bind('!', fm.open_console(cmode.OPEN)) - bind('r', fm.open_console(cmode.OPEN_QUICK)) + map(':', ';', fm.open_console(cmode.COMMAND)) + map('>', fm.open_console(cmode.COMMAND_QUICK)) + map('!', fm.open_console(cmode.OPEN)) + map('r', fm.open_console(cmode.OPEN_QUICK)) - command_list.rebuild_paths() + map.rebuild_paths() -def initialize_console_commands(command_list): +def initialize_console_commands(map): """Initialize the commands for the console widget only""" - bind, alias = make_abbreviations(command_list) # -------------------------------------------------------- movement - bind(KEY_UP, wdg.history_move(-1)) - bind(KEY_DOWN, wdg.history_move(1)) + map(KEY_UP, wdg.history_move(-1)) + map(KEY_DOWN, wdg.history_move(1)) - bind(ctrl('b'), KEY_LEFT, wdg.move(relative = -1)) - bind(ctrl('f'), KEY_RIGHT, wdg.move(relative = 1)) - bind(ctrl('a'), KEY_HOME, wdg.move(absolute = 0)) - bind(ctrl('e'), KEY_END, wdg.move(absolute = -1)) + map(ctrl('b'), KEY_LEFT, wdg.move(relative = -1)) + map(ctrl('f'), KEY_RIGHT, wdg.move(relative = 1)) + map(ctrl('a'), KEY_HOME, wdg.move(absolute = 0)) + map(ctrl('e'), KEY_END, wdg.move(absolute = -1)) # ----------------------------------------- deleting / pasting text - bind(ctrl('d'), KEY_DC, wdg.delete(0)) - bind(ctrl('h'), KEY_BACKSPACE, DEL, wdg.delete(-1)) - bind(ctrl('w'), wdg.delete_word()) - bind(ctrl('k'), wdg.delete_rest(1)) - bind(ctrl('u'), wdg.delete_rest(-1)) - bind(ctrl('y'), wdg.paste()) + map(ctrl('d'), KEY_DC, wdg.delete(0)) + map(ctrl('h'), KEY_BACKSPACE, DEL, wdg.delete(-1)) + map(ctrl('w'), wdg.delete_word()) + map(ctrl('k'), wdg.delete_rest(1)) + map(ctrl('u'), wdg.delete_rest(-1)) + map(ctrl('y'), wdg.paste()) # ----------------------------------------------------- typing keys def type_key(arg): arg.wdg.type_key(arg.keys) for i in range(ord(' '), ord('~')+1): - bind(i, type_key) + map(i, type_key) # ------------------------------------------------ system functions - _system_functions(command_list) + _system_functions(map) - bind(KEY_F1, lambda arg: arg.fm.display_command_help(arg.wdg)) - bind(ctrl('c'), ESC, wdg.close()) - bind(ctrl('j'), KEY_ENTER, wdg.execute()) - bind(TAB, wdg.tab()) - bind(KEY_BTAB, wdg.tab(-1)) + map(KEY_F1, lambda arg: arg.fm.display_command_help(arg.wdg)) + map(ctrl('c'), ESC, wdg.close()) + map(ctrl('j'), KEY_ENTER, wdg.execute()) + map(TAB, wdg.tab()) + map(KEY_BTAB, wdg.tab(-1)) - command_list.rebuild_paths() + map.rebuild_paths() -def initialize_taskview_commands(command_list): +def initialize_taskview_commands(map): """Initialize the commands for the TaskView widget""" - bind, alias = make_abbreviations(command_list) - _basic_movement(command_list) - _vimlike_aliases(command_list) - _system_functions(command_list) + _basic_movement(map) + _vimlike_aliases(map) + _system_functions(map) # -------------------------------------------------- (re)move tasks - bind('K', wdg.task_move(0)) - bind('J', wdg.task_move(-1)) - bind('dd', wdg.task_remove()) + map('K', wdg.task_move(0)) + map('J', wdg.task_move(-1)) + map('dd', wdg.task_remove()) # ------------------------------------------------ system functions - bind('?', fm.display_help()) - bind('w', 'q', ESC, ctrl('d'), ctrl('c'), + map('?', fm.display_help()) + map('w', 'q', ESC, ctrl('d'), ctrl('c'), lambda arg: arg.fm.ui.close_taskview()) - command_list.rebuild_paths() + map.rebuild_paths() -def initialize_pager_commands(command_list): - bind, alias = make_abbreviations(command_list) - _base_pager_commands(command_list) - bind('q', 'i', ESC, KEY_F1, lambda arg: arg.fm.ui.close_pager()) - command_list.rebuild_paths() +def initialize_pager_commands(map): + _base_pager_commands(map) + map('q', 'i', ESC, KEY_F1, lambda arg: arg.fm.ui.close_pager()) + map.rebuild_paths() -def initialize_embedded_pager_commands(command_list): - bind, alias = make_abbreviations(command_list) - _base_pager_commands(command_list) - bind('q', 'i', ESC, lambda arg: arg.fm.ui.close_embedded_pager()) - command_list.rebuild_paths() +def initialize_embedded_pager_commands(map): + _base_pager_commands(map) + map('q', 'i', ESC, lambda arg: arg.fm.ui.close_embedded_pager()) + map.rebuild_paths() - -def _base_pager_commands(command_list): - bind, alias = make_abbreviations(command_list) - _basic_movement(command_list) - _vimlike_aliases(command_list) - _system_functions(command_list) +def _base_pager_commands(map): + _basic_movement(map) + _vimlike_aliases(map) + _system_functions(map) # -------------------------------------------------------- movement - bind(KEY_LEFT, wdg.move_horizontal(relative=-4)) - bind(KEY_RIGHT, wdg.move_horizontal(relative=4)) - bind(KEY_NPAGE, wdg.move(relative=1, pages=True)) - bind(KEY_PPAGE, wdg.move(relative=-1, pages=True)) - bind(ctrl('d'), wdg.move(relative=0.5, pages=True)) - bind(ctrl('u'), wdg.move(relative=-0.5, pages=True)) + map(KEY_LEFT, wdg.move_horizontal(relative=-4)) + map(KEY_RIGHT, wdg.move_horizontal(relative=4)) + map(KEY_NPAGE, wdg.move(relative=1, pages=True)) + map(KEY_PPAGE, wdg.move(relative=-1, pages=True)) + map(ctrl('d'), wdg.move(relative=0.5, pages=True)) + map(ctrl('u'), wdg.move(relative=-0.5, pages=True)) + map(' ', wdg.move(relative=0.8, pages=True)) # ---------------------------------------------------------- others - bind('E', fm.edit_file()) - bind('?', fm.display_help()) + map('E', fm.edit_file()) + map('?', fm.display_help()) # --------------------------------------------- less-like shortcuts - alias(KEY_NPAGE, 'd') - alias(KEY_PPAGE, 'u') + map.alias(KEY_NPAGE, 'd') + map.alias(KEY_PPAGE, 'u') -def _system_functions(command_list): +def _system_functions(map): # Each commandlist should have this bindings - bind, alias = make_abbreviations(command_list) + map(KEY_RESIZE, fm.resize()) + map(KEY_MOUSE, fm.handle_mouse()) + map('Q', fm.exit()) + map(ctrl('L'), fm.redraw_window()) - bind(KEY_RESIZE, fm.resize()) - bind(KEY_MOUSE, fm.handle_mouse()) - bind('Q', fm.exit()) - bind(ctrl('L'), fm.redraw_window()) +def _basic_movement(map): + map(KEY_DOWN, wdg.move(relative=1)) + map(KEY_UP, wdg.move(relative=-1)) + map(KEY_HOME, wdg.move(absolute=0)) + map(KEY_END, wdg.move(absolute=-1)) -def _basic_movement(command_list): - bind, alias = make_abbreviations(command_list) - bind(KEY_DOWN, wdg.move(relative=1)) - bind(KEY_UP, wdg.move(relative=-1)) - bind(KEY_HOME, wdg.move(absolute=0)) - bind(KEY_END, wdg.move(absolute=-1)) + +# ------ newkey: def base_directions(): @@ -500,21 +492,6 @@ def browser_keys(): map('?', KEY_F1, fm.display_help()) map('w', lambda arg: arg.fm.ui.open_taskview()) - # ---------------------------------------------------------- custom - # This is useful to track watched episode of a series. - @map(']') - def tag_next_and_run(arg): - fm = arg.fm - fm.tag_remove() - fm.tag_remove(movedown=False) - fm.tag_toggle() - fm.move_pointer(relative=-2) - fm.move_right() - fm.move_pointer(relative=1) - - # "enter" = shortcut for "1l" - map('<cr>', fm.move(Direction(right=2))) - # ------------------------------------------------ system functions map('ZZ', fm.exit()) map(ctrl('R'), fm.reset()) @@ -535,7 +512,7 @@ def console_keys(): @map('<any>') def type_key(arg): arg.wdg.type_key(arg.match) - + map('<up>', wdg.history_move(-1)) map('<down>', wdg.history_move(1)) map('<tab>', wdg.tab()) diff --git a/ranger/defaults/options.py b/ranger/defaults/options.py index 139cda88..a7090285 100644 --- a/ranger/defaults/options.py +++ b/ranger/defaults/options.py @@ -15,32 +15,71 @@ """ This is the default configuration file of ranger. -If you do any changes, make sure the import-line stays -intact and the type of the value stays the same. + +There are two ways of customizing ranger. The first and recommended +method is creating a file at ~/.ranger/options.py and adding +those lines you want to change. It might look like this: + +from ranger.api.options import * +preview_files = False # I hate previews! +max_history_size = 2000 # I can afford it. + +The other way is directly editing this file. This will make upgrades +of ranger more complicated though. + +Whatever you do, make sure the import-line stays intact and the type +of the values stay the same. """ from ranger.api.options import * -one_kb = 1024 +# Which files are hidden if show_hidden is False? +hidden_filter = regexp( + r'lost\+found|^\.|~$|\.(:?pyc|pyo|bak|swp)$') +show_hidden = False + +# Which colorscheme to use? These colorschemes are available by default: +# default, default88, texas, jungle, snow +# Snow is monochrome, texas and default88 use 88 colors. +colorscheme = 'default' + +# Preview files on the rightmost column? +# And collapse the last column if there is nothing to preview? +preview_files = True +preview_directories = True +max_filesize_for_preview = 300 * 1024 # 300kb +collapse_preview = True -colorscheme = colorschemes.default +# Draw borders around columns? +draw_borders = False +# Set a title for the window? +update_title = True + +# Shorten the title if it gets long? The number defines how many +# directories are displayed at once, False turns off this feature. +shorten_title = 3 + +# How many directory-changes or console-commands should be kept in history? max_history_size = 20 -max_filesize_for_preview = 300 * one_kb + +# Try to keep so much space between the top/bottom border when scrolling: scroll_offset = 2 -preview_files = True -flushinput = True -sort = 'basename' -reverse = False -directories_first = True +# Flush the input after each key hit? (Noticable when ranger lags) +flushinput = True -show_hidden = False -collapse_preview = True +# Save bookmarks (used with mX and `X) instantly? +# This helps to synchronize bookmarks between multiple ranger +# instances but leads to *slight* performance loss. +# When false, bookmarks are saved when ranger is exited. autosave_bookmarks = True -update_title = False +# Makes sense for screen readers: show_cursor = False -hidden_filter = regexp( - r'lost\+found|^\.|~$|\.(:?pyc|pyo|bak|swp)$') +# One of: size, basename, mtime, type +sort = 'basename' +reverse = False +directories_first = True + diff --git a/ranger/ext/__init__.py b/ranger/ext/__init__.py index d4bb9e72..9cf2ee50 100644 --- a/ranger/ext/__init__.py +++ b/ranger/ext/__init__.py @@ -1,16 +1 @@ -# 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/>. - """This package includes extensions with broader usability""" diff --git a/ranger/ext/command_parser.py b/ranger/ext/command_parser.py index 1082e767..a6971631 100644 --- a/ranger/ext/command_parser.py +++ b/ranger/ext/command_parser.py @@ -30,7 +30,7 @@ class LazyParser(object): def chunk(self, n, otherwise=''): """Chunks are pieces of the command seperated by spaces""" if self._chunks is None: - self._chunks = line.split() + self._chunks = self.line.split() if len(self._chunks) > n: return self._chunks[n] diff --git a/ranger/ext/debug.py b/ranger/ext/debug.py deleted file mode 100644 index 88f43340..00000000 --- a/ranger/ext/debug.py +++ /dev/null @@ -1,34 +0,0 @@ -# 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/>. - -LOGFILE = '/tmp/errorlog' - -def log(*objects, **keywords): - """Writes objects to a logfile. - Has the same arguments as print() in python3""" - 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) - -#for python3-only versions, this could be replaced with: -# -#def log(*objects, start='ranger:', sep=' ', end='\n'): -# print(start, *objects, end=end, sep=sep, file=open(LOGFILE, 'a')) - -def trace(): - from traceback import print_stack - print_stack(file=open(LOGFILE, 'a')) diff --git a/ranger/ext/openstruct.py b/ranger/ext/openstruct.py index 56f7de06..a94c3031 100644 --- a/ranger/ext/openstruct.py +++ b/ranger/ext/openstruct.py @@ -13,23 +13,11 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. -class OpenStruct(object): - def __init__(self, __dictionary=None, **__keywords): - if __dictionary: - self.__dict__.update(__dictionary) - if __keywords: - self.__dict__.update(__keywords) +# prepend __ to arguments because one might use "args" +# or "keywords" as a keyword argument. - def __getitem__(self, key): - return self.__dict__[key] - - def __setitem__(self, key, value): - self.__dict__[key] = value - return value - - def __contains__(self, key): - return key in self.__dict__ - -class ReferencedOpenStruct(OpenStruct): - def __init__(self, dictionary): - self.__dict__ = dictionary +class OpenStruct(dict): + """The fusion of dict and struct""" + def __init__(self, *__args, **__keywords): + dict.__init__(self, *__args, **__keywords) + self.__dict__ = self diff --git a/ranger/ext/relpath.py b/ranger/ext/relpath.py deleted file mode 100644 index ddca89a3..00000000 --- a/ranger/ext/relpath.py +++ /dev/null @@ -1,26 +0,0 @@ -# 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/>. - -import os -import ranger - -def relpath(*paths): - """returns the path relative to rangers library directory""" - return os.path.join(ranger.RANGERDIR, *paths) - -def relpath_conf(*paths): - """returns the path relative to rangers configuration directory""" - return os.path.join(ranger.CONFDIR, *paths) - diff --git a/ranger/ext/shutil_generatorized.py b/ranger/ext/shutil_generatorized.py index 8c699f8e..8bf07ace 100644 --- a/ranger/ext/shutil_generatorized.py +++ b/ranger/ext/shutil_generatorized.py @@ -306,12 +306,8 @@ def move(src, dst, overwrite=False): """ real_dst = dst - if not overwrite and os.path.isdir(dst): - real_dst = os.path.join(dst, _basename(src)) - if os.path.exists(real_dst): - raise Error("Destination path '%s' already exists" % real_dst) if not overwrite: - real_dst = get_safe_path(real_dst) + real_dst = get_safe_path(os.path.join(dst, _basename(src))) try: os.rename(src, real_dst) except OSError: diff --git a/ranger/fsobject/directory.py b/ranger/fsobject/directory.py index 5bbbe3e4..8bb8a78a 100644 --- a/ranger/fsobject/directory.py +++ b/ranger/fsobject/directory.py @@ -341,7 +341,7 @@ class Directory(FileSystemObject, Accumulator, SettingsAware): Accumulator.correct_pointer(self) try: - if self == self.fm.env.pwd: + if self == self.fm.env.cwd: self.fm.env.cf = self.pointed_obj except: pass diff --git a/ranger/fsobject/fsobject.py b/ranger/fsobject/fsobject.py index 0e67cba6..4278c3e8 100644 --- a/ranger/fsobject/fsobject.py +++ b/ranger/fsobject/fsobject.py @@ -30,6 +30,7 @@ class FileSystemObject(MimeTypeAware, FileManagerAware): basename = None basename_lower = None _shell_escaped_basename = None + _filetype = None dirname = None extension = None exists = False @@ -86,6 +87,19 @@ class FileSystemObject(MimeTypeAware, FileManagerAware): self._shell_escaped_basename = shell_escape(self.basename) return self._shell_escaped_basename + @property + def filetype(self): + if self._filetype is None: + import subprocess + try: + got = subprocess.Popen(["file", '-Lb', '--mime-type',\ + self.path], stdout=subprocess.PIPE).communicate()[0] + except OSError: + self._filetype = '' + else: + self._filetype = got + return self._filetype + def get_description(self): return "Loading " + str(self) @@ -105,16 +119,17 @@ class FileSystemObject(MimeTypeAware, FileManagerAware): def set_mimetype(self): """assign attributes such as self.video according to the mimetype""" - try: - self.mimetype = self.mimetypes[self.extension] - except KeyError: + self.mimetype = self.mimetypes.guess_type(self.basename, False)[0] + if self.mimetype is None: self.mimetype = '' self.video = self.mimetype.startswith('video') self.image = self.mimetype.startswith('image') self.audio = self.mimetype.startswith('audio') self.media = self.video or self.image or self.audio - self.document = self.mimetype.startswith('text') or (self.extension in DOCUMENT_EXTENSIONS) or (self.basename in DOCUMENT_BASENAMES) + self.document = self.mimetype.startswith('text') \ + or (self.extension in DOCUMENT_EXTENSIONS) \ + or (self.basename in DOCUMENT_BASENAMES) self.container = self.extension in CONTAINER_EXTENSIONS keys = ('video', 'audio', 'image', 'media', 'document', 'container') @@ -152,7 +167,7 @@ class FileSystemObject(MimeTypeAware, FileManagerAware): self.islink = stat.S_ISLNK(self.stat.st_mode) self.accessible = True - if os.access(self.path, os.F_OK): + if self.accessible and os.access(self.path, os.F_OK): self.exists = True self.accessible = True @@ -203,12 +218,12 @@ class FileSystemObject(MimeTypeAware, FileManagerAware): else: perms = ['-'] - for who in "USR", "GRP", "OTH": - for what in "rwx": - if mode & getattr(stat, "S_I" + what.upper() + who): - perms.append( what.lower() ) + for who in ("USR", "GRP", "OTH"): + for what in "RWX": + if mode & getattr(stat, "S_I" + what + who): + perms.append(what.lower()) else: - perms.append( '-' ) + perms.append('-') self.permissions = ''.join(perms) return self.permissions diff --git a/ranger/gui/colorscheme.py b/ranger/gui/colorscheme.py index 867aec70..199a5523 100644 --- a/ranger/gui/colorscheme.py +++ b/ranger/gui/colorscheme.py @@ -41,7 +41,6 @@ If your colorscheme-file contains more than one colorscheme, specify it with: colorscheme = colorschemes.filename.classname """ -from ranger.ext.openstruct import ReferencedOpenStruct from curses import color_pair from ranger.gui.color import get_color from ranger.gui.context import Context @@ -89,8 +88,17 @@ class ColorScheme(object): def use(self, context): """ Use the colorscheme to determine the (fg, bg, attr) tuple. - This is a dummy function which always returns default_colors. - Override this in your custom colorscheme! + + When no colorscheme is found, ranger will fall back to this very + basic colorscheme where directories are blue and bold, and + selected files have the color inverted. + + Override this method in your own colorscheme. """ - from ranger.gui.color import default_colors - return default_colors + fg, attr = -1, 0 + if context.highlight or context.selected: + attr = 262144 + if context.directory: + attr |= 2097152 + fg = 4 + return fg, -1, attr diff --git a/ranger/gui/context.py b/ranger/gui/context.py index 25544932..d31124ca 100644 --- a/ranger/gui/context.py +++ b/ranger/gui/context.py @@ -25,7 +25,7 @@ CONTEXT_KEYS = ['reset', 'error', 'scroll', 'all', 'bot', 'top', 'percentage', 'marked', 'tagged', 'tag_marker', 'help_markup', - 'seperator', 'key', 'special', + 'seperator', 'key', 'special', 'border', 'title', 'text', 'highlight', 'bars', 'quotes', 'keybuffer'] diff --git a/ranger/gui/ui.py b/ranger/gui/ui.py index 05efa639..2d86736c 100644 --- a/ranger/gui/ui.py +++ b/ranger/gui/ui.py @@ -13,6 +13,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. +import os import socket import sys import curses @@ -22,12 +23,16 @@ from .displayable import DisplayableContainer from ranger.container.keymap import CommandArgs from .mouse_event import MouseEvent +TERMINALS_WITH_TITLE = ("xterm", "xterm-256color", "rxvt", + "rxvt-256color", "rxvt-unicode", "aterm", "Eterm", + "screen", "screen-256color") + class UI(DisplayableContainer): is_set_up = False mousemask = curses.ALL_MOUSE_EVENTS | curses.REPORT_MOUSE_POSITION load_mode = False def __init__(self, keymap=None, env=None, fm=None): - import os + self._draw_title = os.environ["TERM"] in TERMINALS_WITH_TITLE os.environ['ESCDELAY'] = '25' # don't know a cleaner way if env is not None: @@ -195,13 +200,15 @@ class UI(DisplayableContainer): """Erase the window, then draw all objects in the container""" self.win.touchwin() DisplayableContainer.draw(self) - if self.settings.update_title: - hostname = str(socket.gethostname()) - try: - cwd = self.fm.env.pwd.path - except: - cwd = ' - ranger' - sys.stdout.write("\033]2;" + hostname + cwd + "\007") + if self._draw_title and self.settings.update_title: + cwd = self.fm.env.cwd.path + if cwd.startswith(self.env.home_path): + cwd = '~' + cwd[len(self.env.home_path):] + if self.settings.shorten_title: + split = cwd.rsplit(os.sep, self.settings.shorten_title) + if os.sep in split[0]: + cwd = os.sep.join(split[1:]) + sys.stdout.write("\033]2;ranger:" + cwd + "\007") self.win.refresh() def finalize(self): diff --git a/ranger/gui/widgets/browsercolumn.py b/ranger/gui/widgets/browsercolumn.py index 2550062f..238a4803 100644 --- a/ranger/gui/widgets/browsercolumn.py +++ b/ranger/gui/widgets/browsercolumn.py @@ -32,7 +32,7 @@ PREVIEW_BLACKLIST = re.compile(r""" # binary files: | torrent | class | so | img | py[co] | dmg # containers: - | iso | rar | zip | 7z | tar | gz | bz2 + | iso | rar | zip | 7z | tar | gz | bz2 | tgz ) # ignore filetype-independent suffixes: (\.part|\.bak|~)? @@ -41,7 +41,7 @@ PREVIEW_BLACKLIST = re.compile(r""" $ """, re.VERBOSE | re.IGNORECASE) -class BrowserColumn(Pager, Widget): +class BrowserColumn(Pager): main_column = False display_infostring = False scroll_begin = 0 @@ -53,6 +53,14 @@ class BrowserColumn(Pager, Widget): old_cf = None def __init__(self, win, level): + """ + win = the curses window object of the BrowserView + level = what to display? + + level >0 => previews + level 0 => current file/directory + level <0 => parent directories + """ Pager.__init__(self, win) Widget.__init__(self, win) self.level = level @@ -100,6 +108,10 @@ class BrowserColumn(Pager, Widget): if not self._preview_this_file(self.target): return False + if self.target.is_directory: + if self.level > 0 and not self.settings.preview_directories: + return False + return True def poke(self): @@ -108,13 +120,12 @@ class BrowserColumn(Pager, Widget): def draw(self): """Call either _draw_file() or _draw_directory()""" - from ranger import log - if self.target != self.old_dir: self.need_redraw = True self.old_dir = self.target - if self.target and self.target.is_directory: + if self.target and self.target.is_directory \ + and (self.level <= 0 or self.settings.preview_directories): if self.target.pointed_obj != self.old_cf: self.need_redraw = True self.old_cf = self.target.pointed_obj @@ -167,6 +178,9 @@ class BrowserColumn(Pager, Widget): """Draw the contents of a directory""" import stat + if self.level > 0 and not self.settings.preview_directories: + return + base_color = ['in_browser'] self.target.use() @@ -207,7 +221,7 @@ class BrowserColumn(Pager, Widget): this_color = base_color + list(drawed.mimetype_tuple) text = drawed.basename - tagged = drawed.realpath in self.fm.tags + tagged = self.fm.tags and drawed.realpath in self.fm.tags if i == selected_i: this_color.append('selected') diff --git a/ranger/gui/widgets/browserview.py b/ranger/gui/widgets/browserview.py index 080f1be0..8d6dc611 100644 --- a/ranger/gui/widgets/browserview.py +++ b/ranger/gui/widgets/browserview.py @@ -14,6 +14,7 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. """The BrowserView manages a set of BrowserColumns.""" +import curses from . import Widget from .browsercolumn import BrowserColumn from .pager import Pager @@ -31,10 +32,13 @@ class BrowserView(Widget, DisplayableContainer): DisplayableContainer.__init__(self, win) self.ratios = ratios self.preview = preview + self.old_cf = self.env.cf + self.old_prevfile = None + self.old_prevdir = None # normalize ratios: ratio_sum = float(sum(ratios)) - self.ratios = tuple(map(lambda x: x / ratio_sum, ratios)) + self.ratios = tuple(x / ratio_sum for x in ratios) if len(self.ratios) >= 2: self.stretch_ratios = self.ratios[:-2] + \ @@ -64,11 +68,23 @@ class BrowserView(Widget, DisplayableContainer): if self.draw_bookmarks: self._draw_bookmarks() else: + if self.old_cf != self.env.cf: + self.need_clear = True + if self.settings.draw_borders: + if self.old_prevdir != self.settings.preview_directories: + self.need_clear = True + if self.old_prevfile != self.settings.preview_files: + self.need_clear = True if self.need_clear: self.win.erase() self.need_redraw = True self.need_clear = False + self.old_cf = self.env.cf + self.old_prevfile = self.settings.preview_files + self.old_prevdir = self.settings.preview_directories DisplayableContainer.draw(self) + if self.settings.draw_borders: + self._draw_borders() def finalize(self): if self.pager.visible: @@ -105,32 +121,90 @@ class BrowserView(Widget, DisplayableContainer): string = " " + key + ": " + mark.path self.addnstr(line, 0, string.ljust(maxlen), self.wid) + def _draw_borders(self): + win = self.win + self.color('in_browser', 'border') + + left_start = 0 + right_end = self.wid - 1 + + rows = [row for row in self.container \ + if isinstance(row, BrowserColumn)] + rows.sort(key=lambda row: row.x) + + for child in rows: + if not child.has_preview(): + left_start = child.x + child.wid + else: + break + if not self.pager.visible: + for child in reversed(rows): + if not child.has_preview(): + right_end = child.x - 1 + else: + break + if right_end < left_start: + right_end = self.wid - 1 + + win.hline(0, left_start, curses.ACS_HLINE, right_end - left_start) + win.hline(self.hei - 1, left_start, curses.ACS_HLINE, + right_end - left_start) + win.vline(1, left_start, curses.ACS_VLINE, self.hei - 2) + + for child in rows: + if not child.has_preview(): + continue + if child.main_column and self.pager.visible: + win.vline(1, right_end, curses.ACS_VLINE, self.hei - 2) + break + x = child.x + child.wid + y = self.hei - 1 + try: + win.vline(1, x, curses.ACS_VLINE, y - 1) + win.addch(0, x, curses.ACS_TTEE, 0) + win.addch(y, x, curses.ACS_BTEE, 0) + except: + # in case it's off the boundaries + pass + + win.addch(0, left_start, curses.ACS_ULCORNER) + win.addch(self.hei - 1, left_start, curses.ACS_LLCORNER) + win.addch(0, right_end, curses.ACS_URCORNER) + try: + win.addch(self.hei - 1, right_end, curses.ACS_LRCORNER) + except: + pass + def resize(self, y, x, hei, wid): """Resize all the columns according to the given ratio""" DisplayableContainer.resize(self, y, x, hei, wid) - left = 0 + borders = self.settings.draw_borders + pad = 1 if borders else 0 + left = pad cut_off_last = self.preview and not self.preview_available \ and self.stretch_ratios if cut_off_last: - generator = zip(self.stretch_ratios, range(len(self.ratios))) + generator = enumerate(self.stretch_ratios) else: - generator = zip(self.ratios, range(len(self.ratios))) + generator = enumerate(self.ratios) last_i = len(self.ratios) - 1 - for ratio, i in generator: + for i, ratio in generator: wid = int(ratio * self.wid) if i == last_i: - wid = int(self.wid - left + 1) + wid = int(self.wid - left + 1 - pad) if i == last_i - 1: - self.pager.resize(0, left, hei, max(1, self.wid - left)) + self.pager.resize(pad, left, hei - pad * 2, \ + max(1, self.wid - left - pad)) try: - self.container[i].resize(0, left, hei, max(1, wid-1)) + self.container[i].resize(pad, left, hei - pad * 2, \ + max(1, wid - 1)) except KeyError: pass @@ -148,6 +222,7 @@ class BrowserView(Widget, DisplayableContainer): def open_pager(self): self.pager.visible = True self.pager.focused = True + self.need_clear = True self.pager.open() try: self.container[-2].visible = False @@ -158,6 +233,7 @@ class BrowserView(Widget, DisplayableContainer): def close_pager(self): self.pager.visible = False self.pager.focused = False + self.need_clear = True self.pager.close() try: self.container[-2].visible = True diff --git a/ranger/gui/widgets/console.py b/ranger/gui/widgets/console.py index 7ed00a7e..4dea98c7 100644 --- a/ranger/gui/widgets/console.py +++ b/ranger/gui/widgets/console.py @@ -23,7 +23,7 @@ import curses from collections import deque from . import Widget -from ranger import commands +from ranger.defaults import commands from ranger.gui.widgets.console_mode import is_valid_mode, mode_to_class from ranger import log from ranger.ext.shell_escape import shell_quote @@ -129,9 +129,13 @@ class Console(Widget): def press(self, key): from curses.ascii import ctrl, ESC + keytuple = self.env.keybuffer.tuple_with_numbers() try: - cmd = self.commandlist[self.env.keybuffer.tuple_with_numbers()] + cmd = self.commandlist[keytuple] except KeyError: + # An unclean hack to allow unicode input. + # This whole part should be replaced. + self.type_key(chr(keytuple[0])) self.env.key_clear() return @@ -292,26 +296,17 @@ class CommandConsole(ConsoleWithTab): self.close() def _get_cmd(self): - command_class = self._get_cmd_class() - if command_class: - return command_class(self.line, self.mode) - else: - return None - - def _get_cmd_class(self): try: - command_name = self.line.split()[0] - except IndexError: - return None - - try: - return commands.get_command(command_name) + command_class = self._get_cmd_class() except KeyError: self.fm.notify("Invalid command! Press ? for help.", bad=True) + except: return None - except ValueError as e: - self.fm.notify(e) - return None + else: + return command_class(self.line, self.mode) + + def _get_cmd_class(self): + return commands.get_command(self.line.split()[0]) def _get_tab(self): if ' ' in self.line: @@ -339,9 +334,14 @@ class QuickCommandConsole(CommandConsole): """ prompt = '>' def on_line_change(self): - cmd = self._get_cmd() - if cmd and cmd.quick_open(): - self.execute(cmd) + try: + cls = self._get_cmd_class() + except (KeyError, ValueError, IndexError): + pass + else: + cmd = cls(self.line, self.mode) + if cmd and cmd.quick_open(): + self.execute(cmd) class SearchConsole(Console): @@ -352,11 +352,11 @@ class SearchConsole(Console): def execute(self): import re - if self.fm.env.pwd: + if self.fm.env.cwd: regexp = re.compile(self.line, re.L | re.U | re.I) self.fm.env.last_search = regexp if self.fm.search(order='search'): - self.fm.env.cf = self.fm.env.pwd.pointed_obj + self.fm.env.cf = self.fm.env.cwd.pointed_obj self.close() @@ -414,7 +414,7 @@ class OpenConsole(ConsoleWithTab): else: before_word, start_of_word = self.line.rsplit(' ', 1) return (before_word + ' ' + file.shell_escaped_basename \ - for file in self.fm.env.pwd.files \ + for file in self.fm.env.cwd.files \ if file.shell_escaped_basename.startswith(start_of_word)) def _substitute_metachars(self, command): @@ -576,10 +576,11 @@ class QuickOpenConsole(ConsoleWithTab): def _is_app(self, arg): - return self.fm.apps.has(arg) + return self.fm.apps.has(arg) or \ + (not self._is_flags(arg) and arg in self.fm.executables) def _is_flags(self, arg): - from ranger.runner import ALLOWED_FLAGS + from ranger.core.runner import ALLOWED_FLAGS return all(x in ALLOWED_FLAGS for x in arg) def _is_mode(self, arg): diff --git a/ranger/gui/widgets/pager.py b/ranger/gui/widgets/pager.py index 03a421cf..c5ed8af1 100644 --- a/ranger/gui/widgets/pager.py +++ b/ranger/gui/widgets/pager.py @@ -229,7 +229,7 @@ class Pager(Widget): while True: try: line = self._get_line(i).expandtabs(4) - line = line[startx:self.wid - 1 + startx].rstrip() + line = line[startx:self.wid + startx].rstrip() yield line except IndexError: raise StopIteration diff --git a/ranger/gui/widgets/statusbar.py b/ranger/gui/widgets/statusbar.py index f15156df..6f52f8ef 100644 --- a/ranger/gui/widgets/statusbar.py +++ b/ranger/gui/widgets/statusbar.py @@ -81,8 +81,8 @@ class StatusBar(Widget): if not self.result: self.need_redraw = True - if self.old_du and not self.env.pwd.disk_usage: - self.old_du = self.env.pwd.disk_usage + if self.old_du and not self.env.cwd.disk_usage: + self.old_du = self.env.cwd.disk_usage self.need_redraw = True if self.old_cf != self.env.cf: @@ -135,7 +135,8 @@ class StatusBar(Widget): def _get_left_part(self, bar): left = bar.left - if self.column is not None: + if self.column is not None and self.column.target is not None\ + and self.column.target.is_directory: target = self.column.target.pointed_obj else: target = self.env.at_level(0).pointed_obj @@ -195,6 +196,8 @@ class StatusBar(Widget): return target = self.column.target + if target is None: + return if not target.content_loaded or not target.accessible: return diff --git a/ranger/gui/widgets/titlebar.py b/ranger/gui/widgets/titlebar.py index cb6e8cdd..e1be8e97 100644 --- a/ranger/gui/widgets/titlebar.py +++ b/ranger/gui/widgets/titlebar.py @@ -54,20 +54,14 @@ class TitleBar(Widget): self.result = bar.combine() def _get_left_part(self, bar): - import socket, os, pwd - - try: - username = pwd.getpwuid(os.geteuid()).pw_name - except: - username = "???" - if username == 'root': + if self.env.username == 'root': clr = 'bad' else: clr = 'good' - bar.add(username, 'hostname', clr, fixedsize=True) + bar.add(self.env.username, 'hostname', clr, fixedsize=True) bar.add('@', 'hostname', clr, fixedsize=True) - bar.add(socket.gethostname(), 'hostname', clr, fixedsize=True) + bar.add(self.env.hostname, 'hostname', clr, fixedsize=True) for path in self.env.pathway: if path.islink: diff --git a/ranger/help/console.py b/ranger/help/console.py index 7ba15799..3a4428f3 100644 --- a/ranger/help/console.py +++ b/ranger/help/console.py @@ -127,7 +127,7 @@ one unambiguous match, <RETURN> will be pressed for you, giving you a very fast way to browse your files. -All commands are defined in ranger/commands.py. You can refer to this +All commands are defined in ranger/defaults/commands.py. You can refer to this file for a list of commands. Implementing new commands should be intuitive: Create a new class, a subclass of Command, and define the execute method is usually enough. For parsing command input, the command parser in diff --git a/ranger/help/fileop.py b/ranger/help/fileop.py index 5b7a0f0b..53ce9ff8 100644 --- a/ranger/help/fileop.py +++ b/ranger/help/fileop.py @@ -19,6 +19,7 @@ 4.1. Destructive Operations 4.2. The Selection 4.3. Copying and Pasting +4.4. Task View ============================================================================== @@ -28,7 +29,7 @@ These are all the operations which can change, and with misuse, possibly harm your files: :chmod <number> Change the rights of the selection -:delete DELETES ALL FILES IN THE SELECTION WITHOUT CONFIRMATION +:delete DELETES ALL FILES IN THE SELECTION :rename <newname> Change the name of the current file pp, pl, po Pastes the copied files in different ways @@ -74,6 +75,26 @@ If renaming is not possible because the source and the destination are on separate devices, it will be copied and eventually the source is deleted. This implies that a file can only be cut + pasted once. + +============================================================================== +4.4. Task View + +The task view lets you manage IO tasks like copying, moving and +loading directories by changing their priority or stop them. + + w open or close the task view + dd stop the task + J decrease the priority of the task + K increase the priority of the task + +The execution of tasks is not parallel but sequential. Only the +topmost task is executed. Ranger constantly switches between +handling GUI and executing tasks. One movement of the throbber at +the top right represents such a switch, so while the throbber is +standing still, ranger is locked by a Input/Output operation and +you will not be able to input any commands. + + ============================================================================== """ # vim:tw=78:sw=4:sts=8:ts=8:ft=help diff --git a/ranger/help/movement.py b/ranger/help/movement.py index 28e2c38b..a0407838 100644 --- a/ranger/help/movement.py +++ b/ranger/help/movement.py @@ -58,8 +58,8 @@ Special keys like Home, Page Up,.. work as expected. These keys work like in vim: - ^D move half the screen up - ^U move half the screen down + ^U move half the screen up + ^D move half the screen down ^B move up by one screen ^F move down by one screen diff --git a/ranger/shared/mimetype.py b/ranger/shared/mimetype.py index 93015a73..1a7f79a0 100644 --- a/ranger/shared/mimetype.py +++ b/ranger/shared/mimetype.py @@ -13,16 +13,13 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. -from ranger.ext.relpath import relpath +from ranger import relpath +import mimetypes class MimeTypeAware(object): mimetypes = {} __initialized = False def __init__(self): if not MimeTypeAware.__initialized: + MimeTypeAware.mimetypes = mimetypes.MimeTypes() + MimeTypeAware.mimetypes.read(relpath('data/mime.types')) MimeTypeAware.__initialized = True - import os, sys, pickle - MimeTypeAware.mimetypes.clear() - - f = open(relpath('data/mime.dat'), 'rb') - MimeTypeAware.mimetypes.update(pickle.load(f)) - f.close() diff --git a/ranger/shared/settings.py b/ranger/shared/settings.py index b549bd20..cdddd623 100644 --- a/ranger/shared/settings.py +++ b/ranger/shared/settings.py @@ -13,7 +13,10 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. +import os import types +from inspect import isclass, ismodule +import ranger from ranger.ext.openstruct import OpenStruct from ranger.gui.colorscheme import ColorScheme @@ -22,16 +25,19 @@ ALLOWED_SETTINGS = { 'show_cursor': bool, 'autosave_bookmarks': bool, 'collapse_preview': bool, + 'draw_borders': bool, 'sort': str, 'reverse': bool, 'directories_first': bool, 'update_title': bool, + 'shorten_title': int, # Note: False is an instance of int 'max_filesize_for_preview': (int, type(None)), 'max_history_size': (int, type(None)), 'scroll_offset': int, 'preview_files': bool, + 'preview_directories': bool, 'flushinput': bool, - 'colorscheme': (ColorScheme, types.ModuleType), + 'colorscheme': str, 'hidden_filter': lambda x: isinstance(x, str) or hasattr(x, 'match'), } @@ -41,67 +47,91 @@ class SettingsAware(object): @staticmethod def _setup(): - from inspect import isclass, ismodule - from ranger.gui.colorscheme import ColorScheme + settings = OpenStruct() - # overwrite single default options with custom options from ranger.defaults import options - try: - import options as custom_options - for setting in ALLOWED_SETTINGS: - if hasattr(custom_options, setting): - setattr(options, setting, getattr(custom_options, setting)) - elif not hasattr(options, setting): - raise Exception("This option was not defined: " + setting) - except ImportError: - pass + for setting in ALLOWED_SETTINGS: + try: + settings[setting] = getattr(options, setting) + except AttributeError: + raise Exception("The option `{0}' was not defined" \ + " in the defaults!".format(setting)) + + import sys + if not ranger.arg.clean: + # overwrite single default options with custom options + try: + import options as my_options + except ImportError: + pass + else: + for setting in ALLOWED_SETTINGS: + try: + settings[setting] = getattr(my_options, setting) + except AttributeError: + pass - assert check_option_types(options) + assert check_option_types(settings) - try: - import apps - except ImportError: - from ranger.defaults import apps - - try: - import keys - except ImportError: - from ranger.defaults import keys + # Find the colorscheme. First look for it at ~/.ranger/colorschemes, + # then at RANGERDIR/colorschemes. If the file contains a class + # named Scheme, it is used. Otherwise, an arbitrary other class + # is picked. + scheme_name = settings.colorscheme - # If a module is specified as the colorscheme, replace it with one - # valid colorscheme inside that module. + def exists(colorscheme): + return os.path.exists(colorscheme + '.py') - all_content = options.colorscheme.__dict__.items() + def is_scheme(x): + return isclass(x) and issubclass(x, ColorScheme) - if isclass(options.colorscheme) and \ - issubclass(options.colorscheme, ColorScheme): - options.colorscheme = options.colorscheme() + # create ~/.ranger/colorschemes/__init__.py if it doesn't exist + if os.path.exists(ranger.relpath_conf('colorschemes')): + initpy = ranger.relpath_conf('colorschemes', '__init__.py') + if not os.path.exists(initpy): + open(initpy, 'a').close() - elif ismodule(options.colorscheme): - def is_scheme(x): - return isclass(x) and issubclass(x, ColorScheme) + if exists(ranger.relpath_conf('colorschemes', scheme_name)): + scheme_supermodule = 'colorschemes' + elif exists(ranger.relpath('colorschemes', scheme_name)): + scheme_supermodule = 'ranger.colorschemes' + else: + scheme_supermodule = None # found no matching file. - if hasattr(options.colorscheme, 'Scheme') \ - and is_scheme(options.colorscheme.Scheme): - options.colorscheme = options.colorscheme.Scheme() + if scheme_supermodule is None: + print("ERROR: colorscheme not found, fall back to builtin scheme") + if ranger.arg.debug: + raise Exception("Cannot locate colorscheme!") + settings.colorscheme = ColorScheme() + else: + scheme_module = getattr(__import__(scheme_supermodule, + globals(), locals(), [scheme_name], 0), scheme_name) + assert ismodule(scheme_module) + if hasattr(scheme_module, 'Scheme') \ + and is_scheme(scheme_module.Scheme): + settings.colorscheme = scheme_module.Scheme() else: - for name, var in options.colorscheme.__dict__.items(): + for name, var in scheme_module.__dict__.items(): if var != ColorScheme and is_scheme(var): - options.colorscheme = var() + settings.colorscheme = var() break else: raise Exception("The module contains no " \ "valid colorscheme!") - else: - raise Exception("Cannot locate colorscheme!") - for setting in ALLOWED_SETTINGS: - SettingsAware.settings[setting] = getattr(options, setting) - - SettingsAware.settings.keys = keys - SettingsAware.settings.apps = apps + try: + import apps + except ImportError: + from ranger.defaults import apps + settings.apps = apps + try: + import keys + except ImportError: + from ranger.defaults import keys + settings.keys = keys + SettingsAware.settings = settings def check_option_types(opt): import inspect |