about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--.pylintrc2
-rw-r--r--Makefile2
-rw-r--r--README.md8
-rw-r--r--doc/ranger.135
-rw-r--r--doc/ranger.pod36
-rw-r--r--doc/rifle.12
-rwxr-xr-xdoc/tools/convert_papermode_to_metadata.py2
-rwxr-xr-xdoc/tools/performance_test.py42
-rw-r--r--examples/rc_emacs.conf1
-rwxr-xr-xexamples/rifle_sxiv.sh2
-rw-r--r--ranger/__init__.py2
-rw-r--r--ranger/api/commands.py12
-rw-r--r--ranger/colorschemes/default.py3
-rwxr-xr-xranger/config/commands.py112
-rw-r--r--ranger/config/rc.conf23
-rw-r--r--ranger/config/rifle.conf5
-rw-r--r--ranger/container/bookmarks.py17
-rw-r--r--ranger/container/directory.py51
-rw-r--r--ranger/container/file.py1
-rw-r--r--ranger/container/fsobject.py112
-rw-r--r--ranger/container/settings.py19
-rw-r--r--ranger/container/tags.py2
-rw-r--r--ranger/core/actions.py16
-rw-r--r--ranger/core/fm.py11
-rw-r--r--ranger/core/main.py30
-rw-r--r--ranger/core/metadata.py39
-rw-r--r--ranger/core/runner.py4
-rw-r--r--ranger/core/tab.py2
-rw-r--r--ranger/data/mime.types1
-rwxr-xr-xranger/data/scope.sh20
-rw-r--r--ranger/ext/accumulator.py4
-rw-r--r--ranger/ext/cached_function.py1
-rw-r--r--ranger/ext/direction.py23
-rw-r--r--ranger/ext/img_display.py3
-rw-r--r--ranger/ext/lazy_property.py37
-rw-r--r--ranger/ext/next_available_filename.py1
-rwxr-xr-xranger/ext/rifle.py5
-rw-r--r--ranger/ext/signals.py6
-rw-r--r--ranger/ext/vcs/vcs.py7
-rw-r--r--ranger/ext/widestring.py4
-rw-r--r--ranger/gui/bar.py1
-rw-r--r--ranger/gui/context.py2
-rw-r--r--ranger/gui/ui.py7
-rw-r--r--ranger/gui/widgets/browsercolumn.py13
-rw-r--r--ranger/gui/widgets/console.py40
-rw-r--r--ranger/gui/widgets/statusbar.py11
-rw-r--r--ranger/gui/widgets/taskview.py2
-rw-r--r--ranger/gui/widgets/view_base.py1
48 files changed, 596 insertions, 186 deletions
diff --git a/.pylintrc b/.pylintrc
index d108c93f..75bb7baf 100644
--- a/.pylintrc
+++ b/.pylintrc
@@ -8,7 +8,7 @@ max-branches=16
 
 [FORMAT]
 max-line-length = 99
-disable=locally-disabled,locally-enabled,missing-docstring,duplicate-code,fixme,cyclic-import,redefined-variable-type
+disable=locally-disabled,locally-enabled,missing-docstring,duplicate-code,fixme,cyclic-import,redefined-variable-type,stop-iteration-return
 
 [TYPECHECK]
 ignored-classes=ranger.core.actions.Actions
diff --git a/Makefile b/Makefile
index a2fe08cc..99d3f53e 100644
--- a/Makefile
+++ b/Makefile
@@ -95,7 +95,7 @@ test_doctest:
 	done
 
 test_pytest:
-	echo "Running py.test tests..."
+	@echo "Running py.test tests..."
 	py.test tests
 
 test: test_pylint test_flake8 test_doctest test_pytest
diff --git a/README.md b/README.md
index edbc2c4d..071b51d6 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-ranger 1.9.0b5
+ranger 1.9.0b6
 ==============
 
 [![Build Status](https://travis-ci.org/ranger/ranger.svg?branch=master)](https://travis-ci.org/ranger/ranger)
@@ -108,6 +108,6 @@ current file.  The second is the main column and the first shows the parent
 directory.
 
 Ranger can automatically copy default configuration files to `~/.config/ranger`
-if you run it with the switch `--copy-config`. See `ranger --help` for a
-description of that switch.  Also check `ranger/config/` for the default
-configuration.
+if you run it with the switch `--copy-config=( rc | scope | ... | all )`.
+See `ranger --help` for a description of that switch.  Also check
+`ranger/config/` for the default configuration.
diff --git a/doc/ranger.1 b/doc/ranger.1
index 940ffc0a..50b83bdf 100644
--- a/doc/ranger.1
+++ b/doc/ranger.1
@@ -129,7 +129,7 @@
 .\" ========================================================================
 .\"
 .IX Title "RANGER 1"
-.TH RANGER 1 "ranger-1.9.0b5" "2017-03-23" "ranger manual"
+.TH RANGER 1 "ranger-1.9.0b6" "12/07/2017" "ranger manual"
 .\" For nroff, turn off justification.  Always turn off hyphenation; it makes
 .\" way too many mistakes in technical documents.
 .if n .ad l
@@ -143,6 +143,7 @@ ranger \- visual file manager
 [\fB\-\-copy\-config\fR=\fIwhich\fR]
 [\fB\-\-choosefile\fR=\fItarget\fR] [\fB\-\-choosefiles\fR=\fItarget\fR]
 [\fB\-\-choosedir\fR=\fItarget\fR] [\fB\-\-selectfile\fR=\fIfilepath\fR]
+[\fB\-\-show\-only\-dirs\fR]
 [\fB\-\-list\-unused\-keys\fR] [\fB\-\-list\-tagged\-files\fR=\fItag\fR]
 [\fB\-\-profile\fR] [\fB\-\-cmd\fR=\fIcommand\fR] [\fIpath\fR]
 .SH "DESCRIPTION"
@@ -225,6 +226,10 @@ write the last visited directory into \fItargetfile\fR.
 .IP "\fB\-\-selectfile\fR=\fItargetfile\fR" 14
 .IX Item "--selectfile=targetfile"
 Open ranger with \fItargetfile\fR selected.
+.IP "\fB\-\-show\-only\-dirs\fR" 14
+.IX Item "--show-only-dirs"
+Display only the directories. May be used in conjunction with
+\&\fB\-\-choosedir\fR=\fItargetfile\fR.
 .IP "\fB\-\-list\-unused\-keys\fR" 14
 .IX Item "--list-unused-keys"
 List common keys which are not bound to any action in the \*(L"browser\*(R" context.
@@ -416,8 +421,8 @@ By default, all the flags are off unless specified otherwise in the
 An uppercase flag negates the effect: \*(L"ffcccFsf\*(R" is equivalent to \*(L"cs\*(R".
 .PP
 The terminal program name for the \*(L"t\*(R" flag is taken from the environment
-variable \f(CW$TERMCMD\fR.  If it doesn't exist, it tries to extract it from \f(CW$TERM\fR and
-uses \*(L"xterm\*(R" as a fallback if that fails.
+variable \f(CW$TERMCMD\fR.  If it doesn't exist, it tries to extract it from \f(CW$TERM\fR,
+uses \*(L"x\-terminal-emulator\*(R" as a fallback, and then \*(L"xterm\*(R" if that fails.
 .PP
 Examples: \f(CW\*(C`:open_with c\*(C'\fR will open the file that you currently point at, even
 if you have selected other files.  \f(CW\*(C`:shell \-w df\*(C'\fR will run \*(L"df\*(R" and wait for
@@ -484,6 +489,13 @@ Move up and down in the parent directory.
 .IP "^R" 14
 .IX Item "^R"
 Reload everything
+.IP "F" 14
+.IX Item "F"
+Toggle \fIfreeze_files\fR setting.  When active (indicated by a cyan \fI\s-1FROZEN\s0\fR
+message in the status bar), directories and files will not be loaded, improving
+performance when all the files you need are already loaded.  This does not
+affect file previews, which can be toggled with \fIzI\fR.  Also try disabling the
+preview of directories with \fIzP\fR.
 .IP "^L" 14
 .IX Item "^L"
 Redraw the screen
@@ -762,6 +774,11 @@ currently running tasks which support progress bars?
 Flush the input after each key hit?  One advantage is that when scrolling down
 with \*(L"j\*(R", ranger stops scrolling instantly when you release the key.  One
 disadvantage is that when you type commands blindly, some keys might get lost.
+.IP "freeze_files [bool] <F>" 4
+.IX Item "freeze_files [bool] <F>"
+When active, directories and files will not be loaded, improving performance
+when all the files you need are already loaded.  This does not affect file
+previews.
 .IP "hidden_filter [string]" 4
 .IX Item "hidden_filter [string]"
 A regular expression pattern for files which should be hidden.  For example,
@@ -799,6 +816,14 @@ all directories above the current one as well?
 .IP "mouse_enabled [bool] <zm>" 4
 .IX Item "mouse_enabled [bool] <zm>"
 Enable mouse input?
+.IP "one_indexed [bool]" 4
+.IX Item "one_indexed [bool]"
+Start line numbers from 1.  Possible values are:
+.Sp
+.Vb 2
+\& false      start line numbers from 0
+\& true       start line numbers from 1
+.Ve
 .IP "padding_right [bool]" 4
 .IX Item "padding_right [bool]"
 When collapse_preview is on and there is no preview, should there remain a
@@ -822,6 +847,10 @@ to disable this feature.
 Which script should handle generating previews?  If the file doesn't exist, or
 use_preview_script is off, ranger will handle previews itself by just printing
 the content.
+.IP "save_backtick_bookmark [bool]" 4
+.IX Item "save_backtick_bookmark [bool]"
+Save the \f(CW\*(C`\`\*(C'\fR bookmark to disk.  This bookmark is used to switch to the last
+directory by typing \f(CW\*(C`\`\`\*(C'\fR.
 .IP "save_console_history [bool]" 4
 .IX Item "save_console_history [bool]"
 Should the console history be saved on exit?  If disabled, the console history
diff --git a/doc/ranger.pod b/doc/ranger.pod
index ebeeafbe..310ab1fd 100644
--- a/doc/ranger.pod
+++ b/doc/ranger.pod
@@ -12,6 +12,7 @@ B<ranger> [B<--version>] [B<--help>] [B<--debug>] [B<--clean>]
 [B<--copy-config>=I<which>]
 [B<--choosefile>=I<target>] [B<--choosefiles>=I<target>]
 [B<--choosedir>=I<target>] [B<--selectfile>=I<filepath>]
+[B<--show-only-dirs>]
 [B<--list-unused-keys>] [B<--list-tagged-files>=I<tag>]
 [B<--profile>] [B<--cmd>=I<command>] [I<path>]
 
@@ -118,6 +119,11 @@ write the last visited directory into I<targetfile>.
 
 Open ranger with I<targetfile> selected.
 
+=item B<--show-only-dirs>
+
+Display only the directories. May be used in conjunction with
+B<--choosedir>=I<targetfile>.
+
 =item B<--list-unused-keys>
 
 List common keys which are not bound to any action in the "browser" context.
@@ -315,8 +321,8 @@ F<rifle.conf> configuration file.  You can specify as many flags as you want.
 An uppercase flag negates the effect: "ffcccFsf" is equivalent to "cs".
 
 The terminal program name for the "t" flag is taken from the environment
-variable $TERMCMD.  If it doesn't exist, it tries to extract it from $TERM and
-uses "xterm" as a fallback if that fails.
+variable $TERMCMD.  If it doesn't exist, it tries to extract it from $TERM,
+uses "x-terminal-emulator" as a fallback, and then "xterm" if that fails.
 
 Examples: C<:open_with c> will open the file that you currently point at, even
 if you have selected other files.  C<:shell -w df> will run "df" and wait for
@@ -395,6 +401,14 @@ Move up and down in the parent directory.
 
 Reload everything
 
+=item F
+
+Toggle I<freeze_files> setting.  When active (indicated by a cyan I<FROZEN>
+message in the status bar), directories and files will not be loaded, improving
+performance when all the files you need are already loaded.  This does not
+affect file previews, which can be toggled with I<zI>.  Also try disabling the
+preview of directories with I<zP>.
+
 =item ^L
 
 Redraw the screen
@@ -752,6 +766,12 @@ Flush the input after each key hit?  One advantage is that when scrolling down
 with "j", ranger stops scrolling instantly when you release the key.  One
 disadvantage is that when you type commands blindly, some keys might get lost.
 
+=item freeze_files [bool] <F>
+
+When active, directories and files will not be loaded, improving performance
+when all the files you need are already loaded.  This does not affect file
+previews.
+
 =item hidden_filter [string]
 
 A regular expression pattern for files which should be hidden.  For example,
@@ -792,6 +812,13 @@ all directories above the current one as well?
 
 Enable mouse input?
 
+=item one_indexed [bool]
+
+Start line numbers from 1.  Possible values are:
+
+ false      start line numbers from 0
+ true       start line numbers from 1
+
 =item padding_right [bool]
 
 When collapse_preview is on and there is no preview, should there remain a
@@ -821,6 +848,11 @@ Which script should handle generating previews?  If the file doesn't exist, or
 use_preview_script is off, ranger will handle previews itself by just printing
 the content.
 
+=item save_backtick_bookmark [bool]
+
+Save the C<`> bookmark to disk.  This bookmark is used to switch to the last
+directory by typing C<``>.
+
 =item save_console_history [bool]
 
 Should the console history be saved on exit?  If disabled, the console history
diff --git a/doc/rifle.1 b/doc/rifle.1
index 95c9ce50..8531d69c 100644
--- a/doc/rifle.1
+++ b/doc/rifle.1
@@ -129,7 +129,7 @@
 .\" ========================================================================
 .\"
 .IX Title "RIFLE 1"
-.TH RIFLE 1 "rifle-1.9.0b5" "2017-03-23" "rifle manual"
+.TH RIFLE 1 "rifle-1.9.0b6" "12/07/2017" "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/doc/tools/convert_papermode_to_metadata.py b/doc/tools/convert_papermode_to_metadata.py
index e4010a73..57459097 100755
--- a/doc/tools/convert_papermode_to_metadata.py
+++ b/doc/tools/convert_papermode_to_metadata.py
@@ -1,4 +1,4 @@
-#!/bin/python
+#!/usr/bin/env python
 """
 usage: ./convert_papermode_to_metadata.py
 
diff --git a/doc/tools/performance_test.py b/doc/tools/performance_test.py
new file mode 100755
index 00000000..3b9099d5
--- /dev/null
+++ b/doc/tools/performance_test.py
@@ -0,0 +1,42 @@
+#!/usr/bin/env python
+
+from __future__ import (absolute_import, division, print_function)
+
+import sys
+import time
+
+sys.path.insert(0, '../..')
+sys.path.insert(0, '.')
+
+
+def main():
+    import ranger.container.directory
+    import ranger.core.shared
+    import ranger.container.settings
+    import ranger.core.fm
+    from ranger.ext.openstruct import OpenStruct
+    ranger.args = OpenStruct()
+    ranger.args.clean = True
+    ranger.args.debug = False
+
+    settings = ranger.container.settings.Settings()
+    ranger.core.shared.SettingsAware.settings_set(settings)
+    fm = ranger.core.fm.FM()
+    ranger.core.shared.FileManagerAware.fm_set(fm)
+
+    time1 = time.time()
+    fm.initialize()
+    try:
+        usr = ranger.container.directory.Directory('/usr')
+        usr.load_content(schedule=False)
+        for fileobj in usr.files:
+            if fileobj.is_directory:
+                fileobj.load_content(schedule=False)
+    finally:
+        fm.destroy()
+    time2 = time.time()
+    print("%dms" % ((time2 - time1) * 1000))
+
+
+if __name__ == '__main__':
+    main()
diff --git a/examples/rc_emacs.conf b/examples/rc_emacs.conf
index d3707a12..26074a42 100644
--- a/examples/rc_emacs.conf
+++ b/examples/rc_emacs.conf
@@ -406,6 +406,7 @@ map <C-x>zs    toggle_option sort_case_insensitive
 map <C-x>zu    toggle_option autoupdate_cumulative_size
 map <C-x>zv    toggle_option use_preview_script
 map <C-x>zf    console filter%space
+map <C-x>nn    narrow
 
 # Bookmarks
 map <C-x>rb<any> enter_bookmark %any
diff --git a/examples/rifle_sxiv.sh b/examples/rifle_sxiv.sh
index 8cb13907..0bdd892d 100755
--- a/examples/rifle_sxiv.sh
+++ b/examples/rifle_sxiv.sh
@@ -24,7 +24,7 @@ if [ $# -eq 0 ]; then
     exit
 fi
 
-[ "$1" == '--' ] && shift
+[ "$1" = '--' ] && shift
 
 abspath () {
     case "$1" in
diff --git a/ranger/__init__.py b/ranger/__init__.py
index d98a2bf5..f3495197 100644
--- a/ranger/__init__.py
+++ b/ranger/__init__.py
@@ -14,7 +14,7 @@ import os
 
 # Information
 __license__ = 'GPL3'
-__version__ = '1.9.0b5'
+__version__ = '1.9.0b6'
 __author__ = __maintainer__ = 'Roman Zimbelmann'
 __email__ = 'hut@hut.pm'
 
diff --git a/ranger/api/commands.py b/ranger/api/commands.py
index 24a82d0b..9c687927 100644
--- a/ranger/api/commands.py
+++ b/ranger/api/commands.py
@@ -54,8 +54,8 @@ class CommandContainer(FileManagerAware):
         cmd_cls = self.get_command(cmd_name)
         if cmd_cls is None:
             self.fm.notify('alias failed: No such command: {0}'.format(cmd_name), bad=True)
-            return None
-        self.commands[name] = _command_init(command_alias_factory(name, cmd_cls, full_command))
+        else:
+            self.commands[name] = _command_init(command_alias_factory(name, cmd_cls, full_command))
 
     def load_commands_from_module(self, module):
         for var in vars(module).values():
@@ -293,7 +293,7 @@ class Command(FileManagerAware):
 
             # no results, return None
             if not dirnames:
-                return
+                return None
 
             # one result. since it must be a directory, append a slash.
             if len(dirnames) == 1:
@@ -357,7 +357,7 @@ class Command(FileManagerAware):
         else:
             # no results, return None
             if not names:
-                return
+                return None
 
             # one result. append a slash if it's a directory
             if len(names) == 1:
@@ -374,7 +374,7 @@ class Command(FileManagerAware):
         programs = [program for program in get_executables() if
                     program.startswith(self.rest(1))]
         if not programs:
-            return
+            return None
         if len(programs) == 1:
             return self.start(1) + programs[0]
         programs.sort()
@@ -397,7 +397,7 @@ def command_function_factory(func):
 
         def execute(self):  # pylint: disable=too-many-branches
             if not func:
-                return
+                return None
             if len(self.args) == 1:
                 try:
                     return func(**{'narg': self.quantifier})
diff --git a/ranger/colorschemes/default.py b/ranger/colorschemes/default.py
index 7d2b124f..c88cdc7c 100644
--- a/ranger/colorschemes/default.py
+++ b/ranger/colorschemes/default.py
@@ -98,6 +98,9 @@ class Default(ColorScheme):
             if context.marked:
                 attr |= bold | reverse
                 fg = yellow
+            if context.frozen:
+                attr |= bold | reverse
+                fg = cyan
             if context.message:
                 if context.bad:
                     attr |= bold
diff --git a/ranger/config/commands.py b/ranger/config/commands.py
index 4cedc4e1..299f17c2 100755
--- a/ranger/config/commands.py
+++ b/ranger/config/commands.py
@@ -219,6 +219,8 @@ class cd(Command):
                 return matches
             paths = matches
 
+        return None
+
     def _tab_smart(self, dest, dest_abs):
         tokens = []
         basepath = dest_abs
@@ -457,6 +459,7 @@ class set_(Command):
         if name == "colorscheme":
             return sorted(self.firstpart + colorscheme for colorscheme
                           in get_all_colorschemes(self.fm) if colorscheme.startswith(value))
+        return None
 
 
 class setlocal(set_):
@@ -785,6 +788,7 @@ class load_copy_buffer(Command):
                                   for g in fobj.read().split("\n") if exists(g))
         fobj.close()
         self.fm.ui.redraw_main_column()
+        return None
 
 
 class save_copy_buffer(Command):
@@ -804,6 +808,7 @@ class save_copy_buffer(Command):
                                   (fname or self.copy_buffer_filename), bad=True)
         fobj.write("\n".join(fobj.path for fobj in self.fm.copy_buffer))
         fobj.close()
+        return None
 
 
 class unmark_tag(mark_tag):
@@ -925,7 +930,7 @@ class rename(Command):
             return self.fm.notify('Syntax: rename <newname>', bad=True)
 
         if new_name == self.fm.thisfile.relative_path:
-            return
+            return None
 
         if access(new_name, os.F_OK):
             return self.fm.notify("Can't rename: file already exists!", bad=True)
@@ -937,6 +942,8 @@ class rename(Command):
             self.fm.thisdir.pointed_obj = file_new
             self.fm.thisfile = file_new
 
+        return None
+
     def tab(self, tabnum):
         return self._tab_directory_content()
 
@@ -1118,7 +1125,7 @@ class relink(Command):
             return self.fm.notify('%s is not a symlink!' % tfile.relative_path, bad=True)
 
         if new_path == os.readlink(tfile.path):
-            return
+            return None
 
         try:
             os.remove(tfile.path)
@@ -1130,6 +1137,8 @@ class relink(Command):
         self.fm.thisdir.pointed_obj = tfile
         self.fm.thisfile = tfile
 
+        return None
+
     def tab(self, tabnum):
         if not self.rest(1):
             return self.line + os.readlink(self.fm.thisfile.path)
@@ -1159,7 +1168,7 @@ class help_(Command):
         self.fm.ui.console.ask(
             "View [m]an page, [k]ey bindings, [c]ommands or [s]ettings? (press q to abort)",
             callback,
-            list("mkcsq") + [chr(27)]
+            list("mqkcs")
         )
 
 
@@ -1177,6 +1186,8 @@ class copymap(Command):
         for arg in self.args[2:]:
             self.fm.ui.keymaps.copy(self.context, self.arg(1), arg)
 
+        return None
+
 
 class copypmap(copymap):
     """:copypmap <keys> <newkeys1> [<newkeys2>...]
@@ -1361,7 +1372,10 @@ class scout(Command):
 
         if self.OPEN_ON_ENTER in flags or \
                 (self.AUTO_OPEN in flags and count == 1):
-            self.fm.move(right=1)
+            if pattern == '..':
+                self.fm.cd(pattern)
+            else:
+                self.fm.move(right=1)
 
         if self.KEEP_OPEN in flags and thisdir != self.fm.thisdir:
             # reopen the console:
@@ -1469,6 +1483,22 @@ class scout(Command):
         return count == 1
 
 
+class narrow(Command):
+    """
+    :narrow
+
+    Show only the files selected right now. If no files are selected,
+    disable narrowing.
+    """
+    def execute(self):
+        if self.fm.thisdir.marked_items:
+            selection = [f.basename for f in self.fm.thistab.get_selection()]
+            self.fm.thisdir.narrow_filter = selection
+        else:
+            self.fm.thisdir.narrow_filter = None
+        self.fm.thisdir.refilter()
+
+
 class filter_inode_type(Command):
     """
     :filter_inode_type [dfl]
@@ -1480,22 +1510,12 @@ class filter_inode_type(Command):
         f display files
         l display links
     """
-    # pylint: disable=bad-whitespace
-    FILTER_DIRS  = 'd'
-    FILTER_FILES = 'f'
-    FILTER_LINKS = 'l'
-    # pylint: enable=bad-whitespace
 
     def execute(self):
         if not self.arg(1):
-            self.fm.thisdir.inode_type_filter = None
+            self.fm.thisdir.inode_type_filter = ""
         else:
-            self.fm.thisdir.inode_type_filter = lambda file: (
-                True if (
-                    (self.FILTER_DIRS in self.arg(1) and file.is_directory) or
-                    (self.FILTER_FILES in self.arg(1) and file.is_file and not file.is_link) or
-                    (self.FILTER_LINKS in self.arg(1) and file.is_link)
-                ) else False)
+            self.fm.thisdir.inode_type_filter = self.arg(1)
         self.fm.thisdir.refilter()
 
 
@@ -1670,3 +1690,63 @@ class linemode(default_linemode):
         # Ask the browsercolumns to redraw
         for col in self.fm.ui.browser.columns:
             col.need_redraw = True
+
+
+class yank(Command):
+    """:yank [name|dir|path]
+
+    Copies the file's name (default), directory or path into both the primary X
+    selection and the clipboard.
+    """
+
+    modes = {
+        '': 'basename',
+        'name': 'basename',
+        'dir': 'dirname',
+        'path': 'path',
+    }
+
+    def execute(self):
+        import subprocess
+
+        def clipboards():
+            from ranger.ext.get_executables import get_executables
+            clipboard_managers = {
+                'xclip': [
+                    ['xclip'],
+                    ['xclip', '-selection', 'clipboard'],
+                ],
+                'xsel': [
+                    ['xsel'],
+                    ['xsel', '-b'],
+                ],
+                'pbcopy': [
+                    ['pbcopy'],
+                ],
+            }
+            ordered_managers = ['pbcopy', 'xclip', 'xsel']
+            executables = get_executables()
+            for manager in ordered_managers:
+                if manager in executables:
+                    return clipboard_managers[manager]
+            return []
+
+        clipboard_commands = clipboards()
+
+        selection = self.get_selection_attr(self.modes[self.arg(1)])
+        new_clipboard_contents = "\n".join(selection)
+        for command in clipboard_commands:
+            process = subprocess.Popen(command, universal_newlines=True,
+                                       stdin=subprocess.PIPE)
+            process.communicate(input=new_clipboard_contents)
+
+    def get_selection_attr(self, attr):
+        return [getattr(item, attr) for item in
+                self.fm.thistab.get_selection()]
+
+    def tab(self, tabnum):
+        return (
+            self.start(1) + mode for mode
+            in sorted(self.modes.keys())
+            if mode
+        )
diff --git a/ranger/config/rc.conf b/ranger/config/rc.conf
index 9af5a953..d7f61550 100644
--- a/ranger/config/rc.conf
+++ b/ranger/config/rc.conf
@@ -167,6 +167,10 @@ set padding_right true
 # When false, bookmarks are saved when ranger is exited.
 set autosave_bookmarks true
 
+# Save the "`" bookmark to disk.  This can be used to switch to the last
+# directory by typing "``".
+set save_backtick_bookmark true
+
 # You can display the "real" cumulative size of directories by using the
 # command :get_cumulative_size or typing "dc".  The size is expensive to
 # calculate and will not be updated automatically.  You can choose
@@ -221,6 +225,9 @@ set clear_filters_on_dir_change false
 # Disable displaying line numbers in main column
 set line_numbers false
 
+# Start line numbers from 1 instead of 0
+set one_indexed false
+
 # Save tabs on exit
 set save_tabs_on_exit false
 
@@ -228,6 +235,10 @@ set save_tabs_on_exit false
 # the top and vice versa.
 set wrap_scroll false
 
+# Set the global_inode_type_filter to nothing.  Possible options: d, f and l for
+# directories, files and symlinks respectively.
+set global_inode_type_filter
+
 # ===================================================================
 # == Local Options
 # ===================================================================
@@ -262,11 +273,12 @@ alias travel     scout -aefklst
 # ===================================================================
 
 # Basic
-map     Q quit!
+map     Q quitall
 map     q quit
 copymap q ZZ ZQ
 
 map R     reload_cwd
+map F     set freeze_files!
 map <C-r> reset
 map <C-l> redraw_window
 map <C-c> abort
@@ -309,7 +321,7 @@ map uV      toggle_visual_mode reverse=True
 
 # For the nostalgics: Midnight Commander bindings
 map <F1> help
-map <F2> console rename%space
+map <F2> rename_append
 map <F3> display_file
 map <F4> edit
 map <F5> copy
@@ -375,10 +387,9 @@ map g? cd /usr/share/doc/ranger
 map E  edit
 map du shell -p du --max-depth=1 -h --apparent-size
 map dU shell -p du --max-depth=1 -h --apparent-size | sort -rh
-map yp shell -f echo -n %d/%f     | xsel -i && xsel -o | xsel -i -b
-map yd shell -f echo -n %d        | xsel -i && xsel -o | xsel -i -b
-map yn shell -f echo -n %f        | xsel -i && xsel -o | xsel -i -b
-map ys shell -f printf '%%s\n' %s | xsel -i && xsel -o | xsel -i -b
+map yp yank path
+map yd yank dir
+map yn yank name
 
 # Filesystem Operations
 map =  chmod
diff --git a/ranger/config/rifle.conf b/ranger/config/rifle.conf
index 39dee7e9..8bd5f565 100644
--- a/ranger/config/rifle.conf
+++ b/ranger/config/rifle.conf
@@ -149,6 +149,7 @@ ext pdf, has atril,    X, flag f = atril -- "$@"
 ext pdf, has okular,   X, flag f = okular -- "$@"
 ext pdf, has epdfview, X, flag f = epdfview -- "$@"
 ext pdf, has qpdfview, X, flag f = qpdfview "$@"
+ext pdf, has open,     X, flat f = open "$@"
 
 ext docx?, has catdoc,       terminal = catdoc -- "$@" | "$PAGER"
 
@@ -162,6 +163,9 @@ ext djvu, has zathura,X, flag f = zathura -- "$@"
 ext djvu, has evince, X, flag f = evince -- "$@"
 ext djvu, has atril,  X, flag f = atril -- "$@"
 
+ext epub, has ebook-viewer, X, flag f = ebook-viewer -- "$@"
+ext mobi, has ebook-viewer, X, flag f = ebook-viewer -- "$@"
+
 #-------------------------------------------
 # Image Viewing:
 #-------------------------------------------
@@ -175,6 +179,7 @@ mime ^image, has mirage,    X, flag f = mirage -- "$@"
 mime ^image, has ristretto, X, flag f = ristretto "$@"
 mime ^image, has eog,       X, flag f = eog -- "$@"
 mime ^image, has eom,       X, flag f = eom -- "$@"
+mime ^image, has nomacs,    X, flag f = nomacs -- "$@"
 mime ^image, has gimp,      X, flag f = gimp -- "$@"
 ext xcf,                    X, flag f = gimp -- "$@"
 
diff --git a/ranger/container/bookmarks.py b/ranger/container/bookmarks.py
index cba07367..59838c00 100644
--- a/ranger/container/bookmarks.py
+++ b/ranger/container/bookmarks.py
@@ -28,7 +28,8 @@ class Bookmarks(FileManagerAware):
     autosave = True
     load_pattern = re.compile(r"^[\d\w']:.")
 
-    def __init__(self, bookmarkfile, bookmarktype=str, autosave=False):
+    def __init__(self, bookmarkfile, bookmarktype=str, autosave=False,
+                 nonpersistent_bookmarks=()):
         """Initializes Bookmarks.
 
         <bookmarkfile> specifies the path to the file where
@@ -39,6 +40,7 @@ class Bookmarks(FileManagerAware):
         self.original_dict = {}
         self.path = bookmarkfile
         self.bookmarktype = bookmarktype
+        self.nonpersistent_bookmarks = set(nonpersistent_bookmarks)
 
     def load(self):
         """Load the bookmarks from path/bookmarks"""
@@ -174,7 +176,8 @@ class Bookmarks(FileManagerAware):
             self.fm.notify('Bookmarks error: {0}'.format(str(ex)), bad=True)
             return
         for key, value in self.dct.items():
-            if isinstance(key, str) and key in ALLOWED_KEYS:
+            if isinstance(key, str) and key in ALLOWED_KEYS \
+                    and key not in self.nonpersistent_bookmarks:
                 fobj.write("{0}:{1}\n".format(str(key), str(value)))
         fobj.close()
 
@@ -189,6 +192,16 @@ class Bookmarks(FileManagerAware):
 
         self._update_mtime()
 
+    def enable_saving_backtick_bookmark(self, boolean):
+        """
+        Adds or removes the ' from the list of nonpersitent bookmarks
+        """
+        if boolean:
+            if "'" in self.nonpersistent_bookmarks:
+                self.nonpersistent_bookmarks.remove("'")  # enable
+        else:
+            self.nonpersistent_bookmarks.add("'")  # disable
+
     def _load_dict(self):
         if self.path is None:
             return {}
diff --git a/ranger/container/directory.py b/ranger/container/directory.py
index 168a46c7..18b1687c 100644
--- a/ranger/container/directory.py
+++ b/ranger/container/directory.py
@@ -93,6 +93,12 @@ def mtimelevel(path, level):
     return mtime
 
 
+class InodeFilterConstants(object):  # pylint: disable=too-few-public-methods
+    DIRS = 'd'
+    FILES = 'f'
+    LINKS = 'l'
+
+
 class Directory(  # pylint: disable=too-many-instance-attributes,too-many-public-methods
         FileSystemObject, Accumulator, Loadable):
     is_directory = True
@@ -108,6 +114,7 @@ class Directory(  # pylint: disable=too-many-instance-attributes,too-many-public
     files_all = None
     filter = None
     temporary_filter = None
+    narrow_filter = None
     inode_type_filter = None
     marked_items = None
     scroll_begin = 0
@@ -122,8 +129,8 @@ class Directory(  # pylint: disable=too-many-instance-attributes,too-many-public
     content_outdated = False
     content_loaded = False
 
-    vcs = None
     has_vcschild = False
+    _vcs_signal_handler_installed = False
 
     cumulative_size_calculated = False
 
@@ -160,11 +167,20 @@ class Directory(  # pylint: disable=too-many-instance-attributes,too-many-public
 
         self.settings = LocalSettings(path, self.settings)
 
-        if self.settings.vcs_aware:
-            self.vcs = Vcs(self)
-
         self.use()
 
+    @lazy_property
+    def vcs(self):
+        if not self._vcs_signal_handler_installed:
+            self.settings.signal_bind(
+                'setopt.vcs_aware', self.vcs__reset,  # pylint: disable=no-member
+                weak=True, autosort=False,
+            )
+            self._vcs_signal_handler_installed = True
+        if self.settings.vcs_aware:
+            return Vcs(self)
+        return None
+
     def signal_function_factory(self, function):
         def signal_function():
             self.load_if_outdated()
@@ -252,11 +268,32 @@ class Directory(  # pylint: disable=too-many-instance-attributes,too-many-public
                         return False
                 return True
             filters.append(hidden_filter_func)
+        if self.narrow_filter:
+            # pylint: disable=unsupported-membership-test
+
+            # Pylint complains that self.narrow_filter is by default
+            # None but the execution won't reach this line if it is
+            # still None.
+            filters.append(lambda fobj: fobj.basename in self.narrow_filter)
+        if self.settings.global_inode_type_filter or self.inode_type_filter:
+            def inode_filter_func(obj):
+                # Use local inode_type_filter if present, global otherwise
+                inode_filter = self.inode_type_filter or self.settings.global_inode_type_filter
+                # Apply filter
+                if InodeFilterConstants.DIRS in inode_filter and \
+                        obj.is_directory:
+                    return True
+                elif InodeFilterConstants.FILES in inode_filter and \
+                        obj.is_file and not obj.is_link:
+                    return True
+                elif InodeFilterConstants.LINKS in inode_filter and \
+                        obj.is_link:
+                    return True
+                return False
+            filters.append(inode_filter_func)
         if self.filter:
             filter_search = self.filter.search
             filters.append(lambda fobj: filter_search(fobj.basename))
-        if self.inode_type_filter:
-            filters.append(self.inode_type_filter)
         if self.temporary_filter:
             temporary_filter_search = self.temporary_filter.search
             filters.append(lambda fobj: temporary_filter_search(fobj.basename))
@@ -436,6 +473,8 @@ class Directory(  # pylint: disable=too-many-instance-attributes,too-many-public
         Use this sparingly since it takes rather long.
         """
         self.content_outdated = False
+        if self.settings.freeze_files:
+            return
 
         if not self.loading:
             if not self.loaded:
diff --git a/ranger/container/file.py b/ranger/container/file.py
index 17ca577c..d2daa169 100644
--- a/ranger/container/file.py
+++ b/ranger/container/file.py
@@ -48,7 +48,6 @@ class File(FileSystemObject):
     preview_data = None
     preview_known = False
     preview_loading = False
-    linemode = "filename"
     _firstbytes = None
 
     @property
diff --git a/ranger/container/fsobject.py b/ranger/container/fsobject.py
index d24a01ce..0c9f70f6 100644
--- a/ranger/container/fsobject.py
+++ b/ranger/container/fsobject.py
@@ -6,7 +6,7 @@ from __future__ import (absolute_import, division, print_function)
 import re
 from grp import getgrgid
 from os import lstat, stat
-from os.path import abspath, basename, dirname, realpath, splitext, extsep, relpath
+from os.path import abspath, basename, dirname, realpath, relpath
 from pwd import getpwuid
 from time import time
 
@@ -47,42 +47,39 @@ def safe_path(path):
     return path.translate(_SAFE_STRING_TABLE)
 
 
-class FileSystemObject(  # pylint: disable=too-many-instance-attributes
+class FileSystemObject(  # pylint: disable=too-many-instance-attributes,too-many-public-methods
         FileManagerAware, SettingsAware):
-    (basename,
-     relative_path,
-     relative_path_lower,
-     dirname,
-     extension,
-     infostring,
-     path,
-     permissions,
-     stat) = (None,) * 9
-
-    (content_loaded,
-     force_load,
-
-     is_device,
-     is_directory,
-     is_file,
-     is_fifo,
-     is_link,
-     is_socket,
-
-     accessible,
-     exists,       # "exists" currently means "link_target_exists"
-     loaded,
-     marked,
-     runnable,
-     stopped,
-     tagged,
-
-     audio,
-     container,
-     document,
-     image,
-     media,
-     video) = (False,) * 21
+    basename = None
+    relative_path = None
+    infostring = None
+    path = None
+    permissions = None
+    stat = None
+
+    content_loaded = False
+    force_load = False
+
+    is_device = False
+    is_directory = False
+    is_file = False
+    is_fifo = False
+    is_link = False
+    is_socket = False
+
+    accessible = False
+    exists = False  # "exists" currently means "link_target_exists"
+    loaded = False
+    marked = False
+    runnable = False
+    stopped = False
+    tagged = False
+
+    audio = False
+    container = False
+    document = False
+    image = False
+    media = False
+    video = False
 
     size = 0
 
@@ -91,7 +88,6 @@ class FileSystemObject(  # pylint: disable=too-many-instance-attributes
     vcsstatus = None
     vcsremotestatus = None
 
-    linemode = DEFAULT_LINEMODE
     linemode_dict = dict(
         (linemode.name, linemode()) for linemode in
         [DefaultLinemode, TitleLinemode, PermissionsLinemode, FileInfoLinemode,
@@ -107,34 +103,41 @@ class FileSystemObject(  # pylint: disable=too-many-instance-attributes
             self.relative_path = self.basename
         else:
             self.relative_path = relpath(path, basename_is_rel_to)
-        self.relative_path_lower = self.relative_path.lower()
-        self.extension = splitext(self.basename)[1].lstrip(extsep) or None
-        self.dirname = dirname(path)
         self.preload = preload
         self.display_data = {}
 
+    def __repr__(self):
+        return "<{0} {1}>".format(self.__class__.__name__, self.path)
+
+    @lazy_property
+    def extension(self):
         try:
             lastdot = self.basename.rindex('.') + 1
-            self.extension = self.basename[lastdot:].lower()
+            return self.basename[lastdot:].lower()
         except ValueError:
-            self.extension = None
+            return None
 
+    @lazy_property
+    def relative_path_lower(self):
+        return self.relative_path.lower()
+
+    @lazy_property
+    def linemode(self):  # pylint: disable=method-hidden
         # Set the line mode from fm.default_linemodes
         for method, argument, linemode in self.fm.default_linemodes:
             if linemode in self.linemode_dict:
                 if method == "always":
-                    self.linemode = linemode
-                    break
-                if method == "path" and argument.search(path):
-                    self.linemode = linemode
-                    break
+                    return linemode
+                if method == "path" and argument.search(self.path):
+                    return linemode
                 if method == "tag" and self.realpath in self.fm.tags and \
                         self.fm.tags.marker(self.realpath) in argument:
-                    self.linemode = linemode
-                    break
+                    return linemode
+        return DEFAULT_LINEMODE
 
-    def __repr__(self):
-        return "<{0} {1}>".format(self.__class__.__name__, self.path)
+    @lazy_property
+    def dirname(self):
+        return dirname(self.path)
 
     @lazy_property
     def shell_escaped_basename(self):
@@ -260,16 +263,19 @@ class FileSystemObject(  # pylint: disable=too-many-instance-attributes
                 return None  # it is impossible to get the link destination
         return self.path
 
-    def load(self):
+    def load(self):  # pylint: disable=too-many-statements
         """Loads information about the directory itself.
 
         reads useful information about the filesystem-object from the
         filesystem and caches it for later use
         """
 
+        self.loaded = True
+        if self.settings.freeze_files:
+            return
+
         self.display_data = {}
         self.fm.update_preview(self.path)
-        self.loaded = True
 
         # Get the stat object, either from preload or from [l]stat
         self.permissions = None
diff --git a/ranger/container/settings.py b/ranger/container/settings.py
index 70e299c7..bb902f9d 100644
--- a/ranger/container/settings.py
+++ b/ranger/container/settings.py
@@ -30,6 +30,7 @@ ALLOWED_SETTINGS = {
     'cd_bookmarks': bool,
     'cd_tab_case': str,
     'cd_tab_smart': bool,
+    'clear_filters_on_dir_change': bool,
     'collapse_preview': bool,
     'colorscheme': str,
     'column_ratios': (tuple, list),
@@ -41,13 +42,17 @@ ALLOWED_SETTINGS = {
     'draw_borders': bool,
     'draw_progress_bar_in_status_bar': bool,
     'flushinput': bool,
+    'freeze_files': bool,
+    'global_inode_type_filter': str,
     'hidden_filter': str,
+    'hostname_in_titlebar': bool,
     'idle_delay': int,
     'line_numbers': str,
     'max_console_history_size': (int, type(None)),
     'max_history_size': (int, type(None)),
     'metadata_deep_search': bool,
     'mouse_enabled': bool,
+    'one_indexed': bool,
     'open_all_images': bool,
     'padding_right': bool,
     'preview_directories': bool,
@@ -56,41 +61,41 @@ ALLOWED_SETTINGS = {
     'preview_images_method': str,
     'preview_max_size': int,
     'preview_script': (str, type(None)),
+    'save_backtick_bookmark': bool,
     'save_console_history': bool,
+    'save_tabs_on_exit': bool,
     'scroll_offset': int,
     'shorten_title': int,
     'show_cursor': bool,  # TODO: not working?
-    'show_selection_in_titlebar': bool,
     'show_hidden_bookmarks': bool,
     'show_hidden': bool,
+    'show_selection_in_titlebar': bool,
     'sort_case_insensitive': bool,
     'sort_directories_first': bool,
     'sort_reverse': bool,
-    'sort_unicode': bool,
     'sort': str,
+    'sort_unicode': bool,
     'status_bar_on_top': bool,
-    'hostname_in_titlebar': bool,
     'tilde_in_titlebar': bool,
     'unicode_ellipsis': bool,
     'update_title': bool,
     'update_tmux_title': bool,
     'use_preview_script': bool,
-    'viewmode': str,
     'vcs_aware': bool,
     'vcs_backend_bzr': str,
     'vcs_backend_git': str,
     'vcs_backend_hg': str,
     'vcs_backend_svn': str,
+    'viewmode': str,
     'wrap_scroll': bool,
     'xterm_alt_key': bool,
-    'clear_filters_on_dir_change': bool,
-    'save_tabs_on_exit': bool,
 }
 
 ALLOWED_VALUES = {
     'cd_tab_case': ['sensitive', 'insensitive', 'smart'],
     'confirm_on_delete': ['multiple', 'always', 'never'],
     'line_numbers': ['false', 'absolute', 'relative'],
+    'one_indexed': [False, True],
     'preview_images_method': ['w3m', 'iterm2', 'urxvt', 'urxvt-full'],
     'vcs_backend_bzr': ['disabled', 'local', 'enabled'],
     'vcs_backend_git': ['enabled', 'disabled', 'local'],
@@ -298,6 +303,8 @@ class LocalSettings(object):  # pylint: disable=too-few-public-methods
     def __getattr__(self, name):
         if name.startswith('_'):
             return self.__dict__[name]
+        if name.startswith('signal_'):
+            return getattr(self._parent, name)
         return self._parent.get(name, self._path)
 
     def __iter__(self):
diff --git a/ranger/container/tags.py b/ranger/container/tags.py
index 7aed5131..dabaf6a8 100644
--- a/ranger/container/tags.py
+++ b/ranger/container/tags.py
@@ -102,7 +102,7 @@ class Tags(object):
     def _parse(self, fobj):
         result = dict()
         for line in fobj:
-            line = line.strip()
+            line = line.rstrip('\n')
             if len(line) > 2 and line[1] == ':':
                 tag, path = line[0], line[2:]
                 if tag in ALLOWED_KEYS:
diff --git a/ranger/core/actions.py b/ranger/core/actions.py
index 3b30fe6b..0298af19 100644
--- a/ranger/core/actions.py
+++ b/ranger/core/actions.py
@@ -64,7 +64,7 @@ class Actions(  # pylint: disable=too-many-instance-attributes,too-many-public-m
     def reset(self):
         """:reset
 
-        Reset the filemanager, clearing the directory buffer.
+        Reset the filemanager, clearing the directory buffer, reload rifle config
         """
         old_path = self.thisdir.path
         self.previews = {}
@@ -73,6 +73,7 @@ class Actions(  # pylint: disable=too-many-instance-attributes,too-many-public-m
         self.change_mode('normal')
         if self.metadata:
             self.metadata.reset()
+        self.rifle.reload_config()
 
     def change_mode(self, mode=None):
         """:change_mode <mode>
@@ -228,7 +229,7 @@ class Actions(  # pylint: disable=too-many-instance-attributes,too-many-public-m
         cmd_class = self.commands.get_command(command_name)
         if cmd_class is None:
             self.notify("Command not found: `%s'" % command_name, bad=True)
-            return
+            return None
         cmd = cmd_class(string, quantifier=quantifier)
 
         if cmd.resolve_macros and _MacroTemplate.delimiter in cmd.line:
@@ -251,6 +252,7 @@ class Actions(  # pylint: disable=too-many-instance-attributes,too-many-public-m
             if ranger.args.debug:
                 raise
             self.notify(ex)
+        return None
 
     def substitute_macros(self, string,  # pylint: disable=redefined-outer-name
                           additional=None, escape=False):
@@ -461,6 +463,7 @@ class Actions(  # pylint: disable=too-many-instance-attributes,too-many-public-m
         """
         cwd = self.thisdir
         kw.setdefault('cycle', self.fm.settings['wrap_scroll'])
+        kw.setdefault('one_indexed', self.fm.settings['one_indexed'])
         direction = Direction(kw)
         if 'left' in direction or direction.left() > 0:
             steps = direction.left()
@@ -737,6 +740,7 @@ class Actions(  # pylint: disable=too-many-instance-attributes,too-many-public-m
     # -- Searching
     # --------------------------
 
+    # TODO: Do we still use this method? Should we remove it?
     def search_file(self, text, offset=1, regexp=True):
         if isinstance(text, str) and regexp:
             try:
@@ -745,6 +749,7 @@ class Actions(  # pylint: disable=too-many-instance-attributes,too-many-public-m
                 return False
         self.thistab.last_search = text
         self.search_next(order='search', offset=offset)
+        return None
 
     def search_next(self, order=None, offset=1, forward=True):
         original_order = order
@@ -795,6 +800,7 @@ class Actions(  # pylint: disable=too-many-instance-attributes,too-many-public-m
                 return cwd.cycle(forward=None)
 
             return cwd.cycle(forward=forward)
+        return None
 
     def set_search_method(self, order, forward=True):  # pylint: disable=unused-argument
         if order in ('search', 'tag', 'size', 'mimetype', 'ctime', 'mtime', 'atime'):
@@ -1025,7 +1031,8 @@ class Actions(  # pylint: disable=too-many-instance-attributes,too-many-public-m
             return path
 
         cacheimg = os.path.join(ranger.args.cachedir, self.sha1_encode(path))
-        if os.path.isfile(cacheimg) and \
+        if self.settings.preview_images and \
+                os.path.isfile(cacheimg) and \
                 os.path.getmtime(cacheimg) > os.path.getmtime(path):
             data['foundpreview'] = True
             data['imagepreview'] = True
@@ -1081,6 +1088,7 @@ class Actions(  # pylint: disable=too-many-instance-attributes,too-many-public-m
                 else:
                     pager.set_source(self.thisfile.get_preview_source(
                         pager.wid, pager.hei))
+            return None
 
         def on_destroy(signal):  # pylint: disable=unused-argument
             try:
@@ -1171,6 +1179,7 @@ class Actions(  # pylint: disable=too-many-instance-attributes,too-many-public-m
         newtab = tablist[(current_index + offset) % len(tablist)]
         if newtab != self.current_tab:
             self.tab_open(newtab)
+        return None
 
     def tab_new(self, path=None, narg=None):
         if narg:
@@ -1178,6 +1187,7 @@ class Actions(  # pylint: disable=too-many-instance-attributes,too-many-public-m
         for i in range(1, 10):
             if i not in self.tabs:
                 return self.tab_open(i, path)
+        return None
 
     def tab_switch(self, path, create_directory=False):
         """Switches to tab of given path, opening a new tab as necessary.
diff --git a/ranger/core/fm.py b/ranger/core/fm.py
index b8d38397..c55a3922 100644
--- a/ranger/core/fm.py
+++ b/ranger/core/fm.py
@@ -105,6 +105,11 @@ class FM(Actions,  # pylint: disable=too-many-instance-attributes
         self.settings.signal_bind('setopt.preview_images_method', set_image_displayer,
                                   priority=settings.SIGNAL_PRIORITY_AFTER_SYNC)
 
+        self.settings.signal_bind(
+            'setopt.preview_images',
+            lambda signal: signal.fm.previews.clear(),
+        )
+
         if ranger.args.clean:
             self.tags = TagsDummy("")
         elif self.tags is None:
@@ -120,6 +125,8 @@ class FM(Actions,  # pylint: disable=too-many-instance-attributes
                 bookmarktype=Directory,
                 autosave=self.settings.autosave_bookmarks)
             self.bookmarks.load()
+            self.bookmarks.enable_saving_backtick_bookmark(
+                self.settings.save_backtick_bookmark)
 
         self.ui.setup_curses()
         self.ui.initialize()
@@ -186,6 +193,10 @@ class FM(Actions,  # pylint: disable=too-many-instance-attributes
             'setopt.metadata_deep_search',
             lambda signal: setattr(signal.fm.metadata, 'deep_search', signal.value)
         )
+        self.settings.signal_bind(
+            'setopt.save_backtick_bookmark',
+            lambda signal: signal.fm.bookmarks.enable_saving_backtick_bookmark(signal.value)
+        )
 
     def destroy(self):
         debug = ranger.args.debug
diff --git a/ranger/core/main.py b/ranger/core/main.py
index 38513970..0148e2b5 100644
--- a/ranger/core/main.py
+++ b/ranger/core/main.py
@@ -119,6 +119,10 @@ def main(
         FileManagerAware.fm_set(fm)
         load_settings(fm, args.clean)
 
+        if args.show_only_dirs:
+            from ranger.container.directory import InodeFilterConstants
+            fm.settings.global_inode_type_filter = InodeFilterConstants.DIRS
+
         if args.list_unused_keys:
             from ranger.ext.keybinding_parser import (special_keys,
                                                       reversed_special_keys)
@@ -274,6 +278,8 @@ def parse_arguments():
     parser.add_option('--choosedir', type='string', metavar='PATH',
                       help="Makes ranger act like a directory chooser. When ranger quits"
                       ", it will write the name of the last visited directory to PATH")
+    parser.add_option('--show-only-dirs', action='store_true',
+                      help="Show only directories, no files or links")
     parser.add_option('--selectfile', type='string', metavar='filepath',
                       help="Open ranger with supplied file selected.")
     parser.add_option('--list-unused-keys', action='store_true',
@@ -350,19 +356,6 @@ def load_settings(  # pylint: disable=too-many-locals,too-many-branches,too-many
                 LOG.debug("Loaded custom commands from '%s'", custom_comm_path)
             sys.dont_write_bytecode = old_bytecode_setting
 
-        allow_access_to_confdir(ranger.args.confdir, False)
-
-        # Load rc.conf
-        custom_conf = fm.confpath('rc.conf')
-        default_conf = fm.relpath('config', 'rc.conf')
-
-        if os.environ.get('RANGER_LOAD_DEFAULT_RC', 'TRUE').upper() != 'FALSE':
-            fm.source(default_conf)
-        if os.access(custom_conf, os.R_OK):
-            fm.source(custom_conf)
-
-        allow_access_to_confdir(ranger.args.confdir, True)
-
         # XXX Load plugins (experimental)
         plugindir = fm.confpath('plugins')
         try:
@@ -399,6 +392,17 @@ def load_settings(  # pylint: disable=too-many-locals,too-many-branches,too-many
             ranger.fm = None
 
         allow_access_to_confdir(ranger.args.confdir, False)
+        # Load rc.conf
+        custom_conf = fm.confpath('rc.conf')
+        default_conf = fm.relpath('config', 'rc.conf')
+
+        custom_conf_is_readable = os.access(custom_conf, os.R_OK)
+        if (os.environ.get('RANGER_LOAD_DEFAULT_RC', 'TRUE').upper() != 'FALSE' or
+                not custom_conf_is_readable):
+            fm.source(default_conf)
+        if custom_conf_is_readable:
+            fm.source(custom_conf)
+
     else:
         fm.source(fm.relpath('config', 'rc.conf'))
 
diff --git a/ranger/core/metadata.py b/ranger/core/metadata.py
index 28b1f5b7..75f7ba3c 100644
--- a/ranger/core/metadata.py
+++ b/ranger/core/metadata.py
@@ -90,26 +90,25 @@ class MetadataManager(object):
     def _get_entry(self, filename):
         if filename in self.metadata_cache:
             return self.metadata_cache[filename]
-        else:
-
-            # Try to find an entry for this file in any of
-            # the applicable .metadata.json files
-            for metafile in self._get_metafile_names(filename):
-                entries = self._get_metafile_content(metafile)
-                # Check for a direct match:
-                if filename in entries:
-                    entry = entries[filename]
-                # Check for a match of the base name:
-                elif basename(filename) in entries:
-                    entry = entries[basename(filename)]
-                else:
-                    # No match found, try another entry
-                    continue
-
-                self.metadata_cache[filename] = entry
-                return entry
-
-            raise KeyError
+
+        # Try to find an entry for this file in any of
+        # the applicable .metadata.json files
+        for metafile in self._get_metafile_names(filename):
+            entries = self._get_metafile_content(metafile)
+            # Check for a direct match:
+            if filename in entries:
+                entry = entries[filename]
+            # Check for a match of the base name:
+            elif basename(filename) in entries:
+                entry = entries[basename(filename)]
+            else:
+                # No match found, try another entry
+                continue
+
+            self.metadata_cache[filename] = entry
+            return entry
+
+        raise KeyError
 
     def _get_metafile_content(self, metafile):
         import json
diff --git a/ranger/core/runner.py b/ranger/core/runner.py
index 8c3e3162..bb4e512a 100644
--- a/ranger/core/runner.py
+++ b/ranger/core/runner.py
@@ -27,7 +27,7 @@ from __future__ import (absolute_import, division, print_function)
 import logging
 import os
 import sys
-from subprocess import Popen, PIPE
+from subprocess import Popen, PIPE, STDOUT
 from ranger.ext.get_executables import get_executables, get_term
 from ranger.ext.popen_forked import Popen_forked
 
@@ -185,7 +185,7 @@ class Runner(object):  # pylint: disable=too-few-public-methods
 
         if 'p' in context.flags:
             popen_kws['stdout'] = PIPE
-            popen_kws['stderr'] = PIPE
+            popen_kws['stderr'] = STDOUT
             toggle_ui = False
             pipe_output = True
             context.wait = False
diff --git a/ranger/core/tab.py b/ranger/core/tab.py
index 160f590f..1d5e69d4 100644
--- a/ranger/core/tab.py
+++ b/ranger/core/tab.py
@@ -111,7 +111,7 @@ class Tab(FileManagerAware, SettingsAware):  # pylint: disable=too-many-instance
         """Enter given path"""
         # TODO: Ensure that there is always a self.thisdir
         if path is None:
-            return
+            return None
         path = str(path)
 
         # clear filter in the folder we're leaving
diff --git a/ranger/data/mime.types b/ranger/data/mime.types
index f338ab84..c1124271 100644
--- a/ranger/data/mime.types
+++ b/ranger/data/mime.types
@@ -14,6 +14,7 @@ audio/flac              flac
 audio/musepack          mpc mpp mp+
 audio/ogg               oga ogg spx
 audio/wavpack           wv wvc
+audio/webm              weba
 
 video/mkv               mkv
 video/webm              webm
diff --git a/ranger/data/scope.sh b/ranger/data/scope.sh
index 8386eac2..560e27da 100755
--- a/ranger/data/scope.sh
+++ b/ranger/data/scope.sh
@@ -95,6 +95,15 @@ handle_image() {
 
         # Image
         image/*)
+            local orientation
+            orientation="$( identify -format '%[EXIF:Orientation]\n' -- "${FILE_PATH}" )"
+            # If orientation data is present and the image actually
+            # needs rotating ("1" means no rotation)...
+            if [[ -n "$orientation" && "$orientation" != 1 ]]; then
+                # ...auto-rotate the image according to the EXIF data.
+                convert -- "${FILE_PATH}" -auto-orient "${IMAGE_CACHE_PATH}" && exit 6
+            fi
+
             # `w3mimgdisplay` will be called for all images (unless overriden as above),
             # but might fail for unsupported types.
             exit 7;;
@@ -104,6 +113,15 @@ handle_image() {
         #     # Thumbnail
         #     ffmpegthumbnailer -i "${FILE_PATH}" -o "${IMAGE_CACHE_PATH}" -s 0 && exit 6
         #     exit 1;;
+        # PDF
+        # application/pdf)
+        #     pdftoppm -f 1 -l 1 \
+        #              -scale-to-x 1920 \
+        #              -scale-to-y -1 \
+        #              -singlefile \
+        #              -jpeg -tiffcompression jpeg \
+        #              -- "${FILE_PATH}" "${IMAGE_CACHE_PATH%.*}" \
+        #         && exit 6 || exit 1;;
     esac
 }
 
@@ -149,11 +167,11 @@ handle_fallback() {
 }
 
 
-handle_extension
 MIMETYPE="$( file --dereference --brief --mime-type -- "${FILE_PATH}" )"
 if [[ "${PV_IMAGE_ENABLED}" == 'True' ]]; then
     handle_image "${MIMETYPE}"
 fi
+handle_extension
 handle_mime "${MIMETYPE}"
 handle_fallback
 
diff --git a/ranger/ext/accumulator.py b/ranger/ext/accumulator.py
index b0e4a1c5..c2e33b59 100644
--- a/ranger/ext/accumulator.py
+++ b/ranger/ext/accumulator.py
@@ -29,12 +29,12 @@ class Accumulator(object):
 
     def move_to_obj(self, arg, attr=None):
         if not arg:
-            return
+            return None
 
         lst = self.get_list()
 
         if not lst:
-            return
+            return None
 
         do_get_attr = isinstance(attr, str)
 
diff --git a/ranger/ext/cached_function.py b/ranger/ext/cached_function.py
index 4255443c..7fdd579e 100644
--- a/ranger/ext/cached_function.py
+++ b/ranger/ext/cached_function.py
@@ -4,6 +4,7 @@
 from __future__ import (absolute_import, division, print_function)
 
 
+# Similar to functools.lru_cache of python3
 def cached_function(fnc):
     cache = {}
 
diff --git a/ranger/ext/direction.py b/ranger/ext/direction.py
index bbb69c9b..7df45556 100644
--- a/ranger/ext/direction.py
+++ b/ranger/ext/direction.py
@@ -20,6 +20,8 @@ False
 
 from __future__ import (absolute_import, division, print_function)
 
+import math
+
 
 class Direction(dict):
 
@@ -94,6 +96,10 @@ class Direction(dict):
     def cycle(self):
         return self.get('cycle') in (True, 'true', 'on', 'yes')
 
+    def one_indexed(self):
+        return ('one_indexed' in self and
+                self.get('one_indexed') in (True, 'true', 'on', 'yes'))
+
     def multiply(self, n):
         for key in ('up', 'right', 'down', 'left'):
             try:
@@ -127,7 +133,10 @@ class Direction(dict):
         pos = direction
         if override is not None:
             if self.absolute():
-                pos = override
+                if self.one_indexed():
+                    pos = override - 1
+                else:
+                    pos = override
             else:
                 pos *= override
         if self.pages():
@@ -142,8 +151,16 @@ class Direction(dict):
         if self.cycle():
             cycles, pos = divmod(pos, (maximum + offset - minimum))
             self['_move_cycles'] = int(cycles)
-            return int(minimum + pos)
-        return int(max(min(pos, maximum + offset - 1), minimum))
+            ret = minimum + pos
+        else:
+            ret = max(min(pos, maximum + offset - 1), minimum)
+        # Round towards the direction we're moving from.
+        # From the UI point of view, round down. See: #912.
+        if direction < 0:
+            ret = int(math.ceil(ret))
+        else:
+            ret = int(ret)
+        return ret
 
     def move_cycles(self):
         return self.get('_move_cycles', 0)
diff --git a/ranger/ext/img_display.py b/ranger/ext/img_display.py
index 15eecd1b..abcdd7b1 100644
--- a/ranger/ext/img_display.py
+++ b/ranger/ext/img_display.py
@@ -32,6 +32,7 @@ W3MIMGDISPLAY_PATHS = [
     '/usr/libexec/w3m/w3mimgdisplay',
     '/usr/lib64/w3m/w3mimgdisplay',
     '/usr/libexec64/w3m/w3mimgdisplay',
+    '/usr/local/libexec/w3m/w3mimgdisplay',
 ]
 
 
@@ -121,6 +122,8 @@ class W3MImageDisplayer(ImageDisplayer):
         self.process.stdin.write(input_gen)
         self.process.stdin.flush()
         self.process.stdout.readline()
+        self.quit()
+        self.is_initialized = False
 
     def clear(self, start_x, start_y, width, height):
         if not self.is_initialized or self.process.poll() is not None:
diff --git a/ranger/ext/lazy_property.py b/ranger/ext/lazy_property.py
index 92dc309d..bb54bd5e 100644
--- a/ranger/ext/lazy_property.py
+++ b/ranger/ext/lazy_property.py
@@ -1,4 +1,6 @@
-# From http://blog.pythonisito.com/2008/08/lazy-descriptors.html
+# This file is part of ranger, the console file manager.
+# License: GNU GPL version 3, see the file "AUTHORS" for details.
+# Based on http://blog.pythonisito.com/2008/08/lazy-descriptors.html
 
 from __future__ import (absolute_import, division, print_function)
 
@@ -7,16 +9,30 @@ class lazy_property(object):  # pylint: disable=invalid-name,too-few-public-meth
     """A @property-like decorator with lazy evaluation
 
     >>> class Foo:
+    ...     counter = 0
     ...     @lazy_property
     ...     def answer(self):
-    ...         print("calculating answer...")
-    ...         return 2*3*7
+    ...         Foo.counter += 1
+    ...         return Foo.counter
     >>> foo = Foo()
     >>> foo.answer
-    calculating answer...
-    42
+    1
     >>> foo.answer
-    42
+    1
+    >>> foo.answer__reset()
+    >>> foo.answer
+    2
+    >>> foo.answer
+    2
+
+    Avoid interaction between multiple objects:
+
+    >>> bar = Foo()
+    >>> bar.answer
+    3
+    >>> foo.answer__reset()
+    >>> bar.answer
+    3
     """
 
     def __init__(self, method):
@@ -27,6 +43,15 @@ class lazy_property(object):  # pylint: disable=invalid-name,too-few-public-meth
     def __get__(self, obj, cls=None):
         if obj is None:  # to fix issues with pydoc
             return None
+
+        reset_function_name = self.__name__ + "__reset"
+
+        if not hasattr(obj, reset_function_name):
+            def reset_function():
+                setattr(obj, self.__name__, self)
+                del obj.__dict__[self.__name__]  # force "__get__" being called
+            obj.__dict__[reset_function_name] = reset_function
+
         result = self._method(obj)
         obj.__dict__[self.__name__] = result
         return result
diff --git a/ranger/ext/next_available_filename.py b/ranger/ext/next_available_filename.py
index 91d48631..0a5e0856 100644
--- a/ranger/ext/next_available_filename.py
+++ b/ranger/ext/next_available_filename.py
@@ -19,3 +19,4 @@ def next_available_filename(fname, directory="."):
     for i in range(1, len(existing_files) + 1):
         if fname + str(i) not in existing_files:
             return fname + str(i)
+    return None
diff --git a/ranger/ext/rifle.py b/ranger/ext/rifle.py
index cfb07f5f..a6c0b9f0 100755
--- a/ranger/ext/rifle.py
+++ b/ranger/ext/rifle.py
@@ -244,6 +244,7 @@ class Rifle(object):  # pylint: disable=too-many-instance-attributes
             return bool(os.environ.get(argument))
         elif function == 'else':
             return True
+        return None
 
     def get_mimetype(self, fname):
         # Spawn "file" to determine the mime-type of the given file.
@@ -295,7 +296,7 @@ class Rifle(object):  # pylint: disable=too-many-instance-attributes
                     count = self._skip
                 yield (count, cmd, self._app_label, self._app_flags)
 
-    def execute(self, files,  # pylint: disable=too-many-branches,too-many-statements
+    def execute(self, files,  # noqa: E501 pylint: disable=too-many-branches,too-many-statements,too-many-locals
                 number=0, label=None, flags="", mimetype=None):
         """Executes the given list of files.
 
@@ -379,6 +380,8 @@ class Rifle(object):  # pylint: disable=too-many-instance-attributes
             finally:
                 self.hook_after_executing(command, self._mimetype, self._app_flags)
 
+        return None
+
 
 def find_conf_path():
     # Find configuration file path
diff --git a/ranger/ext/signals.py b/ranger/ext/signals.py
index cbd35643..67c8960d 100644
--- a/ranger/ext/signals.py
+++ b/ranger/ext/signals.py
@@ -155,6 +155,7 @@ class SignalDispatcher(object):
                 key=lambda handler: -handler.priority)
         return handler
 
+    # TODO: Do we still use this method? Should we remove it?
     def signal_force_sort(self, signal_name=None):
         """Forces a sorting of signal handlers by priority.
 
@@ -165,11 +166,12 @@ class SignalDispatcher(object):
             for handlers in self._signals.values():
                 handlers.sort(
                     key=lambda handler: -handler.priority)
+            return None
         elif signal_name in self._signals:
             self._signals[signal_name].sort(
                 key=lambda handler: -handler.priority)
-        else:
-            return False
+            return None
+        return False
 
     def signal_unbind(self, signal_handler):
         """Removes a signal binding.
diff --git a/ranger/ext/vcs/vcs.py b/ranger/ext/vcs/vcs.py
index ba28d141..e2838f8d 100644
--- a/ranger/ext/vcs/vcs.py
+++ b/ranger/ext/vcs/vcs.py
@@ -112,7 +112,11 @@ class Vcs(object):  # pylint: disable=too-many-instance-attributes
     def _run(self, args, path=None,  # pylint: disable=too-many-arguments
              catchout=True, retbytes=False, rstrip_newline=True):
         """Run a command"""
-        cmd = [self.repotype] + args
+        if self.repotype == 'hg':
+            # use "chg", a faster built-in client
+            cmd = ['chg'] + args
+        else:
+            cmd = [self.repotype] + args
         if path is None:
             path = self.path
 
@@ -125,6 +129,7 @@ class Vcs(object):  # pylint: disable=too-many-instance-attributes
             else:
                 with open(os.devnull, mode='w') as fd_devnull:
                     subprocess.check_call(cmd, cwd=path, stdout=fd_devnull, stderr=fd_devnull)
+                return None
         except (subprocess.CalledProcessError, OSError):
             raise VcsError('{0:s}: {1:s}'.format(str(cmd), path))
 
diff --git a/ranger/ext/widestring.py b/ranger/ext/widestring.py
index ed66f3c7..2721643c 100644
--- a/ranger/ext/widestring.py
+++ b/ranger/ext/widestring.py
@@ -1,4 +1,4 @@
-# -*- encoding: utf8 -*-
+# -*- encoding: utf-8 -*-
 # This file is part of ranger, the console file manager.
 # License: GNU GPL version 3, see the file "AUTHORS" for details.
 
@@ -81,6 +81,7 @@ class WideString(object):  # pylint: disable=too-few-public-methods
             return WideString(self.string + string)
         elif isinstance(string, WideString):
             return WideString(self.string + string.string, self.chars + string.chars)
+        return None
 
     def __radd__(self, string):
         """
@@ -91,6 +92,7 @@ class WideString(object):  # pylint: disable=too-few-public-methods
             return WideString(string + self.string)
         elif isinstance(string, WideString):
             return WideString(string.string + self.string, string.chars + self.chars)
+        return None
 
     def __str__(self):
         return self.string
diff --git a/ranger/gui/bar.py b/ranger/gui/bar.py
index 64bd6ce1..3f4b891c 100644
--- a/ranger/gui/bar.py
+++ b/ranger/gui/bar.py
@@ -77,6 +77,7 @@ class Bar(object):
                 else:
                     item.cut_off(oversize)
                     break
+        return None
 
     def fill_gap(self, char, wid, gapwidth=False):
         del self.gap[:]
diff --git a/ranger/gui/context.py b/ranger/gui/context.py
index 7c7f1727..d8d1957c 100644
--- a/ranger/gui/context.py
+++ b/ranger/gui/context.py
@@ -16,7 +16,7 @@ CONTEXT_KEYS = [
     'good', 'bad',
     'space', 'permissions', 'owner', 'group', 'mtime', 'nlink',
     'scroll', 'all', 'bot', 'top', 'percentage', 'filter',
-    'flat', 'marked', 'tagged', 'tag_marker', 'cut', 'copied',
+    'flat', 'marked', 'tagged', 'tag_marker', 'cut', 'copied', 'frozen',
     'help_markup',  # COMPAT
     'seperator', 'key', 'special', 'border',  # COMPAT
     'title', 'text', 'highlight', 'bars', 'quotes', 'tab', 'loaded',
diff --git a/ranger/gui/ui.py b/ranger/gui/ui.py
index 5d53603f..990db0ad 100644
--- a/ranger/gui/ui.py
+++ b/ranger/gui/ui.py
@@ -102,6 +102,7 @@ class UI(  # pylint: disable=too-many-instance-attributes,too-many-public-method
             pass
 
         self.settings.signal_bind('setopt.mouse_enabled', _setup_mouse)
+        self.settings.signal_bind('setopt.freeze_files', self.redraw_statusbar)
         _setup_mouse(dict(value=self.settings.mouse_enabled))
 
         if not self.is_set_up:
@@ -452,6 +453,9 @@ class UI(  # pylint: disable=too-many-instance-attributes,too-many-public-method
     def redraw_main_column(self):
         self.browser.main_column.need_redraw = True
 
+    def redraw_statusbar(self):
+        self.status.need_redraw = True
+
     def close_taskview(self):
         self.taskview.visible = False
         self.browser.visible = True
@@ -505,6 +509,7 @@ class UI(  # pylint: disable=too-many-instance-attributes,too-many-public-method
         if viewmode == 'miller':
             from ranger.gui.widgets.view_miller import ViewMiller
             return ViewMiller
-        if viewmode == 'multipane':
+        elif viewmode == 'multipane':
             from ranger.gui.widgets.view_multipane import ViewMultipane
             return ViewMultipane
+        return None
diff --git a/ranger/gui/widgets/browsercolumn.py b/ranger/gui/widgets/browsercolumn.py
index 14fde110..b3272cbc 100644
--- a/ranger/gui/widgets/browsercolumn.py
+++ b/ranger/gui/widgets/browsercolumn.py
@@ -17,6 +17,10 @@ from . import Widget
 from .pager import Pager
 
 
+def hook_before_drawing(fsobject, color_list):
+    return fsobject, color_list
+
+
 class BrowserColumn(Pager):  # pylint: disable=too-many-instance-attributes
     main_column = False
     display_infostring = False
@@ -203,7 +207,12 @@ class BrowserColumn(Pager):  # pylint: disable=too-many-instance-attributes
         if self.settings.line_numbers == 'relative':
             line_number = abs(selected_i - i)
             if line_number == 0:
-                line_number = selected_i
+                if self.settings.one_indexed:
+                    line_number = selected_i + 1
+                else:
+                    line_number = selected_i
+        elif self.settings.one_indexed:
+            line_number += 1
 
         return linum_format.format(line_number)
 
@@ -382,6 +391,8 @@ class BrowserColumn(Pager):  # pylint: disable=too-many-instance-attributes
             display_data = []
             drawn.display_data[key] = display_data
 
+            drawn, this_color = hook_before_drawing(drawn, this_color)
+
             predisplay = predisplay_left + predisplay_right
             for txt, color in predisplay:
                 attr = self.settings.colorscheme.get_attr(*(this_color + color))
diff --git a/ranger/gui/widgets/console.py b/ranger/gui/widgets/console.py
index 2d905f62..13201e34 100644
--- a/ranger/gui/widgets/console.py
+++ b/ranger/gui/widgets/console.py
@@ -87,21 +87,28 @@ class Console(Widget):  # pylint: disable=too-many-instance-attributes,too-many-
                 fobj.close()
         Widget.destroy(self)
 
+    def _calculate_offset(self):
+        wid = self.wid - 2
+        whalf = wid // 2
+        if self.pos < whalf or len(self.line) < wid:
+            return 0
+        if self.pos > len(self.line) - (wid - whalf):
+            return len(self.line) - wid
+        return self.pos - whalf
+
     def draw(self):
         self.win.erase()
         if self.question_queue:
             assert isinstance(self.question_queue[0], tuple)
             assert len(self.question_queue[0]) == 3
-            self.addstr(0, 0, self.question_queue[0][0])
+            self.addstr(0, 0, self.question_queue[0][0][self.pos:])
             return
 
         self.addstr(0, 0, self.prompt)
         line = WideString(self.line)
-        overflow = -self.wid + len(self.prompt) + len(line) + 1
-        if overflow > 0:
-            self.addstr(0, len(self.prompt), str(line[overflow:]))
-        else:
-            self.addstr(0, len(self.prompt), self.line)
+        if line:
+            x = self._calculate_offset()
+            self.addstr(0, len(self.prompt), str(line[x:]))
 
     def finalize(self):
         move = self.fm.ui.win.move
@@ -112,7 +119,8 @@ class Console(Widget):  # pylint: disable=too-many-instance-attributes,too-many-
                 pass
         else:
             try:
-                pos = uwid(self.line[0:self.pos]) + len(self.prompt)
+                x = self._calculate_offset()
+                pos = uwid(self.line[x:self.pos]) + len(self.prompt)
                 move(self.y, self.x + min(self.wid - 1, pos))
             except curses.error:
                 pass
@@ -202,7 +210,7 @@ class Console(Widget):  # pylint: disable=too-many-instance-attributes,too-many-
             return
 
         if self.question_queue:
-            self.unicode_buffer, answer, self.pos = result
+            self.unicode_buffer, answer, _ = result
             self._answer_question(answer)
         else:
             self.unicode_buffer, self.line, self.pos = result
@@ -273,22 +281,28 @@ class Console(Widget):  # pylint: disable=too-many-instance-attributes,too-many-
         if direction.horizontal():
             # Ensure that the pointer is moved utf-char-wise
             if self.fm.py3:
+                if self.question_queue:
+                    umax = len(self.question_queue[0][0]) + 1 - self.wid
+                else:
+                    umax = len(self.line) + 1
                 self.pos = direction.move(
                     direction=direction.right(),
                     minimum=0,
-                    maximum=len(self.line) + 1,
+                    maximum=umax,
                     current=self.pos)
             else:
-                if self.fm.py3:
-                    uchar = list(self.line)
-                    upos = len(self.line[:self.pos])
+                if self.question_queue:
+                    uchar = list(self.question_queue[0][0].decode('utf-8', 'ignore'))
+                    upos = len(self.question_queue[0][0][:self.pos].decode('utf-8', 'ignore'))
+                    umax = len(uchar) + 1 - self.wid
                 else:
                     uchar = list(self.line.decode('utf-8', 'ignore'))
                     upos = len(self.line[:self.pos].decode('utf-8', 'ignore'))
+                    umax = len(uchar) + 1
                 newupos = direction.move(
                     direction=direction.right(),
                     minimum=0,
-                    maximum=len(uchar) + 1,
+                    maximum=umax,
                     current=upos)
                 self.pos = len(''.join(uchar[:newupos]).encode('utf-8', 'ignore'))
 
diff --git a/ranger/gui/widgets/statusbar.py b/ranger/gui/widgets/statusbar.py
index eb2250ae..266d48ca 100644
--- a/ranger/gui/widgets/statusbar.py
+++ b/ranger/gui/widgets/statusbar.py
@@ -234,7 +234,7 @@ class StatusBar(Widget):  # pylint: disable=too-many-instance-attributes
             except KeyError:
                 return str(gid)
 
-    def _get_right_part(self, bar):  # pylint: disable=too-many-branches
+    def _get_right_part(self, bar):  # pylint: disable=too-many-branches,too-many-statements
         right = bar.right
         if self.column is None:
             return
@@ -256,6 +256,10 @@ class StatusBar(Widget):  # pylint: disable=too-many-instance-attributes
             right.add(str(self.fm.thisdir.flat), base, 'flat')
             right.add(", ", "space")
 
+        if self.fm.thisdir.narrow_filter:
+            right.add("narrowed")
+            right.add(", ", "space")
+
         if self.fm.thisdir.filter:
             right.add("f=`", base, 'filter')
             right.add(self.fm.thisdir.filter.pattern, base, 'filter')
@@ -298,6 +302,11 @@ class StatusBar(Widget):  # pylint: disable=too-many-instance-attributes
         else:
             right.add('0/0  All', base, 'all')
 
+        if self.settings.freeze_files:
+            # Indicate that files are frozen and will not be loaded
+            right.add("  ", "space")
+            right.add('FROZEN', base, 'frozen')
+
     def _print_result(self, result):
         self.win.move(0, 0)
         for part in result:
diff --git a/ranger/gui/widgets/taskview.py b/ranger/gui/widgets/taskview.py
index 2c0cafb0..a4633e15 100644
--- a/ranger/gui/widgets/taskview.py
+++ b/ranger/gui/widgets/taskview.py
@@ -84,7 +84,7 @@ class TaskView(Widget, Accumulator):
         if i is None:
             i = self.pointer
 
-        self.fm.loader.move(_from=i, to=to)
+        self.fm.loader.move(pos_src=i, pos_dest=to)
 
     def press(self, key):
         self.fm.ui.keymaps.use_keymap('taskview')
diff --git a/ranger/gui/widgets/view_base.py b/ranger/gui/widgets/view_base.py
index 5cdb2615..cb205d92 100644
--- a/ranger/gui/widgets/view_base.py
+++ b/ranger/gui/widgets/view_base.py
@@ -109,6 +109,7 @@ class ViewBase(Widget, DisplayableContainer):  # pylint: disable=too-many-instan
 
     def _draw_hints(self):
         self.columns[-1].clear_image(force=True)
+        self.color_reset()
         self.need_clear = True
         hints = []
         for key, value in self.fm.ui.keybuffer.pointer.items():