自从用了vim后,感觉到了终端中的应用程序也可以有类似于图形化的操作和鼠标支持。无论是谁,在使用电脑的时候总是离不开文件操作的,那么有没有什么简单易用的类似于图形化的文件管理工具呢?
ranger
安装
在archlinux中安装
sudo pacman -S  --noconfirm ranger
安装依赖
sudo pacman -S  --noconfirm libcaca highlight atool lynx w3m elinks  mediainfo
在macOS中安装
安装ranger,可以使用基本的功能
brew install ranger
安装依赖,这样可以使用一些扩展的功能,主要是预览相关的。
brew install libcaca highlight atool lynx w3m elinks poppler transmission mediainfo exiftool
使用

支持鼠标操作
文本文件上按回车可以直接打开vim编辑文件
响应非常快,非常快
配置ranger使其支持图片浏览
创建imgcat
vim imgcat
并写入以下内容:
#!/bin/bash
tmux requires unrecognized OSC sequences to be wrapped with DCS tmux;
 ST, and for all ESCs in  to be replaced with ESC ESC. It  
only accepts ESC backslash for ST. We use TERM instead of TMUX because TERM
gets passed through ssh.
function print_osc() {
if [[ $TERM == screen* ]]; then
printf "\033Ptmux;\033\033]"
else
printf "\033]"
fi
}
More of the tmux workaround described above.
function print_st() {
if [[ $TERM == screen* ]]; then
printf "\a\033\"
else
printf "\a"
fi
}
function load_version() {
if [ -z (base64 --version 2>&1)
export IMGCAT_BASE64_VERSION
fi
}
function b64_encode() {
load_version
if [[ $IMGCAT_BASE64_VERSION =~ GNU ]]; then
# Disable line wrap
base64 -w0
else
base64
fi
}
function b64_decode() {
load_version
if [[ $IMGCAT_BASE64_VERSION =~ fourmilab ]]; then
BASE64ARG=-d
elif [[ $IMGCAT_BASE64_VERSION =~ GNU ]]; then
BASE64ARG=-di
else
BASE64ARG=-D
fi
base64 $BASE64ARG
}
print_image filename inline base64contents print_filename
filename: Filename to convey to client
inline: 0 or 1
base64contents: Base64-encoded contents
print_filename: If non-empty, print the filename
before outputting the image
function print_image() {
print_osc
printf '1337;File='
if [[ -n (printf "%s" "$1" | b64_encode)"
fi
printf "%s" "$3" | b64_decode | wc -c | awk '{printf "size=%d",$1}'
printf ";inline=%s" "$2"
printf ":"
printf "%s" "$3"
print_st
printf '\n'
if [[ -n $4 ]]; then
    echo "$1"
fi
}
function error() {
echo "ERROR: $*" 1>&2
}
function show_help() {
echo "Usage: imgcat [-p] filename ..." 1>&2
echo "   or: cat filename | imgcat" 1>&2
}
function check_dependency() {
if ! (builtin command -V "$1" >/dev/null 2>&1); then
echo "imgcat: missing dependency: can't find $1" 1>&2
exit 1
fi
}
Main
if [ -t 0 ]; then
has_stdin=f
else
has_stdin=t
fi
Show help if no arguments and no stdin.
if [ $has_stdin = f ] && [ $# -eq 0 ]; then
show_help
exit
fi
check_dependency awk
check_dependency base64
check_dependency wc
Look for command line flags.
while [ $# -gt 0 ]; do
case "(curl -s "$2" | b64_encode) || (
error "No such file or url $2"
exit 2
)
has_stdin=f
print_image "encoded_image" "{@:1:1}" "-u" "#" -eq 2 ]; then
exit
fi
;;
-*)
error "Unknown option flag: $1"
show_help
exit 1
;;
*)
if [ -r "$1" ]; then
has_stdin=f
print_image "(b64_encode <"print_filename"
else
error "imgcat: $1: No such file or directory"
exit 2
fi
;;
esac
shift
done
Read and print stdin
if [ (cat | b64_encode)" ""
fi
exit 0
把imgcat放到path中方便调用
设置可执行权限
chmod +x imgcat
复制到path之中
cp imgcat /usr/local/bin/
做完这一步,就可以使用imgcat 图片文件.png来在iterm2终端中显示图片了。

如果您是第一次使用游侠,请生成游侠配置文件。
ranger --copy-config=all
现在,您可以转到~/.config/ranger生成的文件中:
cd ~/.config/ranger
➜  ranger ls -la
总用量 132
drwxr-xr-x 2 itkey users  4096  4月 13 16:25 .
drwxr-xr-x 6 itkey users  4096  4月 13 16:07 ..
-rw-r--r-- 1 itkey users 62106  4月 13 16:25 commands_full.py
-rw-r--r-- 1 itkey users  2763  4月 13 16:25 commands.py
-rw-r--r-- 1 itkey users 24193  4月 13 16:25 rc.conf
-rw-r--r-- 1 itkey users 14071  4月 13 16:25 rifle.conf
-rwxr-xr-x 1 itkey users 13758  4月 13 16:25 scope.sh
让我们快速浏览它们:
commands.py:与以下命令一起启动的命令 :
commands_full.py:全套命令
rc.conf:配置和绑定
rifle.conf:文件关联(用于打开文件的程序)
scope.sh:负责各种文件预览
目前,对我们来说唯一重要的文件是rc.conf。在您喜欢的编辑器中将其打开,并更改以下两行,如下所示:
set preview_images false 修改成 set preview_images true
set preview_images_method w3m 修改成 set preview_images_method iterm2

配置环境变量
vim ~/.zshrc在环境变量中增加 下面一行
export RANGER_LOAD_DEFAULT_RC=FALSE
预览高度显示
安装highlight后预览就自动高度显示了,不用额外配置
sudo pacman -S  --noconfirm highlight

常用操作
大部分操作与vim类似,常用操作如下:
yy复制
dd剪切
pp粘贴
cw重命名方法1
a重命名方法2
增加图标显示
效果如下

设置方法:
https://github.com/alexanderjeurissen/ranger_devicons
从github下载代码:
git clone https://github.com/alexanderjeurissen/ranger_devicons ~/.config/ranger/plugins/ranger_devicons
echo "default_linemode devicons" >> $HOME/.config/ranger/rc.conf
第二行,意思编辑rc.conf文件,并在文件中加入:
default_linemode devicons
重新进入ranger就发现可以有图标了,这样观感就好了很多了。
如果出现字体乱码可以参考:
《macOS中iTerm或终端字体乱码解决办法》https://blog.csdn.net/lxyoucan/article/details/115695733
显示边框线

编辑rc.conf文件
#显示边框线
set draw_borders true
1
2
解决卡住
在macOS中如果开着文件预览,在快速切换文件的过程中,有极高的概率会卡住。遇到这个问题我是这么解决的。
关闭文件预览修改rc.conf set preview_files false 这样基本就没有卡住的情况了
如果不想关闭文件预览,我就不太想关,感觉有时还是挺实用的,如果遇到卡住不能动可以按 Ctrl - C 即可解除卡住的情况。
可以按W查看运行日志,知道为什么会卡,按w显示当前的任务列表。
仅预览2MB以下的文件,降低卡住概率
目前我发现卡住基本是因为预览大文件导致的,预览大文件(10MB以上的文体之类)在没有预览完成时,不停的j k 浏览文件,这样就会卡住。
修改rc.conf
只预览2MB以内的文件
set preview_max_size 2048000
经过这个设置后,我发现卡住的概率极大的减少。如果遇到大于2MB需要预览可以手动按i。
配置优化
修改配色风格
default, jungle, snow, solarized四种可选
default, jungle, snow, solarized
set colorscheme jungle
显示行号
用习惯vim的我,还是喜欢有行号的,可以 行号j k快速跳转
Possible values: false, absolute, relative.
set line_numbers relative
1
2
行号默认是从0开始的,设置成从1开始
Start line numbers from 1 instead of 0
set one_indexed true
1
2
没预览时不折叠预览区
因为我设置了只预览2MB以下的文件,如果遇到大文件不预览。默认情况下窗口会自动变大,看起来不舒服,那就把它关掉吧!
没有文件预览时,是否折叠右侧窗口
set collapse_preview false
强制在root中开启文件预览
可能是为了安全考虑,ranger默认在root用户中不启动预览功能。如何在root用户中也开启预览呢?
我在这里找到了解决办法:https://bbs.archlinux.org/viewtopic.php?id=183674
具体操作如下:
ranger按gR 进入ranger安装目录,找到ranger/core/main.py

找到Running as root, disabling the file previews.

这样操作完成后,发现在ROOT下面也可以正常预览文件了。
iterm2中alt+数字 无效
在iterm2中使用alt+数字创建tab页面无效,设置了set xterm_alt_key true依然无效。
最终解决办法:

退出ranger保留路径方法一
环境变量(如:~/.zshrc)中加入如下的函数。
ranger 自动进入目录
function ranger-cd {
# 创建一个临时文件并存储
tempfile="(mktemp -t tmp.XXXXXX)"
	# 运行ranger并要求其将最后一条路径输出到临时文件
    ranger --choosedir="tempfile" "{@:-(pwd)}"
# 如果临时文件存在,则读取并且临时文件的内容不等于当前路径
test -f "$tempfile" &&
if [ "$(cat -- "$tempfile")" != "$(echo -n `pwd`)" ]; then
	# 将目录更改为临时文件中的路径
    cd -- "$(cat "$tempfile")"
fi
# 这行删除临时文件不是非常必要,因为Linux应该在下次启动时处理它
rm -f -- "$tempfile"
}
alias rcd=ranger-cd
下次使用rcd运行ranger,退出ranger后会自动cd 进ranger浏览的目录。
退出ranger保留路径方法二(推荐)
环境变量(如:~/.zshrc),加入下面一行。
alias nav='ranger --choosedir=$HOME/.rangerdir; LASTDIR=cat $HOME/.rangerdir; cd "$LASTDIR"'
1
下次使用nav运行ranger,退出ranger后会自动cd 进ranger浏览的目录。
这种方法更简单明了,推荐使用。
使用体验总结
archlinux中使用目前没有遇到过卡顿的情况,但是在macOS中多次遇到卡死的情况。应该主要跟预览有关吧。
如果不小心点到gif图片会卡死,界面无法操作,要等一会儿才可以。
在macOS中使用ranger打开视频文本时也遇到过卡死的情况。
关闭图片预览功能就可以解决了,这个bug有可能是跟iterm2的图片预览功能有关吧。
快捷键解释
快捷键	说明
Q	全部退出
q	退出
ZZ	退出
ZQ	退出
R	刷新reload_cwd
F	冻结文件(只读模式)
~	set viewmode!
i	display_file
<right>	tab_move 1 <alt>
?	help
W	查看运行日志
w	taskview_open
S	打开命令行shell $SHELL
:	console
;	console
!	console shell%space
@	console -p6 shell %%s
console shell -p%space
s	console shell%space
r	chain draw_possible_programs; console open_with%space
f	console find%space
cd	console cd%space
cw	重命名console rename%space
ct	search_next order=tag
cs	按文件大小排序search_next order=size
ci	按文件类型排序search_next order=mimetype
cc	按创建时间排序search_next order=ctime
cm	按修改时间排序search_next order=mtime
ca	search_next order=atime
Mf	显示文件名称linemode filename
Mi	linemode fileinfo
Mm	显示时间linemode mtime
Mh	linemode humanreadablemtime
Mp	linemode permissions
Ms	linemode sizemtime
MH	linemode sizehumanreadablemtime
Mt	linemode metatitle
t	tag_toggle
ut	tag_remove
uv	取消选择mark_files all=True val=False
uV	反选toggle_visual_mode reverse=True
ud	uncut
uy	uncut
uq	tab_restore
um
um
"
v	全选或反选mark_files all=True toggle=True
V	选择模式toggle_visual_mode
k	move up=1
j	move down=1
h	move left=1
l	move right=1
gg	move to=0
gh	cd ~
ge	cd /etc
gu	cd /usr
gd	cd /dev
gl	cd -r .
gL	cd -r %f
go	cd /opt
gv	cd /var
gm	cd /media
gi	eval fm.cd(’/run/media/’ + os.getenv(‘USER’))
gM	cd /mnt
gs	cd /srv
gp	cd /tmp
gr	cd /
gR	eval fm.cd(ranger.RANGERDIR)
g/	cd /
g?	cd /usr/share/doc/ranger
gt	tab_move 1
gT	tab_move -1
gn	tab_new
gc	tab_close
G	move to=-1
J	move down=0.5 pages=True
K	move up=0.5 pages=True
H	history_go -1
L	history_go 1
]	move_parent 1
[	move_parent -1
}	traverse
{	traverse_backwards
)	jump_non
E	edit
du	shell -p du --max-depth=1 -h --apparent-size
dU	shell -p du --max-depth=1 -h --apparent-size | sort -rh
dD	console delete
dT	console trash
dd	cut
da	cut mode=add
dr	cut mode=remove
dt	cut mode=toggle
dgg	eval fm.cut(dirarg=dict(to=0), narg=quantifier)
dG	eval fm.cut(dirarg=dict(to=-1), narg=quantifier)
dj	eval fm.cut(dirarg=dict(down=1), narg=quantifier)
dk	eval fm.cut(dirarg=dict(up=1), narg=quantifier)
dc	get_cumulative_size
yp	复制文件全路径
yd	复制文件目录路径
yn	复制文件名
y.	复制文件名不包含扩展名
yy	复制文件
ya	copy mode=add
yr	copy mode=remove
yt	copy mode=toggle
ygg	eval fm.copy(dirarg=dict(to=0), narg=quantifier)
yG	eval fm.copy(dirarg=dict(to=-1), narg=quantifier)
yj	eval fm.copy(dirarg=dict(down=1), narg=quantifier)
yk	eval fm.copy(dirarg=dict(up=1), narg=quantifier)
=	chmod
a	rename_append
A	eval fm.open_console('rename ’ + fm.thisfile.relative_path.replace("%", “%%”))
I	eval fm.open_console('rename ’ + fm.thisfile.relative_path.replace("%", “%%”), position=7)
pp	粘贴
po	粘贴 强制覆盖
pP	paste append=True
pO	paste overwrite=True append=True
pl	粘贴软链接paste_symlink relative=False
pL	paste_symlink relative=True
phl	paste_hardlink
pht	paste_hardlinked_subtree
pd	console paste dest=
p 
p' 
/	console search%space
n	search_next
N	search_next forward=False
or	反转排序set sort_reverse!
oz	set sort=random
os	根据文件大小排序 chain set sort=size; set sort_reverse=False
ob	根据文件名称排序 chain set sort=basename; set sort_reverse=False
on	chain set sort=natural; set sort_reverse=False
om	根据修改时间排序chain set sort=mtime; set sort_reverse=False
oc	chain set sort=ctime; set sort_reverse=False
oa	chain set sort=atime; set sort_reverse=False
ot	chain set sort=type; set sort_reverse=False
oe	chain set sort=extension; set sort_reverse=False
oS	chain set sort=size; set sort_reverse=True
oB	chain set sort=basename; set sort_reverse=True
oN	chain set sort=natural; set sort_reverse=True
oM	chain set sort=mtime; set sort_reverse=True
oC	chain set sort=ctime; set sort_reverse=True
oA	chain set sort=atime; set sort_reverse=True
oT	chain set sort=type; set sort_reverse=True
oE	根据扩展名排序 chain set sort=extension; set sort_reverse=True
zc	set collapse_preview!
zd	切换目录是否排在文件前面set sort_directories_first!
zh	set show_hidden!
zI	set flushinput!
zi	切换是否预览图片set preview_images!
zm	切换是否允许鼠标set mouse_enabled!
zp	切换是否预览文件set preview_files!
zP	切换是否预览目录set preview_directories!
zs	set sort_case_insensitive!
zu	set autoupdate_cumulative_size!
zv	set use_preview_script!
zf	过滤文件console filter%space
zz	过滤文件console filter%space
.d	只显示目录filter_stack add type d
.f	只显示文件filter_stack add type f
.l	filter_stack add type l
.m	console filter_stack add mime%space
.n	console filter_stack add name%space
.#	console filter_stack add hash%space
."	filter_stack add duplicate
.’	filter_stack add unique
.|	filter_stack add or
.&	filter_stack add and
.!	filter_stack add not
.r	filter_stack rotate
.c	filter_stack clear
.*	filter_stack decompose
.p	filter_stack pop
…	filter_stack show
```	draw_bookmarks
’<any>	enter_bookmark %any
’<bg>	draw_bookmarks
m<any>	set_bookmark %any
m<bg>	draw_bookmarks
+ur	shell -f chmod u+r %s
+uw	shell -f chmod u+w %s
+ux	shell -f chmod u+x %s
+uX	shell -f chmod u+X %s
+us	shell -f chmod u+s %s
+ut	shell -f chmod u+t %s
+gr	shell -f chmod g+r %s
+gw	shell -f chmod g+w %s
+gx	shell -f chmod g+x %s
+gX	shell -f chmod g+X %s
+gs	shell -f chmod g+s %s
+gt	shell -f chmod g+t %s
+or	shell -f chmod o+r %s
+ow	shell -f chmod o+w %s
+ox	shell -f chmod o+x %s
+oX	shell -f chmod o+X %s
+os	shell -f chmod o+s %s
+ot	shell -f chmod o+t %s
+ar	shell -f chmod a+r %s
+aw	shell -f chmod a+w %s
+ax	shell -f chmod a+x %s
+aX	shell -f chmod a+X %s
+as	shell -f chmod a+s %s
+at	shell -f chmod a+t %s
+r	shell -f chmod u+r %s
+w	shell -f chmod u+w %s
+x	shell -f chmod u+x %s
+X	shell -f chmod u+X %s
+s	shell -f chmod u+s %s
+t	shell -f chmod u+t %s
-ur	shell -f chmod u-r %s
-uw	shell -f chmod u-w %s
-ux	shell -f chmod u-x %s
-uX	shell -f chmod u-X %s
-us	shell -f chmod u-s %s
-ut	shell -f chmod u-t %s
-gr	shell -f chmod g-r %s
-gw	shell -f chmod g-w %s
-gx	shell -f chmod g-x %s
-gX	shell -f chmod g-X %s
-gs	shell -f chmod g-s %s
-gt	shell -f chmod g-t %s
-or	shell -f chmod o-r %s
-ow	shell -f chmod o-w %s
-ox	shell -f chmod o-x %s
-oX	shell -f chmod o-X %s
-os	shell -f chmod o-s %s
-ot	shell -f chmod o-t %s
-ar	shell -f chmod a-r %s
-aw	shell -f chmod a-w %s
-ax	shell -f chmod a-x %s
-aX	shell -f chmod a-X %s
-as	shell -f chmod a-s %s
-at	shell -f chmod a-t %s
-r	shell -f chmod u-r %s
-w	shell -f chmod u-w %s
-x	shell -f chmod u-x %s
-X	shell -f chmod u-X %s
-s	shell -f chmod u-s %s
-t	shell -f chmod u-t %s
Keybindings	in `console’
<c-i>	eval fm.ui.console.tab()
<s-tab>	eval fm.ui.console.tab(-1)
<escape>	eval fm.ui.console.close()
<c-j>	eval fm.ui.console.execute()
<c-l>	redraw_window
<c-c>	eval fm.ui.console.close()
<up>	eval fm.ui.console.history_move(-1)
<down>	eval fm.ui.console.history_move(1)
<left>	eval fm.ui.console.move(left=1)
<right>	eval fm.ui.console.move(right=1)
<home>	eval fm.ui.console.move(right=0, absolute=True)
<end>	eval fm.ui.console.move(right=-1, absolute=True)
<alt>b	eval fm.ui.console.move_word(left=1)
<alt>f	eval fm.ui.console.move_word(right=1)
<alt>``<left>	eval fm.ui.console.move_word(left=1)
alt>```	eval fm.ui.console.move_word(right=1)
<alt>d	eval fm.ui.console.delete_word(backward=False)
<backspace>	eval fm.ui.console.delete(-1)
<delete>	eval fm.ui.console.delete(0)
<c-w>	eval fm.ui.console.delete_word()
<c-k>	eval fm.ui.console.delete_rest(1)
<c-u>	eval fm.ui.console.delete_rest(-1)
<c-y>	eval fm.ui.console.paste()
<c-g>	eval fm.ui.console.close()
<c-p>	eval fm.ui.console.history_move(-1)
<c-n>	eval fm.ui.console.history_move(1)
<c-b>	eval fm.ui.console.move(left=1)
<c-f>	eval fm.ui.console.move(right=1)
<c-a>	eval fm.ui.console.move(right=0, absolute=True)
<c-e>	eval fm.ui.console.move(right=-1, absolute=True)
<c-d>	eval fm.ui.console.delete(0)
<c-h>	eval fm.ui.console.delete(-1)
backspace2>`	eval fm.ui.console.delete(-1)
allow_quantifiers>`	false
Keybindings	in `pager’
<down>	pager_move down=1
<up>	pager_move up=1
<left>	pager_move left=4
<right>	pager_move right=4
<home>	pager_move to=0
<end>	pager_move to=-1
<pagedown>	pager_move down=1.0 pages=True
<pageup>	pager_move up=1.0 pages=True
<c-d>	pager_move down=0.5 pages=True
<c-u>	pager_move up=0.5 pages=True
k	pager_move up=1
<c-p>	pager_move up=1
j	pager_move down=1
<c-n>	pager_move down=1
<c-j>	pager_move down=1
h	pager_move left=4
l	pager_move right=4
g	pager_move to=0
G	pager_move to=-1
d	pager_move down=0.5 pages=True
u	pager_move up=0.5 pages=True
n	pager_move down=1.0 pages=True
f	pager_move down=1.0 pages=True
<c-f>	pager_move down=1.0 pages=True
<space>	pager_move down=1.0 pages=True
p	pager_move up=1.0 pages=True
b	pager_move up=1.0 pages=True
<c-b>	pager_move up=1.0 pages=True
<c-l>	redraw_window
<escape>	pager_close
q	pager_close
Q	pager_close
i	pager_close
<f3>	pager_close
E	edit_file
Keybindings	in `taskview’
<up>	taskview_move up=1
<down>	taskview_move down=1
<home>	taskview_move to=0
<end>	taskview_move to=-1
<pagedown>	eval -q fm.ui.taskview.task_move(-1)
<pageup>	eval -q fm.ui.taskview.task_move(0)
<c-d>	taskview_move down=0.5 pages=True
<c-u>	taskview_move up=0.5 pages=True
k	taskview_move up=1
<c-p>	taskview_move up=1
j	taskview_move down=1
<c-n>	taskview_move down=1
<c-j>	taskview_move down=1
g	taskview_move to=0
G	taskview_move to=-1
u	taskview_move up=0.5 pages=True
n	taskview_move down=1.0 pages=True
f	taskview_move down=1.0 pages=True
<c-f>	taskview_move down=1.0 pages=True
<space>	taskview_move down=1.0 pages=True
p	taskview_move up=1.0 pages=True
b	taskview_move up=1.0 pages=True
<c-b>	taskview_move up=1.0 pages=True
J	eval -q fm.ui.taskview.task_move(-1)
K	eval -q fm.ui.taskview.task_move(0)
dd	eval -q fm.ui.taskview.task_remove()
<delete>	eval -q fm.ui.taskview.task_remove()
<c-l>	redraw_window
<escape>	taskview_close
q	taskview_close
Q	taskview_close
w	taskview_close
<c-c>	taskview_close
参考
《RANGER IMAGE PREVIEW ON OSX WITH ITERM2》
https://www.everythingcli.org/ranger-image-preview-on-osx-with-iterm2/
《File icons for the Ranger file manager》https://github.com/alexanderjeurissen/ranger_devicons
《Add filetype glyphs (icons) 》https://github.com/ranger/ranger/issues/298
《osx can’t use alt- to switch tab》https://github.com/ranger/ranger/issues/420
《如何退出Ranger文件浏览器回到命令提示符,但保留当前目录?》
https://qastack.cn/superuser/1043806/how-to-exit-the-ranger-file-explorer-back-to-command-prompt-but-keep-the-current-directory