About

Lem 是一个用 Common Lisp 写的模仿 Emacs 的一个编辑器. 不过目前体验上来说和 Emacs 只能说不太能比, 有许多奇奇妙妙的小 bug (特性?) 以及一些比较遗憾功能缺失 (比如我现在觉得 directory-mode 和 Emacs 的 dired 完全不能比, 详见 一些吐槽).

不过作为一个用来玩乐的编辑器, 我觉得是挺不错的.

Clone, Compile, Patch, Compile… Right?

Clone and Compile

我不是很喜欢 fukamachi qlot 那套依赖包管理的做法. 虽然现在觉得在本地保存所有的项目相关的包确实是一个超级明智的决定 (尤其是在未来有了一堆的包依赖的时候, 你说是吧 Python, NPM). But anyway, 我更喜欢直接用 quicklisp 直接把所有的依赖都装在一起. 这是个人的喜好差异了, 假如你想要用官方推荐的方式来进行安装的话, 请参考 Installation (Lem) 的官方安装指南.

cd $HOME && mkdir -pv common-lisp
cd common-lisp
git clone https://github.com/lem-project/lem.git

说明: ~/common-lisp 是一个 lisp 构建系统 (ASDF) 会搜索的地方, 将你的源代码目录置于其下方可以让其知道要如何载入. 而 quicklisp 的工作是根据在 asdf 中定义的依赖关系, 帮你从网上把源代码下载下来, 并放到一个 asdf 知道如何载入的地方.

等下, 假如你没有 Common Lisp 和 quicklisp 环境配置的话... 1. 安装 SBCL 环境 + macOS: `brew install sbcl` + Ubuntu: `sudo apt install sbcl` + Windows: 不熟 2. 下载并配置 quicklisp + `curl -L https://beta.quicklisp.org/quicklisp.lisp -o quicklisp.lisp` + `sbcl --load quicklisp.lisp --eval "(quicklisp-quickstart:install)" --eval "(ql:add-to-init-file)" --eval "(quit)"` 详见 [Getting started with Common Lisp](https://lispcookbook.github.io/cl-cookbook/getting-started.html).

进入到 lem 项目目录下方, 这里并不使用 Lem 默认的 Makefile 进行编辑, 而是采用:

cd lem
sbcl --dynamic-space-size 4GiB --noinform --nosysinit \
     --eval "(ql:quickload :lem-sdl2)" \
     --eval "(lem:init-at-build-time)" \
     --eval "(sb-ext:save-lisp-and-die \"lem\" \
                                       :compression t \
                                       :toplevel #'lem:main \
                                       :executable t \
                                       :save-runtime-options t)"

手动进行编译.

注: 这里 :compression 参数设置成了 t, 可以大幅减少最终二进制文件的大小; :save-runtime-options 让 Lem 使用和编译其时相同的运行时参数 (--dynamic-space-size 4GiB).

运行 ./lem 即可看到用 SDL2 作为前端显示的 Lem 编辑器了.

来点配置

和 Emacs 的配置类似的, 我们把配置放在 ~/.lem/init.lisp 处. 在里面你可以写各种各样的 Lisp 代码, 比如可以写一些简单的按键绑定:

(in-package :lem)

;;; Key binding

(define-key *global-keymap* "C--" 'undo)
(define-key *global-keymap* "S--" 'font-size-decrease)
(define-key *global-keymap* "S-=" 'font-size-increase)
(define-key *global-keymap* "S-+" 'font-size-increase)
(define-key *global-keymap* "S-f" 'lem/isearch:isearch-forward)
(define-key *global-keymap* "S-v" 'yank)
(define-key *global-keymap* "S-c" 'copy-region)

注: 这里的按键绑定的命名规则同 Emacs. 会发现基本的设计都挺类似的.

注2: 一个小技巧, 在 lisp-mode 中, 在一个 S-expr 上按快捷键 C-c C-c 可以

注3: 发现用 ncurses 的版本配合 iTerm2 的效果其实也很不错 (尤其是那个比较炫酷的那个光标特效, 没啥用, 但是很帅).

来点 Patch

现在你就可以用 Lem 来编辑 Lem 的源代码了. 通常, 大家会认为改了代码之后我们需要重新编译代码并重启我们的程序… 但是在 Lisp 世界中, 这并不是必要的 – 你完全可以在运行 Lem 的同时修改其功能:

比如 M-x start-lisp-repl 可以帮你打开一个 Lisp 的 REPL, 同时这个 REPL 也是 Lem 当前控制的环境. 你可以使用 M-h 快捷键来唤起一个小窗口, 在其中有一堆的选项来帮助你了解当前光标下的东西是什么.

比如你可以用 Describe symbol 来查看当前函数/变量对应的符号的文档, 或者用 Find definition 来查看函数的定义等等.

一些吐槽

性能和内存占用

貌似在 SBCL 里面的内存占用还是有点大… 开了几个 buffer 之后 sdl2 版本的内存占用来到了 800MB 左右, 啥也不开的状态是 290MB. 作为对比的, ncurses 的版本的内存占用大概是 200MB 左右 (不过不清楚多开了几个 buffer 之后会有啥效果). 所以我感觉还是主要使用 ncurses 的版本会比较好一些.

还没有测试过比较大的文件的编辑性能. 其他需要测试一下.

总体上来说感觉还是挺流畅的, 不过也有一些因为不熟练导致的卡手感, 然后 sdl2 的版本因为没有平滑滚动 (对应 Emacs 中的 pixel-scrolling), 感觉还是有点卡顿感.

并且发现用 sdl2 的版本的耗电量还挺高的…

不过 sdl2 的版本, 它可以支持各种图形和富媒体, 感觉还是有很多东西可以玩的.

多窗口

还是很想要多窗口, 不过感觉不是什么大问题, 应该可以用一些别的方法来搞定.

不过奇怪的是 server 版本的 Lem (用网页作为显示前端) 也是只能支持一个窗口, 这个就感觉有点搞了…

Org-Mode

是的, 没有 Org-Mode. (或者说没有很好的 Org-Mode 的支持), 所以这个博客也是用回了 Markdown 来做标记语言.

我缺的 C-c C-c (文学编程) 这块谁来补啊…

Directory-Mode

感觉也不是很好用, all-the-icons 感觉虽然好看是好看, 但是感觉主要还是功能上缺失了好多. 感觉可以有空去 Emacs 那里抄.

Compile

也是一个最近开始常用的小功能, 感觉配置好就是一个 C-c C-c 的事, 写代码快速开发感觉很舒服 – 什么才叫做代码的所见即所得啊 (bushi).

Terminal, Shell

不好用就是说, 并且 vterm 貌似在 mac 这边的设置有些问题, 这个我觉得可以用别的方式去进行, 比如 port 一个 eshell 或者 eat.

Tramp

卧槽, 我超想要这个的… 虽然 Emacs 的 Tramp 有点慢… 但是 Tramp 感觉很爽诶.

Other

嘛, 没法要求一个新生的编辑器 (还是一个小众编程语言 + 没钱宣传) 和 Emacs OS 比较, 不过感觉有很多东西可以去写.

已经自带的这些, 比如 lsp 或者 auto-save-mode 感觉还行, 不知道之后使用的时候会遇到啥或者有啥想法, 感觉可以之后做一些从 Emacs 那边抄代码和抄插件的一些工作.