summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md40
-rw-r--r--README.md6
-rw-r--r--doc/ranger.12
-rw-r--r--doc/rifle.14
-rw-r--r--examples/rc_emacs.conf1
-rw-r--r--ranger/__init__.py2
-rw-r--r--ranger/api/commands.py2
-rw-r--r--ranger/config/commands.py14
-rw-r--r--ranger/config/rifle.conf8
-rw-r--r--ranger/container/fsobject.py10
-rw-r--r--ranger/core/actions.py94
-rw-r--r--ranger/core/loader.py10
-rw-r--r--ranger/data/mime.types1
-rwxr-xr-xranger/data/scope.sh8
-rwxr-xr-xranger/ext/rifle.py4
-rw-r--r--ranger/gui/colorscheme.py2
-rw-r--r--ranger/gui/curses_shortcuts.py8
-rw-r--r--ranger/gui/widgets/__init__.py2
-rw-r--r--ranger/gui/widgets/browsercolumn.py7
-rw-r--r--ranger/gui/widgets/titlebar.py4
20 files changed, 157 insertions, 72 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index da47c5bd..bff84808 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,20 @@
-# 2015-05-04: version 1.7.1
+This log documents changes between stable versions.
+
+# 2015-10-04: version 1.7.2
+* Fixed file name arguments passed to `sxiv` and `feh` when using `:flat`
+* Fixed removal of empty directories when using `:rename`
+* Fixed free disk space display on Mac OS X
+* Fixed `examples/vim_file_chooser` to work with gvim too
+* Fixed some other rare crashes and bugs
+* Fixed downward mouse wheel scrolling
+* Fixed warning about regex splits being drawin in title bar since python3.5
+* Really fixed `S` key binding not working when SHELL=fish
+* Improved `doc/cheatsheet.svg`
+* Added some entries to rifle.conf
+* Added key bindings `pO` and `pP` which work like `po` and `pp` but queue the
+  operation in a first-in-first-out order.
 
+# 2015-05-04: version 1.7.1
 * Added `doc/cheatsheet.svg`
 * Added `examples/rc_emacs.conf`, a config file adding emacs-like key bindings
 * Added `env` keyword in rifle.conf
@@ -7,7 +22,6 @@
 * Fixed `S` key binding not working when SHELL=fish
 
 # 2015-04-13: version 1.7.0
-
 * The default editor is now `vim` instead of `nano`
 * Added automatic updates of tags when a file is renamed from within ranger
 * Added `preview_images_method` which can be set to `iterm2` to use native
@@ -32,7 +46,6 @@
 * Fixed broken copying of symlinks
 
 # 2013-05-24: Version 1.6.1
-
 * Added support for version control systems, see:
   http://lists.nongnu.org/archive/html/ranger-users/2013-03/msg00007.html
 * Added :scout command as a unified backend to :find, :search, etc
@@ -41,7 +54,6 @@
 * Now previewing with `i` uses the whole available width.
 
 # 2013-02-22: Version 1.6.0
-
 * Overhauled all config files.  Please update them or use the --clean switch
 * Added `examples/` directory to source code which contains sample programs or
   plugins that can be used together with ranger
@@ -80,17 +92,14 @@
 * Fixed `draw_borders=true` in combination with `padding_right=false`
 
 # 2012-08-10: Version 1.5.5
-
 * Ensure that detached programs continue to run when ranger is killed
 
 # 2012-05-03: Version 1.5.4
-
 * Added exiftool to scope.sh by default
 * Fixed a crash when entering a directory with a unicode name
 * Speedup in `ranger.ext.get_executables`
 
 # 2012-03-05: Version 1.5.3
-
 * Added --selectfile option that selects a certain file on startup
 * Added --list-tagged-files option
 * Added --cmd option to run commands on startup
@@ -113,12 +122,10 @@
 * Fixed crash when opening images with sxiv/feh by running `ranger <image>`
 
 # 2011-10-23: Version 1.5.2
-
 * Fixed graphical bug that appears in certian cases when drawing
   characters at the right edge.
 
 # 2011-10-23: Version 1.5.1
-
 * Added `fm.select_file(path)`
 * Added --choosefiles option (like --choosefile, but chooses multiple files)
 * Fixed --list-unused-keys
@@ -130,7 +137,6 @@
 * Fixed parsing of chained commands (like in the binding `om`)
 
 # 2011-10-11: Version 1.5.0
-
 * Full python3.2 compatibility
 * Added new configuration file `rc.conf` which contains a list
   of commands that are executed on startup - mainly used for keybindings
@@ -162,7 +168,6 @@
 * Countless small fixes and improvements
 
 # 2011-10-02: Version 1.4.4
-
 * Added keys for chmod (like +ow for `chmod o+w`, etc)
 * Added `c` flag for running files
 * Added various key bindings
@@ -179,24 +184,20 @@
 * Improved hints
 
 # 2011-04-05: Version 1.4.3
-
 * Fixed mimetype checking when invoking ranger with a filename
 * Fixed loss of bookmarks when disk is full
 * Minor improvements
 
 # 2011-03-05: Version 1.4.2
-
 * Added --choosefile and --choosedir flag
 * Added use of bookmarks in tab completion of the :cd command
 * Fixed bug with detached programs and python 3.2
 
 # 2011-01-04: Version 1.4.1
-
 * Fixed crash when preview failed under some circumstances
 * Fixed graphical bug when pressing i
 
 # 2010-12-22: Version 1.4.0
-
 * Added option to use any external scripts for previews (see scope.sh)
 * Added key: zv to toggle the use of the external script
 * Added indicator for the used filter (type `zf`)
@@ -214,7 +215,6 @@
 * Some restructuration of the source code
 
 # 2010-12-13: Version 1.2.3
-
 * Enable binding to alt-keys
 * Fixed memory leak in garbage collecting of old, unused directory objects
 * Fixed python3 incompatibilities
@@ -222,7 +222,6 @@
 * Fixed lazy lookup of some FSObject attributes
 
 # 2010-10-10: Version 1.2.2
-
 * Prevent currently used directories from being garbage collected
 * Disable mouse buttons when console is open
 * Fixed :cd command: Without arguments, cd's into $HOME
@@ -231,11 +230,9 @@
 * Several other clean-ups and fixes
 
 # 2010-09-16: Version 1.2.1
-
 * Fixed yy/pp bug when yanking multiple directories
 
 # 2010-09-13: Version 1.2.0
-
 * !!! Changed the default configuration directory to ~/.config/ranger !!!
 * Removed `Console Modes`, each old mode is now a simple command
 * Disabled file previews by default if ranger is used by root
@@ -249,20 +246,17 @@
 * Several clean-ups and fixes
 
 # 2010-07-17: Version 1.1.2
-
 * Fix crash when using scrollwheel to scroll down in some cases
 * The command `ranger dir1 dir2 ...` opens multiple directories in tabs
 * Removed pydoc html documentation by default, re-create it with `make doc`
 * Minor fixes
 
 # 2010-06-18: Version 1.1.1
-
 * New install script, `setup.py`
 * New flag for running programs: `w` (waits for enter press)
 * Minor fixes
 
 # 2010-06-09: Version 1.1.0
-
 * Added a man page
 * Tab support
 * Improved directory loading performance
@@ -277,3 +271,5 @@
 * New syntax for ~/.ranger/keys.py
 * Several user contributions
 * And tons of general improvements
+
+NOTE: The syntax for configuration is still subject to change.
diff --git a/README.md b/README.md
index 2ee3bcd6..57b2631d 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-ranger v.1.7.1
+ranger v.1.7.2
 ==============
 ranger is a console file manager with VI key bindings.  It provides a
 minimalistic and nice curses interface with a view on the directory hierarchy.
@@ -52,8 +52,8 @@ Features
 
 Dependencies
 ------------
-* Python (tested with version 2.6, 2.7, 3.1, 3.2) with support for ncurses
-  and (optionally) wide-unicode.
+* Python (tested with version 2.6, 2.7, 3.1, 3.2) with the "curses" module
+  and (optionally) wide-unicode support.
 * A pager ("less" by default)
 
 Optional:
diff --git a/doc/ranger.1 b/doc/ranger.1
index ea720903..f426d5c6 100644
--- a/doc/ranger.1
+++ b/doc/ranger.1
@@ -133,7 +133,7 @@
 .\" ========================================================================
 .\"
 .IX Title "RANGER 1"
-.TH RANGER 1 "ranger-1.7.1" "07/15/2015" "ranger manual"
+.TH RANGER 1 "ranger-1.7.2" "10/04/2015" "ranger manual"
 .\" For nroff, turn off justification.  Always turn off hyphenation; it makes
 .\" way too many mistakes in technical documents.
 .if n .ad l
diff --git a/doc/rifle.1 b/doc/rifle.1
index 3bb74dd8..32501ee0 100644
--- a/doc/rifle.1
+++ b/doc/rifle.1
@@ -1,4 +1,4 @@
-.\" Automatically generated by Pod::Man 2.28 (Pod::Simple 3.28)
+.\" Automatically generated by Pod::Man 2.28 (Pod::Simple 3.29)
 .\"
 .\" Standard preamble:
 .\" ========================================================================
@@ -133,7 +133,7 @@
 .\" ========================================================================
 .\"
 .IX Title "RIFLE 1"
-.TH RIFLE 1 "rifle-1.7.1" "05/04/2015" "rifle manual"
+.TH RIFLE 1 "rifle-1.7.2" "10/04/2015" "rifle manual"
 .\" For nroff, turn off justification.  Always turn off hyphenation; it makes
 .\" way too many mistakes in technical documents.
 .if n .ad l
diff --git a/examples/rc_emacs.conf b/examples/rc_emacs.conf
index e8b76ff2..f5e66b89 100644
--- a/examples/rc_emacs.conf
+++ b/examples/rc_emacs.conf
@@ -419,7 +419,6 @@ eval for arg in "rwxXst": cmd("map <C-x>-{0}  shell -f chmod u-{0} %s".format(ar
 
 # Search for letters as you type them
 #eval for arg in "abcdefghijklmnopqrstuvwxyz": cmd("map {0} console search_inc {0}".format(arg))
-map <allow_quantifiers> false
 
 # ===================================================================
 # == Define keys for the console
diff --git a/ranger/__init__.py b/ranger/__init__.py
index 8a1e7459..20c8ab35 100644
--- a/ranger/__init__.py
+++ b/ranger/__init__.py
@@ -14,7 +14,7 @@ import tempfile
 
 # Information
 __license__ = 'GPL3'
-__version__ = '1.7.1'
+__version__ = '1.7.2'
 __author__ = __maintainer__ = 'Roman Zimbelmann'
 __email__ = 'hut@hut.pm'
 
diff --git a/ranger/api/commands.py b/ranger/api/commands.py
index 2cf96a9f..ca713d0c 100644
--- a/ranger/api/commands.py
+++ b/ranger/api/commands.py
@@ -47,7 +47,7 @@ class CommandContainer(object):
                 continue
             attribute = getattr(obj, attribute_name)
             if hasattr(attribute, '__call__'):
-                cmd = type(attribute_name, (FunctionCommand, ), dict())
+                cmd = type(attribute_name, (FunctionCommand, ), dict(__doc__=attribute.__doc__))
                 cmd._based_function = attribute
                 cmd._function_name = attribute.__name__
                 cmd._object_name = obj.__class__.__name__
diff --git a/ranger/config/commands.py b/ranger/config/commands.py
index 9f0481ce..4f7f109a 100644
--- a/ranger/config/commands.py
+++ b/ranger/config/commands.py
@@ -226,7 +226,7 @@ class shell(Command):
         else:
             before_word, start_of_word = self.line.rsplit(' ', 1)
             return (before_word + ' ' + file.shell_escaped_basename \
-                    for file in self.fm.thisdir.files \
+                    for file in self.fm.thisdir.files or [] \
                     if file.shell_escaped_basename.startswith(start_of_word))
 
 class open_with(Command):
@@ -342,12 +342,12 @@ class set_(Command):
         if not name:
             return sorted(self.firstpart + setting for setting in settings)
         if not value and not name_done:
-            return (self.firstpart + setting for setting in settings \
+            return sorted(self.firstpart + setting for setting in settings \
                     if setting.startswith(name))
         if not value:
             # Cycle through colorschemes when name, but no value is specified
             if name == "colorscheme":
-                return (self.firstpart + colorscheme for colorscheme \
+                return sorted(self.firstpart + colorscheme for colorscheme \
                         in get_all_colorschemes())
             return self.firstpart + str(settings[name])
         if bool in settings.types_of(name):
@@ -357,7 +357,7 @@ class set_(Command):
                 return self.firstpart + 'False'
         # Tab complete colorscheme values if incomplete value is present
         if name == "colorscheme":
-            return (self.firstpart + colorscheme for colorscheme \
+            return sorted(self.firstpart + colorscheme for colorscheme \
                     in get_all_colorschemes() if colorscheme.startswith(value))
 
 
@@ -548,7 +548,7 @@ class mark_tag(Command):
     def execute(self):
         cwd = self.fm.thisdir
         tags = self.rest(1).replace(" ","")
-        if not self.fm.tags:
+        if not self.fm.tags or not cwd.files:
             return
         for fileobj in cwd.files:
             try:
@@ -1131,7 +1131,7 @@ class scout(Command):
         self.fm.thistab.last_search = regex
         self.fm.set_search_method(order="search")
 
-        if self.MARK in flags or self.UNMARK in flags:
+        if (self.MARK in flags or self.UNMARK in flags) and thisdir.files:
             value = flags.find(self.MARK) > flags.find(self.UNMARK)
             if self.FILTER in flags:
                 for f in thisdir.files:
@@ -1234,7 +1234,7 @@ class scout(Command):
         cwd     = self.fm.thisdir
         pattern = self.pattern
 
-        if not pattern:
+        if not pattern or not cwd.files:
             return 0
         if pattern == '.':
             return 0
diff --git a/ranger/config/rifle.conf b/ranger/config/rifle.conf
index 95e4242a..31db35a4 100644
--- a/ranger/config/rifle.conf
+++ b/ranger/config/rifle.conf
@@ -57,6 +57,7 @@
 ext x?html?, has surf,           X, flag f = surf -- file://"$1"
 ext x?html?, has vimprobable,    X, flag f = vimprobable -- "$@"
 ext x?html?, has vimprobable2,   X, flag f = vimprobable2 -- "$@"
+ext x?html?, has qutebrowser,    X, flag f = qutebrowser -- "$@"
 ext x?html?, has dwb,            X, flag f = dwb -- "$@"
 ext x?html?, has jumanji,        X, flag f = jumanji -- "$@"
 ext x?html?, has luakit,         X, flag f = luakit -- "$@"
@@ -107,9 +108,9 @@ ext php = php -- "$1"
 #--------------------------------------------
 # Audio without X
 #-------------------------------------------
-mime ^audio|ogg$, terminal, has mplayer  = mplayer -- "$@"
-mime ^audio|ogg$, terminal, has mplayer2 = mplayer2 -- "$@"
 mime ^audio|ogg$, terminal, has mpv      = mpv -- "$@"
+mime ^audio|ogg$, terminal, has mplayer2 = mplayer2 -- "$@"
+mime ^audio|ogg$, terminal, has mplayer  = mplayer -- "$@"
 ext midi?,        terminal, has wildmidi = wildmidi -- "$@"
 
 #--------------------------------------------
@@ -201,3 +202,6 @@ label wallpaper, number 14, mime ^image, has feh, X = feh --bg-fill "$1"
               !mime ^text, !ext xml|json|csv|tex|py|pl|rb|js|sh|php  = ask
 label editor, !mime ^text, !ext xml|json|csv|tex|py|pl|rb|js|sh|php  = $EDITOR -- "$@"
 label pager,  !mime ^text, !ext xml|json|csv|tex|py|pl|rb|js|sh|php  = "$PAGER" -- "$@"
+
+# The very last action, so that it's never triggered accidently, is to execute a program:
+mime application/x-executable = "$1"
diff --git a/ranger/container/fsobject.py b/ranger/container/fsobject.py
index 334cc2f9..aa848b7a 100644
--- a/ranger/container/fsobject.py
+++ b/ranger/container/fsobject.py
@@ -30,7 +30,7 @@ else:
     from string import maketrans
 _unsafe_chars = '\n' + ''.join(map(chr, range(32))) + ''.join(map(chr, range(128, 256)))
 _safe_string_table = maketrans(_unsafe_chars, '?' * len(_unsafe_chars))
-_extract_number_re = re.compile(r'([^0-9]?)(\d*)')
+_extract_number_re = re.compile(r'(\d+)')
 
 def safe_path(path):
     return path.translate(_safe_string_table)
@@ -144,13 +144,13 @@ class FileSystemObject(FileManagerAware, SettingsAware):
 
     @lazy_property
     def basename_natural(self):
-        return [c if i % 3 == 1 else (int(c) if c else 0) for i, c in \
-            enumerate(_extract_number_re.split(self.relative_path))]
+        return [int(s) if s.isdigit() else s \
+                for s in _extract_number_re.split(self.relative_path)]
 
     @lazy_property
     def basename_natural_lower(self):
-        return [c if i % 3 == 1 else (int(c) if c else 0) for i, c in \
-            enumerate(_extract_number_re.split(self.relative_path_lower))]
+        return [int(s) if s.isdigit() else s \
+                for s in _extract_number_re.split(self.relative_path_lower)]
 
     @lazy_property
     def safe_basename(self):
diff --git a/ranger/core/actions.py b/ranger/core/actions.py
index 8167dbcf..26dcf4f7 100644
--- a/ranger/core/actions.py
+++ b/ranger/core/actions.py
@@ -41,11 +41,17 @@ class Actions(FileManagerAware, SettingsAware):
     # --------------------------
 
     def exit(self):
-        """Exit the program"""
+        """:exit
+
+        Exit the program.
+        """
         raise SystemExit()
 
     def reset(self):
-        """Reset the filemanager, clearing the directory buffer"""
+        """:reset
+
+        Reset the filemanager, clearing the directory buffer.
+        """
         old_path = self.thisdir.path
         self.previews = {}
         self.garbage_collect(-1)
@@ -55,6 +61,10 @@ class Actions(FileManagerAware, SettingsAware):
             self.metadata.reset()
 
     def change_mode(self, mode):
+        """:change_mode <mode>
+
+        Change mode to "visual" (selection) or "normal" mode.
+        """
         if mode == self.mode:
             return
         if mode == 'visual':
@@ -103,6 +113,10 @@ class Actions(FileManagerAware, SettingsAware):
         raise ValueError("Invalid value `%s' for option `%s'!" % (name, value))
 
     def toggle_visual_mode(self, reverse=False, narg=None):
+        """:toggle_visual_mode
+
+        Toggle the visual mode (see :change_mode).
+        """
         if self.mode == 'normal':
             self._visual_reverse = reverse
             if narg != None:
@@ -112,14 +126,23 @@ class Actions(FileManagerAware, SettingsAware):
             self.change_mode('normal')
 
     def reload_cwd(self):
+        """:reload_cwd
+
+        Reload the current working directory.
+        """
         try:
             cwd = self.thisdir
         except:
             pass
-        cwd.unload()
-        cwd.load_content()
+        else:
+            cwd.unload()
+            cwd.load_content()
 
     def notify(self, text, duration=4, bad=False):
+        """:notify <text>
+
+        Display the text in the statusbar.
+        """
         if isinstance(text, Exception):
             if ranger.arg.debug:
                 raise
@@ -135,6 +158,10 @@ class Actions(FileManagerAware, SettingsAware):
             print(text)
 
     def abort(self):
+        """:abort
+
+        Empty the first queued action.
+        """
         try:
             item = self.loader.queue[0]
         except:
@@ -150,16 +177,25 @@ class Actions(FileManagerAware, SettingsAware):
         self.ui.redraw_main_column()
 
     def redraw_window(self):
-        """Redraw the window"""
+        """:redraw
+
+        Redraw the window.
+        """
         self.ui.redraw_window()
 
     def open_console(self, string='', prompt=None, position=None):
-        """Open the console"""
+        """:open_console [string]
+
+        Open the console.
+        """
         self.change_mode('normal')
         self.ui.open_console(string, prompt=prompt, position=position)
 
     def execute_console(self, string='', wildcards=[], quantifier=None):
-        """Execute a command for the console"""
+        """:execute_console [string]
+
+        Execute a command for the console
+        """
         command_name = string.lstrip().split()[0]
         cmd_class = self.commands.get_command(command_name, abbrev=False)
         if cmd_class is None:
@@ -291,6 +327,10 @@ class Actions(FileManagerAware, SettingsAware):
         return macros
 
     def source(self, filename):
+        """:source <filename>
+
+        Load a config file.
+        """
         filename = os.path.expanduser(filename)
         for line in open(filename, 'r'):
             line = line.lstrip().rstrip("\r\n")
@@ -538,12 +578,18 @@ class Actions(FileManagerAware, SettingsAware):
         self.execute_file(file, label='editor')
 
     def toggle_option(self, string):
-        """Toggle a boolean option named <string>"""
+        """:toggle_option <string>
+
+        Toggle a boolean option named <string>.
+        """
         if isinstance(self.settings[string], bool):
             self.settings[string] ^= True
 
     def set_option(self, optname, value):
-        """Set the value of an option named <optname>"""
+        """:set_option <optname>
+
+        Set the value of an option named <optname>.
+        """
         self.settings[optname] = value
 
     def sort(self, func=None, reverse=None):
@@ -680,6 +726,10 @@ class Actions(FileManagerAware, SettingsAware):
     # file is important to you in any context.
 
     def tag_toggle(self, paths=None, value=None, movedown=None, tag=None):
+        """:tag_toggle <character>
+
+        Toggle a tag <character>.
+        """
         if not self.tags:
             return
         if paths is None:
@@ -1113,8 +1163,10 @@ class Actions(FileManagerAware, SettingsAware):
         for cmd_name in sorted(self.commands.commands):
             cmd = self.commands.commands[cmd_name]
             if hasattr(cmd, '__doc__') and cmd.__doc__:
-                write(cleandoc(cmd.__doc__))
-                write("\n\n" + "-" * 60 + "\n")
+                doc = cleandoc(cmd.__doc__)
+                if doc[0] == ':':
+                    write(doc)
+                    write("\n\n" + "-" * 60 + "\n")
             else:
                 undocumented.append(cmd)
 
@@ -1144,12 +1196,20 @@ class Actions(FileManagerAware, SettingsAware):
     # --------------------------
 
     def uncut(self):
+        """:uncut
+
+        Empty the copy buffer.
+        """
         self.copy_buffer = set()
         self.do_cut = False
         self.ui.browser.main_column.request_redraw()
 
     def copy(self, mode='set', narg=None, dirarg=None):
-        """Copy the selected items.  Modes are: 'set', 'add', 'remove'."""
+        """:copy [mode=set]
+
+        Copy the selected items.
+        Modes are: 'set', 'add', 'remove'.
+        """
         assert mode in ('set', 'add', 'remove')
         cwd = self.thisdir
         if not narg and not dirarg:
@@ -1176,6 +1236,11 @@ class Actions(FileManagerAware, SettingsAware):
         self.ui.browser.main_column.request_redraw()
 
     def cut(self, mode='set', narg=None, dirarg=None):
+        """:cut [mode=set]
+
+        Cut the selected items.
+        Modes are: 'set, 'add, 'remove.
+        """
         self.copy(mode=mode, narg=narg, dirarg=dirarg)
         self.do_cut = True
         self.ui.browser.main_column.request_redraw()
@@ -1224,7 +1289,10 @@ class Actions(FileManagerAware, SettingsAware):
                     next_available_filename(target_path))
 
     def paste(self, overwrite=False, append=False):
-        """Paste the selected items into the current directory"""
+        """:paste
+
+        Paste the selected items into the current directory.
+        """
         loadable = CopyLoader(self.copy_buffer, self.do_cut, overwrite)
         self.loader.add(loadable, append=append)
         self.do_cut = False
diff --git a/ranger/core/loader.py b/ranger/core/loader.py
index 411b16ec..2184d2b1 100644
--- a/ranger/core/loader.py
+++ b/ranger/core/loader.py
@@ -6,6 +6,7 @@ from time import time, sleep
 from subprocess import Popen, PIPE
 from ranger.core.shared import FileManagerAware
 from ranger.ext.signals import SignalDispatcher
+from ranger.ext.human_readable import human_readable
 import math
 import os.path
 import sys
@@ -77,13 +78,14 @@ class CopyLoader(Loadable, FileManagerAware):
             # TODO: Don't calculate size when renaming (needs detection)
             bytes_per_tick = shutil_g.BLOCK_SIZE
             size = max(1, self._calculate_size(bytes_per_tick))
+            size_str = " (" + human_readable(self._calculate_size(1)) + ")"
             done = 0
             if self.do_cut:
                 self.original_copy_buffer.clear()
                 if len(self.copy_buffer) == 1:
-                    self.description = "moving: " + self.one_file.path
+                    self.description = "moving: " + self.one_file.path + size_str
                 else:
-                    self.description = "moving files from: " + self.one_file.dirname
+                    self.description = "moving files from: " + self.one_file.dirname + size_str
                 for f in self.copy_buffer:
                     for tf in self.fm.tags.tags:
                         if tf == f.path or str(tf).startswith(f.path):
@@ -101,9 +103,9 @@ class CopyLoader(Loadable, FileManagerAware):
                     done += d
             else:
                 if len(self.copy_buffer) == 1:
-                    self.description = "copying: " + self.one_file.path
+                    self.description = "copying: " + self.one_file.path + size_str
                 else:
-                    self.description = "copying files from: " + self.one_file.dirname
+                    self.description = "copying files from: " + self.one_file.dirname + size_str
                 for f in self.copy_buffer:
                     if os.path.isdir(f.path) and not os.path.islink(f.path):
                         d = 0
diff --git a/ranger/data/mime.types b/ranger/data/mime.types
index b3c3e8dc..f338ab84 100644
--- a/ranger/data/mime.types
+++ b/ranger/data/mime.types
@@ -24,3 +24,4 @@ video/divx              div divx
 text/x-ruby             rb
 application/javascript  js
 
+application/djvu        djvu
diff --git a/ranger/data/scope.sh b/ranger/data/scope.sh
index 19404019..afaf131f 100755
--- a/ranger/data/scope.sh
+++ b/ranger/data/scope.sh
@@ -30,7 +30,7 @@ maxln=200    # Stop after $maxln lines.  Can be used like ls | head -n $maxln
 
 # Find out something about the file:
 mimetype=$(file --mime-type -Lb "$path")
-extension=$(/bin/echo "${path##*.}" | tr "[:upper:]" "[:lower:]")
+extension=$(/bin/echo "${path##*.}" | awk '{print tolower($0)}')
 
 # Functions:
 # runs a command and saves its output into $output.  Useful if you need
@@ -44,7 +44,7 @@ dump() { /bin/echo "$output"; }
 trim() { head -n "$maxln"; }
 
 # wraps highlight to treat exit code 141 (killed by SIGPIPE) as success
-highlight() { command highlight "$@"; test $? = 0 -o $? = 141; }
+safepipe() { "$@"; test $? = 0 -o $? = 141; }
 
 # Image previews, if enabled in ranger.
 if [ "$preview_images" = "True" ]; then
@@ -91,7 +91,9 @@ esac
 case "$mimetype" in
     # Syntax highlight for text files:
     text/* | */xml)
-        try highlight --out-format=ansi "$path" && { dump | trim; exit 5; } || exit 2;;
+        try safepipe highlight --out-format=ansi "$path" && { dump | trim; exit 5; }
+        try safepipe pygmentize "$path" && { dump | trim; exit 5; }
+        exit 2;;
     # Ascii-previews of images:
     image/*)
         img2txt --gamma=0.6 --width="$width" "$path" && exit 4 || exit 1;;
diff --git a/ranger/ext/rifle.py b/ranger/ext/rifle.py
index 4f1ef1b9..5d13a5bf 100755
--- a/ranger/ext/rifle.py
+++ b/ranger/ext/rifle.py
@@ -19,7 +19,7 @@ import re
 from subprocess import Popen, PIPE
 import sys
 
-__version__ = 'rifle 1.7.1'
+__version__ = 'rifle 1.7.2'
 
 # Options and constants that a user might want to change:
 DEFAULT_PAGER = 'less'
@@ -231,7 +231,7 @@ class Rifle(object):
             self._app_flags = argument
             return True
         elif function == 'X':
-            return 'DISPLAY' in os.environ
+            return sys.platform == 'darwin' or 'DISPLAY' in os.environ
         elif function == 'env':
             return bool(os.environ.get(argument))
         elif function == 'else':
diff --git a/ranger/gui/colorscheme.py b/ranger/gui/colorscheme.py
index d6afcacc..d2b3b2d2 100644
--- a/ranger/gui/colorscheme.py
+++ b/ranger/gui/colorscheme.py
@@ -86,7 +86,7 @@ def _colorscheme_name_to_class(signal):
     usecustom = not ranger.arg.clean
 
     def exists(colorscheme):
-        return os.path.exists(colorscheme + '.py')
+        return os.path.exists(colorscheme + '.py') or os.path.exists(colorscheme + '.pyc')
 
     def is_scheme(x):
         try:
diff --git a/ranger/gui/curses_shortcuts.py b/ranger/gui/curses_shortcuts.py
index 187891c6..e7573f17 100644
--- a/ranger/gui/curses_shortcuts.py
+++ b/ranger/gui/curses_shortcuts.py
@@ -25,20 +25,28 @@ class CursesShortcuts(SettingsAware):
     """
 
     def addstr(self, *args):
+        y, x = self.win.getyx()
+
         try:
             self.win.addstr(*args)
         except:
             if len(args) > 1:
+                self.win.move(y, x)
+
                 try:
                     self.win.addstr(*_fix_surrogates(args))
                 except:
                     pass
 
     def addnstr(self, *args):
+        y, x = self.win.getyx()
+
         try:
             self.win.addnstr(*args)
         except:
             if len(args) > 2:
+                self.win.move(y, x)
+
                 try:
                     self.win.addnstr(*_fix_surrogates(args))
                 except:
diff --git a/ranger/gui/widgets/__init__.py b/ranger/gui/widgets/__init__.py
index f2e52c0a..bd0f2337 100644
--- a/ranger/gui/widgets/__init__.py
+++ b/ranger/gui/widgets/__init__.py
@@ -21,3 +21,5 @@ class Widget(Displayable):
                 'ahead':    ('>', ["vcsahead"]),
                 'diverged': ('Y', ["vcsdiverged"]),
                 'unknown':  ('?', ["vcsunknown"])}
+
+    ellipsis = { False: '~', True: '…' }
diff --git a/ranger/gui/widgets/browsercolumn.py b/ranger/gui/widgets/browsercolumn.py
index b38d0b5b..52ef62b8 100644
--- a/ranger/gui/widgets/browsercolumn.py
+++ b/ranger/gui/widgets/browsercolumn.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 # This file is part of ranger, the console file manager.
 # License: GNU GPL version 3, see the file "AUTHORS" for details.
 
@@ -7,6 +6,7 @@
 import curses
 import stat
 from time import time
+from os.path import splitext
 
 from . import Widget
 from .pager import Pager
@@ -23,7 +23,6 @@ class BrowserColumn(Pager):
     scroll_begin = 0
     target = None
     last_redraw_time = -1
-    ellipsis = { False: '~', True: '…' }
 
     old_dir = None
     old_thisfile = None
@@ -342,8 +341,12 @@ class BrowserColumn(Pager):
 
     def _draw_text_display(self, text, space):
         wtext = WideString(text)
+        wext = WideString(splitext(text)[1])
         wellip = WideString(self.ellipsis[self.settings.unicode_ellipsis])
         if len(wtext) > space:
+            wtext = wtext[:max(1, space - len(wext) - len(wellip))] + wellip + wext
+        # Truncate again if still too long.
+        if len(wtext) > space:
             wtext = wtext[:max(0, space - len(wellip))] + wellip
 
         return [[str(wtext), []]]
diff --git a/ranger/gui/widgets/titlebar.py b/ranger/gui/widgets/titlebar.py
index c3785986..dbd08981 100644
--- a/ranger/gui/widgets/titlebar.py
+++ b/ranger/gui/widgets/titlebar.py
@@ -98,7 +98,7 @@ class TitleBar(Widget):
         bar.add(self.fm.username, 'hostname', clr, fixed=True)
         bar.add('@', 'hostname', clr, fixed=True)
         bar.add(self.fm.hostname, 'hostname', clr, fixed=True)
-        bar.add(':', 'hostname', clr, fixed=True)
+        bar.add(' ', 'hostname', clr, fixed=True)
 
         pathway = self.fm.thistab.pathway
         if self.settings.tilde_in_titlebar and \
@@ -140,7 +140,7 @@ class TitleBar(Widget):
             if not dirname:
                 result += ":/"
             elif len(dirname) > 15:
-                result += ":" + dirname[:14] + "~"
+                result += ":" + dirname[:14] + self.ellipsis[self.settings.unicode_ellipsis]
             else:
                 result += ":" + dirname
         return result