diff options
-rw-r--r-- | CHANGELOG.md | 12 | ||||
-rw-r--r-- | Dockerfile | 8 | ||||
-rw-r--r-- | Makefile | 6 | ||||
-rw-r--r-- | README.md | 8 | ||||
-rw-r--r-- | doc/cheatsheet.svg | 4 | ||||
-rw-r--r-- | doc/howto-publish-a-release.md | 34 | ||||
-rw-r--r-- | doc/ranger.1 | 31 | ||||
-rw-r--r-- | doc/ranger.pod | 26 | ||||
-rw-r--r-- | doc/rifle.1 | 4 | ||||
-rw-r--r-- | examples/plugin_avfs.py | 33 | ||||
-rw-r--r-- | ranger/__init__.py | 2 | ||||
-rw-r--r-- | ranger/config/__init__.py | 2 | ||||
-rwxr-xr-x | ranger/config/commands.py | 16 | ||||
-rw-r--r-- | ranger/config/rc.conf | 15 | ||||
-rw-r--r-- | ranger/config/rifle.conf | 3 | ||||
-rw-r--r-- | ranger/container/settings.py | 1 | ||||
-rw-r--r-- | ranger/core/actions.py | 19 | ||||
-rw-r--r-- | ranger/core/main.py | 70 | ||||
-rwxr-xr-x | ranger/data/scope.sh | 2 | ||||
-rwxr-xr-x | ranger/ext/rifle.py | 16 | ||||
-rw-r--r-- | ranger/gui/curses_shortcuts.py | 4 | ||||
-rw-r--r-- | ranger/gui/widgets/view_base.py | 66 | ||||
-rwxr-xr-x | setup.py | 2 |
23 files changed, 289 insertions, 95 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c0a16cf..346b18dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ This log documents changes between stable versions. +# 2018-02-22: version 1.9.1 +* Fixed the rifle config backwards compatibility (regression in 1.9.0) +* Fixed the POSIX compatibility of `Makefile` +* Fixed `--choosefile`, `--choosefiles` and `--choosedir` so they work + with the process substitution (`>(...)` in Bash) +* Changed the default `gt` binding to `gp` due to a conflict +* Changed the help message for `--choosefile`, `--choosefiles` and + `--choosedir` to avoid confusion +* Changed the behavior of `:reset` to reload the tags too +* Added `geeqie` to the default `rifle.conf` + # 2018-01-25: version 1.9.0 * Fixed memory leak in w3m image preview * Fixed `Q` binding, map it to `quitall` instead of `quit!` @@ -75,6 +86,7 @@ This log documents changes between stable versions. * Added support for `$XDG_DATA_HOME` * Avoid exiting ranger while copying. Use `:quit!` to quit while copying. * Improved scope.sh (better performance & readability) +* Improved logs handling by migrating to the python standard logging library (PR #725) * Changed `ranger --choosefiles` to return all selected files in all paths * Changed interpretation of commands: treat tabs as argument separators * Changed `<C-n>` to open new tab in current directory rather than `$HOME` diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..36ad0a95 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,8 @@ +# Usage instructions: +# 1. "docker build -t ranger/ranger:latest ." +# 2. "docker run -it ranger/ranger" + +FROM debian + +RUN apt-get update && apt-get install -y ranger +ENTRYPOINT ["ranger"] diff --git a/Makefile b/Makefile index 99d3f53e..47e2fa01 100644 --- a/Makefile +++ b/Makefile @@ -67,9 +67,9 @@ doc: cleandoc TEST_PATHS_MAIN = \ $(shell find ./ranger -mindepth 1 -maxdepth 1 -type d \ - -and -not -name '__pycache__' \ - -and -not -path './ranger/config' \ - -and -not -path './ranger/data' \ + ! -name '__pycache__' \ + ! -path './ranger/config' \ + ! -path './ranger/data' \ ) \ ./ranger/__init__.py \ $(shell find ./doc/tools ./examples -type f -name '*.py') \ diff --git a/README.md b/README.md index e16ea540..ef644ae6 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -ranger 1.9.0 +ranger 1.9.1 ============ [![Build Status](https://travis-ci.org/ranger/ranger.svg?branch=master)](https://travis-ci.org/ranger/ranger) @@ -29,10 +29,10 @@ About ----- * Authors: see `AUTHORS` file * License: GNU General Public License Version 3 -* Website: http://ranger.github.io/ -* Download: http://ranger.github.io/ranger-stable.tar.gz +* Website: https://ranger.github.io/ +* Download: https://ranger.github.io/ranger-stable.tar.gz * Bug reports: https://github.com/ranger/ranger/issues -* git clone http://git.sv.gnu.org/r/ranger.git +* git clone https://github.com/ranger/ranger.git Design Goals diff --git a/doc/cheatsheet.svg b/doc/cheatsheet.svg index f8a97bff..3794a2da 100644 --- a/doc/cheatsheet.svg +++ b/doc/cheatsheet.svg @@ -4059,7 +4059,7 @@ sodipodi:role="line">ranger cheatsheet</tspan></text> <a id="a5535" - xlink:href="http://ranger.github.io" + xlink:href="https://ranger.github.io" style="fill:#0000ff" transform="translate(10,-296.00002)"> <text @@ -4073,7 +4073,7 @@ sodipodi:role="line" x="230" y="567.36218" - style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;line-height:100%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#0000ff">http://ranger.github.io</tspan></text> + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;line-height:100%;font-family:Sans;-inkscape-font-specification:'Sans, Normal';text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#0000ff">https://ranger.github.io</tspan></text> </a> <text xml:space="preserve" diff --git a/doc/howto-publish-a-release.md b/doc/howto-publish-a-release.md index 9b6e1dfe..572a2eb7 100644 --- a/doc/howto-publish-a-release.md +++ b/doc/howto-publish-a-release.md @@ -1,3 +1,26 @@ +Prepare the "stable" branch +--------------------------- +Before you can do anything else, you need to decide what should be included in +the new version. + +**Bugfix releases** bump the third number of the version, e.g. 1.9.0 -> 1.9.1. +They may include bugfix commits that you `git cherry-pick`ed from the master +branch into the stable branch, or you can just do a fast-forward merge of +master into stable, if there were only bugfix commits since the last major +version. You can also add minor new features that are very likely not causing +any bugs. However, there should be absolutely **no** backward-incompatible +changes, like: + +- renamed or removed settings, commands or python functions +- renamed, removed or reordered function arguments +- change in syntax of configuration files or in API of configuration scripts + +New settings are okay, just make sure a sane default value is defined. + +**Major releases** bump the second number of the version, e.g. 1.9.2 -> 1.10.0 +and are necessary if you introduce any breaking changes, like the ones +mentioned in the list above. + Test everything ---------------- * [ ] `make test` @@ -13,7 +36,9 @@ Make a release commit * [ ] `make man` * [ ] Write changelog entry * [ ] Think of a witty commit message -* [ ] Tag signed release +* [ ] Commit +* [ ] Tag the signed release with `git tag -a <commit-id>`, using the same + commit message as annotation * [ ] Push release and tag Make snapshot and test again @@ -28,9 +53,11 @@ Update the website * [ ] Add the new version as `ranger-stable.tar.gz` * [ ] Add the new version as `ranger-X.Y.Z.tar.gz` * [ ] Update both signatures `gpg --local-user 0x00FB5CDF --sign --detach-sign <file>` -* [ ] Update the changelog * [ ] Update the man page -* [ ] Rerun `boobies.py` + * [ ] run `make manhtml` in ranger's repository + * [ ] copy the generated `doc/ranger.1.html` to the `ranger.github.io` repository +* [ ] Rebuild the website, see `README.md` in https://github.com/ranger/ranger.github.io +* [ ] Commit & push the website Make a PyPI release ------------------- @@ -43,7 +70,6 @@ Announce the update ------------------- * [ ] To the mailing list * [ ] In the arch linux forum -* [ ] Write a news entry on savannah Change back to before --------------------- diff --git a/doc/ranger.1 b/doc/ranger.1 index ab47de61..6358e1d6 100644 --- a/doc/ranger.1 +++ b/doc/ranger.1 @@ -129,7 +129,7 @@ .\" ======================================================================== .\" .IX Title "RANGER 1" -.TH RANGER 1 "ranger-1.9.0" "2018-01-28" "ranger manual" +.TH RANGER 1 "ranger-1.9.1" "2018-05-08" "ranger manual" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l @@ -267,7 +267,7 @@ typing \fI"<tagname>\fR. By default, only text files are previewed, but you can enable external preview scripts by setting the option \f(CW\*(C`use_preview_script\*(C'\fR and \f(CW\*(C`preview_files\*(C'\fR to true. .PP -This default script is \fI~/.config/ranger/scope.sh\fR. It contains more +This default script is \fI\f(CI%rangerdir\fI/data/scope.sh\fR. It contains more documentation and calls to the programs \fIlynx\fR and \fIelinks\fR for html, \&\fIhighlight\fR for text/code, \fIimg2txt\fR for images, \fIatool\fR for archives, \&\fIpdftotext\fR for PDFs and \fImediainfo\fR for video and audio files. @@ -463,7 +463,7 @@ sample plugins in the \fI/usr/share/doc/ranger/examples/\fR directory, including hello-world plugin that describes this procedure. .SH "KEY BINDINGS" .IX Header "KEY BINDINGS" -Key bindings are defined in the file \fIranger/config/rc.conf\fR. Check this +Key bindings are defined in the file \fI\f(CI%rangerdir\fI/config/rc.conf\fR. Check this file for a list of all key bindings. You can copy it to your local configuration directory with the \-\-copy\-config=rc option. .PP @@ -800,6 +800,13 @@ this pattern will hide all files that start with a dot or end with a tilde. .Vb 1 \& set hidden_filter ^\e.|~$ .Ve +.IP "hint_collapse_threshold [int]" 4 +.IX Item "hint_collapse_threshold [int]" +The key hint lists up to this size have their sublists expanded. +Otherwise the submaps are replaced with \*(L"...\*(R". +.IP "hostname_in_titlebar [bool]" 4 +.IX Item "hostname_in_titlebar [bool]" +Show hostname in titlebar? .IP "idle_delay [integer]" 4 .IX Item "idle_delay [integer]" The delay that ranger idly waits for user input, in milliseconds, with a @@ -932,9 +939,6 @@ combination, e.g. \*(L"oN\*(R" to sort from Z to A. .IP "status_bar_on_top [bool]" 4 .IX Item "status_bar_on_top [bool]" Put the status bar at the top of the window? -.IP "hostname_in_titlebar [bool]" 4 -.IX Item "hostname_in_titlebar [bool]" -Show hostname in titlebar? .IP "tilde_in_titlebar [bool]" 4 .IX Item "tilde_in_titlebar [bool]" Abbreviate \f(CW$HOME\fR with ~ in the titlebar (first line) of ranger? @@ -1421,6 +1425,9 @@ being bound despite the corresponding line being removed from the user's copy of the configuration file. This behavior may be disabled with an environment variable (see also: \fB\s-1ENVIRONMENT\s0\fR). Note: All other configuration files only read from one source; i.e. default \s-1OR\s0 user, not both. +\&\fIrc.conf\fR and \fIcommands.py\fR are additionally read from \fI/etc/ranger\fR if they +exist for system-wide configuration, user configuration overrides system +configuration which overrides the default configuration. .PP When starting ranger with the \fB\-\-clean\fR option, it will not access or create any of these files. @@ -1533,13 +1540,13 @@ provided along with the source code. \&\s-1GNU\s0 General Public License 3 or (at your option) any later version. .SH "LINKS" .IX Header "LINKS" -.IP "Download: <http://ranger.github.io/ranger\-stable.tar.gz>" 4 -.IX Item "Download: <http://ranger.github.io/ranger-stable.tar.gz>" +.IP "Download: <https://ranger.github.io/ranger\-stable.tar.gz>" 4 +.IX Item "Download: <https://ranger.github.io/ranger-stable.tar.gz>" .PD 0 -.IP "The project page: <http://ranger.github.io/>" 4 -.IX Item "The project page: <http://ranger.github.io/>" -.IP "The mailing list: <http://savannah.nongnu.org/mail/?group=ranger>" 4 -.IX Item "The mailing list: <http://savannah.nongnu.org/mail/?group=ranger>" +.IP "The project page: <https://ranger.github.io/>" 4 +.IX Item "The project page: <https://ranger.github.io/>" +.IP "The mailing list: <https://savannah.nongnu.org/mail/?group=ranger>" 4 +.IX Item "The mailing list: <https://savannah.nongnu.org/mail/?group=ranger>" .IP "\s-1IRC\s0 channel: #ranger on freenode.net" 4 .IX Item "IRC channel: #ranger on freenode.net" .PD diff --git a/doc/ranger.pod b/doc/ranger.pod index ee869393..9fb4cf0d 100644 --- a/doc/ranger.pod +++ b/doc/ranger.pod @@ -174,7 +174,7 @@ typing I<"<tagnameE<gt>>. By default, only text files are previewed, but you can enable external preview scripts by setting the option C<use_preview_script> and C<preview_files> to true. -This default script is F<~/.config/ranger/scope.sh>. It contains more +This default script is F<%rangerdir/data/scope.sh>. It contains more documentation and calls to the programs I<lynx> and I<elinks> for html, I<highlight> for text/code, I<img2txt> for images, I<atool> for archives, I<pdftotext> for PDFs and I<mediainfo> for video and audio files. @@ -364,7 +364,7 @@ hello-world plugin that describes this procedure. =head1 KEY BINDINGS -Key bindings are defined in the file F<ranger/config/rc.conf>. Check this +Key bindings are defined in the file F<%rangerdir/config/rc.conf>. Check this file for a list of all key bindings. You can copy it to your local configuration directory with the --copy-config=rc option. @@ -791,6 +791,15 @@ this pattern will hide all files that start with a dot or end with a tilde. set hidden_filter ^\.|~$ +=item hint_collapse_threshold [int] + +The key hint lists up to this size have their sublists expanded. +Otherwise the submaps are replaced with "...". + +=item hostname_in_titlebar [bool] + +Show hostname in titlebar? + =item idle_delay [integer] The delay that ranger idly waits for user input, in milliseconds, with a @@ -951,10 +960,6 @@ combination, e.g. "oN" to sort from Z to A. Put the status bar at the top of the window? -=item hostname_in_titlebar [bool] - -Show hostname in titlebar? - =item tilde_in_titlebar [bool] Abbreviate $HOME with ~ in the titlebar (first line) of ranger? @@ -1507,6 +1512,9 @@ being bound despite the corresponding line being removed from the user's copy of the configuration file. This behavior may be disabled with an environment variable (see also: B<ENVIRONMENT>). Note: All other configuration files only read from one source; i.e. default OR user, not both. +F<rc.conf> and F<commands.py> are additionally read from F</etc/ranger> if they +exist for system-wide configuration, user configuration overrides system +configuration which overrides the default configuration. When starting ranger with the B<--clean> option, it will not access or create any of these files. @@ -1670,11 +1678,11 @@ GNU General Public License 3 or (at your option) any later version. =over -=item Download: L<http://ranger.github.io/ranger-stable.tar.gz> +=item Download: L<https://ranger.github.io/ranger-stable.tar.gz> -=item The project page: L<http://ranger.github.io/> +=item The project page: L<https://ranger.github.io/> -=item The mailing list: L<http://savannah.nongnu.org/mail/?group=ranger> +=item The mailing list: L<https://savannah.nongnu.org/mail/?group=ranger> =item IRC channel: #ranger on freenode.net diff --git a/doc/rifle.1 b/doc/rifle.1 index 755ac959..ad32e4f4 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.0" "2018-01-25" "rifle manual" +.TH RIFLE 1 "rifle-1.9.1" "05.03.2018" "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/plugin_avfs.py b/examples/plugin_avfs.py new file mode 100644 index 00000000..07968a03 --- /dev/null +++ b/examples/plugin_avfs.py @@ -0,0 +1,33 @@ +# Tested with ranger 1.9.1 +# +# A very simple and possibly buggy support for AVFS +# (http://avf.sourceforge.net/), that allows ranger to handle +# archives. +# +# Run `:avfs' to browse the selected archive. + +from __future__ import (absolute_import, division, print_function) + +import os +import os.path + +from ranger.api.commands import Command + + +class avfs(Command): # pylint: disable=invalid-name + avfs_root = os.path.join(os.environ["HOME"], ".avfs") + avfs_suffix = "#" + + def execute(self): + if os.path.isdir(self.avfs_root): + archive_directory = "".join([ + self.avfs_root, + self.fm.thisfile.path, + self.avfs_suffix, + ]) + if os.path.isdir(archive_directory): + self.fm.cd(archive_directory) + else: + self.fm.notify("This file cannot be handled by avfs.", bad=True) + else: + self.fm.notify("Install `avfs' and run `mountavfs' first.", bad=True) diff --git a/ranger/__init__.py b/ranger/__init__.py index 60a536a0..0d7c8fdc 100644 --- a/ranger/__init__.py +++ b/ranger/__init__.py @@ -14,7 +14,7 @@ import os # Information __license__ = 'GPL3' -__version__ = '1.9.0' +__version__ = '1.9.1' __author__ = __maintainer__ = 'Roman Zimbelmann' __email__ = 'hut@hut.pm' diff --git a/ranger/config/__init__.py b/ranger/config/__init__.py index 71df3cb3..0facbdf8 100644 --- a/ranger/config/__init__.py +++ b/ranger/config/__init__.py @@ -1 +1 @@ -"""Default options and configration files""" +"""Default options and configuration files""" diff --git a/ranger/config/commands.py b/ranger/config/commands.py index a3837d8e..a7fe68b4 100755 --- a/ranger/config/commands.py +++ b/ranger/config/commands.py @@ -3,8 +3,9 @@ # This configuration file is licensed under the same terms as ranger. # =================================================================== # -# NOTE: If you copied this file to ~/.config/ranger/commands_full.py, -# then it will NOT be loaded by ranger, and only serve as a reference. +# NOTE: If you copied this file to /etc/ranger/commands_full.py or +# ~/.config/ranger/commands_full.py, then it will NOT be loaded by ranger, +# and only serve as a reference. # # =================================================================== # This file contains ranger's commands. @@ -13,9 +14,14 @@ # Note that additional commands are automatically generated from the methods # of the class ranger.core.actions.Actions. # -# You can customize commands in the file ~/.config/ranger/commands.py. -# It has the same syntax as this file. In fact, you can just copy this -# file there with `ranger --copy-config=commands' and make your modifications. +# You can customize commands in the files /etc/ranger/commands.py (system-wide) +# and ~/.config/ranger/commands.py (per user). +# They have the same syntax as this file. In fact, you can just copy this +# file to ~/.config/ranger/commands_full.py with +# `ranger --copy-config=commands_full' and make your modifications, don't +# forget to rename it to commands.py. You can also use +# `ranger --copy-config=commands' to copy a short sample commands.py that +# has everything you need to get started. # But make sure you update your configs when you update ranger. # # =================================================================== diff --git a/ranger/config/rc.conf b/ranger/config/rc.conf index 39240b06..ce0240c6 100644 --- a/ranger/config/rc.conf +++ b/ranger/config/rc.conf @@ -1,7 +1,8 @@ # =================================================================== # This file contains the default startup commands for ranger. -# To change them, it is recommended to create the file -# ~/.config/ranger/rc.conf and add your custom commands there. +# To change them, it is recommended to create either /etc/ranger/rc.conf +# (system-wide) or ~/.config/ranger/rc.conf (per user) and add your custom +# commands there. # # If you copy this whole file there, you may want to set the environment # variable RANGER_LOAD_DEFAULT_RC to FALSE to avoid loading it twice. @@ -216,6 +217,10 @@ set cd_tab_fuzzy false # disable this feature. set preview_max_size 0 +# The key hint lists up to this size have their sublists expanded. +# Otherwise the submaps are replaced with "...". +set hint_collapse_threshold 10 + # Add the highlighted file to the path in the titlebar set show_selection_in_titlebar true @@ -270,8 +275,8 @@ alias qall quitall alias qall! quitall! alias setl setlocal -alias filter scout -prt -alias find scout -aeit +alias filter scout -prts +alias find scout -aets alias mark scout -mr alias unmark scout -Mr alias search scout -rs @@ -387,7 +392,7 @@ map gv cd /var map gm cd /media map gM cd /mnt map gs cd /srv -map gt cd /tmp +map gp cd /tmp map gr cd / map gR eval fm.cd(ranger.RANGERDIR) map g/ cd / diff --git a/ranger/config/rifle.conf b/ranger/config/rifle.conf index 564fff8d..66e6a5cd 100644 --- a/ranger/config/rifle.conf +++ b/ranger/config/rifle.conf @@ -151,7 +151,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 pdf, has open, X, flag f = open "$@" ext docx?, has catdoc, terminal = catdoc -- "$@" | "$PAGER" @@ -182,6 +182,7 @@ mime ^image, has ristretto, X, flag f = ristretto "$@" mime ^image, has eog, X, flag f = eog -- "$@" mime ^image, has eom, X, flag f = eom -- "$@" mime ^image, has nomacs, X, flag f = nomacs -- "$@" +mime ^image, has geeqie, X, flag f = geeqie -- "$@" mime ^image, has gimp, X, flag f = gimp -- "$@" ext xcf, X, flag f = gimp -- "$@" diff --git a/ranger/container/settings.py b/ranger/container/settings.py index d0b094d0..9f54f24d 100644 --- a/ranger/container/settings.py +++ b/ranger/container/settings.py @@ -45,6 +45,7 @@ ALLOWED_SETTINGS = { 'freeze_files': bool, 'global_inode_type_filter': str, 'hidden_filter': str, + 'hint_collapse_threshold': int, 'hostname_in_titlebar': bool, 'idle_delay': int, 'iterm2_font_width': int, diff --git a/ranger/core/actions.py b/ranger/core/actions.py index aef0d205..6bbb35aa 100644 --- a/ranger/core/actions.py +++ b/ranger/core/actions.py @@ -7,7 +7,7 @@ from __future__ import (absolute_import, division, print_function) import codecs import os -from os import link, symlink, getcwd, listdir, stat +from os import link, symlink, listdir, stat from os.path import join, isdir, realpath, exists import re import shlex @@ -74,6 +74,7 @@ class Actions( # pylint: disable=too-many-instance-attributes,too-many-public-m if self.metadata: self.metadata.reset() self.rifle.reload_config() + self.fm.tags.sync() def change_mode(self, mode=None): """:change_mode <mode> @@ -837,11 +838,11 @@ class Actions( # pylint: disable=too-many-instance-attributes,too-many-public-m self.ui.redraw_main_column() - def tag_remove(self, paths=None, movedown=None): - self.tag_toggle(paths=paths, value=False, movedown=movedown) + def tag_remove(self, paths=None, movedown=None, tag=None): + self.tag_toggle(paths=paths, value=False, movedown=movedown, tag=tag) - def tag_add(self, paths=None, movedown=None): - self.tag_toggle(paths=paths, value=True, movedown=movedown) + def tag_add(self, paths=None, movedown=None, tag=None): + self.tag_toggle(paths=paths, value=True, movedown=movedown, tag=tag) # -------------------------- # -- Bookmarks @@ -1372,9 +1373,9 @@ class Actions( # pylint: disable=too-many-instance-attributes,too-many-public-m self.notify(new_name) try: if relative: - relative_symlink(fobj.path, join(getcwd(), new_name)) + relative_symlink(fobj.path, join(self.fm.thisdir.path, new_name)) else: - symlink(fobj.path, join(getcwd(), new_name)) + symlink(fobj.path, join(self.fm.thisdir.path, new_name)) except OSError as ex: self.notify('Failed to paste symlink: View log for more info', bad=True, exception=ex) @@ -1383,7 +1384,7 @@ class Actions( # pylint: disable=too-many-instance-attributes,too-many-public-m for fobj in self.copy_buffer: new_name = next_available_filename(fobj.basename) try: - link(fobj.path, join(getcwd(), new_name)) + link(fobj.path, join(self.fm.thisdir.path, new_name)) except OSError as ex: self.notify('Failed to paste hardlink: View log for more info', bad=True, exception=ex) @@ -1391,7 +1392,7 @@ class Actions( # pylint: disable=too-many-instance-attributes,too-many-public-m def paste_hardlinked_subtree(self): for fobj in self.copy_buffer: try: - target_path = join(getcwd(), fobj.basename) + target_path = join(self.fm.thisdir.path, fobj.basename) self._recurse_hardlinked_tree(fobj.path, target_path) except OSError as ex: self.notify('Failed to paste hardlinked subtree: View log for more info', diff --git a/ranger/core/main.py b/ranger/core/main.py index a96b24a1..3d36a357 100644 --- a/ranger/core/main.py +++ b/ranger/core/main.py @@ -267,17 +267,17 @@ def parse_arguments(): parser.add_option('--copy-config', type='string', metavar='which', help="copy the default configs to the local config directory. " "Possible values: all, rc, rifle, commands, commands_full, scope") - parser.add_option('--choosefile', type='string', metavar='PATH', + parser.add_option('--choosefile', type='string', metavar='OUTFILE', help="Makes ranger act like a file chooser. When opening " "a file, it will quit and write the name of the selected " - "file to PATH.") - parser.add_option('--choosefiles', type='string', metavar='PATH', + "file to OUTFILE.") + parser.add_option('--choosefiles', type='string', metavar='OUTFILE', help="Makes ranger act like a file chooser for multiple files " "at once. When opening a file, it will quit and write the name " - "of all selected files to PATH.") - parser.add_option('--choosedir', type='string', metavar='PATH', + "of all selected files to OUTFILE.") + parser.add_option('--choosedir', type='string', metavar='OUTFILE', help="Makes ranger act like a directory chooser. When ranger quits" - ", it will write the name of the last visited directory to PATH") + ", it will write the name of the last visited directory to OUTFILE") parser.add_option('--selectfile', type='string', metavar='filepath', help="Open ranger with supplied file selected.") parser.add_option('--show-only-dirs', action='store_true', @@ -299,7 +299,7 @@ def parse_arguments(): def path_init(option): argval = args.__dict__[option] try: - path = os.path.realpath(argval) + path = os.path.abspath(argval) except OSError as ex: sys.stderr.write( '--{0} is not accessible: {1}\n{2}\n'.format(option, argval, str(ex))) @@ -339,23 +339,50 @@ def load_settings( # pylint: disable=too-many-locals,too-many-branches,too-many fm.commands.load_commands_from_module(commands_default) if not clean: + system_confdir = os.path.join(os.sep, 'etc', 'ranger') + if os.path.exists(system_confdir): + sys.path.append(system_confdir) allow_access_to_confdir(ranger.args.confdir, True) # Load custom commands - custom_comm_path = fm.confpath('commands.py') - if os.path.exists(custom_comm_path): + def import_file(name, path): # From https://stackoverflow.com/a/67692 + # pragma pylint: disable=no-name-in-module,import-error,no-member + if sys.version_info >= (3, 5): + import importlib.util as util + spec = util.spec_from_file_location(name, path) + module = util.module_from_spec(spec) + spec.loader.exec_module(module) + elif (3, 3) <= sys.version_info < (3, 5): + from importlib.machinery import SourceFileLoader + module = SourceFileLoader(name, path).load_module() + else: + import imp + module = imp.load_source(name, path) + # pragma pylint: enable=no-name-in-module,import-error,no-member + return module + + def load_custom_commands(*paths): old_bytecode_setting = sys.dont_write_bytecode sys.dont_write_bytecode = True - try: - import commands as commands_custom - fm.commands.load_commands_from_module(commands_custom) - except ImportError as ex: - LOG.debug("Failed to import custom commands from '%s'", custom_comm_path) - LOG.exception(ex) - else: - LOG.debug("Loaded custom commands from '%s'", custom_comm_path) + for custom_comm_path in paths: + if os.path.exists(custom_comm_path): + try: + commands_custom = import_file('commands', + custom_comm_path) + fm.commands.load_commands_from_module(commands_custom) + except ImportError as ex: + LOG.debug("Failed to import custom commands from '%s'", + custom_comm_path) + LOG.exception(ex) + else: + LOG.debug("Loaded custom commands from '%s'", + custom_comm_path) sys.dont_write_bytecode = old_bytecode_setting + system_comm_path = os.path.join(system_confdir, 'commands.py') + custom_comm_path = fm.confpath('commands.py') + load_custom_commands(system_comm_path, custom_comm_path) + # XXX Load plugins (experimental) plugindir = fm.confpath('plugins') try: @@ -394,12 +421,17 @@ def load_settings( # pylint: disable=too-many-locals,too-many-branches,too-many allow_access_to_confdir(ranger.args.confdir, False) # Load rc.conf custom_conf = fm.confpath('rc.conf') + system_conf = os.path.join(system_confdir, 'rc.conf') default_conf = fm.relpath('config', 'rc.conf') custom_conf_is_readable = os.access(custom_conf, os.R_OK) - if (os.environ.get('RANGER_LOAD_DEFAULT_RC', 'TRUE').upper() != 'FALSE' or - not custom_conf_is_readable): + system_conf_is_readable = os.access(system_conf, os.R_OK) + if (os.environ.get('RANGER_LOAD_DEFAULT_RC', 'TRUE').upper() != + 'FALSE' or + not (custom_conf_is_readable or system_conf_is_readable)): fm.source(default_conf) + if system_conf_is_readable: + fm.source(system_conf) if custom_conf_is_readable: fm.source(custom_conf) diff --git a/ranger/data/scope.sh b/ranger/data/scope.sh index 35021129..540a910e 100755 --- a/ranger/data/scope.sh +++ b/ranger/data/scope.sh @@ -31,7 +31,7 @@ IMAGE_CACHE_PATH="${4}" # Full path that should be used to cache image preview PV_IMAGE_ENABLED="${5}" # 'True' if image previews are enabled, 'False' otherwise. FILE_EXTENSION="${FILE_PATH##*.}" -FILE_EXTENSION_LOWER="${FILE_EXTENSION,,}" +FILE_EXTENSION_LOWER=$(echo ${FILE_EXTENSION} | tr '[:upper:]' '[:lower:]') # Settings HIGHLIGHT_SIZE_MAX=262143 # 256KiB diff --git a/ranger/ext/rifle.py b/ranger/ext/rifle.py index 36f3243e..672b0597 100755 --- a/ranger/ext/rifle.py +++ b/ranger/ext/rifle.py @@ -21,7 +21,7 @@ import re from subprocess import Popen, PIPE import sys -__version__ = 'rifle 1.9.0' +__version__ = 'rifle 1.9.1' # Options and constants that a user might want to change: DEFAULT_PAGER = 'less' @@ -261,6 +261,14 @@ class Rifle(object): # pylint: disable=too-many-instance-attributes process = Popen(["file", "--mime-type", "-Lb", fname], stdout=PIPE, stderr=PIPE) mimetype, _ = process.communicate() self._mimetype = mimetype.decode(ENCODING).strip() + if self._mimetype == 'application/octet-stream': + try: + process = Popen(["mimetype", "--output-format", "%m", fname], + stdout=PIPE, stderr=PIPE) + mimetype, _ = process.communicate() + self._mimetype = mimetype.decode(ENCODING).strip() + except OSError: + pass return self._mimetype def _build_command(self, files, action, flags): @@ -343,10 +351,8 @@ class Rifle(object): # pylint: disable=too-many-instance-attributes else: if 'PAGER' not in os.environ: os.environ['PAGER'] = DEFAULT_PAGER - if 'VISUAL' not in os.environ and 'EDITOR' not in os.environ: - os.environ['VISUAL'] = DEFAULT_EDITOR - # necessary for compatibility with old rifle.conf - os.environ['EDITOR'] = DEFAULT_EDITOR + if 'EDITOR' not in os.environ: + os.environ['EDITOR'] = os.environ.get('VISUAL', DEFAULT_EDITOR) command = self.hook_command_postprocessing(command) self.hook_before_executing(command, self._mimetype, self._app_flags) try: diff --git a/ranger/gui/curses_shortcuts.py b/ranger/gui/curses_shortcuts.py index ac067d01..14f1e0e4 100644 --- a/ranger/gui/curses_shortcuts.py +++ b/ranger/gui/curses_shortcuts.py @@ -35,7 +35,9 @@ class CursesShortcuts(SettingsAware): try: self.win.addstr(*args) - except (curses.error, TypeError): + except (curses.error, TypeError, ValueError): + # a TypeError changed to ValueError from version 3.5 onwards + # https://bugs.python.org/issue22215 if len(args) > 1: self.win.move(y, x) diff --git a/ranger/gui/widgets/view_base.py b/ranger/gui/widgets/view_base.py index cb205d92..80061004 100644 --- a/ranger/gui/widgets/view_base.py +++ b/ranger/gui/widgets/view_base.py @@ -112,16 +112,62 @@ class ViewBase(Widget, DisplayableContainer): # pylint: disable=too-many-instan self.color_reset() self.need_clear = True hints = [] - for key, value in self.fm.ui.keybuffer.pointer.items(): - key = key_to_string(key) - if isinstance(value, dict): - text = '...' - else: - text = value - if text.startswith('hint') or text.startswith('chain hint'): - continue - hints.append((key, text)) - hints.sort(key=lambda t: t[1]) + + def populate_hints(keymap, prefix=""): + for key, value in keymap.items(): + key = prefix + key_to_string(key) + if isinstance(value, dict): + populate_hints(value, key) + else: + text = value + if text.startswith('hint') or text.startswith('chain hint'): + continue + hints.append((key, text)) + populate_hints(self.fm.ui.keybuffer.pointer) + + def sort_hints(hints): + """Sort the hints by the action string but first group them by the + first key. + + """ + from itertools import groupby + + # groupby needs the list to be sorted. + hints.sort(key=lambda t: t[0]) + + def group_hints(hints): + def first_key(hint): + return hint[0][0] + + def action_string(hint): + return hint[1] + + return (sorted(group, key=action_string) + for _, group + in groupby( + hints, + key=first_key)) + + grouped_hints = group_hints(hints) + + # If there are too many hints, collapse the sublists. + if len(hints) > self.fm.settings.hint_collapse_threshold: + def first_key_in_group(group): + return group[0][0][0] + grouped_hints = ( + [(first_key_in_group(hint_group), "...")] + if len(hint_group) > 1 + else hint_group + for hint_group in grouped_hints + ) + + # Sort by the first action in group. + grouped_hints = sorted(grouped_hints, key=lambda g: g[0][1]) + + def flatten(nested_list): + return [item for inner_list in nested_list for item in inner_list] + return flatten(grouped_hints) + hints = sort_hints(hints) hei = min(self.hei - 1, len(hints)) ystart = self.hei - hei diff --git a/setup.py b/setup.py index f8b8df14..d7c54b00 100755 --- a/setup.py +++ b/setup.py @@ -72,7 +72,7 @@ def main(): author=ranger.__author__, author_email=ranger.__email__, license=ranger.__license__, - url='http://ranger.github.io', + url='https://ranger.github.io', keywords='file-manager vim console file-launcher file-preview', classifiers=[ 'Environment :: Console', |