about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/doctest.yml30
-rw-r--r--.github/workflows/py37.yml30
-rw-r--r--.github/workflows/python.yml30
-rw-r--r--.github/workflows/shellcheck.yml22
-rw-r--r--Makefile18
-rw-r--r--README.md48
-rw-r--r--doc/ranger.1142
-rw-r--r--doc/ranger.desktop1
-rw-r--r--doc/ranger.pod136
-rw-r--r--doc/rifle.122
-rw-r--r--examples/rc_emacs.conf8
-rwxr-xr-xranger/config/commands.py120
-rw-r--r--ranger/config/rc.conf10
-rw-r--r--ranger/config/rifle.conf26
-rw-r--r--ranger/container/fsobject.py6
-rw-r--r--ranger/container/settings.py5
-rw-r--r--ranger/core/actions.py8
-rw-r--r--ranger/core/fm.py25
-rw-r--r--ranger/core/main.py10
-rw-r--r--ranger/core/runner.py4
-rw-r--r--ranger/data/mime.types4
-rwxr-xr-xranger/data/scope.sh1
-rw-r--r--ranger/ext/img_display.py35
-rwxr-xr-xranger/ext/rifle.py7
-rw-r--r--ranger/gui/widgets/statusbar.py6
25 files changed, 571 insertions, 183 deletions
diff --git a/.github/workflows/doctest.yml b/.github/workflows/doctest.yml
new file mode 100644
index 00000000..f12cb926
--- /dev/null
+++ b/.github/workflows/doctest.yml
@@ -0,0 +1,30 @@
+name: Python doctest and pytest
+
+on:
+  push:
+    paths:
+      - '.github/workflows/doctest.yml'
+      - '*.py'
+
+jobs:
+  test_py:
+    runs-on: ubuntu-latest
+    strategy:
+      max-parallel: 4
+      matrix:
+        python-version: [2.7, 3.5, 3.6]
+    steps:
+    - uses: actions/checkout@v1
+      with:
+        fetch-depth: 1
+    - name: Set up Python ${{ matrix.python-version }}
+      uses: actions/setup-python@v1
+      with:
+        python-version: ${{ matrix.python-version }}
+    - name: Install dependencies
+      run: |
+        python -m pip install --upgrade pip
+        pip install -r requirements.txt
+    - name: doctest
+      run: |
+        make test_doctest test_other
diff --git a/.github/workflows/py37.yml b/.github/workflows/py37.yml
new file mode 100644
index 00000000..ca8210a2
--- /dev/null
+++ b/.github/workflows/py37.yml
@@ -0,0 +1,30 @@
+name: Python 3.7 lints and tests
+
+on:
+  push:
+    paths:
+      - '.github/workflows/py37.yml'
+      - '*.py'
+
+jobs:
+  test_py:
+    runs-on: ubuntu-latest
+    strategy:
+      max-parallel: 4
+      matrix:
+        python-version: [3.7]
+    steps:
+    - uses: actions/checkout@v1
+      with:
+        fetch-depth: 1
+    - name: Set up Python ${{ matrix.python-version }}
+      uses: actions/setup-python@v1
+      with:
+        python-version: ${{ matrix.python-version }}
+    - name: Install dependencies
+      run: |
+        python -m pip install --upgrade pip
+        pip install -r <(sed 's/<2//' requirements.txt)
+    - name: Lint and test with pylint, flake8, doctest, pytest
+      run: |
+        make test_py
diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml
new file mode 100644
index 00000000..1daba84c
--- /dev/null
+++ b/.github/workflows/python.yml
@@ -0,0 +1,30 @@
+name: Python lints and tests
+
+on:
+  push:
+    paths:
+      - '.github/workflows/python.yml'
+      - '*.py'
+
+jobs:
+  test_py:
+    runs-on: ubuntu-latest
+    strategy:
+      max-parallel: 4
+      matrix:
+        python-version: [2.7, 3.5, 3.6]
+    steps:
+    - uses: actions/checkout@v1
+      with:
+        fetch-depth: 1
+    - name: Set up Python ${{ matrix.python-version }}
+      uses: actions/setup-python@v1
+      with:
+        python-version: ${{ matrix.python-version }}
+    - name: Install dependencies
+      run: |
+        python -m pip install --upgrade pip
+        pip install -r requirements.txt
+    - name: Lint and test with pylint, flake8, -d-o-c-t-e-s-t-, -p-y-t-e-s-t-
+      run: |
+        make test_pylint test_flake8 test_pytest
diff --git a/.github/workflows/shellcheck.yml b/.github/workflows/shellcheck.yml
new file mode 100644
index 00000000..0d10cf61
--- /dev/null
+++ b/.github/workflows/shellcheck.yml
@@ -0,0 +1,22 @@
+name: Shellcheck scope.sh
+
+on: 
+  push:
+    paths:
+      - '.github/workflows/shellcheck.yml'
+      - 'ranger/data/scope.sh'
+
+jobs:
+  test_shellcheck:
+    runs-on: ubuntu-latest
+    steps:
+    - uses: actions/checkout@v1
+      with:
+        fetch-depth: 1
+    - name: Install newer shellcheck (0.7.0 rather than 0.4.6)
+      run: |
+        curl -LO "https://storage.googleapis.com/shellcheck/shellcheck-stable.linux.x86_64.tar.xz"
+        tar xf shellcheck-stable.linux.x86_64.tar.xz
+    - name: Shellcheck scope.sh
+      run: |
+        env PATH=shellcheck-stable:$PATH make test_shellcheck
diff --git a/Makefile b/Makefile
index 87c5ff1b..15dbb9db 100644
--- a/Makefile
+++ b/Makefile
@@ -125,11 +125,19 @@ test_other:
 test: test_py test_shellcheck
 	@echo "Finished testing: All tests passed!"
 
-man:
-	pod2man --stderr --center='ranger manual' --date='$(NAME)-$(VERSION)' \
-		--release=$(shell date +%x) doc/ranger.pod doc/ranger.1
-	pod2man --stderr --center='rifle manual' --date='$(NAME_RIFLE)-$(VERSION_RIFLE)' \
-		--release=$(shell date +%x) doc/rifle.pod doc/rifle.1
+doc/ranger.1: doc/ranger.pod
+	pod2man --stderr --center='ranger manual' \
+		--date='$(NAME)-$(VERSION)' \
+		--release=$(shell date -u '+%Y-%m-%d') \
+		doc/ranger.pod doc/ranger.1
+
+doc/rifle.1: doc/rifle.pod
+	pod2man --stderr --center='rifle manual' \
+		--date='$(NAME_RIFLE)-$(VERSION_RIFLE)' \
+		--release=$(shell date -u '+%Y-%m-%d') \
+		doc/rifle.pod doc/rifle.1
+
+man: doc/ranger.1 doc/rifle.1
 
 manhtml:
 	pod2html doc/ranger.pod --outfile=doc/ranger.1.html
diff --git a/README.md b/README.md
index be17f0f9..85f6137e 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,8 @@
 ranger 1.9.2
 ============
 
+<img src="https://ranger.github.io/ranger_logo.png" width="150">
+
 [![Build Status](https://travis-ci.org/ranger/ranger.svg?branch=master)](https://travis-ci.org/ranger/ranger)
 <a href="https://repology.org/metapackage/ranger/versions">
   <img src="https://repology.org/badge/latest-versions/ranger.svg" alt="latest packaged version(s)">
@@ -73,26 +75,36 @@ Dependencies
   and (optionally) wide-unicode support
 * A pager (`less` by default)
 
-Optional:
+### Optional dependencies
+
+For general usage:
 
-* The `file` program for determining file types
-* The Python module `chardet`, in case of encoding detection problems
+* `file` for determining file types
+* `chardet` (Python package) for improved encoding detection of text files
 * `sudo` to use the "run as root" feature
-* `w3m` for the `w3mimgdisplay` program to preview images
-* `python-bidi` for correct display of RTL file names (Hebrew, Arabic)
+* `python-bidi` to display right-to-left file names correctly (Hebrew, Arabic)
 
-Optional, for enhanced file previews (with `scope.sh`):
+For enhanced file previews (with `scope.sh`):
 
 * `img2txt` (from `caca-utils`) for ASCII-art image previews
+* `w3mimgdisplay`, `ueberzug`, `kitty`, `terminology` or `urxvt` for image
+  previews
+* `convert` (from `imagemagick`) to auto-rotate images and for SVG previews
+* `ffmpegthumbnailer` for video thumbnails
 * `highlight` or `pygmentize` for syntax highlighting of code
-* `atool`, `bsdtar` and/or `unrar` for previews of archives
-* `lynx`, `w3m` or `elinks` for previews of html pages
-* `pdftotext` or `mutool` for `pdf` previews
+* `atool`, `bsdtar`, `unrar` and/or `7z` to preview archives
+* `bsdtar`, `tar`, `unrar` and/or `unzip` to preview archives as their first
+  image
+* `lynx`, `w3m` or `elinks` to preview html pages
+* `pdftotext` or `mutool` for textual `pdf` previews, `pdftoppm` to preview as
+  image
+* `djvutxt` for textual DjVu previews, `ddjvu` to preview as image
+* `calibre` or `epub-thumbnailer` for image previews of ebooks
 * `transmission-show` for viewing BitTorrent information
 * `mediainfo` or `exiftool` for viewing information about media files
 * `odt2txt` for OpenDocument text files (`odt`, `ods`, `odp` and `sxw`)
-* `chardet` (Python package) for improved encoding detection of text files
-
+* `python` or `jq` for JSON files
+* `fontimage` for font previews
 
 Installing
 ----------
@@ -141,3 +153,17 @@ Ranger can automatically copy default configuration files to `~/.config/ranger`
 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.
+
+
+Going Further
+---------------
+* To get the most out of ranger, read the [Official User Guide](https://github.com/ranger/ranger/wiki/Official-user-guide).
+* For frequently asked questions, see the [FAQ](https://github.com/ranger/ranger/wiki/FAQ%3A-Frequently-Asked-Questions).
+* For more information on customization, see the [wiki](https://github.com/ranger/ranger/wiki).
+
+
+Community
+---------------
+For help, support, or if you just want to hang out with us, you can find us here:
+* **IRC**: channel **#ranger** on [freenode](https://freenode.net/kb/answer/chat)
+* **Reddit**: [r/ranger](https://www.reddit.com/r/ranger/)
diff --git a/doc/ranger.1 b/doc/ranger.1
index 2f233c95..a6e20b4c 100644
--- a/doc/ranger.1
+++ b/doc/ranger.1
@@ -133,12 +133,11 @@
 .\" ========================================================================
 .\"
 .IX Title "RANGER 1"
-.TH RANGER 1 "ranger-1.9.2" "2019-06-18" "ranger manual"
+.TH RANGER 1 "ranger-1.9.2" "2019-10-02" "ranger manual"
 .\" For nroff, turn off justification.  Always turn off hyphenation; it makes
 .\" way too many mistakes in technical documents.
 .if n .ad l
 .nh
-.SH "NAME"
 ranger \- visual file manager
 .SH "SYNOPSIS"
 .IX Header "SYNOPSIS"
@@ -290,18 +289,6 @@ Independently of the preview script, there is a feature to preview images
 by drawing them directly into the terminal. To enable this feature, set the
 option \f(CW\*(C`preview_images\*(C'\fR to true and enable one of the image preview modes:
 .PP
-\fIw3m\fR
-.IX Subsection "w3m"
-.PP
-This does not work over ssh, requires certain terminals (tested on \*(L"xterm\*(R" and
-\&\*(L"urxvt\*(R") and is incompatible with tmux, although it works with screen.
-.PP
-To enable this feature, install the program \*(L"w3m\*(R" and set the option
-\&\f(CW\*(C`preview_images_method\*(C'\fR to w3m.
-.PP
-When using a terminal with a nonzero border which is not automatically detected, the w3m preview will be misaligned.
-Use the \f(CW\*(C`w3m_offset\*(C'\fR option to manually adjust the image offset. This should be the same value as the terminal's border value.
-.PP
 \fIiTerm2\fR
 .IX Subsection "iTerm2"
 .PP
@@ -314,6 +301,14 @@ This feature relies on the dimensions of the terminal's font.  By default, a
 width of 8 and height of 11 are used.  To use other values, set the options
 \&\f(CW\*(C`iterm2_font_width\*(C'\fR and \f(CW\*(C`iterm2_font_height\*(C'\fR to the desired values.
 .PP
+\fIkitty\fR
+.IX Subsection "kitty"
+.PP
+This only works in Kitty. It requires \s-1PIL\s0 (or pillow) to work.
+Allows remote image previews, for example in an ssh session.
+.PP
+To enable this feature, set the option \f(CW\*(C`preview_images_method\*(C'\fR to kitty.
+.PP
 \fIterminology\fR
 .IX Subsection "terminology"
 .PP
@@ -321,6 +316,16 @@ This only works in terminology. It can render vector graphics, but works only lo
 .PP
 To enable this feature, set the option \f(CW\*(C`preview_images_method\*(C'\fR to terminology.
 .PP
+\fIueberzug\fR
+.IX Subsection "ueberzug"
+.PP
+U\*:berzug is a command line utility which draws images on terminals using child
+windows. It requires \s-1PIL\s0 (or pillow) and relies on X11. This makes it
+compatible (in a limited way, i.e., tmux splits are not supported) with many
+terminals and tmux but not the Linux console or Wayland.
+.PP
+To enable this feature, set the option \f(CW\*(C`preview_images_method\*(C'\fR to ueberzug.
+.PP
 \fIurxvt\fR
 .IX Subsection "urxvt"
 .PP
@@ -339,13 +344,17 @@ window.
 .PP
 To enable this feature, set the option \f(CW\*(C`preview_images_method\*(C'\fR to urxvt-full.
 .PP
-\fIkitty\fR
-.IX Subsection "kitty"
+\fIw3m\fR
+.IX Subsection "w3m"
 .PP
-This only works on Kitty. It requires \s-1PIL\s0 (or pillow) to work.
-Allows remote image previews, for example in an ssh session.
+This does not work over ssh, requires certain terminals (tested on \*(L"xterm\*(R" and
+\&\*(L"urxvt\*(R") and is incompatible with tmux, although it works with screen.
 .PP
-To enable this feature, set the option \f(CW\*(C`preview_images_method\*(C'\fR to kitty.
+To enable this feature, install the program \*(L"w3m\*(R" and set the option
+\&\f(CW\*(C`preview_images_method\*(C'\fR to w3m.
+.PP
+When using a terminal with a nonzero border which is not automatically detected, the w3m preview will be misaligned.
+Use the \f(CW\*(C`w3m_offset\*(C'\fR option to manually adjust the image offset. This should be the same value as the terminal's border value.
 .SS "\s-1SELECTION\s0"
 .IX Subsection "SELECTION"
 The \fIselection\fR is defined as \*(L"All marked files \s-1IF THERE ARE ANY,\s0 otherwise
@@ -432,6 +441,10 @@ the end of a command when needed, while preventing editors to strip spaces off
 the end of the line automatically.
 .PP
 To write a literal %, you need to escape it by writing %%.
+.PP
+Note that macros are expanded twice when using chain. For example, to insert
+a space character in a chained command, you would write %%space:
+ chain command1; command2%%space
 .SS "\s-1BOOKMARKS\s0"
 .IX Subsection "BOOKMARKS"
 Type \fBm<key>\fR to bookmark the current directory. You can re-enter this
@@ -687,6 +700,9 @@ Open the console with the most recent command.
 .IX Item "Alt-N"
 Open a tab. N has to be a number from 0 to 9. If the tab doesn't exist yet, it
 will be created.
+.IP "Alt-l, Alt-r" 14
+.IX Item "Alt-l, Alt-r"
+Shift a tab left, respectively right.
 .IP "gn, ^N" 14
 .IX Item "gn, ^N"
 Create a new tab.
@@ -967,6 +983,13 @@ all directories above the current one as well?
 .IP "mouse_enabled [bool] <zm>" 4
 .IX Item "mouse_enabled [bool] <zm>"
 Enable mouse input?
+.IP "nested_ranger_warning [string]" 4
+.IX Item "nested_ranger_warning [string]"
+Warn at startup if \f(CW\*(C`RANGER_LEVEL\*(C'\fR is greater than 0, in other words give a
+warning when you nest ranger in a subshell started by ranger. Allowed values
+are \f(CW\*(C`true\*(C'\fR, \f(CW\*(C`false\*(C'\fR and \f(CW\*(C`error\*(C'\fR. The special value \f(CW\*(C`error\*(C'\fR promotes the
+warning to an error, this is usually shown as red text but will crash ranger
+when run with the \f(CW\*(C`\-\-debug\*(C'\fR flag.
 .IP "one_indexed [bool]" 4
 .IX Item "one_indexed [bool]"
 Start line numbers from 1.  Possible values are:
@@ -1104,6 +1127,10 @@ Sets the state for the version control backend. The possible values are:
 \& local      display only local state.
 \& enabled    display both, local and remote state. May be slow for hg and bzr.
 .Ve
+.IP "vcs_msg_length [int]" 4
+.IX Item "vcs_msg_length [int]"
+Length to truncate first line of the commit messages to when shown in
+the statusbar.  Defaults to 50.
 .IP "viewmode [string]" 4
 .IX Item "viewmode [string]"
 Sets the view mode, which can be \fBmiller\fR to display the files in the
@@ -1188,6 +1215,7 @@ ranger.  For your convenience, this is a list of the \*(L"public\*(R" commands i
 \& terminal
 \& tmap key command
 \& touch filename
+\& trash
 \& travel pattern
 \& tunmap keys...
 \& unmap keys...
@@ -1233,33 +1261,27 @@ example, \fB+ar\fR allows reading for everyone, \-ow forbids others to write and
 777= allows everything.
 .Sp
 See also: man 1 chmod
-.IP "cmap \fIkey\fR \fIcommand\fR" 2
-.IX Item "cmap key command"
-Binds keys for the console. Works like the \f(CW\*(C`map\*(C'\fR command.
 .IP "console [\-p\fIN\fR] \fIcommand\fR" 2
 .IX Item "console [-pN] command"
 Opens the console with the command already typed in.  The cursor is placed at
 \&\fIN\fR.
+.IP "copymap  \fIkey\fR \fInewkey\fR [\fInewkey2\fR ...]" 2
+.IX Item "copymap key newkey [newkey2 ...]"
+.PD 0
 .IP "copycmap \fIkey\fR \fInewkey\fR [\fInewkey2\fR ...]" 2
 .IX Item "copycmap key newkey [newkey2 ...]"
-See \f(CW\*(C`copymap\*(C'\fR
-.IP "copymap \fIkey\fR \fInewkey\fR [\fInewkey2\fR ...]" 2
-.IX Item "copymap key newkey [newkey2 ...]"
-Copies the keybinding \fIkey\fR to \fInewkey\fR in the \*(L"browser\*(R" context.  This is a
-deep copy, so if you change the new binding (or parts of it) later, the old one
-is not modified.
-.Sp
-To copy key bindings of the console, taskview, or pager use \*(L"copycmap\*(R",
-\&\*(L"copytmap\*(R" or \*(L"copypmap\*(R".
 .IP "copypmap \fIkey\fR \fInewkey\fR [\fInewkey2\fR ...]" 2
 .IX Item "copypmap key newkey [newkey2 ...]"
-See \f(CW\*(C`copymap\*(C'\fR
 .IP "copytmap \fIkey\fR \fInewkey\fR [\fInewkey2\fR ...]" 2
 .IX Item "copytmap key newkey [newkey2 ...]"
-See \f(CW\*(C`copymap\*(C'\fR
-.IP "cunmap [\fIkeys...\fR]" 2
-.IX Item "cunmap [keys...]"
-Removes key mappings of the console. Works like the \f(CW\*(C`unmap\*(C'\fR command.
+.PD
+Copies the keybinding \fIkey\fR to \fInewkey\fR in the \*(L"browser\*(R" context.  This is a
+deep copy, so if you change the new binding (or parts of it) later, the old one
+is not modified. For example, \fIcopymap j down\fR will make the key sequence
+\&\*(L"down\*(R" move the cursor down one item.
+.Sp
+To copy key bindings of the console, pager or taskview use \*(L"copycmap\*(R",
+\&\*(L"copypmap\*(R" or \*(L"copytmap\*(R" respectively.
 .IP "default_linemode [\fIpath=regexp\fR | \fItag=tags\fR] \fIlinemodename\fR" 2
 .IX Item "default_linemode [path=regexp | tag=tags] linemodename"
 Sets the default linemode.  See \fIlinemode\fR command.
@@ -1365,16 +1387,24 @@ See the \fIranger.core.linemode\fR module for some examples.
 .IX Item "load_copy_buffer"
 Load the copy buffer from \fI~/.config/ranger/copy_buffer\fR.  This can be used to
 pass the list of copied files to another ranger instance.
-.IP "map \fIkey\fR \fIcommand\fR" 2
+.IP "map  \fIkey\fR \fIcommand\fR" 2
 .IX Item "map key command"
+.PD 0
+.IP "cmap \fIkey\fR \fIcommand\fR" 2
+.IX Item "cmap key command"
+.IP "pmap \fIkey\fR \fIcommand\fR" 2
+.IX Item "pmap key command"
+.IP "tmap \fIkey\fR \fIcommand\fR" 2
+.IX Item "tmap key command"
+.PD
 Assign the key combination to the given command.  Whenever you type the
 key/keys, the command will be executed.  Additionally, if you use a quantifier
 when typing the key, like 5j, it will be passed to the command as the attribute
 \&\*(L"self.quantifier\*(R".
 .Sp
 The keys you bind with this command are accessible in the file browser only,
-not in the console, task view or pager.  To bind keys there, use the commands
-\&\*(L"cmap\*(R", \*(L"tmap\*(R" or \*(L"pmap\*(R".
+not in the console, pager or taskview.  To bind keys there, use the commands
+\&\*(L"cmap\*(R", \*(L"pmap\*(R" or \*(L"tmap\*(R".
 .IP "mark \fIpattern\fR" 2
 .IX Item "mark pattern"
 Mark all files matching the regular expression pattern.
@@ -1408,16 +1438,10 @@ of applications is generated by the external file opener \*(L"rifle\*(R" and can
 displayed when pressing \*(L"r\*(R" in ranger.
 .Sp
 Note that if you specify an application, the mode is ignored.
-.IP "pmap \fIkey\fR \fIcommand\fR" 2
-.IX Item "pmap key command"
-Binds keys for the pager. Works like the \f(CW\*(C`map\*(C'\fR command.
 .IP "prompt_metadata [\fIkeys ...\fR]" 2
 .IX Item "prompt_metadata [keys ...]"
 Prompt the user to input metadata with the \f(CW\*(C`meta\*(C'\fR command for multiple keys in
 a row.
-.IP "punmap [\fIkeys ...\fR]" 2
-.IX Item "punmap [keys ...]"
-Removes key mappings of the pager. Works like the \f(CW\*(C`unmap\*(C'\fR command.
 .IP "quit" 2
 .IX Item "quit"
 Closes the current tab, if there's only one tab. Otherwise quits if there are no tasks in progress.
@@ -1544,12 +1568,19 @@ Scroll the file preview by \fIvalue\fR lines.
 .IP "terminal" 2
 .IX Item "terminal"
 Spawns the \fIx\-terminal-emulator\fR starting in the current directory.
-.IP "tmap \fIkey\fR \fIcommand\fR" 2
-.IX Item "tmap key command"
-Binds keys for the taskview. Works like the \f(CW\*(C`map\*(C'\fR command.
 .IP "touch \fIfilename\fR" 2
 .IX Item "touch filename"
 Creates an empty file with the name \fIfilename\fR, unless it already exists.
+.IP "trash" 2
+.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
+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".
 .IP "travel \fIpattern\fR" 2
 .IX Item "travel pattern"
 Filters the current directory for files containing the letters in the
@@ -1559,13 +1590,18 @@ is automatically reopened, allowing for fast travel.
 To close the console, press \s-1ESC\s0 or execute a file.
 .Sp
 This command is based on the \fIscout\fR command and supports all of its options.
-.IP "tunmap [\fIkeys ...\fR]" 2
-.IX Item "tunmap [keys ...]"
-Removes key mappings of the taskview. Works like the \f(CW\*(C`unmap\*(C'\fR command.
-.IP "unmap [\fIkeys\fR ...]" 2
+.IP "unmap  [\fIkeys\fR ...]" 2
 .IX Item "unmap [keys ...]"
+.PD 0
+.IP "cunmap [\fIkeys\fR ...]" 2
+.IX Item "cunmap [keys ...]"
+.IP "punmap [\fIkeys\fR ...]" 2
+.IX Item "punmap [keys ...]"
+.IP "tunmap [\fIkeys\fR ...]" 2
+.IX Item "tunmap [keys ...]"
+.PD
 Removes the given key mappings in the \*(L"browser\*(R" context.  To unmap key bindings
-in the console, taskview, or pager use \*(L"cunmap\*(R", \*(L"tunmap\*(R" or \*(L"punmap\*(R".
+in the console, pager, or taskview use \*(L"cunmap\*(R", \*(L"punmap\*(R" or \*(L"tunmap\*(R".
 .IP "unmark \fIpattern\fR" 2
 .IX Item "unmark pattern"
 Unmark all files matching a regular expression pattern.
diff --git a/doc/ranger.desktop b/doc/ranger.desktop
index 9c140185..55d68ed8 100644
--- a/doc/ranger.desktop
+++ b/doc/ranger.desktop
@@ -7,3 +7,4 @@ Terminal=true
 Exec=ranger
 Categories=ConsoleOnly;System;FileTools;FileManager
 MimeType=inode/directory;
+Keywords=File;Manager;Browser;Explorer;Launcher;Vi;Vim;Python
diff --git a/doc/ranger.pod b/doc/ranger.pod
index 3b59c9e5..852afcdc 100644
--- a/doc/ranger.pod
+++ b/doc/ranger.pod
@@ -1,3 +1,4 @@
+=encoding utf8
 =head1 NAME
 
 ranger - visual file manager
@@ -201,17 +202,6 @@ Independently of the preview script, there is a feature to preview images
 by drawing them directly into the terminal. To enable this feature, set the
 option C<preview_images> to true and enable one of the image preview modes:
 
-=head3 w3m
-
-This does not work over ssh, requires certain terminals (tested on "xterm" and
-"urxvt") and is incompatible with tmux, although it works with screen.
-
-To enable this feature, install the program "w3m" and set the option
-C<preview_images_method> to w3m.
-
-When using a terminal with a nonzero border which is not automatically detected, the w3m preview will be misaligned.
-Use the C<w3m_offset> option to manually adjust the image offset. This should be the same value as the terminal's border value.
-
 =head3 iTerm2
 
 This only works in iTerm2 compiled with image preview support, but works over
@@ -223,12 +213,28 @@ This feature relies on the dimensions of the terminal's font.  By default, a
 width of 8 and height of 11 are used.  To use other values, set the options
 C<iterm2_font_width> and C<iterm2_font_height> to the desired values.
 
+=head3 kitty
+
+This only works in Kitty. It requires PIL (or pillow) to work.
+Allows remote image previews, for example in an ssh session.
+
+To enable this feature, set the option C<preview_images_method> to kitty.
+
 =head3 terminology
 
 This only works in terminology. It can render vector graphics, but works only locally.
 
 To enable this feature, set the option C<preview_images_method> to terminology.
 
+=head3 ueberzug
+
+Ɯberzug is a command line utility which draws images on terminals using child
+windows. It requires PIL (or pillow) and relies on X11. This makes it
+compatible (in a limited way, i.e., tmux splits are not supported) with many
+terminals and tmux but not the Linux console or Wayland.
+
+To enable this feature, set the option C<preview_images_method> to ueberzug.
+
 =head3 urxvt
 
 This only works in urxvt compiled with pixbuf support. Does not work over ssh.
@@ -245,12 +251,16 @@ window.
 
 To enable this feature, set the option C<preview_images_method> to urxvt-full.
 
-=head3 kitty
+=head3 w3m
 
-This only works on Kitty. It requires PIL (or pillow) to work.
-Allows remote image previews, for example in an ssh session.
+This does not work over ssh, requires certain terminals (tested on "xterm" and
+"urxvt") and is incompatible with tmux, although it works with screen.
 
-To enable this feature, set the option C<preview_images_method> to kitty.
+To enable this feature, install the program "w3m" and set the option
+C<preview_images_method> to w3m.
+
+When using a terminal with a nonzero border which is not automatically detected, the w3m preview will be misaligned.
+Use the C<w3m_offset> option to manually adjust the image offset. This should be the same value as the terminal's border value.
 
 =head2 SELECTION
 
@@ -328,6 +338,10 @@ the end of the line automatically.
 
 To write a literal %, you need to escape it by writing %%.
 
+Note that macros are expanded twice when using chain. For example, to insert
+a space character in a chained command, you would write %%space:
+ chain command1; command2%%space
+
 =head2 BOOKMARKS
 
 Type B<m<keyE<gt>> to bookmark the current directory. You can re-enter this
@@ -635,6 +649,10 @@ Open the console with the most recent command.
 Open a tab. N has to be a number from 0 to 9. If the tab doesn't exist yet, it
 will be created.
 
+=item Alt-l, Alt-r
+
+Shift a tab left, respectively right.
+
 =item gn, ^N
 
 Create a new tab.
@@ -981,6 +999,14 @@ all directories above the current one as well?
 
 Enable mouse input?
 
+=item nested_ranger_warning [string]
+
+Warn at startup if C<RANGER_LEVEL> is greater than 0, in other words give a
+warning when you nest ranger in a subshell started by ranger. Allowed values
+are C<true>, C<false> and C<error>. The special value C<error> promotes the
+warning to an error, this is usually shown as red text but will crash ranger
+when run with the C<--debug> flag.
+
 =item one_indexed [bool]
 
 Start line numbers from 1.  Possible values are:
@@ -1148,6 +1174,11 @@ Sets the state for the version control backend. The possible values are:
  local      display only local state.
  enabled    display both, local and remote state. May be slow for hg and bzr.
 
+=item vcs_msg_length [int]
+
+Length to truncate first line of the commit messages to when shown in
+the statusbar.  Defaults to 50.
+
 =item viewmode [string]
 
 Sets the view mode, which can be B<miller> to display the files in the
@@ -1239,6 +1270,7 @@ ranger.  For your convenience, this is a list of the "public" commands including
  terminal
  tmap key command
  touch filename
+ trash
  travel pattern
  tunmap keys...
  unmap keys...
@@ -1291,39 +1323,26 @@ example, B<+ar> allows reading for everyone, -ow forbids others to write and
 
 See also: man 1 chmod
 
-=item cmap I<key> I<command>
-
-Binds keys for the console. Works like the C<map> command.
-
 =item console [-pI<N>] I<command>
 
 Opens the console with the command already typed in.  The cursor is placed at
 I<N>.
 
-=item copycmap I<key> I<newkey> [I<newkey2> ...]
-
-See C<copymap>
-
-=item copymap I<key> I<newkey> [I<newkey2> ...]
+=item copymap  I<key> I<newkey> [I<newkey2> ...]
 
-Copies the keybinding I<key> to I<newkey> in the "browser" context.  This is a
-deep copy, so if you change the new binding (or parts of it) later, the old one
-is not modified.
-
-To copy key bindings of the console, taskview, or pager use "copycmap",
-"copytmap" or "copypmap".
+=item copycmap I<key> I<newkey> [I<newkey2> ...]
 
 =item copypmap I<key> I<newkey> [I<newkey2> ...]
 
-See C<copymap>
-
 =item copytmap I<key> I<newkey> [I<newkey2> ...]
 
-See C<copymap>
-
-=item cunmap [I<keys...>]
+Copies the keybinding I<key> to I<newkey> in the "browser" context.  This is a
+deep copy, so if you change the new binding (or parts of it) later, the old one
+is not modified. For example, I<copymap j down> will make the key sequence
+"down" move the cursor down one item.
 
-Removes key mappings of the console. Works like the C<unmap> command.
+To copy key bindings of the console, pager or taskview use "copycmap",
+"copypmap" or "copytmap" respectively.
 
 =item default_linemode [I<path=regexp> | I<tag=tags>] I<linemodename>
 
@@ -1442,7 +1461,13 @@ See the I<ranger.core.linemode> module for some examples.
 Load the copy buffer from F<~/.config/ranger/copy_buffer>.  This can be used to
 pass the list of copied files to another ranger instance.
 
-=item map I<key> I<command>
+=item map  I<key> I<command>
+
+=item cmap I<key> I<command>
+
+=item pmap I<key> I<command>
+
+=item tmap I<key> I<command>
 
 Assign the key combination to the given command.  Whenever you type the
 key/keys, the command will be executed.  Additionally, if you use a quantifier
@@ -1450,8 +1475,8 @@ when typing the key, like 5j, it will be passed to the command as the attribute
 "self.quantifier".
 
 The keys you bind with this command are accessible in the file browser only,
-not in the console, task view or pager.  To bind keys there, use the commands
-"cmap", "tmap" or "pmap".
+not in the console, pager or taskview.  To bind keys there, use the commands
+"cmap", "pmap" or "tmap".
 
 =item mark I<pattern>
 
@@ -1489,19 +1514,11 @@ displayed when pressing "r" in ranger.
 
 Note that if you specify an application, the mode is ignored.
 
-=item pmap I<key> I<command>
-
-Binds keys for the pager. Works like the C<map> command.
-
 =item prompt_metadata [I<keys ...>]
 
 Prompt the user to input metadata with the C<meta> command for multiple keys in
 a row.
 
-=item punmap [I<keys ...>]
-
-Removes key mappings of the pager. Works like the C<unmap> command.
-
 =item quit
 
 Closes the current tab, if there's only one tab. Otherwise quits if there are no tasks in progress.
@@ -1640,14 +1657,21 @@ Scroll the file preview by I<value> lines.
 
 Spawns the I<x-terminal-emulator> starting in the current directory.
 
-=item tmap I<key> I<command>
-
-Binds keys for the taskview. Works like the C<map> command.
-
 =item touch I<filename>
 
 Creates an empty file with the name I<filename>, unless it already exists.
 
+=item trash
+
+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
+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".
+
 =item travel I<pattern>
 
 Filters the current directory for files containing the letters in the
@@ -1658,14 +1682,16 @@ To close the console, press ESC or execute a file.
 
 This command is based on the I<scout> command and supports all of its options.
 
-=item tunmap [I<keys ...>]
+=item unmap  [I<keys> ...]
+
+=item cunmap [I<keys> ...]
 
-Removes key mappings of the taskview. Works like the C<unmap> command.
+=item punmap [I<keys> ...]
 
-=item unmap [I<keys> ...]
+=item tunmap [I<keys> ...]
 
 Removes the given key mappings in the "browser" context.  To unmap key bindings
-in the console, taskview, or pager use "cunmap", "tunmap" or "punmap".
+in the console, pager, or taskview use "cunmap", "punmap" or "tunmap".
 
 =item unmark I<pattern>
 
diff --git a/doc/rifle.1 b/doc/rifle.1
index a42734d2..114cc5d0 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.10 (Pod::Simple 3.35)
 .\"
 .\" Standard preamble:
 .\" ========================================================================
@@ -54,16 +54,20 @@
 .\" Avoid warning from groff about undefined register 'F'.
 .de IX
 ..
-.if !\nF .nr F 0
-.if \nF>0 \{\
-.    de IX
-.    tm Index:\\$1\t\\n%\t"\\$2"
+.nr rF 0
+.if \n(.g .if rF .nr rF 1
+.if (\n(rF:(\n(.g==0)) \{\
+.    if \nF \{\
+.        de IX
+.        tm Index:\\$1\t\\n%\t"\\$2"
 ..
-.    if !\nF==2 \{\
-.        nr % 0
-.        nr F 2
+.        if !\nF==2 \{\
+.            nr % 0
+.            nr F 2
+.        \}
 .    \}
 .\}
+.rr rF
 .\"
 .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
 .\" Fear.  Run.  Save yourself.  No user-serviceable parts.
@@ -129,7 +133,7 @@
 .\" ========================================================================
 .\"
 .IX Title "RIFLE 1"
-.TH RIFLE 1 "rifle-1.9.2" "2019-04-03" "rifle manual"
+.TH RIFLE 1 "rifle-1.9.2" "08/18/2019" "rifle manual"
 .\" For nroff, turn off justification.  Always turn off hyphenation; it makes
 .\" way too many mistakes in technical documents.
 .if n .ad l
diff --git a/examples/rc_emacs.conf b/examples/rc_emacs.conf
index ac3937bf..ba8eaaeb 100644
--- a/examples/rc_emacs.conf
+++ b/examples/rc_emacs.conf
@@ -59,6 +59,9 @@ set vcs_backend_git enabled
 set vcs_backend_hg disabled
 set vcs_backend_bzr disabled
 
+# Truncate the long commit messages to this length when shown in the statusbar.
+set vcs_msg_length 50
+
 # Use one of the supported image preview protocols
 set preview_images false
 
@@ -209,6 +212,11 @@ set idle_delay 2000
 # check all directories above the current one as well?
 set metadata_deep_search false
 
+# Warn at startup if RANGER_LEVEL env var is greater than 0, in other words
+# give a warning when you nest ranger in a subshell started by ranger.
+# Special value "error" makes the warning more visible.
+set nested_ranger_warning true
+
 # ===================================================================
 # == Local Options
 # ===================================================================
diff --git a/ranger/config/commands.py b/ranger/config/commands.py
index 2b1f4940..cb6fa132 100755
--- a/ranger/config/commands.py
+++ b/ranger/config/commands.py
@@ -572,7 +572,7 @@ class default_linemode(Command):
 class quit(Command):  # pylint: disable=redefined-builtin
     """:quit
 
-    Closes the current tab, if there's only one tab.
+    Closes the current tab, if there's more than one tab.
     Otherwise quits if there are no tasks in progress.
     """
     def _exit_no_work(self):
@@ -591,7 +591,7 @@ class quit(Command):  # pylint: disable=redefined-builtin
 class quit_bang(Command):
     """:quit!
 
-    Closes the current tab, if there's only one tab.
+    Closes the current tab, if there's more than one tab.
     Otherwise force quits immediately.
     """
     name = 'quit!'
@@ -699,6 +699,64 @@ class delete(Command):
             self.fm.delete(files)
 
 
+class trash(Command):
+    """:trash
+
+    Tries to move the selection or the files passed in arguments (if any) to
+    the trash, using rifle rules with label "trash".
+    The arguments use a shell-like escaping.
+
+    "Selection" is defined as all the "marked files" (by default, you
+    can mark files with space or v). If there are no marked files,
+    use the "current file" (where the cursor is)
+
+    When attempting to trash non-empty directories or multiple
+    marked files, it will require a confirmation.
+    """
+
+    allow_abbrev = False
+    escape_macros_for_shell = True
+
+    def execute(self):
+        import shlex
+        from functools import partial
+
+        def is_directory_with_files(path):
+            return os.path.isdir(path) and not os.path.islink(path) and len(os.listdir(path)) > 0
+
+        if self.rest(1):
+            files = shlex.split(self.rest(1))
+            many_files = (len(files) > 1 or is_directory_with_files(files[0]))
+        else:
+            cwd = self.fm.thisdir
+            tfile = self.fm.thisfile
+            if not cwd or not tfile:
+                self.fm.notify("Error: no file selected for deletion!", bad=True)
+                return
+
+            # relative_path used for a user-friendly output in the confirmation.
+            files = [f.relative_path for f in self.fm.thistab.get_selection()]
+            many_files = (cwd.marked_items or is_directory_with_files(tfile.path))
+
+        confirm = self.fm.settings.confirm_on_delete
+        if confirm != 'never' and (confirm != 'multiple' or many_files):
+            self.fm.ui.console.ask(
+                "Confirm deletion of: %s (y/N)" % ', '.join(files),
+                partial(self._question_callback, files),
+                ('n', 'N', 'y', 'Y'),
+            )
+        else:
+            # no need for a confirmation, just delete
+            self.fm.execute_file(files, label='trash')
+
+    def tab(self, tabnum):
+        return self._tab_directory_content()
+
+    def _question_callback(self, files, answer):
+        if answer == 'y' or answer == 'Y':
+            self.fm.execute_file(files, label='trash')
+
+
 class jump_non(Command):
     """:jump_non [-FLAGS...]
 
@@ -1244,7 +1302,7 @@ class copycmap(copymap):
 
 
 class copytmap(copymap):
-    """:copycmap <keys> <newkeys1> [<newkeys2>...]
+    """:copytmap <keys> <newkeys1> [<newkeys2>...]
 
     Copies a "taskview" keybinding from <keys> to <newkeys>
     """
@@ -1263,30 +1321,69 @@ class unmap(Command):
             self.fm.ui.keymaps.unbind(self.context, arg)
 
 
-class cunmap(unmap):
+class uncmap(unmap):
+    """:uncmap <keys> [<keys2>, ...]
+
+    Remove the given "console" mappings
+    """
+    context = 'console'
+
+
+class cunmap(uncmap):
     """:cunmap <keys> [<keys2>, ...]
 
     Remove the given "console" mappings
+
+    DEPRECATED in favor of uncmap.
     """
-    context = 'browser'
 
+    def execute(self):
+        self.fm.notify("cunmap is deprecated in favor of uncmap!")
+        super(cunmap, self).execute()
 
-class punmap(unmap):
-    """:punmap <keys> [<keys2>, ...]
+
+class unpmap(unmap):
+    """:unpmap <keys> [<keys2>, ...]
 
     Remove the given "pager" mappings
     """
     context = 'pager'
 
 
-class tunmap(unmap):
-    """:tunmap <keys> [<keys2>, ...]
+class punmap(unpmap):
+    """:punmap <keys> [<keys2>, ...]
+
+    Remove the given "pager" mappings
+
+    DEPRECATED in favor of unpmap.
+    """
+
+    def execute(self):
+        self.fm.notify("punmap is deprecated in favor of unpmap!")
+        super(punmap, self).execute()
+
+
+class untmap(unmap):
+    """:untmap <keys> [<keys2>, ...]
 
     Remove the given "taskview" mappings
     """
     context = 'taskview'
 
 
+class tunmap(untmap):
+    """:tunmap <keys> [<keys2>, ...]
+
+    Remove the given "taskview" mappings
+
+    DEPRECATED in favor of untmap.
+    """
+
+    def execute(self):
+        self.fm.notify("tunmap is deprecated in favor of untmap!")
+        super(tunmap, self).execute()
+
+
 class map_(Command):
     """:map <keysequence> <command>
 
@@ -1827,11 +1924,14 @@ class yank(Command):
                     ['xsel'],
                     ['xsel', '-b'],
                 ],
+                'wl-copy': [
+                    ['wl-copy'],
+                ],
                 'pbcopy': [
                     ['pbcopy'],
                 ],
             }
-            ordered_managers = ['pbcopy', 'xclip', 'xsel']
+            ordered_managers = ['pbcopy', 'wl-copy', 'xclip', 'xsel']
             executables = get_executables()
             for manager in ordered_managers:
                 if manager in executables:
diff --git a/ranger/config/rc.conf b/ranger/config/rc.conf
index b4bb4bfc..23601fb6 100644
--- a/ranger/config/rc.conf
+++ b/ranger/config/rc.conf
@@ -67,6 +67,9 @@ set vcs_backend_hg disabled
 set vcs_backend_bzr disabled
 set vcs_backend_svn disabled
 
+# Truncate the long commit messages to this length when shown in the statusbar.
+set vcs_msg_length 50
+
 # Use one of the supported image preview protocols
 set preview_images false
 
@@ -304,6 +307,11 @@ set freeze_files false
 # Print file sizes in bytes instead of the default human-readable format.
 set size_in_bytes false
 
+# Warn at startup if RANGER_LEVEL env var is greater than 0, in other words
+# give a warning when you nest ranger in a subshell started by ranger.
+# Special value "error" makes the warning more visible.
+set nested_ranger_warning true
+
 # ===================================================================
 # == Local Options
 # ===================================================================
@@ -399,6 +407,7 @@ map <F5> copy
 map <F6> cut
 map <F7> console mkdir%space
 map <F8> console delete
+#map <F8> console trash
 map <F10> exit
 
 # In case you work on a keyboard with dvorak layout
@@ -486,6 +495,7 @@ map p`<any> paste dest=%any_path
 map p'<any> paste dest=%any_path
 
 map dD console delete
+map dT console trash
 
 map dd cut
 map ud uncut
diff --git a/ranger/config/rifle.conf b/ranger/config/rifle.conf
index a90646e2..86f53fd1 100644
--- a/ranger/config/rifle.conf
+++ b/ranger/config/rifle.conf
@@ -26,7 +26,7 @@
 #   directory      | $1 is a directory
 #   number <n>     | change the number of this command to n
 #   terminal       | stdin, stderr and stdout are connected to a terminal
-#   X              | $DISPLAY is not empty (i.e. Xorg runs)
+#   X              | A graphical environment is available (darwin, Xorg, or Wayland)
 #
 # There are also pseudo-conditions which have a "side effect":
 #   flag <flags>  | Change how the program is run. See below.
@@ -66,13 +66,13 @@ ext x?html?, has uzbl-tabbed,      X, flag f = uzbl-tabbed -- "$@"
 ext x?html?, has uzbl-browser,     X, flag f = uzbl-browser -- "$@"
 ext x?html?, has uzbl-core,        X, flag f = uzbl-core -- "$@"
 ext x?html?, has midori,           X, flag f = midori -- "$@"
-ext x?html?, has chromium-browser, X, flag f = chromium-browser -- "$@"
-ext x?html?, has chromium,         X, flag f = chromium -- "$@"
-ext x?html?, has google-chrome,    X, flag f = google-chrome -- "$@"
 ext x?html?, has opera,            X, flag f = opera -- "$@"
 ext x?html?, has firefox,          X, flag f = firefox -- "$@"
 ext x?html?, has seamonkey,        X, flag f = seamonkey -- "$@"
 ext x?html?, has iceweasel,        X, flag f = iceweasel -- "$@"
+ext x?html?, has chromium-browser, X, flag f = chromium-browser -- "$@"
+ext x?html?, has chromium,         X, flag f = chromium -- "$@"
+ext x?html?, has google-chrome,    X, flag f = google-chrome -- "$@"
 ext x?html?, has epiphany,         X, flag f = epiphany -- "$@"
 ext x?html?, has konqueror,        X, flag f = konqueror -- "$@"
 ext x?html?, has elinks,            terminal = elinks "$@"
@@ -259,10 +259,26 @@ label wallpaper, number 12, mime ^image, has feh, X = feh --bg-tile "$1"
 label wallpaper, number 13, mime ^image, has feh, X = feh --bg-center "$1"
 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 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" -- "$@"
 
-# The very last action, so that it's never triggered accidentally, is to execute a program:
+
+######################################################################
+# The actions below are left so low down in this file on purpose, so #
+# they are never triggered accidentally.                             #
+######################################################################
+
+# Execute a file as program/script.
 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
diff --git a/ranger/container/fsobject.py b/ranger/container/fsobject.py
index 4fb47354..7de889bf 100644
--- a/ranger/container/fsobject.py
+++ b/ranger/container/fsobject.py
@@ -342,10 +342,10 @@ class FileSystemObject(  # pylint: disable=too-many-instance-attributes,too-many
         if self.permissions is not None:
             return self.permissions
 
-        if self.is_directory:
-            perms = ['d']
-        elif self.is_link:
+        if self.is_link:
             perms = ['l']
+        elif self.is_directory:
+            perms = ['d']
         else:
             perms = ['-']
 
diff --git a/ranger/container/settings.py b/ranger/container/settings.py
index 3075aadf..5f0c528b 100644
--- a/ranger/container/settings.py
+++ b/ranger/container/settings.py
@@ -58,6 +58,7 @@ ALLOWED_SETTINGS = {
     'max_history_size': (int, type(None)),
     'metadata_deep_search': bool,
     'mouse_enabled': bool,
+    'nested_ranger_warning': str,
     'one_indexed': bool,
     'open_all_images': bool,
     'padding_right': bool,
@@ -94,6 +95,7 @@ ALLOWED_SETTINGS = {
     'vcs_backend_git': str,
     'vcs_backend_hg': str,
     'vcs_backend_svn': str,
+    'vcs_msg_length': int,
     'viewmode': str,
     'w3m_delay': float,
     'w3m_offset': int,
@@ -106,6 +108,7 @@ ALLOWED_VALUES = {
     'confirm_on_delete': ['multiple', 'always', 'never'],
     'draw_borders': ['none', 'both', 'outline', 'separators'],
     'line_numbers': ['false', 'absolute', 'relative'],
+    'nested_ranger_warning': ['true', 'false', 'error'],
     'one_indexed': [False, True],
     'preview_images_method': ['w3m', 'iterm2', 'terminology',
                               'urxvt', 'urxvt-full', 'kitty',
@@ -277,7 +280,7 @@ class Settings(SignalDispatcher, FileManagerAware):
         if path:
             if path not in self._localsettings:
                 try:
-                    regex = re.compile(path)
+                    regex = re.compile(re.escape(path))
                 except re.error:  # Bad regular expression
                     return
                 self._localregexes[path] = regex
diff --git a/ranger/core/actions.py b/ranger/core/actions.py
index 435fcf13..18302431 100644
--- a/ranger/core/actions.py
+++ b/ranger/core/actions.py
@@ -1597,20 +1597,22 @@ class Actions(  # pylint: disable=too-many-instance-attributes,too-many-public-m
         Paste the selected items into the current directory or to dest
         if provided.
         """
-        if dest is None or isdir(dest):
+        if dest is None:
+            dest = self.thistab.path
+        if isdir(dest):
             loadable = CopyLoader(self.copy_buffer, self.do_cut, overwrite,
                                   dest)
             self.loader.add(loadable, append=append)
             self.do_cut = False
         else:
-            self.notify('Failed to paste. The given path is invalid.', bad=True)
+            self.notify('Failed to paste. The destination is invalid.', bad=True)
 
     def delete(self, files=None):
         # XXX: warn when deleting mount points/unseen marked files?
-        self.notify("Deleting!")
         # 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)))
         files = [os.path.abspath(path) for path in files]
         for path in files:
             # Untag the deleted files.
diff --git a/ranger/core/fm.py b/ranger/core/fm.py
index 43001e8b..7d23c9b6 100644
--- a/ranger/core/fm.py
+++ b/ranger/core/fm.py
@@ -22,11 +22,7 @@ from ranger.container.tags import Tags, TagsDummy
 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,
-                                    KittyImageDisplayer, UeberzugImageDisplayer,
-                                    ImageDisplayer)
+from ranger.ext.img_display import get_image_displayer
 from ranger.core.metadata import MetadataManager
 from ranger.ext.rifle import Rifle
 from ranger.container.directory import Directory
@@ -104,7 +100,7 @@ class FM(Actions,  # pylint: disable=too-many-instance-attributes
         def set_image_displayer():
             if self.image_displayer:
                 self.image_displayer.quit()
-            self.image_displayer = self._get_image_displayer()
+            self.image_displayer = get_image_displayer(self.settings.preview_images_method)
         set_image_displayer()
         self.settings.signal_bind('setopt.preview_images_method', set_image_displayer,
                                   priority=settings.SIGNAL_PRIORITY_AFTER_SYNC)
@@ -227,23 +223,6 @@ class FM(Actions,  # pylint: disable=too-many-instance-attributes
             for line in entry.splitlines():
                 yield line
 
-    def _get_image_displayer(self):  # pylint: disable=too-many-return-statements
-        if self.settings.preview_images_method == "w3m":
-            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":
-            return URXVTImageFSDisplayer()
-        elif self.settings.preview_images_method == "kitty":
-            return KittyImageDisplayer()
-        elif self.settings.preview_images_method == "ueberzug":
-            return UeberzugImageDisplayer()
-        return ImageDisplayer()
-
     def _get_thisfile(self):
         return self.thistab.thisfile
 
diff --git a/ranger/core/main.py b/ranger/core/main.py
index 23648677..aefaacbc 100644
--- a/ranger/core/main.py
+++ b/ranger/core/main.py
@@ -180,6 +180,16 @@ def main(
             for command in args.cmd:
                 fm.execute_console(command)
 
+        if int(os.environ[level]) > 1:
+            warning = 'Warning:'
+            nested_warning = "You're in a nested ranger instance!"
+            warn_when_nested = fm.settings.nested_ranger_warning.lower()
+            if warn_when_nested == 'true':
+                fm.notify(' '.join((warning, nested_warning)), bad=False)
+            elif warn_when_nested == 'error':
+                fm.notify(' '.join((warning.upper(), nested_warning + '!!')),
+                          bad=True)
+
         if ranger.args.profile:
             import cProfile
             import pstats
diff --git a/ranger/core/runner.py b/ranger/core/runner.py
index f38b026a..d465f070 100644
--- a/ranger/core/runner.py
+++ b/ranger/core/runner.py
@@ -214,7 +214,9 @@ class Runner(object):  # pylint: disable=too-few-public-methods
             toggle_ui = True
             context.wait = True
         if 't' in context.flags:
-            if 'DISPLAY' not in os.environ:
+            if not ('WAYLAND_DISPLAY' in os.environ
+                    or sys.platform == 'darwin'
+                    or 'DISPLAY' in os.environ):
                 return self._log("Can not run with 't' flag, no display found!")
             term = get_term()
             if isinstance(action, str):
diff --git a/ranger/data/mime.types b/ranger/data/mime.types
index 900cb7d9..abee11f6 100644
--- a/ranger/data/mime.types
+++ b/ranger/data/mime.types
@@ -12,11 +12,13 @@
 
 audio/flac              flac
 audio/musepack          mpc mpp mp+
-audio/ogg               oga ogg spx
+audio/ogg               oga ogg spx opus
 audio/wavpack           wv wvc
 audio/webm              weba
 audio/x-ape             ape
 
+image/webp              webp
+
 video/mkv               mkv
 video/webm              webm
 video/flash             flv
diff --git a/ranger/data/scope.sh b/ranger/data/scope.sh
index 306eeed0..eb09b2bf 100755
--- a/ranger/data/scope.sh
+++ b/ranger/data/scope.sh
@@ -45,7 +45,6 @@ HIGHLIGHT_STYLE=${HIGHLIGHT_STYLE:-pablo}
 HIGHLIGHT_OPTIONS="--replace-tabs=${HIGHLIGHT_TABWIDTH} --style=${HIGHLIGHT_STYLE} ${HIGHLIGHT_OPTIONS:-}"
 PYGMENTIZE_STYLE=${PYGMENTIZE_STYLE:-autumn}
 
-
 handle_extension() {
     case "${FILE_EXTENSION_LOWER}" in
         ## Archive
diff --git a/ranger/ext/img_display.py b/ranger/ext/img_display.py
index 2cce5c7a..7e911848 100644
--- a/ranger/ext/img_display.py
+++ b/ranger/ext/img_display.py
@@ -23,6 +23,7 @@ import warnings
 import json
 import threading
 from subprocess import Popen, PIPE
+from collections import defaultdict
 
 import termios
 from contextlib import contextmanager
@@ -72,6 +73,33 @@ class ImgDisplayUnsupportedException(Exception):
     pass
 
 
+def fallback_image_displayer():
+    """Simply makes some noise when chosen. Temporary fallback behavior."""
+
+    raise ImgDisplayUnsupportedException
+
+
+IMAGE_DISPLAYER_REGISTRY = defaultdict(fallback_image_displayer)
+
+
+def register_image_displayer(nickname=None):
+    """Register an ImageDisplayer by nickname if available."""
+
+    def decorator(image_displayer_class):
+        if nickname:
+            registry_key = nickname
+        else:
+            registry_key = image_displayer_class.__name__
+        IMAGE_DISPLAYER_REGISTRY[registry_key] = image_displayer_class
+        return image_displayer_class
+    return decorator
+
+
+def get_image_displayer(registry_key):
+    image_displayer_class = IMAGE_DISPLAYER_REGISTRY[registry_key]
+    return image_displayer_class()
+
+
 class ImageDisplayer(object):
     """Image display provider functions for drawing images in the terminal"""
 
@@ -90,6 +118,7 @@ class ImageDisplayer(object):
         pass
 
 
+@register_image_displayer("w3m")
 class W3MImageDisplayer(ImageDisplayer, FileManagerAware):
     """Implementation of ImageDisplayer using w3mimgdisplay, an utilitary
     program from w3m (a text-based web browser). w3mimgdisplay can display
@@ -243,6 +272,7 @@ class W3MImageDisplayer(ImageDisplayer, FileManagerAware):
 # ranger-independent libraries.
 
 
+@register_image_displayer("iterm2")
 class ITerm2ImageDisplayer(ImageDisplayer, FileManagerAware):
     """Implementation of ImageDisplayer using iTerm2 image display support
     (http://iterm2.com/images.html).
@@ -351,6 +381,7 @@ class ITerm2ImageDisplayer(ImageDisplayer, FileManagerAware):
         return width, height
 
 
+@register_image_displayer("terminology")
 class TerminologyImageDisplayer(ImageDisplayer, FileManagerAware):
     """Implementation of ImageDisplayer using terminology image display support
     (https://github.com/billiob/terminology).
@@ -390,6 +421,7 @@ class TerminologyImageDisplayer(ImageDisplayer, FileManagerAware):
         self.clear(0, 0, 0, 0)
 
 
+@register_image_displayer("urxvt")
 class URXVTImageDisplayer(ImageDisplayer, FileManagerAware):
     """Implementation of ImageDisplayer working by setting the urxvt
     background image "under" the preview pane.
@@ -474,6 +506,7 @@ class URXVTImageDisplayer(ImageDisplayer, FileManagerAware):
         self.clear(0, 0, 0, 0)  # dummy assignments
 
 
+@register_image_displayer("urxvt-full")
 class URXVTImageFSDisplayer(URXVTImageDisplayer):
     """URXVTImageDisplayer that utilizes the whole terminal."""
 
@@ -486,6 +519,7 @@ class URXVTImageFSDisplayer(URXVTImageDisplayer):
         return self._get_centered_offsets()
 
 
+@register_image_displayer("kitty")
 class KittyImageDisplayer(ImageDisplayer, FileManagerAware):
     """Implementation of ImageDisplayer for kitty (https://github.com/kovidgoyal/kitty/)
     terminal. It uses the built APC to send commands and data to kitty,
@@ -681,6 +715,7 @@ class KittyImageDisplayer(ImageDisplayer, FileManagerAware):
         #         continue
 
 
+@register_image_displayer("ueberzug")
 class UeberzugImageDisplayer(ImageDisplayer):
     """Implementation of ImageDisplayer using ueberzug.
     Ueberzug can display images in a Xorg session.
diff --git a/ranger/ext/rifle.py b/ranger/ext/rifle.py
index a55e14c7..a73a188b 100755
--- a/ranger/ext/rifle.py
+++ b/ranger/ext/rifle.py
@@ -237,7 +237,9 @@ class Rifle(object):  # pylint: disable=too-many-instance-attributes
             self._app_flags = argument
             return True
         elif function == 'X':
-            return sys.platform == 'darwin' or 'DISPLAY' in os.environ
+            return ('WAYLAND_DISPLAY' in os.environ
+                    or sys.platform == 'darwin'
+                    or 'DISPLAY' in os.environ)
         elif function == 'env':
             return bool(os.environ.get(argument))
         elif function == 'else':
@@ -293,6 +295,9 @@ class Rifle(object):  # pylint: disable=too-many-instance-attributes
             self._app_flags = ''
             self._app_label = None
             if skip_ask and cmd == ASK_COMMAND:
+                # TODO(vifon): Fix properly, see
+                # https://github.com/ranger/ranger/pull/1341#issuecomment-537264495
+                count += 1
                 continue
             for test in tests:
                 if not self._eval_condition(test, files, None):
diff --git a/ranger/gui/widgets/statusbar.py b/ranger/gui/widgets/statusbar.py
index 71064ed4..fd44613e 100644
--- a/ranger/gui/widgets/statusbar.py
+++ b/ranger/gui/widgets/statusbar.py
@@ -212,7 +212,11 @@ class StatusBar(Widget):  # pylint: disable=too-many-instance-attributes
                 left.add_space()
                 left.add(directory.vcs.rootvcs.head['date'].strftime(self.timeformat), 'vcsdate')
                 left.add_space()
-                left.add(directory.vcs.rootvcs.head['summary'], 'vcscommit')
+                summary_length = self.settings.vcs_msg_length or 50
+                left.add(
+                    directory.vcs.rootvcs.head['summary'][:summary_length],
+                    'vcscommit'
+                )
 
     def _get_owner(self, target):
         uid = target.stat.st_uid