about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--Makefile4
-rw-r--r--doc/howto-publish-a-release.md2
-rw-r--r--doc/ranger.112
-rw-r--r--doc/ranger.pod8
-rw-r--r--doc/rifle.15
-rw-r--r--doc/rifle.pod3
-rwxr-xr-xranger/config/commands.py10
-rw-r--r--ranger/config/rc.conf4
-rw-r--r--ranger/config/rifle.conf14
-rw-r--r--ranger/core/actions.py26
-rw-r--r--ranger/core/filter_stack.py16
-rw-r--r--ranger/core/main.py13
-rw-r--r--ranger/core/tab.py8
-rw-r--r--ranger/ext/img_display.py18
-rw-r--r--ranger/gui/ui.py95
-rwxr-xr-xsetup.py16
16 files changed, 145 insertions, 109 deletions
diff --git a/Makefile b/Makefile
index d70728f6..82a6153a 100644
--- a/Makefile
+++ b/Makefile
@@ -8,9 +8,9 @@ VERSION_RIFLE = $(VERSION)
 SNAPSHOT_NAME ?= $(NAME)-$(VERSION)-$(shell git rev-parse HEAD | cut -b 1-8).tar.gz
 # Find suitable python version (need python >= 2.6 or 3.1):
 PYTHON ?= $(shell \
-	     (python -c 'import sys; sys.exit(sys.version < "2.6")' && \
+	     (which python3) \
+	     || (python -c 'import sys; sys.exit(sys.version < "2.6")' && \
 	      which python) \
-	     || (which python3) \
 	     || (python2 -c 'import sys; sys.exit(sys.version < "2.6")' && \
 	         which python2) \
 	   )
diff --git a/doc/howto-publish-a-release.md b/doc/howto-publish-a-release.md
index 6bd70047..c62a1908 100644
--- a/doc/howto-publish-a-release.md
+++ b/doc/howto-publish-a-release.md
@@ -62,7 +62,7 @@ Update the website
 Make a PyPI release
 -------------------
 * [ ] `git clean --force -d -x`
-* [ ] `SETUPTOOLS_USE=1 python setup.py sdist`
+* [ ] `python setup.py sdist`
 * [ ] `gpg --local-user 0x00000000 --detach-sign --armor dist/*`
 * [ ] `twine upload dist/*`
 
diff --git a/doc/ranger.1 b/doc/ranger.1
index 57646fc7..50d6bb0f 100644
--- a/doc/ranger.1
+++ b/doc/ranger.1
@@ -133,7 +133,7 @@
 .\" ========================================================================
 .\"
 .IX Title "RANGER 1"
-.TH RANGER 1 "ranger-1.9.3" "2019-12-31" "ranger manual"
+.TH RANGER 1 "ranger-1.9.3" "2020-02-22" "ranger manual"
 .\" For nroff, turn off justification.  Always turn off hyphenation; it makes
 .\" way too many mistakes in technical documents.
 .if n .ad l
@@ -1731,9 +1731,9 @@ Creates an empty file with the name \fIfilename\fR, unless it already exists.
 .IX Item "trash"
 Move all files in the selection to the trash using rifle. Rifle tries to use a
 trash manager like \fItrash-cli\fR if available but will fall back to moving files
-to either \fI\f(CI$XDG_DATA_HOME\fI/ranger\-trash\fR or \fI~/.ranger/ranger\-trash\fR. This is
-a less permanent version of \fIdelete\fR, relying on the user to clear out the
-trash whenever it's convenient. While having the possibility of restoring
+to either \fI\f(CI$XDG_DATA_HOME\fI/ranger/trash\fR or \fI~/.local/share/ranger/trash\fR.
+This is a less permanent version of \fIdelete\fR, relying on the user to clear out
+the trash whenever it's convenient. While having the possibility of restoring
 trashed files until this happens. ranger will ask for a confirmation if you
 attempt to trash multiple (marked) files or non-empty directories. This can be
 changed by modifying the setting \*(L"confirm_on_delete\*(R".
@@ -1869,8 +1869,8 @@ the \*(L"S\*(R" key.  Defaults to \*(L"/bin/sh\*(R".
 .IX Item "TERMCMD"
 Defines the terminal emulator command that ranger is going to use with the
 :terminal command and the \*(L"t\*(R" run flag.  Defaults to \*(L"xterm\*(R".
-.IP "\s-1BAT_STYLE\s0" 8
-.IX Item "BAT_STYLE"
+.IP "\s-1BAT_THEME\s0" 8
+.IX Item "BAT_THEME"
 Specifies the theme to be used for syntax highlighting when \fIbat\fR is
 installed, unless \fIhighlight\fR is also installed. Find out possible values by
 running \f(CW\*(C`bat \-\-list\-themes\*(C'\fR.
diff --git a/doc/ranger.pod b/doc/ranger.pod
index ed347665..3f41467d 100644
--- a/doc/ranger.pod
+++ b/doc/ranger.pod
@@ -1879,9 +1879,9 @@ Creates an empty file with the name I<filename>, unless it already exists.
 
 Move all files in the selection to the trash using rifle. Rifle tries to use a
 trash manager like I<trash-cli> if available but will fall back to moving files
-to either F<$XDG_DATA_HOME/ranger-trash> or F<~/.ranger/ranger-trash>. This is
-a less permanent version of I<delete>, relying on the user to clear out the
-trash whenever it's convenient. While having the possibility of restoring
+to either F<$XDG_DATA_HOME/ranger/trash> or F<~/.local/share/ranger/trash>.
+This is a less permanent version of I<delete>, relying on the user to clear out
+the trash whenever it's convenient. While having the possibility of restoring
 trashed files until this happens. ranger will ask for a confirmation if you
 attempt to trash multiple (marked) files or non-empty directories. This can be
 changed by modifying the setting "confirm_on_delete".
@@ -2057,7 +2057,7 @@ the "S" key.  Defaults to "/bin/sh".
 Defines the terminal emulator command that ranger is going to use with the
 :terminal command and the "t" run flag.  Defaults to "xterm".
 
-=item BAT_STYLE
+=item BAT_THEME
 
 Specifies the theme to be used for syntax highlighting when I<bat> is
 installed, unless I<highlight> is also installed. Find out possible values by
diff --git a/doc/rifle.1 b/doc/rifle.1
index 1d3553f4..b3dd6373 100644
--- a/doc/rifle.1
+++ b/doc/rifle.1
@@ -133,7 +133,7 @@
 .\" ========================================================================
 .\"
 .IX Title "RIFLE 1"
-.TH RIFLE 1 "rifle-1.9.3" "2019-12-31" "rifle manual"
+.TH RIFLE 1 "rifle-1.9.3" "2020-02-08" "rifle manual"
 .\" For nroff, turn off justification.  Always turn off hyphenation; it makes
 .\" way too many mistakes in technical documents.
 .if n .ad l
@@ -185,7 +185,8 @@ Print a list of options and exit.
 rifle shares configuration files with ranger, though ranger is not required in
 order to use rifle. The default configuration file \fIrifle.conf\fR is expected
 to be at \fI~/.config/ranger/rifle.conf\fR. However, this can be overridden with
-the \fB\-c\fR option.
+the \fB\-c\fR option. Note that due to the nature of the configuration, rifle will
+only read one file, it will not read the defaults in addition.
 .PP
 This file specifies patterns for determining the commands to open files with.
 The syntax is described in the comments of the default \fIrifle.conf\fR that ships
diff --git a/doc/rifle.pod b/doc/rifle.pod
index b4d76287..e0abaa3b 100644
--- a/doc/rifle.pod
+++ b/doc/rifle.pod
@@ -71,7 +71,8 @@ Print a list of options and exit.
 rifle shares configuration files with ranger, though ranger is not required in
 order to use rifle. The default configuration file F<rifle.conf> is expected
 to be at F<~/.config/ranger/rifle.conf>. However, this can be overridden with
-the B<-c> option.
+the B<-c> option. Note that due to the nature of the configuration, rifle will
+only read one file, it will not read the defaults in addition. 
 
 This file specifies patterns for determining the commands to open files with.
 The syntax is described in the comments of the default F<rifle.conf> that ships
diff --git a/ranger/config/commands.py b/ranger/config/commands.py
index 5defa677..7e244e6f 100755
--- a/ranger/config/commands.py
+++ b/ranger/config/commands.py
@@ -1124,6 +1124,12 @@ class bulkrename(Command):
     After you close it, it will be executed.
     """
 
+    def __init__(self, *args, **kwargs):
+        super(bulkrename, self).__init__(*args, **kwargs)
+        self.flags, _ = self.parse_flags()
+        if not self.flags:
+            self.flags = "w"
+
     def execute(self):
         # pylint: disable=too-many-locals,too-many-statements,too-many-branches
         import sys
@@ -1184,7 +1190,7 @@ class bulkrename(Command):
             script_was_edited = (script_content != cmdfile.read())
 
             # Do the renaming
-            self.fm.run(['/bin/sh', cmdfile.name], flags='w')
+            self.fm.run(['/bin/sh', cmdfile.name], flags=self.flags)
 
         # Retag the files, but only if the script wasn't changed during review,
         # because only then we know which are the source and destination files.
@@ -1704,7 +1710,7 @@ class filter_stack(Command):
             return
         else:
             self.fm.notify(
-                "Unknown subcommand: {}".format(subcommand),
+                "Unknown subcommand: {sub}".format(sub=subcommand),
                 bad=True
             )
             return
diff --git a/ranger/config/rc.conf b/ranger/config/rc.conf
index 9d08a6a7..e1ed1b73 100644
--- a/ranger/config/rc.conf
+++ b/ranger/config/rc.conf
@@ -25,7 +25,6 @@
 #     multipane: Midnight-commander like multipane view showing all tabs next
 #                to each other
 set viewmode miller
-#set viewmode multipane
 
 # How many columns are there, and what are their relative widths?
 set column_ratios 1,3,4
@@ -334,6 +333,7 @@ alias qall! quitall!
 alias setl  setlocal
 
 alias filter     scout -prts
+alias hide       scout -prtsv
 alias find       scout -aets
 alias mark       scout -mr
 alias unmark     scout -Mr
@@ -620,7 +620,7 @@ map m<any>  set_bookmark %any
 map um<any> unset_bookmark %any
 
 map m<bg>   draw_bookmarks
-copymap m<bg>  um<bg> `<bg> '<bg>
+copymap m<bg>  um<bg> `<bg> '<bg> p`<bg> p'<bg>
 
 # Generate all the chmod bindings with some python help:
 eval for arg in "rwxXst": cmd("map +u{0} shell -f chmod u+{0} %s".format(arg))
diff --git a/ranger/config/rifle.conf b/ranger/config/rifle.conf
index 0c821a37..8e2a7a40 100644
--- a/ranger/config/rifle.conf
+++ b/ranger/config/rifle.conf
@@ -87,8 +87,8 @@ ext x?html?, has w3m,               terminal = w3m "$@"
 # Define the "editor" for text files as first action
 mime ^text,  label editor = ${VISUAL:-$EDITOR} -- "$@"
 mime ^text,  label pager  = "$PAGER" -- "$@"
-!mime ^text, label editor, ext xml|json|csv|tex|py|pl|rb|js|sh|php = ${VISUAL:-$EDITOR} -- "$@"
-!mime ^text, label pager,  ext xml|json|csv|tex|py|pl|rb|js|sh|php = "$PAGER" -- "$@"
+!mime ^text, label editor, ext xml|json|csv|tex|py|pl|rb|rs|js|sh|php = ${VISUAL:-$EDITOR} -- "$@"
+!mime ^text, label pager,  ext xml|json|csv|tex|py|pl|rb|rs|js|sh|php = "$PAGER" -- "$@"
 
 ext 1                         = man "$1"
 ext s[wmf]c, has zsnes, X     = zsnes "$1"
@@ -262,13 +262,13 @@ label wallpaper, number 14, mime ^image, has feh, X = feh --bg-fill "$1"
 #-------------------------------------------
 # Generic file openers
 #-------------------------------------------
-label open, has xdg-open = xdg-open -- "$@"
+label open, has xdg-open = xdg-open "$@"
 label open, has open     = open -- "$@"
 
 # Define the editor for non-text files + pager as last action
-              !mime ^text, !ext xml|json|csv|tex|py|pl|rb|js|sh|php  = ask
-label editor, !mime ^text, !ext xml|json|csv|tex|py|pl|rb|js|sh|php  = ${VISUAL:-$EDITOR} -- "$@"
-label pager,  !mime ^text, !ext xml|json|csv|tex|py|pl|rb|js|sh|php  = "$PAGER" -- "$@"
+              !mime ^text, !ext xml|json|csv|tex|py|pl|rb|rs|js|sh|php  = ask
+label editor, !mime ^text, !ext xml|json|csv|tex|py|pl|rb|rs|js|sh|php  = ${VISUAL:-$EDITOR} -- "$@"
+label pager,  !mime ^text, !ext xml|json|csv|tex|py|pl|rb|rs|js|sh|php  = "$PAGER" -- "$@"
 
 
 ######################################################################
@@ -281,4 +281,4 @@ mime application/x-executable = "$1"
 
 # Move the file to trash using trash-cli.
 label trash, has trash-put = trash-put -- "$@"
-label trash = mkdir -p -- ${XDG_DATA_DIR:-$HOME/.ranger}/ranger-trash; mv -- "$@" ${XDG_DATA_DIR:-$HOME/.ranger}/ranger-trash
+label trash = mkdir -p -- "${XDG_DATA_HOME:-$HOME/.local/share}/ranger/trash"; mv -- "$@" "${XDG_DATA_HOME:-$HOME/.local/share}/ranger/trash"
diff --git a/ranger/core/actions.py b/ranger/core/actions.py
index c3d7de86..fe7d7e5e 100644
--- a/ranger/core/actions.py
+++ b/ranger/core/actions.py
@@ -16,8 +16,7 @@ import string
 import tempfile
 from inspect import cleandoc
 from stat import S_IEXEC
-from hashlib import sha1
-from sys import version_info
+from hashlib import sha512
 from logging import getLogger
 
 import ranger
@@ -35,7 +34,6 @@ from ranger.container.file import File
 from ranger.core.loader import CommandLoader, CopyLoader
 from ranger.container.settings import ALLOWED_SETTINGS, ALLOWED_VALUES
 
-
 MACRO_FAIL = "<\x01\x01MACRO_HAS_NO_VALUE\x01\01>"
 
 LOG = getLogger(__name__)
@@ -242,14 +240,14 @@ class Actions(  # pylint: disable=too-many-instance-attributes,too-many-public-m
 
         if cmd.resolve_macros and _MacroTemplate.delimiter in cmd.line:
             def any_macro(i, char):
-                return ('any{:d}'.format(i), key_to_string(char))
+                return ('any{0:d}'.format(i), key_to_string(char))
 
             def anypath_macro(i, char):
                 try:
                     val = self.fm.bookmarks[key_to_string(char)]
                 except KeyError:
                     val = MACRO_FAIL
-                return ('any_path{:d}'.format(i), val)
+                return ('any_path{0:d}'.format(i), val)
 
             macros = dict(f(i, char) for f in (any_macro, anypath_macro)
                           for i, char in enumerate(wildcards if wildcards
@@ -1049,11 +1047,12 @@ class Actions(  # pylint: disable=too-many-instance-attributes,too-many-public-m
         return True
 
     @staticmethod
-    def sha1_encode(path):
-        if version_info[0] < 3:
-            return os.path.join(ranger.args.cachedir, sha1(path).hexdigest()) + '.jpg'
-        return os.path.join(ranger.args.cachedir,
-                            sha1(path.encode('utf-8', 'backslashreplace')).hexdigest()) + '.jpg'
+    def sha512_encode(path):
+        stat_ = stat(path)
+        sha = sha512(stat_.st_dev)
+        sha.update(stat_.st_ino)
+        sha.update(stat_.st_mtime)
+        return '{0}.jpg'.format(sha.hexdigest())
 
     def get_preview(self, fobj, width, height):  # pylint: disable=too-many-return-statements
         pager = self.ui.get_pager()
@@ -1121,10 +1120,9 @@ class Actions(  # pylint: disable=too-many-instance-attributes,too-many-public-m
 
         if not os.path.exists(ranger.args.cachedir):
             os.makedirs(ranger.args.cachedir)
-        cacheimg = os.path.join(ranger.args.cachedir, self.sha1_encode(path))
+        cacheimg = os.path.join(ranger.args.cachedir, self.sha512_encode(path))
         if self.settings.preview_images and \
-                os.path.isfile(cacheimg) and \
-                os.path.getmtime(cacheimg) > os.path.getmtime(path):
+                os.path.isfile(cacheimg):
             data['foundpreview'] = True
             data['imagepreview'] = True
             pager.set_image(cacheimg)
@@ -1609,7 +1607,7 @@ class Actions(  # pylint: disable=too-many-instance-attributes,too-many-public-m
         # COMPAT: old command.py use fm.delete() without arguments
         if files is None:
             files = (fobj.path for fobj in self.thistab.get_selection())
-        self.notify("Deleting {}!".format(", ".join(files)))
+        self.notify("Deleting {fls}!".format(fls=", ".join(files)))
         files = [os.path.abspath(path) for path in files]
         for path in files:
             # Untag the deleted files.
diff --git a/ranger/core/filter_stack.py b/ranger/core/filter_stack.py
index bd63f2fe..58ce1a1c 100644
--- a/ranger/core/filter_stack.py
+++ b/ranger/core/filter_stack.py
@@ -55,7 +55,7 @@ class NameFilter(BaseFilter):
         return self.regex.search(fobj.relative_path)
 
     def __str__(self):
-        return "<Filter: name =~ /{}/>".format(self.pattern)
+        return "<Filter: name =~ /{pat}/>".format(pat=self.pattern)
 
 
 @stack_filter("mime")
@@ -71,7 +71,7 @@ class MimeFilter(BaseFilter):
         return self.regex.search(mimetype)
 
     def __str__(self):
-        return "<Filter: mimetype =~ /{}/>".format(self.pattern)
+        return "<Filter: mimetype =~ /{pat}/>".format(pat=self.pattern)
 
 
 @stack_filter("hash")
@@ -97,7 +97,7 @@ class HashFilter(BaseFilter, FileManagerAware):
         return True
 
     def __str__(self):
-        return "<Filter: hash {}>".format(self.filepath)
+        return "<Filter: hash {fp}>".format(fp=self.filepath)
 
 
 def group_by_hash(fsobjects):
@@ -192,7 +192,7 @@ class TypeFilter(BaseFilter):
         return self.type_to_function[self.filetype](fobj)
 
     def __str__(self):
-        return "<Filter: type == '{}'>".format(self.filetype)
+        return "<Filter: type == '{ft}'>".format(ft=self.filetype)
 
 
 @filter_combinator("or")
@@ -216,7 +216,8 @@ class OrFilter(BaseFilter):
         )
 
     def __str__(self):
-        return "<Filter: {}>".format(" or ".join(map(str, self.subfilters)))
+        return "<Filter: {comp}>".format(
+            comp=" or ".join(map(str, self.subfilters)))
 
     def decompose(self):
         return self.subfilters
@@ -236,7 +237,8 @@ class AndFilter(BaseFilter):
         return accept_file(fobj, self.subfilters)
 
     def __str__(self):
-        return "<Filter: {}>".format(" and ".join(map(str, self.subfilters)))
+        return "<Filter: {comp}>".format(
+            comp=" and ".join(map(str, self.subfilters)))
 
     def decompose(self):
         return self.subfilters
@@ -252,7 +254,7 @@ class NotFilter(BaseFilter):
         return not self.subfilter(fobj)
 
     def __str__(self):
-        return "<Filter: not {}>".format(str(self.subfilter))
+        return "<Filter: not {exp}>".format(exp=str(self.subfilter))
 
     def decompose(self):
         return [self.subfilter]
diff --git a/ranger/core/main.py b/ranger/core/main.py
index 7322a501..b16b6318 100644
--- a/ranger/core/main.py
+++ b/ranger/core/main.py
@@ -6,8 +6,10 @@
 from __future__ import (absolute_import, division, print_function)
 
 from logging import getLogger
+import atexit
 import locale
 import os.path
+import shutil
 import sys
 import tempfile
 
@@ -337,6 +339,17 @@ def parse_arguments():
         args.cachedir = mkdtemp(suffix='.ranger-cache')
         args.confdir = None
         args.datadir = None
+
+        @atexit.register
+        def cleanup_cachedir():  # pylint: disable=unused-variable
+            try:
+                shutil.rmtree(args.cachedir)
+            except Exception as ex:  # pylint: disable=broad-except
+                sys.stderr.write(
+                    "Error during the temporary cache directory cleanup:\n"
+                    "{ex}\n".format(ex=ex)
+                )
+
     else:
         args.cachedir = path_init('cachedir')
         args.confdir = path_init('confdir')
diff --git a/ranger/core/tab.py b/ranger/core/tab.py
index 1d5e69d4..7bb45d75 100644
--- a/ranger/core/tab.py
+++ b/ranger/core/tab.py
@@ -4,7 +4,7 @@
 from __future__ import (absolute_import, division, print_function)
 
 import os
-from os.path import abspath, normpath, join, expanduser, isdir
+from os.path import abspath, normpath, join, expanduser, isdir, dirname
 import sys
 
 from ranger.container import settings
@@ -123,9 +123,11 @@ class Tab(FileManagerAware, SettingsAware):  # pylint: disable=too-many-instance
 
         # get the absolute path
         path = normpath(join(self.path, expanduser(path)))
+        selectfile = None
 
         if not isdir(path):
-            return False
+            selectfile = path
+            path = dirname(path)
         new_thisdir = self.fm.get_directory(path)
 
         try:
@@ -155,6 +157,8 @@ class Tab(FileManagerAware, SettingsAware):  # pylint: disable=too-many-instance
         self.thisdir.sort_directories_first = self.fm.settings.sort_directories_first
         self.thisdir.sort_reverse = self.fm.settings.sort_reverse
         self.thisdir.sort_if_outdated()
+        if selectfile:
+            self.thisdir.move_to_obj(selectfile)
         if previous and previous.path != path:
             self.thisfile = self.thisdir.pointed_obj
         else:
diff --git a/ranger/ext/img_display.py b/ranger/ext/img_display.py
index ffaa4c07..70983bc7 100644
--- a/ranger/ext/img_display.py
+++ b/ranger/ext/img_display.py
@@ -233,7 +233,7 @@ class W3MImageDisplayer(ImageDisplayer, FileManagerAware):
         # max_height_pixels = (max_height - 1) * fonth - 2
 
         # get image size
-        cmd = "5;{}\n".format(path)
+        cmd = "5;{path}\n".format(path=path)
 
         self.process.stdin.write(cmd)
         self.process.stdin.flush()
@@ -590,7 +590,7 @@ class KittyImageDisplayer(ImageDisplayer, FileManagerAware):
             self.stream = True
         else:
             raise ImgDisplayUnsupportedException(
-                'kitty replied an unexpected response: {}'.format(resp))
+                'kitty replied an unexpected response: {r}'.format(r=resp))
 
         # get the image manipulation backend
         try:
@@ -616,7 +616,8 @@ class KittyImageDisplayer(ImageDisplayer, FileManagerAware):
         # a is the display command, with T going for immediate output
         # i is the id entifier for the image
         cmds = {'a': 'T', 'i': self.image_id}
-        # sys.stderr.write('{}-{}@{}x{}\t'.format(start_x, start_y, width, height))
+        # sys.stderr.write('{0}-{1}@{2}x{3}\t'.format(
+        #     start_x, start_y, width, height))
 
         # finish initialization if it is the first call
         if self.needs_late_init:
@@ -673,12 +674,13 @@ class KittyImageDisplayer(ImageDisplayer, FileManagerAware):
         if b'OK' in resp:
             return
         else:
-            raise ImageDisplayError('kitty replied "{}"'.format(resp))
+            raise ImageDisplayError('kitty replied "{r}"'.format(r=resp))
 
     def clear(self, start_x, start_y, width, height):
         # let's assume that every time ranger call this
         # it actually wants just to remove the previous image
-        # TODO: implement this using the actual x, y, since the protocol supports it
+        # TODO: implement this using the actual x, y, since the protocol
+        #       supports it
         cmds = {'a': 'd', 'i': self.image_id}
         for cmd_str in self._format_cmd_str(cmds):
             self.stdbout.write(cmd_str)
@@ -690,7 +692,8 @@ class KittyImageDisplayer(ImageDisplayer, FileManagerAware):
         self.fm.ui.win.refresh()
 
     def _format_cmd_str(self, cmd, payload=None, max_slice_len=2048):
-        central_blk = ','.join(["{}={}".format(k, v) for k, v in cmd.items()]).encode('ascii')
+        central_blk = ','.join(["{k}={v}".format(k=k, v=v)
+                                for k, v in cmd.items()]).encode('ascii')
         if payload is not None:
             # we add the m key to signal a multiframe communication
             # appending the end (m=0) key to a single message has no effect
@@ -706,7 +709,8 @@ class KittyImageDisplayer(ImageDisplayer, FileManagerAware):
             yield self.protocol_start + central_blk + b';' + self.protocol_end
 
     def quit(self):
-        # clear all remaining images, then check if all files went through or are orphaned
+        # clear all remaining images, then check if all files went through or
+        # are orphaned
         while self.image_id >= 1:
             self.clear(0, 0, 0, 0)
         # for k in self.temp_paths:
diff --git a/ranger/gui/ui.py b/ranger/gui/ui.py
index d2dbb759..a2ea7778 100644
--- a/ranger/gui/ui.py
+++ b/ranger/gui/ui.py
@@ -9,6 +9,7 @@ import threading
 import curses
 from subprocess import CalledProcessError
 
+from ranger.ext.get_executables import get_executables
 from ranger.ext.keybinding_parser import KeyBuffer, KeyMaps, ALT_KEY
 from ranger.ext.lazy_property import lazy_property
 from ranger.ext.signals import Signal
@@ -49,6 +50,16 @@ def _setup_mouse(signal):
         curses.mousemask(0)
 
 
+def _in_tmux():
+    return ('TMUX' in os.environ
+            and 'tmux' in get_executables())
+
+
+def _in_screen():
+    return ('screen' in os.environ['TERM']
+            and 'screen' in get_executables())
+
+
 class UI(  # pylint: disable=too-many-instance-attributes,too-many-public-methods
         DisplayableContainer):
     ALLOWED_VIEWMODES = 'miller', 'multipane'
@@ -73,8 +84,7 @@ class UI(  # pylint: disable=too-many-instance-attributes,too-many-public-method
         self.multiplexer = None
         self._draw_title = None
         self._tmux_automatic_rename = None
-        self._tmux_title = None
-        self._screen_title = None
+        self._multiplexer_title = None
         self.browser = None
 
         if fm is not None:
@@ -469,58 +479,63 @@ class UI(  # pylint: disable=too-many-instance-attributes,too-many-public-method
     # Handles window renaming behaviour of the terminal multiplexers
     # GNU Screen and Tmux
     def handle_multiplexer(self):
-        if self.settings.update_tmux_title:
-            if 'TMUX' in os.environ:
-                # Stores the automatic-rename setting
-                # prints out a warning if the allow-rename in tmux is not set
-                tmux_allow_rename = check_output(
-                    ['tmux', 'show-window-options', '-v',
-                     'allow-rename']).strip()
-                if tmux_allow_rename == 'off':
-                    self.fm.notify('Warning: allow-rename not set in Tmux!',
-                                   bad=True)
-                elif self._tmux_title is None:
-                    self._tmux_title = check_output(
-                        ['tmux', 'display-message', '-p', '#W']).strip()
-                else:
+        if (self.settings.update_tmux_title and not self._multiplexer_title):
+            try:
+                if _in_tmux():
+                    # Stores the automatic-rename setting
+                    # prints out a warning if allow-rename isn't set in tmux
                     try:
+                        tmux_allow_rename = check_output(
+                            ['tmux', 'show-window-options', '-v',
+                             'allow-rename']).strip()
+                    except CalledProcessError:
+                        tmux_allow_rename = 'off'
+                    if tmux_allow_rename == 'off':
+                        self.fm.notify('Warning: allow-rename not set in Tmux!',
+                                       bad=True)
+                    else:
+                        self._multiplexer_title = check_output(
+                            ['tmux', 'display-message', '-p', '#W']).strip()
                         self._tmux_automatic_rename = check_output(
                             ['tmux', 'show-window-options', '-v',
                              'automatic-rename']).strip()
                         if self._tmux_automatic_rename == 'on':
                             check_output(['tmux', 'set-window-option',
                                           'automatic-rename', 'off'])
-                    except CalledProcessError:
-                        pass
-            elif 'screen' in os.environ['TERM'] and self._screen_title is None:
-                # Stores the screen window name before renaming it
-                # gives out a warning if $TERM is not "screen"
-                try:
-                    self._screen_title = check_output(
+                elif _in_screen():
+                    # Stores the screen window name before renaming it
+                    # gives out a warning if $TERM is not "screen"
+                    self._multiplexer_title = check_output(
                         ['screen', '-Q', 'title']).strip()
-                except CalledProcessError:
-                    self._screen_title = None
+            except CalledProcessError:
+                self.fm.notify("Couldn't access previous multiplexer window"
+                               " name, won't be able to restore.",
+                               bad=False)
+            if not self._multiplexer_title:
+                self._multiplexer_title = os.path.basename(
+                    os.environ.get("SHELL", "shell"))
 
             sys.stdout.write("\033kranger\033\\")
             sys.stdout.flush()
 
     # Restore window name
     def restore_multiplexer_name(self):
-        try:
-            if 'TMUX' in os.environ:
-                if self._tmux_automatic_rename:
-                    check_output(['tmux', 'set-window-option',
-                                  'automatic-rename',
-                                  self._tmux_automatic_rename])
-                else:
-                    check_output(['tmux', 'set-window-option', '-u',
-                                  'automatic-rename'])
-                if self._tmux_title:
-                    check_output(['tmux', 'rename-window', self._tmux_title])
-            elif 'screen' in os.environ['TERM'] and self._screen_title:
-                check_output(['screen', '-X', 'title', self._screen_title])
-        except CalledProcessError:
-            self.fm.notify("Could not restore window-name!", bad=True)
+        if self._multiplexer_title:
+            try:
+                if _in_tmux():
+                    if self._tmux_automatic_rename:
+                        check_output(['tmux', 'set-window-option',
+                                      'automatic-rename',
+                                      self._tmux_automatic_rename])
+                    else:
+                        check_output(['tmux', 'set-window-option', '-u',
+                                      'automatic-rename'])
+            except CalledProcessError:
+                self.fm.notify("Could not restore multiplexer window name!",
+                               bad=True)
+
+            sys.stdout.write("\033k{}\033\\".format(self._multiplexer_title))
+            sys.stdout.flush()
 
     def hint(self, text=None):
         self.status.hint = text
diff --git a/setup.py b/setup.py
index edf48c4a..493deadd 100755
--- a/setup.py
+++ b/setup.py
@@ -4,11 +4,13 @@
 
 from __future__ import (absolute_import, division, print_function)
 
-from distutils import log  # pylint: disable=import-error,no-name-in-module
 from hashlib import sha512
 import os
 import shutil
 
+from setuptools import setup
+from setuptools.command.install_lib import install_lib
+
 import ranger
 
 
@@ -16,16 +18,6 @@ SCRIPTS_PATH = 'build_scripts'
 EXECUTABLES_PATHS = ['/ranger/data/scope.sh']
 
 
-# pylint: disable=import-error,no-name-in-module,ungrouped-imports
-if os.environ.get('SETUPTOOLS_USE'):
-    from setuptools import setup
-    from setuptools.command.install_lib import install_lib
-else:
-    from distutils.core import setup
-    from distutils.command.install_lib import install_lib
-# pylint: enable=import-error,no-name-in-module,ungrouped-imports
-
-
 def findall(directory):
     return [os.path.join(directory, f) for f in os.listdir(directory)
             if os.path.isfile(os.path.join(directory, f))]
@@ -59,7 +51,7 @@ class InstallLib(install_lib):
             for exe_path in EXECUTABLES_PATHS:
                 if path.endswith(exe_path):
                     mode = ((os.stat(path).st_mode) | 0o555) & 0o7777
-                    log.info('changing mode of %s to %o', path, mode)
+                    print('changing mode of %s to %o' % (path, mode))
                     os.chmod(path, mode)