Don't use Vim

The ORIGINAL post Don’t use Vim Don’t do the crime, if you can’t do the time. – Anthony Vincenzo “Tony” Baretta Vim is an amazing text editor. I love it. Really, I wouldn’t organize a Vim advent calendar if I didn’t. But, as amazing as it is, Vim is not for everyone. It can’t solve all your problems, or be a TUI version of your favorite IDE, or make you a better programmer, or land you that dream job in the Bay Area. But Vim can help you be more mindful, focused, and efficient, as long as you approach it with the right mindset. ...

August 29, 2022 · 10 min · Me

Vim OR Emacs?

随便聊聊我对Vim和Emacs的看法吧,说说我对这两大成名已久的古老编辑器的看法以及我的立场。 我并不打算在这里详细说明Vim或Emacs是怎么使用的,因为互联网上已经有足够多的资料,肯定比我讲的好的多。而且我自己也只用了Vim两年左右,并不资深,而Emacs我更是几乎等于一窍不通。所以我仅列出Vim和Emacs在我有限的了解里表现出的优点和缺点。可以的话,尽量互相对应。 免责声明:这场旷日持久的战争对于很多人,尤其是Linux爱好者来说,恐怕已经不是什么新鲜事了。我相信每个人都有自己的立场,也有自己的理由。所以在这里,我只是表达我的个人看法,对特性的总结可能有偏差,但立场没有对错,也没有优劣。 Vim “编辑器之神” 严格来说Vim是上个世纪90年代才诞生的,远不如Emacs来的古老(70年代)。但其前身Vi(Vim = Vi IMproved,但好像有个说法是谦虚的Bram Moolenaar最一开始将m定义为IMitation1),也是在70年代诞生的。这段历史其实很有意思,可以从TAOUP中略窥一二,但这里暂且不说。Vi和Vim在纯文本的操作逻辑上是非常非常相似的,而这种操作模式也是Vim最广为人知的特性,所以通常意义上我认为Vim和Emacs同样古老。 Vim 作为最有名的“模式”编辑器之一,我认为这种“模式”正是Vim给后继者/现代编辑器提供的最宝贵的财富。初学者一般会认为Vim的学习曲线非常陡峭,但实际上,跨过了模式编辑的适应期之后,多数人-可能是主体是程序员吧:),在大多场景下应该会爱上这种方式。因为它解放了键盘上的很多按键,进而解放了很多操作,从而让一种“操作文本”的迷你语言(我认为这就是一个层面的语言)成为一种高效而核心的理念。这种操作模式现在可以说是广泛应用在现代编辑器中,例如VSCode、JetBrains家的IDE,都有对应的vim插件。这类插件本质上提供的就是这个操作模式。甚至不少人表示,即使Vim这个软件看起来有些过时,但如果重新实现一个,仍然会保留这种模式。其集大成者自然是NeoVim。这里不展开。 优点 模式编辑,以及引入模式带来的默认情况下更高效/人性化的键位设置,和这套模式在现代其他编辑器里的广泛移植。 完美运行在TUI环境下,劫持全键盘操作 跨平台,而且几乎在所有的UNIX发行版上都默认安装,至少是Vi。这也是为什么Linux运维人员使用Vi/Vim的比例要高得多 占用资源少 超高度的扩展和定制性。你几乎可以修改所有你能想到的配置来满足自己平常的编辑需求 开源软件,活跃的社区。 完备的内部帮助文档 更符合UNIX哲学(小而精工具组合完成更复杂的任务) 缺点 不好上手。StackOverflow点击最多的问题之一, “How do I exit Vim?” 图形界面支持一般,不管是Windows上的GVim还是MacOS上的MacVim,都只是TUI版本Vim的一层简单包装。所以很多在现代编辑器上习以为常的操作,像右击唤出菜单什么的,可能做需要额外配置。可能也正因如此,Vim作为本质上为Terminal开发的编辑器,在“前端交互”或者说“作为其他开发工具的前端”这点上,远不如Emacs灵活 中文支持不好。一方面是字符集的问题,像分词之类的功能受到影响;另一方面是输入法的问题,在中文输入法下,Normal模式的很多操作会被输入法劫持,需要额外的解决方案。多数情况下,这些方案或许管用,但都并不优雅。英语母语者就很少有这两个问题 Vimscript(原生Vim使用的脚本语言)比起lisp虽然形式上更像现代的脚本语言,但真的足够晦涩难懂,表达力欠缺。NeoVim的蓬勃发展或许能解决这个问题 作为一个软件本身看上去有点过时,而且软件工程组织并不好,维护也更多是集中在一个人身上 Emacs “神之编辑器” Emacs我使用的并不多,只是偶尔看到Battle贴心血来潮会偶尔使用一下,或者是看到颇具盛名的doomemacs/spacemacs的安利贴时进行一些尝试,但我仍然斗胆表达一下我的看法。另外说一句,Emacs是自由软件运动的标志性产物,自由软件运动更多的是一种思想解放:)。 它是“伪装成编辑器的操作系统” 优点 上手快 跨平台,TUI/GUI下都能很好地使用,在GUI工作得更好,同时也支持全键盘操作 lisp/elisp的最佳学习平台 比Vim更高的扩展性,因为它自己就是个Lisp解释器,Lisp是图灵完备的语言。所以,你可以在Emacs里面实现一个Vim,甚至可以用它煮咖啡,字面意义上的。 开源软件,较活跃的社区 完备的帮助和提示系统,我认为这里做的比Vim更好,比如可以通过 C-h + k 来查看对应快捷键绑定了什么功能 Org mode,可能是最强的GTD工具 作为软件工程实践更加出色,Richard Stallman的开发和维护工具顺利交接给了其他人。比Vim具有更低的选择复杂度,这点在TAOUP中也有提到 缺点 默认情况下近乎反人类的键位设置,以及其小拇指的伤害:(,因为默认键位用到大量功能键,有的还会与操作系统默认配置,或者与其他软件冲突。比如ctrl+space很多情况下会被操作系统设置为切换输入法,从而使其在Emacs中的功能失效,需要额外配置 多数情况下占用资源相对Vim较多,启动也更慢,这在现代计算机上这并不是什么问题,但在很多小型或嵌入式设备上,可能无法使用自己顺手的Emacs配置 容易陷入“玩”Emacs的“陷阱”中,而且lisp是一门经典且值得学习,但并不广泛应用的语言,你几乎只会在Emacs中大量用到它。相比之下,Vim可以使用python、lua等语言进行插件编写,不用重复造轮子 与传统UNIX哲学稍稍相悖,everything in one and elisp. 现代流行度稍逊于Vim,很多问题可能得自己解决,很让人头秃 两者的选择 简单概括2 Emacs, “a great operating system, lacking only a decent editor ...

July 23, 2022 · 1 min · ChaosNyaruko

我与Vim

我的Vim使用经历 我使用Vim的时间并不长。上大学的时候有一门课讲计算机体系架构,那是我第一次了解Ubuntu和Linux,那个时候习惯了各种现代编程工具的我(我是EE出身,很多是硬件专属,比如Keil、Xilinx/Quartus系列的,当时这两家都还没被收购呢…)。我认为Vim这个编辑器实在过于反直觉,很难用,在简单完成课程大作业后,我便再没使用Vim了,会的操作也只有i进入Insert Mode,:wq 退出而己。工作后一开始由于是在Windows环境下做C++工作,VS是我的主力代码编程器,后来进入后端领域后,才发现周围同事真的有不少是用Vim或者Vim插件进行编码的,加之常常要进服务器查看日志修改配置,我便强迫自己更进一步地学习Vim。一年多后,Vim已经成了我的主要编辑器。 为什么后来坚持使用Vim 可以说我正式用Vim的时间并不长,也就一年多,为什么我现在会使用Vim作为我的主编辑器呢,和很多人的理由可能不一样,我的主要理由并不是效率,或者是其超高的可定制性。我想有以下几个主要原因吧: 在绝大多数场景下获得相同的体验。我在工具的使用上倾向于一种“确定感”,也许不会是效率最高或者操作最快的,但这种感觉会在主观上让我很舒服。我现在是一个后端工程师,经常需要看一些服务器日志或者改一些配置,虽然公司可能提供了一些平台,让我们可以使用前端的Web页面进行搜索,但在频繁切换搜索关键字的时候总归是不习惯。而Vim在几乎所有Linux服务器上都有预装,再不济也有vi,这让我的查找工作流基本上是确定和一致的,对我来说效率得到了不小的提升。此外,由于有时我也会在远程的开发机上写代码(有时因为本机负载重,有时是懒得同步等等),同步一下Vim的配置后也可以几乎获得一样的体验,这种可以说是另一种层面的“开箱即用”的确定性,让我十分舒适。顺带提一句,在全拼输入法因为云输入法流行变得非常好用的今天,我也依然在使用看上去已经落伍过时的86版五笔输入法,就是因为我在几乎所有可以安装五笔输入法的环境里都能获得基本一致的体验,五笔本身重码率低,也加强了这种确定感。 Vim是非常好用的TUI编辑器,这意味着我在阅读代码或者编写代码的时候几乎不需要去够鼠标(当然查阅文档很多时候还是免不了,但更连续)。用鼠标并不一定就意味着低效,但对我来说如果单纯敲代码的时候要频繁去够鼠标定位我的光标,频繁地在键盘和鼠标之间移动会让我非常烦躁。我不确定我的“心流”会不会因此被打断,但情绪一定是受到影响了。这一点也许Emacs或者很多IDE默认也有快捷键可以做到,但我要记住很多奇奇怪怪的快捷键组合,而且对于IDE来说,我一旦更换了,就意味着我要重新学习一套快捷键,这真的是会造成一定的学习和切换负担的。在这一点上,Emacs可能也和Vim一样,当有自己熟悉的工作流之后可以用很久,但我并不喜欢Emacs那种极度依赖功能键的操作方式。关于这两者的对比后面再稍微展开聊聊,这里先放放。接触或者熟悉Vim的人可能知道,Vim在Normal Mode下的操作真的很像’speaking a language’,其operator + motion / text object 的设计在习惯之后真的非常自然和高效,而默认的Emacs键位对我来说稍有些别扭。 Vim是UNIX “组合”理念的经典体现,Vim作为UNIX环境下最为经典的TUI编程器之一,可以和许多命令行工具相结合,而我本人是非常喜欢UNIX这种理念的,每个组件可能都不大,但组合起来就能发挥无穷无尽的可能性。写一个测试脚本时,你可以写个Makefile,然后简单地调用make实现临时运行,不需要另开一个shell(虽然也可以这么做)。在Command Mode下也可以通过 !{cmd}调用几乎所有命令行工具,并和r/w结合与buffer互动。Vim的这种高度的可“组合”性(在这个语境下相对于Emacs的高“扩展”性)让Vim在默认配置下就已经非常好用。 Vim非常轻量。我日常工作里可能要同时开几个代码工程进行参考或者编辑,如果都使用IDE,我的电脑内存可能会爆,而且有时只是临时打开某个文件查看一下。这种场景下Vim就非常适合我了,配合tmux/iterm2等工具,即使在配置很低的电脑上,我的工作体验也不会受到什么影响。 Vim对于我的缺陷 当然Vim也不是尽善尽美的,对于我来说,Vim目前至少有以下几个缺陷: 中文输入。这可以说是让Vim成为我的通用编辑器的路上最大的阻碍。虽然大多数编辑代码的情况下我都不太需要中文输入法,但是在写一些简单文章,比如这篇文章的时候,在Insert Mode下使用中文输入法,切回Normal Mode的时候需要手动切回英文(Vim的使用者会相当频繁地切到Normal Node进行移动和修改),每次我都要按系统的中文切换快捷,有时忘了还得退格重新操作,确实让我苦恼。我也曾经在网上搜索到过一些解决方案,但后来出于各种考虑还是放弃了:1. 大段输入中文的场景一般都是特定场景或者特定格式需要,那我为何不选择更合适的工具呢,比如Typora写中文markdown, 用CTex写LaTex,甚至是用Word写有特定排版要求的文章,毕竟我只是需要更适合的工具,并不强求“Everything in Vim"。但我得承认,在用Vim写下这篇文章的过程当中,体验并不好。 Vimscript 非常晦涩,而且并不通用。这个可能也是很多初中级的Vim都感同身受的一点,Vim自己的脚本语言和很多现代语言差距比较明显,甚至比Emacs Lisp这门古老的语言都难看懂。在没有一些基础知识或者读过足够插件源码的话,很难一眼看懂一个函数是在做什么,或者细节是怎么实现的。这门奇怪的语言确实造成了一定的插件开发或者自定义的高门槛。好在Vim也支持和Python、Rudy等语言进行交互,Vimscript9也在发展中,更是有NeoVim这个项目,引领插件生态往更常规的lua语言环境去迁移。作为一个相当初级的用户,这对我来说并不是不可接受的。 会有种疯狂折腾配置的冲动。这可能是可定制编辑器的通病了,我支持适度演化和更新自己的配置文件,但有的时候会走火入魔,导致磨刀磨太多,在上面花了太多的时间,导致耽误了真正重要的事。这应该算是我自己的问题,并不是编辑器本身的过错。我相信磨刀不误砍柴工,但也要把握度,重复造轮子性价比并不高。但如果目的就是学了学习,就是为了折腾(程序员的浪漫),那么多踩踩坑,花时间将铁杵磨成针也未尝不可。 读复杂代码或者重构的时候有时不如IDE。我承认也许我们可以将Vim配置的具备IDE大部分功能,但这要花费不少精力。Vim始终只是一个文本编辑器,在代码跳转/引用查询/代码重构等专门功能上可能或多或少存在一些缺陷。也许我们可以解决所有问题,让它像IDE一样工作,但对于精力和时间有限的,像我这样的一般程序员,为何不让它做自己最擅长的事情呢。现代IDE都基本都可以配置Vim插件,甚至可以将IDE的功能与Vim的键位在语义上进行绑定,如果会基础的Vim操作的话迁移成本非常低,比如ideaVim,基本满足我对Vim编辑移动的要求,所以我在看一些陌生项目代码、或是重构、写单元测试时,也时常会开启我的Goland/VS/Pycharm等,毕竟商业公司对这些典型需求做了非常好的适配,也非常好用。正如我上面所说的,我并不期望“Everything in Vim”。 Vim, Emacs 和 其他编辑器/IDE 这里我无意引起战争(笑)。它们都仅仅是工具而已,我用Vim只是因为它适合当前的我,适合我现在的工作流,满足我大多数的需求。 相比Emacs,我是因为先接触了Vim,而且Vim在大多数类UNIX环境里都有预装而选择了它,加之Emacs对功能键依赖大(有的终端模拟器需要额外配置Meta键)。Emacs我了解有限,它更像是一个Lisp解释器和运行环境,因此它的功能可以更丰富(甚至可以在里面实现一个Vim,比如Evil-Mode)。Vim和Emacs作为编辑器界的老前辈,带来的不仅仅是编辑器本身,更是文化、设计理念以及如今在命令行环境下几乎约定俗成的操作习惯。在terminal里常用ctrl-a/ctrl-e/ctrl-u/ctrl-k/alt-w/alt-b等快捷键,或者经常在less/man/git diff等页面进行移动搜索的同学应该知道我在说什么。如果有机会,我可能还是会学习一下Emacs和Lisp编程,因为各类EmacsTalk和使用者的体会让我对它充满了好奇心。 至于其他编辑器,像VSCode、Sublime Text或者是IDE,我认为他们与Vim/Emacs并不是竞争者(严格来说Emacs和Vim也并不是一个赛道上的),而是相辅相成的。IDE在现代编程工作里面多数情况下确实有着更高的生产力,但这和使用高效/舒服的编辑手段并不冲突。就像我之前所说,很多现代编辑器或IDE都有Vim插件,而macOS下很多图形界面的光标移动快捷键也和Emacs一脉相承,它们完全可以组合起来,来实现满足每一个人特定的需求(比如煮咖啡^_^) 写在后面 如果有机会,我可能考虑录个Vim相关的入门视频,会比文字直观许多。虽然网上已经有很多了,但我也许能以一个初学者、一个非高级用户的视角,给大家介绍一下一个“简陋”的编辑器是怎么满足我日常工作的工作流的。而Vim也是一个常学常新,可以一直学习的东西。生命不息,学习不止。Peace~。

February 23, 2022 · 1 min · ChaosNyaruko

Go中的内存可见性与happens-before

什么是内存模型 Go的内存模型特指在并发的场景下,一个goroutine所写的变量在另一个goroutine能在哪些情况下被观察到 在计算中,内存模型描述了多线程如何通过内存的交互来共享数据 官方建议 程序可能会并发地访问/修改一些变量,多个goroutine的并发访问一定要保证“可串行化”,尤其是绝对不允许出现数据竞争的场景下 为了保证数据访问的串行化访问,没有数据竞争,在Go语言中,尽量通过channel或者各种同步原语对数据的并发访问进行保护,例如sync 、sync/atomic等 强烈推荐阅读官方文档 If you must read the rest of this document to understand the behavior of your program, you are being too clever. Don’t be clever. C语言中的内存可见性 内存可见性是一个通用性质的问题,类似于 c/c++,golang,java 都存在相应的策略。作为比较,我们先思考下 c 语言,在 c 里面却几乎没有 happens-before 的理论规则,究其原因还是由于 c 太底层了,常见 c 的内存可见性一般用两个比较原始的手段来保证: volatile 关键字(很多语言都有这个关键字,但是含义大相径庭,这里只讨论 c ) memory barrier volatile volatile 声明的变量不会被编译器优化掉,在访问的时候能确保从内存获取,否则很有可能变量的读写都暂时只在寄存器。但是,c 里面的 volatile 关键字并不能确保严格的 happens-before 关系,也不能阻止 cpu 指令的乱序执行,且 volatile 也不能保证原子操作。 以一个常见的c代码为例: // done 为全局变量 int done = 0; while ( ! done ) { /* 循环内容 */ } // done 的值,会在另一个线程里会修改成 1; 这段代码,编译器根据自己的优化理解,可能在编译期间直接展开翻译成(或者每次都直接取寄存器里的值,寄存器里永远存的是 0 ): ...

November 4, 2021 · 7 min · ChaosNyaruko

如何看别人的代码(转载)

本文系转载 关于看别人的代码 自己曾是过来人,经常遇到刚毕业的同学很反感看别人的代码,也很反感使用别人的代码,甚至与他人协作开发还有点小抗拒 据我个人总结,出现这种问题的根本原因,是因为经验不足,无法瞬间秒懂别人写的代码(其他的原因可能根本原因都是这个),以前我觉得自己太菜了感觉分享此类心得会被人笑话,但是现在,我阅码无数,因工作原因腾讯几大最热门游戏源码我都瞄过,且因本人目前工作关系,几乎查阅过字节80%游戏的反编译代码,我有多年的逆向分析经验,如何快速定位感兴趣的代码也有些许心得。然后我来分享几点,如何超高速秒懂别人代码的几个心得。 在讨论心得之前,先讲一个理论原则,这个原则应该是科班《数据结构》里的内容,大意是指一个程序的输出仅与输入(输入不仅包括UI输入,控制台输入,也包括网络输入,甚至随机数也算是输入,任何外部的数据都算输入)有关。好,记住这点,将大大加快你阅码速度。 首先,第一点,最简单,也是最吃经验的一点,就是面对一份庞大的代码,如何快速定位自己感兴趣的代码,这最简单的一点就是全局搜索字符串和猜测函数名,这点应该都是大家的共识,函数名猜测,这是共识,就跟公理一样不需要证明了(当然也吃经验和英语水平)。另外是字符串搜索,一个程序,目光所及固定可见字符串,90%都可以在源代码中找到,关键代码基本上就在附近。 其次,是找关键代码的思维,不好描述,我举个例子: 比如你想找一个游戏代码里面发包相关的函数,通过Send关键字搜索发现没有相关函数的时候,此时可以换种思维,思考一下发包上下游关系,发包可能要对包进行压缩,加密,可以尝试搜索compress,encrypt等关键字,交叉引用看看是否有你感兴趣的代码,也可以通过上游的Login看看有没有关键的函数,Logon啊这些,甚至是相近的 Message,Msg啊这些都可以是关键字进行搜索,如果百般尝试最终无果的话,动用我们linux系统调用的“原子技术”,从send一步步反推吧~。 有一些好的项目,基本上从文件名就可以知道这个文件做了什么功能的。如果以上,可能比较吃经验,那么以下这个,我应该可以把这个过程讲清楚 找到了代码之后如何看懂(这里的看懂,指的是了解这个函数哪些做了什么事情,输出了什么东西)呢? 看懂一个函数,无非是看懂这个函数对哪些数据做了什么处理,最终对外输出了什么数据,因为函数的本质就是这个,函数无法再做其他事情了,所以,此时,你需要一个能将某个变量高亮的IDE,选中所有参数,看看函数对参数做了什么处理,应该是一目了然,秒懂应该没有问题,接下来以C讲几个特殊case分支(以下讲解仅限值传递类语言,比如C。引用传递类语言例如java,C#等的除外,看完应该也应该知道为什么要除外了) 参数进入了另一个函数,如果此参数前没有&,那么直接忽略 参数进入了另一个函数,如果此参数前面有&,那么跟进此函数,循环本过程看懂该子函数 高亮返回值和指针进来的参数,看如何构造的返回值以及有没有对指针参数指向内容进行修改,因为不高亮的地方,不用黑科技是改不了的 如果中间有赋值的地方,高亮赋值后的变量继续看 注意看一下,此函数有没有对全局变量做处理 如果是引用传递类的语言,比如java,C++(C++属于显式引用传递,看一下子函数形参里有没有&就知道了),C#这类语言就麻烦一点,可能还要跟进每个子函数看下,有没有做处理 如果是面向对象类的语言,可能还要麻烦点,因为有个this指针,本函数可能无形当中还会对本对象进行一些修改,注意那些凭空多出来的没有定义就拿来用的变量就行(所以,你们现在清楚将成员变量命名为m_开头是多么重要了吧?因为能让别人秒懂!) 好了,讲完了,讲完了,之后,也许有人已经知道了 linus大神为何如此不待见C++了吧,因为C++的确是一门自己用起来很爽,但是要让别人看懂你写的代码,的确可以让人口吐芬芳。据我这么多年的经验,在看懂别人写的代码难易程度上,C最简单,C#次之,C++最难懂(仅根据语言特性来分,无关我对这些语言的熟悉程度,特性一样的语言效果等同)。 当你看懂了一个函数的输入输出以后,你基本上已经认定了这个写法是没问题的,不然如果代码有bug,你在查阅的时候应该就已经发现了。所以,此时此刻,你再使用别人的代码,或者修改别人的代码,还有那么抗拒吗?

September 1, 2021 · 1 min · ChaosNyaruko