diff options
-rw-r--r-- | examples/README | 3 | ||||
-rw-r--r-- | examples/plugin_file_filter.py | 6 | ||||
-rw-r--r-- | ranger/config/commands.py | 77 | ||||
-rw-r--r-- | ranger/config/rc.conf | 6 | ||||
-rw-r--r-- | ranger/container/settingobject.py | 4 | ||||
-rw-r--r-- | ranger/core/actions.py | 1 | ||||
-rw-r--r-- | ranger/ext/widestring.py | 19 | ||||
-rw-r--r-- | ranger/fsobject/directory.py | 16 | ||||
-rw-r--r-- | ranger/gui/bar.py | 2 |
9 files changed, 112 insertions, 22 deletions
diff --git a/examples/README b/examples/README index 8606a89d..7c71d9cf 100644 --- a/examples/README +++ b/examples/README @@ -1,2 +1,5 @@ The files in this directory contain applications or extensions of ranger which are put here for your inspiration and as references. + +In order to use a plugin from this directory, you need to copy it to +~/.config/ranger/plugins/ diff --git a/examples/plugin_file_filter.py b/examples/plugin_file_filter.py index 99d026bb..39e4e285 100644 --- a/examples/plugin_file_filter.py +++ b/examples/plugin_file_filter.py @@ -6,11 +6,11 @@ import ranger.fsobject.directory old_accept_file = ranger.fsobject.directory.accept_file # Define a new one -def custom_accept_file(fname, mypath, hidden_filter, name_filter): - if hidden_filter and mypath == '/' and fname in ('boot', 'sbin', 'proc', 'sys'): +def custom_accept_file(fname, directory, hidden_filter, name_filter): + if hidden_filter and directory.path == '/' and fname in ('boot', 'sbin', 'proc', 'sys'): return False else: - return old_accept_file(fname, mypath, hidden_filter, name_filter) + return old_accept_file(fname, directory, hidden_filter, name_filter) # Overwrite the old function import ranger.fsobject.directory diff --git a/ranger/config/commands.py b/ranger/config/commands.py index 02ef0351..c98f36f9 100644 --- a/ranger/config/commands.py +++ b/ranger/config/commands.py @@ -1056,6 +1056,81 @@ class pmap(map_): context = 'pager' +# TODO: Maybe merge this with :find? +class narrow(Command): + """ + :narrow <string> + + Displays only the files which contain <string> in their basename. + Unlike :filter, this command executes the selection and removes the filter + again when run. + """ + + def execute(self): + self.cancel() # Clean up + if self.rest(1) == "..": + self.fm.move(left=1) + else: + self.fm.move(right=1) + + def cancel(self): + self.fm.thisdir.temporary_filter = None + self.fm.thisdir.load_content(schedule=False) + + def quick(self): + self.fm.thisdir.temporary_filter = self.build_regex(self.rest(1)) + self.fm.thisdir.load_content(schedule=False) + + def tab(self): + if self.fm.env.cwd.files[-1] is not self.fm.env.cf: + self.fm.move(down=1) + else: + # We're at the bottom, so wrap + self.fm.move(to=0) + + def build_regex(self, arg): + regex = "%s" + if arg.endswith("$"): + arg = arg[:-1] + regex += "$" + if arg.startswith("^"): + arg = arg[1:] + regex = "^" + regex + + case_insensitive = arg.lower() == arg + flags = re.I if case_insensitive else 0 + return re.compile(regex % ".*".join(arg), flags) + + +class travel(narrow, Command): + """ + :travel <string> + + Displays only the files which contain <string> in their basename. + Unlike :narrow, this leaves open the console so you can travel faster + from directory to directory. + """ + + def execute(self): + thisfile = self.fm.thisfile + narrow.execute(self) + + # reopen the console: + if thisfile and thisfile.is_directory or self.rest(1) == "..": + self.fm.open_console(self.__class__.__name__ + " ") + if self.rest(1) != "..": + self.fm.block_input(0.5) + + def quick(self): + narrow.quick(self) + arg = self.rest(1) + + if arg == ".": + return False # Make sure we can always use ".." + elif arg and len(self.fm.thisdir.files) == 1 or arg == "..": + return True + + class filter(Command): """ :filter <string> @@ -1067,6 +1142,8 @@ class filter(Command): self.fm.set_filter(self.rest(1)) self.fm.reload_cwd() + quick = execute + class grep(Command): """ diff --git a/ranger/config/rc.conf b/ranger/config/rc.conf index bc9d89e8..ef84f9a0 100644 --- a/ranger/config/rc.conf +++ b/ranger/config/rc.conf @@ -3,10 +3,8 @@ # To change them, it is recommended to create the file # ~/.config/ranger/rc.conf and add your custom commands there. # -# If you copy this whole file there, add this line to your options.py -# so it is not loaded twice: -# -# load_default_rc = False +# If you copy this whole file there, you may want to install the plugin +# "plugins/plugin_skip_default_rc.py" to avoid loading the rc.conf twice. # # The purpose of this file is mainly to define keybindings and settings. # For running more complex python code, please create a plugin in "plugins/" or diff --git a/ranger/container/settingobject.py b/ranger/container/settingobject.py index c5148e6d..b587676a 100644 --- a/ranger/container/settingobject.py +++ b/ranger/container/settingobject.py @@ -26,8 +26,8 @@ ALLOWED_SETTINGS = { 'mouse_enabled': bool, 'padding_right': bool, 'preview_directories': bool, - 'preview_images': bool, 'preview_files': bool, + 'preview_images': bool, 'preview_script': (str, type(None)), 'save_console_history': bool, 'scroll_offset': int, @@ -35,11 +35,11 @@ ALLOWED_SETTINGS = { 'show_cursor': bool, 'show_hidden_bookmarks': bool, 'show_hidden': bool, - 'status_bar_on_top': bool, 'sort_case_insensitive': bool, 'sort_directories_first': bool, 'sort_reverse': bool, 'sort': str, + 'status_bar_on_top': bool, 'tilde_in_titlebar': bool, 'unicode_ellipsis': bool, 'update_title': bool, diff --git a/ranger/core/actions.py b/ranger/core/actions.py index b02160aa..e0612952 100644 --- a/ranger/core/actions.py +++ b/ranger/core/actions.py @@ -44,7 +44,6 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware): def reset(self): """Reset the filemanager, clearing the directory buffer""" old_path = self.thisdir.path - self.restorable_tabs = {} self.previews = {} self.garbage_collect(-1) self.enter_dir(old_path) diff --git a/ranger/ext/widestring.py b/ranger/ext/widestring.py index dac54efd..31e41210 100644 --- a/ranger/ext/widestring.py +++ b/ranger/ext/widestring.py @@ -36,7 +36,14 @@ def string_to_charlist(string): if east_asian_width(c) in WIDE_SYMBOLS: result.append('') else: - string = string.decode('utf-8', 'ignore') + try: + # This raised a "UnicodeEncodeError: 'ascii' codec can't encode + # character u'\xe4' in position 10: ordinal not in range(128)" + # for me once. I thought errors='ignore' means IGNORE THE DAMN + # ERRORS but apparently it doesn't. + string = string.decode('utf-8', 'ignore') + except UnicodeEncodeError: + return [] for c in string: result.append(c.encode('utf-8')) if east_asian_width(c) in WIDE_SYMBOLS: @@ -46,7 +53,15 @@ def string_to_charlist(string): class WideString(object): def __init__(self, string, chars=None): - self.string = string + try: + self.string = str(string) + except UnicodeEncodeError: + # Here I assume that string is a "unicode" object, because why else + # would str(string) raise a UnicodeEncodeError? + try: + self.string = string.encode('latin-1', 'ignore') + except: + self.string = "" if chars is None: self.chars = string_to_charlist(string) else: diff --git a/ranger/fsobject/directory.py b/ranger/fsobject/directory.py index 8381634e..bd266982 100644 --- a/ranger/fsobject/directory.py +++ b/ranger/fsobject/directory.py @@ -37,16 +37,13 @@ def sort_naturally(path): def sort_naturally_icase(path): return path.basename_natural_lower -def accept_file(fname, dirname, hidden_filter, name_filter): - if hidden_filter: - try: - if hidden_filter.search(fname): - return False - except: - if hidden_filter in fname: - return False +def accept_file(fname, directory, hidden_filter, name_filter): + if hidden_filter and hidden_filter.search(fname): + return False if name_filter and name_filter not in fname: return False + if directory.temporary_filter and not directory.temporary_filter.search(fname): + return False return True class Directory(FileSystemObject, Accumulator, Loadable, SettingsAware): @@ -60,6 +57,7 @@ class Directory(FileSystemObject, Accumulator, Loadable, SettingsAware): filenames = None files = None filter = None + temporary_filter = None marked_items = None scroll_begin = 0 @@ -218,7 +216,7 @@ class Directory(FileSystemObject, Accumulator, Loadable, SettingsAware): filenames = [mypath + (mypath == '/' and fname or '/' + fname)\ for fname in filelist if accept_file( - fname, mypath, hidden_filter, self.filter)] + fname, self, hidden_filter, self.filter)] yield self.load_content_mtime = os.stat(mypath).st_mtime diff --git a/ranger/gui/bar.py b/ranger/gui/bar.py index a6596bf5..ebd56166 100644 --- a/ranger/gui/bar.py +++ b/ranger/gui/bar.py @@ -115,7 +115,7 @@ class ColoredString(object): self.string = WideString(string) self.lst = lst self.fixed = False - if not len(string): + if not len(string) or not len(self.string.chars): self.min_size = 0 elif PY3: self.min_size = utf_char_width(string[0]) |