BNU-FZH

fengzhenhua@outlook.com

Emacs 是神的编辑器,而 Vim 是编辑器之神。二者为何会有如此美誉,且听本文向你一一道来。

0. 序章:神器的传说

在这个蔚蓝色的星球上,流传着两大神器的传说: 据说Emacs是神的编辑器,而Vim是编辑器之神。

追求独步天下的高手和低手们争着一睹它们的风采,可看到它们朴素单薄的界面后,不禁心下怀疑:这就是神器吗?甚至有人生了轻视之心。

肤浅的人嗤之以鼻,说:什么年代了,还抱着这么老土的玩意不放,真他妈Geek!同学,请冷静下来,听我说:它们的确够老了,都几十年的寿命了,但你想想为什么,为什么这么古老的编辑器,却有越来越多的人皈依它们。

Windows下用UltraEdit和Editplus的人质问:它们到底比UltraEdit和Editplus好在哪里?我说:不可同日而语。

连UltraEdit和EditPlus都没用过的同学问:它们就相当于Linux上的 Notepad吧?我说:请你从我的眼前消失。

一些人勇敢地拾起了Vim或Emacs,却发现学习曲线陡峭而漫长,于是在没发现它们的强大之前就放弃了,说:太难用了,把键盘当鼠标用的烂玩意,有什么好的?

还是有一些人留下来了,坚定地守护着这两大神器。一些说葡萄太酸的人想离开又不甘心,总是问:它们到底神在哪里啊?我不禁想起了李宗盛的几句歌词:

1
2
3
4
<span></span>有人问我你究竟是哪里好,
这么多年我还忘不掉?
春风再美也比不上你的笑,
没见过你的人不会明了。

也许你不会明了,我还是要努力讲一讲。

1. 无敌的可扩展性

1.1 可扩展性给了软件强大的生命

曾几何时,Windows用户对软件的可扩展性没有概念,他们只能对他们使用的软件进行非常有限的定制。扩展软件的权利保留在软件开发者手中。软件的使用者如果想要新的功能和特性,只能等待软件的升级。有能力的用户等不及了,为了添加自己想要的功能,从0开始写了一款新的软件。就这样,新的功能意味着新的软件,Windows下的软件前赴后继,迅速地更新换代着。因此,Windows下的软件都很短命。

Linux和开源软件渐渐流行起来,人们才发现:可扩展性才能给软件强大的生命。在MS的VS横行的今天,Eclipse为什么被评为最好的IDE?就是因为它在IDE中最具可扩展性。在IE几乎一统天下的时候,为什么Firefox能夺走越来越多的用户,也是因为它的可扩展性。提供了良好的扩展接口,用户自然会写出各种各样的插件,来满足用户自己形形色色的要求。这样,软件在用户的推动下自然变得强大了。

Emacs和Vim没有被时代淘汰,反而越发强大,也正是因为在数不清的编辑器中,他们具有无可匹敌的可扩展性。

1.2 Emacs是伪装成编辑器的操作系统

有句夸张的话说:Emacs是伪装成编辑器的操作系统。细细想来,这句话并不夸张。

Emacs其实是个Lisp的解释器,因此可以用Lisp灵活地扩展。Lisp是什么东西,这同样是种很有生命力的编程语言。在C语言还没有发明的年代,MIT的人工智能实验室写ITS操作系统时,一部分用的是汇编语言,还有一部分就是用的Lisp。现在,Lisp仍在人工智能研究领域广泛使用着。

有这么牛逼的扩展语言,注定Emacs向着无所不能的方向发展。渐渐地,人们用Emacs不再限于写程序,写文档,而且在Emacs里管理文件系统,运行终端,收邮件,上网,听音乐……,真是一发不可收拾。甚至,有人用Emacs控制咖啡机煮咖啡。

这种大而全的扩展,背离了“一个程序只做一件事并做好它”的Unix哲学,被Unix的忠诚用户所诟病。可是真的背离了吗?Emacs说过自己是一个编辑器吗?

正是因为Emacs的无敌的可扩展性,人们才分不清Emacs到底是不是一个编辑器了。但,就是有人喜欢这种All-in-One的哲学,喜欢在Emacs中完成每件事。所以才会有人写《生活在Emacs中》,所以,Emacs才会成为一种信仰。

1.3 Vim不只是Vi

Vim是Vi最受欢迎的变种之一,除了继承了Vi迅捷的编辑方式,Vim的功能已经比原始的Vi强大得多。这也得益于它可以用Vim脚本无限地扩展。Vim.org 上已经有数千个脚本了,给Vim增加各种各样的特性和功能。

为了证明Vim的可扩展性不输于Emacs,也有用户写了在Vim中玩游戏、运行Shell、和集成GDB在Vim内部调试的插件。客观地讲,Vim的脚本语言与Emacs的ELisp相比,略显逊色,但这丝毫不妨碍它把Vim扩展成非常优秀的编辑器。

说到底,Vim的前身Vi和Emacs的设计采用了不同的哲学,Vi更符合Unix传统,它通过管道机制和系统内各种积木工具打交道,它讲究的是和系统内的工具程序协作来完成用户的任务。和Emacs相比,它的定位很明确,就是要做一个强大的编辑器。因此Vim的绝大部分扩展,都是为了更好地完成编辑文本的任务。

海纳百川,有容乃大。Emacs和Vim通过别的编辑器无法比肩的可扩展性,不断吸收广大用户的智慧,是它们能成为“神器”的原因之一。

2. 特立独行的魅力

2.1 可扩展性让你倾注了灵魂

一旦你意识到Vim或Emacs的强大,你就踏上了不停发掘它们潜力的漫漫长路。你不停地改进自己的配置文件,你不停地搜索更好的插件,甚至有一天你开始动手写自己的插件。就像剑客保养自己的剑一样,你也甘心花时间提升你的Vim或Emacs。经年累月,不知不觉,你已经在那把剑上倾注了你的灵魂。

2.2 独特的操作方式让你中了毒

Emacs和Vim有着迥异的操作方式,却成了Unix/Linux世界中两种代表性的操作方式,有些软件的操作方式类似Vi,而有些软件的方式类似Emacs,甚至有些软件提供了Vi的键绑定和Emacs的键绑定让你选择。而无论哪种操作方式,对Windows用户来说都是古怪的。虽说古怪,多少代人也验证了这两种操作方式的高效。

Emacs号称Ctrl到死的编辑器。其实它几乎用了所有的辅助键,听说过没有,Emacs = Esc + Meta + Alt + Ctrl + Shift。所以高德纳大师说操作Emacs,就像弹奏管风琴。Emacs使用非常多的组合按键,这大概也是它高效于其它无模式编辑器的原因之一。你也可以定义自己的组合键序列,调用自己写的lisp函数,完成自己想要的功能。

Vi一向是以快速的文本编辑闻名于世的。它的按键更简洁,通常是单个字符按键,就实现某种操作。但这是以有模式为代价的。你要不停地按Esc在从它的插入模式返回Normal模式。客观得讲,在文本编辑方面,Vim比Emacs高效,因为它提供了一些Emacs没有对应功能的操作来辅助高效的文本编辑。但它的模式切换也让一些人受不了,于是那些人选择了Emacs。

不管你选择了Vim还是Emacs,你都要为习惯它们独特的操作方式而努力,这是一个技艺积累的过程。当你习惯了Vim或Emacs,你会有欲罢不能的感觉,你希望用它们完成尽可能多的任务,因为你再用别的编辑器也已经不习惯。

用Vim或Emacs就像吸食毒品,慢慢地就会上瘾。它们会带给你渐渐强烈的快感,但你也向它们献出了自己的灵魂。这时,你只能称它们为神器。

3. 黑客的编辑器

Vim的前身Vi的作者Bill Joy和Emacs的作者Richard Stallman都是那个时代著名的黑客,所以这两款编辑器一开始面向的主要用户就是写程序的人,现在仍然是。它们对编程加入了越来越多的支持,如语法高亮、智能缩进、关键字补全甚至集成调试。也有越来越多的程序员从IDE转向了Vim和Emacs。

用Vim和Emacs编程到底有什么好处?我想首先是它们高效的编辑操作会提高你的编程效率。其次你可以用它们完成各种语言的编程,所谓一剑在手,夫复何求。你不用再因为编程语言不同去学习不同的IDE的使用,那些庞大的IDE的升级换代也与你再不相关,你把精力用于学习编程语言本身就好了。听说Google和微软内部开发也都不用IDE的,他们也会用Emacs或Vim。

因为我写的程序不多,还不能深入体会用Vim或Emacs开发程序的乐趣。我只是觉得这很酷,你看,Linux之父Linus多年来用的是一款MicroEmacs,它比GNU Emacs或XEmacs少许多功能,但Linus就是用它在维护Linux。 微软的大牛Don Box,Com之父,一直用Emacs,他说谁也不能夺走他的编辑器。他还在网上放了一段他用Emacs写C#程序的视频。

编程大师们的选择,也是Emacs和Vim被追捧为神器的原因之一。

4. 神器引发的圣战

Vim用户和Emacs用户有着旗鼓相当的品位,应该互相欣赏才对。现实却是,忠诚于Vim的用户和忠诚于Emacs的用户互不相容,常常没完没了地打口水仗。Emacs用户说Vim的操作方式单一而古怪,Vim用户说Emacs体积庞大,启动缓慢。

很有点一山不容二虎的意思,大概因为二者都处于神器的高度,才会斗争不断吧。也可能是因为二者截然不同的设计哲学吸引的用户在价值观上也互不认同。

正因为两者难分高下,新人总是在Vim和Emacs之间犹豫不定,很难决定到底要皈依哪一个神。

参考文章

为何 Emacs 和 Vim 被称为两大神器

normal模式下

移动/编辑相关

快捷键 作用
h
j
k
l
ctrl + j/k 上下跳4行
ctrl + u/d 上下9行
i 在光标前插入
a 在光标后插入
A 到末尾插入
I 到首插入
s 删当前字符并进入插入模式
zc 折叠代码
zo 打开折叠
u 撤销上一次代码修改/undo
ctrl + r 与u相反/redo

tab/buffer/标签相关(按vim的用法来说应该叫buffer)

快捷键 作用
ctrl + h/l 左右切换tab
ctrl + w 关闭当前tab
<leader>bl 关闭右边所有tab
<leader>bh 关闭左边所有tab
<leader>bc 选择关闭tab

窗口相关

快捷键 作用
option + h/j/k/l 左下上右切换窗口
sv 左右分屏
sh 上下分屏
sc 关闭当前窗口
<leader> + t 底部打开terminal
<leader> + vt 侧边打开terminal
s, 当前窗口左右比例缩小
s. 当前窗口左右比例放大
sj 当前窗口上下比例放大
sk 当前窗口上下比例缩小

tree(侧边栏)相关

快捷键 作用
ctrl + m 隐藏与显示tree
Enter 打开tree中选中的文件
v 左右分屏打开
h 上下分屏
i 忽略node_modules
. 显示与隐藏隐藏文件
F5 refresh file
a create file
d remove file
r rename file
x cut file
c copy file
p paste file
s system_open file
o open file

telescope搜索相关

快捷键 作用
ctrl + p 搜索文件
ctrl + f 全局搜索
ctrl + j 向下移动选择文件
ctrl + k 向上移动选择文件
ctrl + n 历史搜索下一个
ctrl + p 历史搜索上一个
ctrl + c 关闭搜索页面
ctrl + u 预览上滚
ctrl + d 预览下滚

LSP相关

快捷键 作用
gd 跳到变量的定义处
gh 悬浮显示当前变量的信息
gp 显示当前文件的错误的代码信息
gj 跳到下一个错误代码的地方
gk 跳到上一个错误代码的地方
<leader> + f 格式化代码
ctrl + j/n 选择下一个提示
ctrl + k/p 选择上一个提示
Enter 确认选择
<leader> + rn 重命名变量名

退出

快捷键 作用
q :q
qq :q!
Q :qa!

Inser模式下

移动/编辑相关

快捷键 作用
option + h/j/k/l 左下上右移动
ctrl + b 到末尾
ctrl + e 到首
ctrl + j 开辟新行

Visual模式下

移动相关

快捷键 作用
j 向下移动代码
k 向上移动选中的代码
< 左缩进代码
右缩进代码
= 选中代码后格式化代码

常用命令

命令 作用
:q 退出
:q! 强制退出
:w 保存
:qa 退出并关闭
:qa! 强制退出并关闭
:wq 保存并退出
:PackerCompile 每次改变插件配置时,必须运行此命令或 PackerSync, 重新生成编译的加载文件
:PackerClean 清除所有不用的插件
:PackerInstall 清除,然后安装缺失的插件
:PackerUpdate 清除,然后更新并安装插件
:PackerSync(最常使用) 执行 PackerUpdate 后,再执行 PackerCompile
:h base-directories 查看详细文档
:echo stdpath("data") 查看你系统下Neovim的数据存储在标准数据目录的实际路径
:colorscheme Tab键 查看内置主题色
:echo $VIMRUNTIME 查看VIMRUNTIME 具体的路径
:h nvim-tree.setup 查看nvim-tree的帮助文档
:NvimTreeToggle 再按Enter即可打开或关闭侧边栏
:checkhealth telescope 检查telescope依赖情况
:Telescope find_files 打开搜索文件窗口,快速打开文件
:Telescope live_grep 可以打开搜索窗口,输入内容后,结果会实时显示
:Telescope buffers 命令可以列出打开的 buffers
:Telescope git_files 列出 git 文件
:Telescope man_pages 列出帮助
:Telescope env 打开环境变量列表
Telescope colorscheme 换肤功能
:TSInstallInfo 命令查看 language parsers 列表与安装状态
:TSInstall <language_to_install> 安装指定的 Language parser 例如:TSInstall javascript
:TSModuleInfo 查看你的模块是否开启成功
LSP相关命令
:h lsp 查看 LSP 文档
:LspInstallInfo 安装 LSP Servers的图形化界面
j/k 移动光标到你要安装的 server
i 安装server
X 卸载该 server
u 更新 server
U 更新所有 servers
c 检查 server 新版本
C 检查所有 servers 的新版本
Esc 关闭窗口
? 显示其他帮助信息
:LspInfo 查看绑定的 Language Server 信息
:NullLsInfo 查看源的激活情况
:lua vim.lsp.buf.formatting_sync() 格式化代码
:lua vim.lsp.buf.formatting_sync(nil, 9999) 不加参数可能会报Time out
echo executable('xxx') 查看某个命令是否可用 例如echo executable('rubocop')查看rubocop是否可用,一般用来排查格式化代码时需要的命令是否已安装

参考文章

Neovim 是一个现代的、快速的且与vim完全兼容的文本编辑器。它支持插件、LSP、GUI、web browsers 等等。各种各样的插件可以极大的提高Neovim的工作效率,随着使用时间的增加安装的插件也越来越多,所以有必要使用一个管理插件的插件来规范管理大量的插件,这样的插件称为插件管理器。Neovim 有各种各样的插件管理器,本文的目的就是列出这些常用的插件管理器,以方便读者选择。

  • lazy.nvim: lazy.nvim is a modern plugin manager for Neovim.
  • pckr.nvim: Spiritual successor of https://github.com/wbthomason/packer.nvim
  • packer.nvim: packer.nvim is currently unmaintained. For the time being (as of August, 2023), it is recommended to use one of the following plugin managers instead: lazy.nvim or pckr.nvim
  • paq-nvim: Paq is a Neovim package manager written in Lua.
  • neopm:Plugin manager for neovim, pre-alpha stage. Expect breaking changes.
  • dep: A versatile, declarative and correct neovim package manager in Lua. Originally written for personal use by luaneko.
  • optpack.nvim: This is a neovim plugin manager that uses only opt package.
  • pact.nvim: pact is a semver focused, pessimistic plugin manager for Neovim.
  • vim-plug:A minimalist Vim plugin manager.Just one file with no dependencies. Super easy to set up.
  • Vundle.vim:Vundle is short for Vim bundle and is a Vim plugin manager.
  • pathogen.vim:Manage your 'runtimepath' with ease. In practical terms, pathogen.vim makes it super easy to install plugins and runtime files in their own private directories.
  • dein.vim: Dein.vim is a dark powered Vim/Neovim plugin manager.
  • volt: Multi-platform CLI tool managing Vim plugin life

项目地址:https://github.com/echasnovski/mini.nvim

项目简介

Mini.nvim 是一个由开发者 echasnovski 创建的简洁高效的Neovim配置库。它旨在提供一个基础但全面的功能集,让你的Neovim体验既精简又高效。作为一个开源项目,Mini.nvim 已经吸引了众多用户和贡献者,并且持续更新以适应不断变化的开发需求。

技术分析

Neovim 基础

Neovim 是 Vim 的一个分支,具有更高的可扩展性和性能优化。Mini.nvim 利用了 Neovim 的这些优势,通过精心挑选的插件和配置,实现了极佳的交互性和速度。

Lua 配置

Mini.nvim 使用 Lua 语言进行配置,这是一种轻量级、快速且易于阅读的语言。Lua 的使用使得配置文件更易理解,降低了维护难度,同时也方便了对现有配置的个性化修改。

插件选择

该项目选用了诸如 nvim-lspconfig(用于语言服务器协议支持), telescope.nvim(用于查找和选择文件),和 treesitter(语法高亮和结构解析)等优秀插件,为开发环境提供了强大的功能,而不会牺牲性能。

敏捷性与性能

Mini.nvim 的设计注重启动速度和运行效率。它的核心理念是“只加载你需要的东西”,避免了不必要的资源消耗,确保在日常使用中流畅无阻。

应用场景

  • 开发环境: Mini.nvim 提供了一套完整的 LSP 支持,可以满足大多数编程语言的代码智能提示和自动完成。
  • 文本编辑: 对于日常文档编辑,其优秀的搜索、替换和导航工具使工作效率倍增。
  • 远程工作: 在低带宽或资源有限的环境中,Mini.nvim 的轻量化特性尤为突出。

特点

  1. 简洁 - 只包含必要的组件,避免了过度配置。
  2. 模块化 - 容易添加或移除特定功能,便于自定义。
  3. 高性能 - 专为速度和低内存占用优化。
  4. 可扩展 - 灵活地与新的插件和配置集成。
  5. 社区驱动 - 有活跃的开发社区支持,问题反馈和新特性更新迅速。

结语

无论是初识Neovim的新手,还是寻求简约高效的老手,Mini.nvim 都是一个值得尝试的选择。其优化的配置和强大的功能组合,能够提升你的编辑器体验,助你在编程旅程中更加得心应手。

项目简介

Gogh 是一个为终端用户提供高度可定制主题的Go语言项目。它允许你在终端中轻松切换和个性化你的命令行界面,让你的日常操作变得更有趣,更具个性化。

技术分析

Gogh 基于 Go 语言编写,这使得它具有良好的跨平台支持和优秀的性能。其设计理念是简洁、易用,通过提供一系列预设的主题,同时也支持用户自行创建和管理主题。它的核心功能包括:

  1. 主题库:Gogh 内置了丰富的主题集合,你可以方便地选择并应用。
  2. 动态配置:在运行时可以实时更改主题,无需重启终端。
  3. 颜色检测:自动检测并适应256色或真彩色终端。
  4. 易于扩展:由于使用Go语言,开发者可以通过简单的API来添加新的主题或者修改现有功能。

应用场景

无论你是初级用户还是经验丰富的开发人员,Gogh 都能在提升你的终端体验方面发挥大作用:

  • 美化工作环境:让每天都要面对的命令行更加美观舒适,提升工作效率。
  • 教育用途:通过改变终端样式,帮助初学者更好地理解和区分不同的命令输出。
  • 个人品牌化:自定义独特的主题,展示你的个性和技术风格。

特点与优势

  1. 轻量级:Gogh 的体积小,不占用过多系统资源,适用于各种环境。
  2. 兼容性好:不仅支持主流的Linux发行版,也兼容macOS和Windows系统。
  3. 社区活跃:持续更新和完善,社区成员积极贡献新主题和建议。
  4. 安装便捷:只需一行命令即可完成安装,简单快速。

结语

如果你对个性化你的终端界面感兴趣,或者想要给你的命令行体验带来一点新鲜感,那么 Gogh 绝对值得一试。尝试一下,看看哪个主题能最好地匹配你的工作风格,或是激发你的创造力吧!开始你的Gogh之旅,让每一次敲击命令都成为视觉享受。

1
2
# 使用以下命令安装 Gogh(根据你的操作系统选择合适的命令)
curl -sSfL https://raw.githubusercontent.com/Mayccoll/Gogh/master/install.sh | sh -

现在,你可以用gogh themes查看所有可用主题,然后使用gogh apply <theme_name>来设置你喜欢的主题。享受这个过程,并分享你的定制成果吧!

一直使用Neovim作为日常办公的主力,偶尔也使用一下系统的剪切板从外部粘贴文本,在X11时直接使用鼠标就能直接粘贴到Neovim中,但是系统升级到wayland之后,每次点鼠标粘贴时都会弹出一个确认的对话框,点击之后才粘贴上!这很影响办公效率,于是今天决定认真对待一下这个问题。启动Neovim,然后输出命令:h clipboard就可以看到全部详细信息了,为了提高效率,此处记录关键内容。

Vim与Neovim使用系统剪切板的不同

Nvim has no direct connection to the system clipboard. Instead it depends on a |provider| which transparently uses shell commands to communicate with the system clipboard or any other clipboard "backend".

设置Neovim所有操作使用剪切板

要始终将剪贴板用于所有操作(而不是显式地与“+”和/或“*”寄存器交互, 需要设置init.vim中加入:

1
set clipboard+=unnamedplus

安装剪切板依赖

The presence of a working clipboard tool implicitly enables the '+' and "*" registers. Nvim looks for these clipboard tools, in order of priority:

  • |g:clipboard| (unless unset or false)
  • pbcopy, pbpaste (macOS)
  • wl-copy, wl-paste (if $WAYLAND_DISPLAY is set)
  • waycopy, waypaste (if $WAYLAND_DISPLAY is set)
  • xsel (if $DISPLAY is set)
  • xclip (if $DISPLAY is set)
  • lemonade (for SSH) https://github.com/pocke/lemonade
  • doitclient (for SSH) https://www.chiark.greenend.org.uk/~sgtatham/doit/
  • win32yank (Windows)
  • termux (via termux-clipboard-set, termux-clipboard-set)
  • tmux (if $TMUX is set)

由于我的电脑同时支持waylandx11, 所以我直接安装了wl-clipboardxclip, 其中wl-clipboard提供命令wl-copywl-paste

在Neovim的粘贴快捷键

"Paste" is a separate concept from |clipboard|: paste means "dump a bunch of text to the editor", whereas clipboard provides features like |quote+| to get and set the OS clipboard directly. For example, middle-click or CTRL-SHIFT-v (macOS: CMD-v) in your terminal is "paste", not "clipboard": the terminal application (Nvim) just gets a stream of text, it does not interact with the clipboard directly.

能过这段话我们可知,在Linux下,使用命令CTRL-SHIFT-v就可以直接将剪切板中的内容粘贴到Neovim中了,在macOS中使用命令CMD-v.

在科研论文中,图片是一个非常重要的组成部分。LaTeX 提供了许多定制化图片的功能。这篇文章将会介绍如何用最常见的格式插入图片、缩放图片、旋转图片,以及如何在文档中引用这些图片。实现插入图片的功能需要在导言引用graphicsgraphicx, 下面就一些重要的点展开讨论。

图片的路径

当你的文档拥有很多个图片的时候,创建多个文件夹来存储图片是一个规划项目的好办法。

命令\graphicspath{ {images/} }告诉 LaTeX 在_images_文件夹中寻找图片。这个路径是当前工作文件夹的相对路径,所以,编译器会在当前文档所在的目录中开始寻找文件。文件夹的路径默认情况下是相对路径,如果没有一个初始的目录被指定,例如:

1
2
%Path relative to the .tex file containing the \includegraphics command
\graphicspath{ {images/} }
阅读全文 »

有时候在编写LaTeX文件时需要插入图片,但是图片源自网络,这时可以使用\write18调用外部命令,下载图片,然后再插入到文件中,引用网络上的一个具体例子为:

\write18 插入图片
1
2
3
4
5
6
\documentclass{article}
\usepackage{graphix}
\begin{document}
\write18{wget http://www.some-site.com/path/to/image.png}
\includegraphic{image.png}
\end{document}

参考:LaTeX技巧427:LaTeX如何插入网络上的图片?

在日常编写脚本的过程中,不可避免的可打开一些文件进行编辑,对于一些特定的文件可以使用某相应的软件打开。但是,若脚本需要处理的有各种各样的文件,若针对每一个文件都设计一个对应程序来打开,原理上可行,但是比较麻烦。现在的Linux基本都内置了命令xdg-open, 它可以自动调用系统的默认程序打开文件,可以大大提高脚本的效率。为了方便查询,此贴出它的帮助文件:

xdg-open --help
1
2
3
4
5
6
7
8
9
10
   xdg-open -- opens a file or URL in the user's preferred
application

Synopsis

xdg-open { file | URL }

xdg-open { --help | --manual | --version }

Use 'man xdg-open' or 'xdg-open --manual' for additional info.

提出这个要求是因为我今天在脚本xugit.sh中加入了根据选项打开文件,避免每次都切换路径的麻烦。尽管有z-lua等路径切换插件,但是在连接U盘时,使用ugit -l选择文件再打开,更加直接。

使用diary.sh写博客已经有近两年了,对于菜单一直没有细致的设计,这主要是因为对Shell理解的不够透彻。今天实现了真正意义上的可选择菜单,实现原理是:不再使用clear每次按键后清屏,改用指定行输出来输出菜单!这样就可以避免每按一次键就闪烁一次的不好体验,同时对于一屏的信息,当只有一二行发生变化时,整体上看很流畅:

运行截图展示

可选择菜单

可选择菜单支持vim的快捷键,即j向下,k向上,同时J向下一页,K向上一页.

shell源代码

可选择菜单shell源码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
DY_FILES=($(ls /home/$USER/))  #设置用来列表输出的数组, 此处可以改为您自己的路径
DY_SET_SIZE(){
TTY_H=$(stty size|awk '{print $1}')
let TTY_H-=2
TTY_W=$(stty size|awk '{print $2}')
}
DY_LINE="-"
DY_MKLINE(){
l=0
while [ $l -lt $TTY_W ]; do
echo -n "$DY_LINE"
let l+=1
done
}
NEO_FORMAT=7 # 高亮行的格式,可以自行修改
# 参数: 输出行,行号,数组号, 高亮行号
NEO_PRINT(){
if [[ $3 -eq $4 ]]; then
echo -e "\033[$1;1H\033[?25l\033[${NEO_FORMAT}m[$2] ${NEO_ARR[$3-1]}\033[0m\033[K\033"
else
echo -e "\033[$1;1H\033[?25l[$2] ${NEO_ARR[$3-1]}\033[K"
fi
}
# 参数:$1 起始点 $2 列表长度 $3 高亮行
NEO_LIA(){
k=0 ; i=$1
while [[ $k -lt $TTY_H ]]; do
let k+=1
if [ $i -lt -$2 ]; then
let i=$i+$2
fi
let i+=1
if [ $i -gt $2 ]; then
let i=$i-$2
fi
if [ $i -lt 1 ]; then
let j=$i+$2
else
j=$i
fi
NEO_PRINT $k $j $i $3
done
}
NEO_SELECT(){
echo -ne "\r\033[${NEO_FORMAT}m[s] 选择\033[0m "; echo -ne "\033[K" ; read TLS_SNum
expr "$TLS_SNum" + 0 &> /dev/null
if [ $? -eq 0 ]; then
if [ $TLS_SNum -lt $1 -o $TLS_SNum -gt $2 ]; then
echo "编号超出范围,请重新选择编号!"
exit
else
NEO_OUT_H=$TLS_SNum
fi
else
echo "输入非数字,请重新输入编号!"
exit
fi
}
# 参数: 输出行,光标所在行
NEO_MENUE(){
let r=$1+2
if [ $NEO_SEL_ON -eq 1 ]; then
echo -ne "\033[$r;1H[j] 向下 [k] 向上 [s] 选择 [q] 退出 \033[${NEO_FORMAT}m$2\033[0m\033[K\033[?25h"
else
echo -ne "\033[$r;1H[j] 向下 [k] 向上 [q] 退出 \033[${NEO_FORMAT}m$2\033[0m\033[K\033[?25h"
fi
}
NEO_LISA(){
DY_SET_SIZE
p=$1 ; let q=$p+$TTY_H; m=$3
if [ $q -gt "${#NEO_ARR[*]}" ]; then
let q=$q-"${#NEO_ARR[*]}"
let p=$p-"${#NEO_ARR[*]}"
let m=$m-"${#NEO_ARR[*]}"
fi
if [ $p -le "-${#NEO_ARR[*]}" ]; then
let q=$q+"${#NEO_ARR[*]}"
let p=$p+"${#NEO_ARR[*]}"
let m=$m+"${#NEO_ARR[*]}"
fi
NEO_LIA $p $2 $m
DY_MKLINE
if [ $m -le 0 ]; then
let NEO_CURRENT=$m+"${#NEO_ARR[*]}"
else
NEO_CURRENT=$m
fi
NEO_MENUE "$TTY_H" "$NEO_CURRENT"
read -s -n 1 ListDo
case "$ListDo" in
j)
let m+=1
if [ $m -gt $q ]; then
let p+=$TTY_H
fi
NEO_LISA $p $2 $m
;;
J)
let p+=$TTY_H
let m=$p+1
NEO_LISA $p $2 $m
;;
k)
let m-=1
if [ $m -le $p ]; then
let p-=$TTY_H
fi
NEO_LISA $p $2 $m
;;
K)
let m=$p
let p-=$TTY_H
NEO_LISA $p $2 $m
;;
"")
if [ $NEO_SEL_ON -eq 1 ]; then
NEO_OUT_H=$m
else
exit
fi
;;
s)
if [ $NEO_SEL_ON -eq 1 ]; then
NEO_SELECT $p $q
else
NEO_LISA $p $2 $m
fi
;;
q)
exit
;;
esac
}
NEO_LIB(){
k=0 ; i=$1
while [[ $k -lt $2 ]]; do
let k+=1
if [ $i -lt -$2 ]; then
let i=$i+$2
fi
let i+=1
if [ $i -gt $2 ]; then
let i=$i-$2
fi
if [ $i -lt 1 ]; then
let j=$i+$2
else
j=$i
fi
NEO_PRINT $k $j $i $3
done
}
NEO_LISB(){
DY_SET_SIZE
p=$1 ; q=$2 ; m=$3
if [ $m -gt $q ]; then
let m=$p+1
fi
if [ $m -le $p ]; then
m=$q
fi
NEO_LIB $p $2 $m
DY_MKLINE
NEO_MENUE $q $m
read -s -n 1 ListDo
case "$ListDo" in
j)
let m+=1
NEO_LISB $p $2 $m
;;
k)
let m-=1
NEO_LISB $p $2 $m
;;
s)
if [ $NEO_SEL_ON -eq 1 ]; then
NEO_SELECT $p $q
else
NEO_LISB $p $2 $m
fi
;;
"")
if [ $NEO_SEL_ON -eq 1 ]; then
NEO_OUT_H=$m
else
exit
fi
;;
q)
exit
;;
esac
}
# 参数:列出的数组, 1开启选择,0关闭选择
NEO_LIST(){
NEO_ARR=($1) ; NEO_SEL_ON=$2
clear
DY_SET_SIZE
if [ "${#NEO_ARR[*]}" -gt $TTY_H ]; then
NEO_LISA 0 "${#NEO_ARR[*]}" 1
else
NEO_LISB 0 "${#NEO_ARR[*]}" 1
fi
echo $NEO_OUT_H # 目标是获得光标所在的行
}
NEO_LIST "${DY_FILES[*]}" 1 # 测试程序命令