├── README.md └── zranger /README.md: -------------------------------------------------------------------------------- 1 | zranger 2 | ======= 3 | 4 | [zsh](http://www.zsh.org/) and [ranger](http://ranger.nongnu.org/) integration 5 | 6 | DESCRIPTION 7 | ----------- 8 | 9 | `zranger` allows easy and quick switching back and forth between `zsh` 10 | and `ranger` while synchronizing their working directories and 11 | preserving the commandline contents. The `ranger` process is kept in 12 | background (using `tmux`) after the first launch so the switching is 13 | almost instantaneous. The new process is created only on the first run 14 | or when the old one is explicitly closed (instead of detaching). 15 | 16 | It's an alternative approach to the problem I've been trying to solve 17 | with [deer](https://github.com/vifon/deer): a fast access to a 18 | ranger-like environment used as an extension of shell. 19 | 20 | FEATURES 21 | -------- 22 | 23 | **Laziness** 24 | 25 | The `ranger` process is started on the first call to `zranger`. No 26 | need to launch a new `ranger` process for each and every shell means 27 | almost no shell startup time penalty. 28 | 29 | **Just works!** 30 | 31 | `zranger` mostly reuses the pre-existing mechanisms. Thanks to that 32 | most of the things just work. Want to close the terminal window with 33 | that button in the corner? Sure, why not! `tmux` has you covered. Or 34 | maybe you'd rather open some `ranger`'s tabs and keep them between 35 | `zranger` invocations? Not a problem. `ranger`'s directory history 36 | works as expected too. 37 | 38 | Due to its simplicity I don't expect to update this project very 39 | often. It does **not** mean that it's abandoned. Feel free to report 40 | bugs and feature request or send pull requests. 41 | 42 | INSTALLATION 43 | ------------ 44 | 45 | `zranger` needs to be configured on both `zsh`'s and `ranger`'s side. 46 | 47 | **zsh** 48 | 49 | Copy the `zranger` file to a directory present in your `$FPATH` (see 50 | below) and add the following snippet to your `zshrc`: 51 | 52 | ```zsh 53 | autoload -U zranger 54 | bindkey -s '\ez' "\eq zranger\n" 55 | ``` 56 | 57 | `$FPATH` is a variable with list of directories searched when 58 | autoloading a function. You can just create a new directory (for 59 | example `~/.fpath`) and add it to that variable in `zshrc`: 60 | 61 | FPATH=$HOME/.fpath:$FPATH 62 | 63 | **ranger** 64 | 65 | Add the following snippet to `ranger`'s `commands.py` file: 66 | 67 | ```python 68 | import os 69 | import signal 70 | def zranger_chdir_handler(signal, frame): 71 | tmpfile = "/tmp/zranger-cwd-{}".format(os.getuid()) 72 | with open(tmpfile, "r") as f: 73 | Command.fm.cd(f.readline().strip()) 74 | os.unlink(tmpfile) 75 | signal.signal(signal.SIGUSR1, zranger_chdir_handler) 76 | ``` 77 | 78 | Additionally you may want to bind a convenient hotkey for returning to 79 | `zsh`. To do this, add this too to `commands.py`: 80 | 81 | ```python 82 | class tmux_detach(Command): 83 | """ 84 | :tmux_detach 85 | 86 | Detach from this tmux session (if inside tmux). 87 | """ 88 | def execute(self): 89 | if not os.environ.get('TMUX'): 90 | return 91 | os.system("tmux detach") 92 | ``` 93 | 94 | and this to `rc.conf`: 95 | 96 | map tmux_detach 97 | 98 | USAGE 99 | ----- 100 | 101 | When finished with the configuration above, you can switch between 102 | `zsh` and `ranger` by pressing `alt+z`. The working directories should 103 | automagically synchronize when doing so. 104 | 105 | DEPENDENCIES 106 | ------------ 107 | 108 | * ranger 109 | * zsh 110 | * tmux 111 | 112 | FAQ 113 | --- 114 | 115 | **When I call zranger with another zranger called from another shell, 116 | the other one quits. Why?** 117 | 118 | It is by design. Keeping multiple `ranger` instances would be both 119 | inefficient and difficult. For the sake of simplicity `zranger` uses 120 | only one shared `ranger` process and detaches all other attached 121 | terminals. When doing this, it tries to be consistent when it comes to 122 | the working directories. If they happen to behave in a weird way, try 123 | increasing the sleep time in the main script a bit (there is a small 124 | race condition). 125 | 126 | I'm very aware of this `zranger`'s shortcoming but I have no good 127 | ideas how to handle it. Please feel free to suggest something. 128 | 129 | **What does the second line added to the zsh config mean?** 130 | 131 | It binds `alt+z` ("\ez") to the key combination `\eq zranger\n`. "\eq" 132 | saves the current commandline contents (as does pressing `alt+q`), the 133 | space prevents this line from being saved in the history 134 | (`HIST_IGNORE_SPACE` option needs to be enabled) and "zranger\n" is 135 | just a regular function call. It needs to be called this way (i.e. by 136 | emulating the keys) because `ranger` has issues when running inside a 137 | zle widget which would be the only alternative. 138 | 139 | **Can I use zranger with Bash?** 140 | 141 | Currently it's not supported but I've successfully run it by creating 142 | a function `zranger` with contents of the main file as its body and 143 | binding it with `bind '"\ez":" zranger\n"'`. YMMV. 144 | 145 | COPYRIGHT 146 | --------- 147 | 148 | Copyright (C) 2014 Wojciech Siewierski 149 | 150 | This program is free software: you can redistribute it and/or modify 151 | it under the terms of the GNU General Public License as published by 152 | the Free Software Foundation, either version 3 of the License, or 153 | (at your option) any later version. 154 | 155 | This program is distributed in the hope that it will be useful, 156 | but WITHOUT ANY WARRANTY; without even the implied warranty of 157 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 158 | GNU General Public License for more details. 159 | 160 | You should have received a copy of the GNU General Public License 161 | along with this program. If not, see . 162 | -------------------------------------------------------------------------------- /zranger: -------------------------------------------------------------------------------- 1 | # -*- sh -*- 2 | 3 | local RANGER_PID 4 | 5 | if RANGER_PID=$(tmux list-panes -s -F '#{pane_pid}' -t ranger 2> /dev/null); then 6 | # Leave the current cwd for ranger to read and cleanup. 7 | pwd > /tmp/zranger-cwd-$UID 8 | # Detach the other zranger instance... 9 | tmux detach-client -s ranger 10 | # ...and give it some time to read ranger's cwd before it changes. 11 | sleep 0.05 # May need some tweaking. 12 | # Tell ranger to read zsh's cwd from /tmp and cd to it. 13 | kill -SIGUSR1 $RANGER_PID 14 | # Attach to it. 15 | TMUX='' tmux attach -t ranger 16 | else 17 | TMUX='' tmux new-session -s ranger 'exec ranger --cmd="set preview_images=false"' 18 | fi 19 | 20 | # A second check needed because the process could have been 21 | # started or stopped in the meantime. 22 | if RANGER_PID=$(tmux list-panes -s -F '#{pane_pid}' -t ranger 2> /dev/null); then 23 | cd -P /proc/$RANGER_PID/cwd 24 | fi 25 | --------------------------------------------------------------------------------