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.16
-rw-r--r--doc/rifle.14
-rwxr-xr-xexamples/rifle_sxiv.sh2
-rw-r--r--ranger/__init__.py2
-rw-r--r--ranger/api/commands.py12
-rwxr-xr-xranger/config/commands.py15
-rw-r--r--ranger/config/rc.conf4
-rw-r--r--ranger/config/rifle.conf1
-rw-r--r--ranger/container/directory.py1
-rw-r--r--ranger/container/file.py1
-rw-r--r--ranger/container/tags.py2
-rw-r--r--ranger/core/actions.py12
-rw-r--r--ranger/core/fm.py3
-rw-r--r--ranger/core/metadata.py39
-rw-r--r--ranger/core/tab.py2
-rwxr-xr-xranger/data/scope.sh20
-rw-r--r--ranger/ext/accumulator.py4
-rw-r--r--ranger/ext/img_display.py60
-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/ui.py3
-rw-r--r--ranger/gui/widgets/console.py20
-rw-r--r--ranger/gui/widgets/taskview.py2
30 files changed, 187 insertions, 64 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 cd00cd95..bb7114a2 100644
--- a/doc/ranger.1
+++ b/doc/ranger.1
@@ -1,4 +1,4 @@
-.\" Automatically generated by Pod::Man 4.09 (Pod::Simple 3.35)
+.\" Automatically generated by Pod::Man 4.07 (Pod::Simple 3.32)
 .\"
 .\" Standard preamble:
 .\" ========================================================================
@@ -129,7 +129,7 @@
 .\" ========================================================================
 .\"
 .IX Title "RANGER 1"
-.TH RANGER 1 "ranger-1.9.0b5" "10/22/2017" "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
@@ -599,7 +599,7 @@ Toggle the mark-status of all files
 .IP "V" 14
 .IX Item "V"
 Starts the visual mode, which selects all files between the starting point and
-the cursor until you press \s-1ESC.\s0  To unselect files in the same way, use \*(L"uV\*(R".
+the cursor until you press \s-1ESC. \s0 To unselect files in the same way, use \*(L"uV\*(R".
 .IP "/" 14
 Search for files in the current directory.
 .IP ":" 14
diff --git a/doc/rifle.1 b/doc/rifle.1
index 9d9e08f9..8531d69c 100644
--- a/doc/rifle.1
+++ b/doc/rifle.1
@@ -1,4 +1,4 @@
-.\" Automatically generated by Pod::Man 4.09 (Pod::Simple 3.35)
+.\" Automatically generated by Pod::Man 4.07 (Pod::Simple 3.32)
 .\"
 .\" Standard preamble:
 .\" ========================================================================
@@ -129,7 +129,7 @@
 .\" ========================================================================
 .\"
 .IX Title "RIFLE 1"
-.TH RIFLE 1 "rifle-1.9.0b5" "10/22/2017" "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/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/config/commands.py b/ranger/config/commands.py
index de3170bb..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)
@@ -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>...]
diff --git a/ranger/config/rc.conf b/ranger/config/rc.conf
index a306594a..6bb8f0d0 100644
--- a/ranger/config/rc.conf
+++ b/ranger/config/rc.conf
@@ -281,7 +281,7 @@ alias travel     scout -aefklst
 # ===================================================================
 
 # Basic
-map     Q quit!
+map     Q quitall
 map     q quit
 copymap q ZZ ZQ
 
@@ -329,7 +329,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
diff --git a/ranger/config/rifle.conf b/ranger/config/rifle.conf
index 1924bff3..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"
 
diff --git a/ranger/container/directory.py b/ranger/container/directory.py
index 8ca533d7..18b1687c 100644
--- a/ranger/container/directory.py
+++ b/ranger/container/directory.py
@@ -179,6 +179,7 @@ class Directory(  # pylint: disable=too-many-instance-attributes,too-many-public
             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():
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/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 5f8f6c53..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):
@@ -738,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:
@@ -746,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
@@ -796,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'):
@@ -1083,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:
@@ -1173,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:
@@ -1180,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 591edecc..c55a3922 100644
--- a/ranger/core/fm.py
+++ b/ranger/core/fm.py
@@ -23,6 +23,7 @@ from ranger.gui.ui import UI
 from ranger.container.bookmarks import Bookmarks
 from ranger.core.runner import Runner
 from ranger.ext.img_display import (W3MImageDisplayer, ITerm2ImageDisplayer,
+                                    TerminologyImageDisplayer,
                                     URXVTImageDisplayer, URXVTImageFSDisplayer, ImageDisplayer)
 from ranger.core.metadata import MetadataManager
 from ranger.ext.rifle import Rifle
@@ -227,6 +228,8 @@ class FM(Actions,  # pylint: disable=too-many-instance-attributes
             return W3MImageDisplayer()
         elif self.settings.preview_images_method == "iterm2":
             return ITerm2ImageDisplayer()
+        elif self.settings.preview_images_method == "terminology":
+            return TerminologyImageDisplayer()
         elif self.settings.preview_images_method == "urxvt":
             return URXVTImageDisplayer()
         elif self.settings.preview_images_method == "urxvt-full":
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/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/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/img_display.py b/ranger/ext/img_display.py
index 5bc1fbe5..01c739d3 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:
@@ -311,6 +314,63 @@ class ITerm2ImageDisplayer(ImageDisplayer, FileManagerAware):
         return width, height
 
 
+class TerminologyImageDisplayer(ImageDisplayer, FileManagerAware):
+    """Implementation of ImageDisplayer using terminology image display support
+    (https://github.com/billiob/terminology).
+
+    Ranger must be running in terminology for this to work.
+    Doesn't work with TMUX :/
+    """
+
+    def __init__(self):
+        self.display_protocol = "\033"
+        self.close_protocol = "\000"
+
+    def draw(self, path, start_x, start_y, width, height):
+        # Save cursor
+        curses.putp(curses.tigetstr("sc"))
+
+        y = start_y
+        # Move to drawing zone
+        self._move_to(start_x, y)
+
+        # Write intent
+        sys.stdout.write("%s}ic#%d;%d;%s%s" % (
+            self.display_protocol,
+            width, height,
+            path,
+            self.close_protocol))
+
+        # Write Replacement commands ('#')
+        for _ in range(0, height):
+            sys.stdout.write("%s}ib%s%s%s}ie%s" % (
+                self.display_protocol,
+                self.close_protocol,
+                "#" * width,
+                self.display_protocol,
+                self.close_protocol))
+            y = y + 1
+            self._move_to(start_x, y)
+
+        # Restore cursor
+        curses.putp(curses.tigetstr("rc"))
+
+        sys.stdout.flush()
+
+    @staticmethod
+    def _move_to(x, y):
+        # curses.move(y, x)
+        tparm = curses.tparm(curses.tigetstr("cup"), y, x)
+        if sys.version_info[0] < 3:
+            sys.stdout.write(tparm)
+        else:
+            sys.stdout.buffer.write(tparm)  # pylint: disable=no-member
+
+    def clear(self, start_x, start_y, width, height):
+        self.fm.ui.win.redrawwin()
+        self.fm.ui.win.refresh()
+
+
 class URXVTImageDisplayer(ImageDisplayer, FileManagerAware):
     """Implementation of ImageDisplayer working by setting the urxvt
     background image "under" the preview pane.
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/ui.py b/ranger/gui/ui.py
index 5877e484..990db0ad 100644
--- a/ranger/gui/ui.py
+++ b/ranger/gui/ui.py
@@ -509,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/console.py b/ranger/gui/widgets/console.py
index 6bcf20e9..13201e34 100644
--- a/ranger/gui/widgets/console.py
+++ b/ranger/gui/widgets/console.py
@@ -87,6 +87,15 @@ 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:
@@ -97,11 +106,9 @@ class Console(Widget):  # pylint: disable=too-many-instance-attributes,too-many-
 
         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
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')