diff options
-rw-r--r-- | ranger/actions.py | 28 | ||||
-rw-r--r-- | ranger/applications.py | 4 | ||||
-rw-r--r-- | ranger/container/commandlist.py | 36 | ||||
-rw-r--r-- | ranger/defaults/keys.py | 9 | ||||
-rw-r--r-- | ranger/environment.py | 14 | ||||
-rw-r--r-- | ranger/fsobject/directory.py | 17 | ||||
-rw-r--r-- | ranger/gui/colorscheme.py | 8 | ||||
-rw-r--r-- | ranger/gui/mouse_event.py | 16 | ||||
-rw-r--r-- | ranger/gui/ui.py | 43 | ||||
-rw-r--r-- | ranger/gui/widgets/console.py | 2 | ||||
-rw-r--r-- | ranger/gui/widgets/filelistcontainer.py | 5 |
11 files changed, 137 insertions, 45 deletions
diff --git a/ranger/actions.py b/ranger/actions.py index a36b0c56..2435480b 100644 --- a/ranger/actions.py +++ b/ranger/actions.py @@ -2,16 +2,20 @@ from ranger.shared import EnvironmentAware, SettingsAware class Actions(EnvironmentAware, SettingsAware): def search_forward(self): + """Search forward for the regexp in self.env.last_search""" if self.env.pwd: if self.env.pwd.search(self.env.last_search): self.env.cf = self.env.pwd.pointed_file def search_backward(self): + """Search backward for the regexp in self.env.last_search""" if self.env.pwd: if self.env.pwd.search(self.env.last_search, -1): self.env.cf = self.env.pwd.pointed_file def interrupt(self): + """Waits a short time. +If CTRL+C is pressed while waiting, the program will be exited""" import time self.env.key_clear() try: @@ -20,15 +24,19 @@ class Actions(EnvironmentAware, SettingsAware): raise SystemExit() def resize(self): + """Update the size of the UI""" self.ui.update_size() def exit(self): + """Exit the program""" raise SystemExit() def enter_dir(self, path): + """Enter the directory at the given path""" self.env.enter_dir(path) def enter_bookmark(self, key): + """Enter the bookmark with the name <key>""" from ranger.container.bookmarks import NonexistantBookmark try: destination = self.bookmarks[key] @@ -40,26 +48,38 @@ class Actions(EnvironmentAware, SettingsAware): pass def set_bookmark(self, key): + """Set the bookmark with the name <key> to the current directory""" self.bookmarks[key] = self.env.pwd.path def unset_bookmark(self, key): + """Delete the bookmark with the name <key>""" self.bookmarks.delete(key) def move_left(self): + """Enter the parent directory""" self.env.enter_dir('..') def move_right(self, mode = 0): + """Enter the current directory or execute the current file""" cf = self.env.cf if not self.env.enter_dir(cf): self.execute_file(cf, mode = mode) def history_go(self, relative): + """Move back and forth in the history""" self.env.history_go(relative) def handle_mouse(self): + """Handle mouse-buttons if one was pressed""" self.ui.handle_mouse() def execute_file(self, files, app = '', flags = '', mode = 0): + """Execute a file. +app is the name of a method in Applications, without the "app_" +flags is a string consisting of applications.ALLOWED_FLAGS +mode is a positive integer. +Both flags and mode specify how the program is run.""" + if type(files) not in (list, tuple): files = [files] @@ -73,35 +93,43 @@ class Actions(EnvironmentAware, SettingsAware): apps = self.apps) def edit_file(self): + """Calls execute_file with the current file and app='editor'""" if self.env.cf is None: return self.execute_file(self.env.cf, app = 'editor') def open_console(self, mode = ':'): + """Open the console if the current UI supports that""" if hasattr(self.ui, 'open_console'): self.ui.open_console(mode) def move_pointer(self, relative = 0, absolute = None): + """Move the pointer down by <relative> or to <absolute>""" self.env.cf = self.env.pwd.move_pointer(relative, absolute) def move_pointer_by_pages(self, relative): + """Move the pointer down by <relative> pages""" self.env.cf = self.env.pwd.move_pointer( relative = int(relative * self.env.termsize[0])) def scroll(self, relative): + """Scroll down by <relative> lines""" if hasattr(self.ui, 'scroll'): self.ui.scroll(relative) self.env.cf = self.env.pwd.pointed_file def redraw(self): + """Redraw the window""" self.ui.redraw() def reset(self): + """Reset the filemanager, clearing the directory buffer""" old_path = self.env.pwd.path self.env.directories = {} self.enter_dir(old_path) def toggle_boolean_option(self, string): + """Toggle a boolean option named <string>""" if isinstance(self.env.settings[string], bool): self.env.settings[string] ^= True diff --git a/ranger/applications.py b/ranger/applications.py index 85dc50f5..39601e0e 100644 --- a/ranger/applications.py +++ b/ranger/applications.py @@ -2,21 +2,25 @@ ALLOWED_FLAGS = 'sdpSDP' class Applications(object): def get(self, app): + """Looks for an application, returns app_default if it doesn't exist""" try: return getattr(self, 'app_' + app) except AttributeError: return self.app_default def has(self, app): + """Returns whether an application is defined""" return hasattr(self, 'app_' + app) def all(self): + """Returns a list with all application functions""" return [x for x in self.__dict__ if x.startswith('app_')] import os null = open(os.devnull, 'a') def run(*args, **kw): + """Run files with the specified parameters""" from subprocess import Popen from subprocess import PIPE from ranger.ext.waitpid_no_intr import waitpid_no_intr diff --git a/ranger/container/commandlist.py b/ranger/container/commandlist.py index a252fea2..9c4c77a0 100644 --- a/ranger/container/commandlist.py +++ b/ranger/container/commandlist.py @@ -1,15 +1,25 @@ +"""CommandLists are dictionary-like objects which give you a command +for a given key combination. CommandLists must be initialized +before use.""" class CommandList(object): + dummy_object = None + dummies_in_paths = False + paths = {} + commandlist = [] def __init__(self): self.commandlist = [] self.paths = {} - self.dummies_in_paths = False - self.dummy_object = None + + def __getitem__(self, key): + """Returns the command with the given key combination""" + return self.paths[key] - # We need to know when to clear the keybuffer (when a wrong key is pressed) - # and when to wait for the rest of the key combination. For "gg" we - # will assign "g" to a dummy which tells the program to do the latter. def rebuild_paths(self): - """ fill the path dictionary with dummie objects """ + """Fill the path dictionary with dummie objects. +We need to know when to clear the keybuffer (when a wrong key is pressed) +and when to wait for the rest of the key combination. For "gg" we +will assign "g" to a dummy which tells the program to do the latter +and wait.""" if self.dummies_in_paths: self.remove_dummies() @@ -22,7 +32,7 @@ class CommandList(object): self.dummies_in_paths = True def keypath(self, tup): - """ split a tuple like (a,b,c,d) into [(a,), (a,b), (a,b,c)] """ + """split a tuple like (a,b,c,d) into [(a,), (a,b), (a,b,c)]""" length = len(tup) if length == 0: @@ -40,7 +50,7 @@ class CommandList(object): return all def remove_dummies(self): - """ remove dummie objects in case you have to rebuild a path dictionary which already contains dummie objects. """ + """remove dummie objects in case you have to rebuild a path dictionary which already contains dummie objects.""" for k in tuple(paths.keys()): if paths[k] == self.dummy_object: del paths[k] self.dummies_in_paths = False @@ -58,21 +68,23 @@ class CommandList(object): raise TypeError('need a str, int or tuple for str_to_tuple') def bind(self, fnc, *keys): - """ create a Command object and assign it to the given key combinations. """ + """create a Command object and assign it to the given key combinations.""" if len(keys) == 0: return keys = tuple(map(self.str_to_tuple, keys)) cmd = Command(fnc, keys) - cmd.commandlist = self self.commandlist.append(cmd) for key in keys: self.paths[key] = cmd class Command(object): + keys = [] def __init__(self, fnc, keys): - self.execute = fnc self.keys = keys - self.commandlist = None + self.execute = fnc + + def execute(self, *args): + """Execute the command.""" diff --git a/ranger/defaults/keys.py b/ranger/defaults/keys.py index 7d6f7bd6..ffd37646 100644 --- a/ranger/defaults/keys.py +++ b/ranger/defaults/keys.py @@ -2,6 +2,7 @@ import curses from curses.ascii import ctrl, ESC def initialize_commands(command_list): + """Initialize the commands for the main user interface""" from ranger.actions import Actions as do from ranger.container.bookmarks import ALLOWED_KEYS as ALLOWED_BOOKMARK_KEYS @@ -89,15 +90,13 @@ def initialize_commands(command_list): def initialize_console_commands(command_list): + """Initialize the commands for the console widget only""" from ranger.actions import Actions as do from ranger.gui.widgets.console import Console def bind(fnc, *keys): command_list.bind(fnc, *keys) - def type_key(key): - return lambda con: con.type_key(key) - # currying def c(fnc, *args, **keywords): return lambda con: fnc(con, *args, **keywords) @@ -122,6 +121,10 @@ def initialize_console_commands(command_list): bind(c_fm(do.redraw), ctrl('L')) bind(c_fm(do.resize), curses.KEY_RESIZE) + + def type_key(key): + return lambda con: con.type_key(key) + for i in range(ord(' '), ord('~')): bind(type_key(i), i) diff --git a/ranger/environment.py b/ranger/environment.py index 9e2c2877..881e25e0 100644 --- a/ranger/environment.py +++ b/ranger/environment.py @@ -23,12 +23,18 @@ class Environment(SettingsAware): EnvironmentAware.env = self def key_append(self, key): + """Append a key to the keybuffer""" self.keybuffer = KeyBuffer(self.keybuffer + (key, )) def key_clear(self): + """Clear the keybuffer""" self.keybuffer = KeyBuffer() def at_level(self, level): + """Returns the FileSystemObject at the given level. +level 1 => preview +level 0 => current file/directory +level <0 => parent directories""" if level <= 0: try: return self.pathway[level - 1] @@ -43,14 +49,16 @@ class Environment(SettingsAware): return self.cf def garbage_collect(self): + """Delete unused directory objects""" from ranger.fsobject.fsobject import FileSystemObject for key in tuple(self.directories.keys()): value = self.directories[key] if isinstance(value, FileSystemObject): - if value.is_older_than(1): + if value.is_older_than(1200): del self.directories[key] def get_directory(self, path): + """Get the directory object at the given path""" path = abspath(path) try: return self.directories[path] @@ -59,7 +67,7 @@ class Environment(SettingsAware): return self.directories[path] def assign_correct_cursor_positions(self): - # Assign correct cursor positions for subdirectories + """Assign correct cursor positions for subdirectories""" last_path = None for path in reversed(self.pathway): if last_path is None: @@ -70,11 +78,13 @@ class Environment(SettingsAware): last_path = path def history_go(self, relative): + """Move relative in history""" if self.history: # self.enter_dir(self.history.move(relative)) self.history.move(relative).go() def enter_dir(self, path, history = True): + """Enter given path""" if path is None: return path = str(path) diff --git a/ranger/fsobject/directory.py b/ranger/fsobject/directory.py index cdcbc2ed..0ebfff13 100644 --- a/ranger/fsobject/directory.py +++ b/ranger/fsobject/directory.py @@ -44,6 +44,8 @@ class Directory(SuperClass, SettingsAware): self.old_directories_first = self.settings.directories_first def load_content(self): + """Loads the contents of the directory. Use this sparingly since +it takes rather long.""" from os.path import join, isdir, basename from os import listdir @@ -85,6 +87,7 @@ class Directory(SuperClass, SettingsAware): self.infostring = BAD_INFO def sort(self): + """Sort the containing files""" if self.files is None: return @@ -102,6 +105,7 @@ class Directory(SuperClass, SettingsAware): self.old_directories_first = self.settings.directories_first def sort_if_outdated(self): + """Sort the containing files if they are outdated""" if self.old_directories_first != self.settings.directories_first: self.sort() @@ -109,6 +113,7 @@ class Directory(SuperClass, SettingsAware): # modify the current directory with this function, make sure # to update fm.env.cf aswell. def move_pointer(self, relative=0, absolute=None): + """Move the index pointer""" if self.empty(): return i = self.pointed_index if isinstance(absolute, int): @@ -124,6 +129,8 @@ class Directory(SuperClass, SettingsAware): return self.pointed_file def move_pointer_to_file_path(self, path): + """Move the index pointer to the index of the file object +with the given path.""" if path is None: return try: path = path.path except AttributeError: pass @@ -140,6 +147,7 @@ class Directory(SuperClass, SettingsAware): return False def search(self, arg, direction = 1): + """Search for a regular expression""" if self.empty() or arg is None: return False elif hasattr(arg, 'search'): @@ -180,12 +188,15 @@ class Directory(SuperClass, SettingsAware): self.pointed_file = self[i] def load_content_once(self): + """Load the contents of the directory if not done yet""" if not self.content_loaded: self.load_content() return True return False def load_content_if_outdated(self): + """Load the contents of the directory if it's +outdated or not done yet""" if self.load_content_once(): return True if self.old_show_hidden != self.settings.show_hidden: @@ -203,21 +214,27 @@ class Directory(SuperClass, SettingsAware): return False def empty(self): + """Is the directory empty?""" return self.files is None or len(self.files) == 0 def __nonzero__(self): + """Always True""" return True def __len__(self): + """The number of containing files""" if not self.accessible: raise ranger.fsobject.NotLoadedYet() return len(self.files) def __getitem__(self, key): + """Get the file by its index""" if not self.accessible: raise ranger.fsobject.NotLoadedYet() return self.files[key] def __eq__(self, other): + """Check for equality of the directories paths""" return isinstance(other, Directory) and self.path == other.path def __neq__(self, other): + """Check for inequality of the directories paths""" return not self.__eq__(other) diff --git a/ranger/gui/colorscheme.py b/ranger/gui/colorscheme.py index 38f4ac5a..a69ed75b 100644 --- a/ranger/gui/colorscheme.py +++ b/ranger/gui/colorscheme.py @@ -35,6 +35,7 @@ class ColorScheme(object): self.cache = {} def get(self, *keys): + """Determine the (fg, bg, attr) tuple or get it from cache""" try: return self.cache[keys] @@ -50,6 +51,7 @@ class ColorScheme(object): return color def get_attr(self, *keys): + """Returns the curses attr integer for the specified keys""" from ranger.gui.color import get_color import curses @@ -58,5 +60,9 @@ class ColorScheme(object): def use(self, context): - return -1, -1, 0 + """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!""" + from ranger.gui.color import default_colors + return default_colors diff --git a/ranger/gui/mouse_event.py b/ranger/gui/mouse_event.py index fa25f5f0..db98e1aa 100644 --- a/ranger/gui/mouse_event.py +++ b/ranger/gui/mouse_event.py @@ -1,5 +1,5 @@ +import curses class MouseEvent(object): - import curses PRESSED = [ 0, curses.BUTTON1_PRESSED, curses.BUTTON2_PRESSED, @@ -7,10 +7,24 @@ class MouseEvent(object): curses.BUTTON4_PRESSED ] def __init__(self, getmouse): + """Creates a MouseEvent object from the result of win.getmouse()""" _, self.x, self.y, _, self.bstate = getmouse def pressed(self, n): + """Returns whether the mouse key n is pressed""" try: return (self.bstate & MouseEvent.PRESSED[n]) != 0 except: return False + + def ctrl(self): + return self.bstate & curses.BUTTON_CTRL + + def alt(self): + return self.bstate & curses.BUTTON_ALT + + def shift(self): + return self.bstate & curses.BUTTON_SHIFT + + def key_invalid(self): + return self.bstate > curses.ALL_MOUSE_EVENTS diff --git a/ranger/gui/ui.py b/ranger/gui/ui.py index 7b7230fb..eb25d9ca 100644 --- a/ranger/gui/ui.py +++ b/ranger/gui/ui.py @@ -48,6 +48,18 @@ class UI(DisplayableContainer): self.setup() self.update_size() + def destroy(self): + """Destroy all widgets and turn off curses""" +# DisplayableContainer.destroy(self) + from ranger import log + log("exiting ui!") + self.win.keypad(0) + curses.nocbreak() + curses.echo() + curses.curs_set(1) + curses.mousemask(0) + curses.endwin() + def handle_mouse(self): """Handles mouse input""" try: @@ -55,20 +67,17 @@ class UI(DisplayableContainer): except: return +# from ranger import log +# log('{0:0>28b} ({0})'.format(event.bstate)) + if DisplayableContainer.click(self, event): return -# if event.pressed(1) or event.pressed(3): -# for displayable in self.container: -# if displayable.contains_point(event.y, event.x): -# displayable.click(event) -# break - -# if event.pressed(4) or event.pressed(2) or event.bstate & 134217728: + n = event.ctrl() and 1 or 3 if event.pressed(4): - self.fm.scroll(relative = -3) - elif event.pressed(2): - self.fm.scroll(relative = 3) + self.fm.scroll(relative = -n) + elif event.pressed(2) or event.key_invalid(): + self.fm.scroll(relative = n) def handle_key(self, key): """Handles key input""" @@ -78,7 +87,7 @@ class UI(DisplayableContainer): return try: - cmd = self.commandlist.paths[tuple(self.env.keybuffer)] + cmd = self.commandlist[tuple(self.env.keybuffer)] except KeyError: self.env.key_clear() return @@ -119,15 +128,3 @@ Extend this method to resize all widgets!""" """Finalize every object in container and refresh the window""" DisplayableContainer.finalize(self) self.win.refresh() - - def destroy(self): - """Destroy all widgets and turn off curses""" -# DisplayableContainer.destroy(self) - from ranger import log - log("exiting ui!") - self.win.keypad(0) - curses.nocbreak() - curses.echo() - curses.curs_set(1) -# curses.mousemask(0) - curses.endwin() diff --git a/ranger/gui/widgets/console.py b/ranger/gui/widgets/console.py index 17197a2e..f4b278c9 100644 --- a/ranger/gui/widgets/console.py +++ b/ranger/gui/widgets/console.py @@ -69,7 +69,7 @@ class Console(Widget): from curses.ascii import ctrl, ESC try: - cmd = self.commandlist.paths[self.env.keybuffer] + cmd = self.commandlist[self.env.keybuffer] except KeyError: self.env.key_clear() return diff --git a/ranger/gui/widgets/filelistcontainer.py b/ranger/gui/widgets/filelistcontainer.py index ed5a36c4..9d95b389 100644 --- a/ranger/gui/widgets/filelistcontainer.py +++ b/ranger/gui/widgets/filelistcontainer.py @@ -19,7 +19,8 @@ class FileListContainer(Widget, DisplayableContainer): if preview: offset += 1 for level in range(len(ratios)): - self.add_obj(FileList(win, level + offset)) + fl = FileList(win, level + offset) + self.add_obj(fl) try: self.main_filelist = self.container[preview and -2 or -1] @@ -32,7 +33,7 @@ class FileListContainer(Widget, DisplayableContainer): def resize(self, y, x, hei, wid): """Resize all the filelists according to the given ratio""" DisplayableContainer.resize(self, y, x, hei, wid) - left = self.y + left = self.x for ratio, i in zip(self.ratios, range(len(self.ratios))): wid = int(ratio * self.wid) try: |