LEM:Extensible editor/IDE well tuned for Common Lisp

简介

LEM是一个用Common Lisp(SBCL/CCL)实现的编辑器,重度模仿了Emacs的操作习惯。使用 Common Lisp作为扩展语言。

主要卖点是内置了Swank支持(就是Emacs插件Slime使用的live coding backend),对于Common Lisp项目,可以在保留部分Emacs编辑习惯上不进行额外配置进行开发。此外还支持像Nvim一样的前后端分离,而且有用Electron写的前端(beta version),官方目前稳定的只有ncurses的终端前端。

启动

安装LEM需要配置roswell,我个人不用这东西,因此用官方推荐的docker来体验,运行

docker run --rm -ti -v `pwd`:/app 40ants/lem:latest

启动lem编辑器。

一些截图

  1. directory-mode(对,高仿dired-mode) & M-x。目前来看,还没有内置ivy/helm这样的功能。

  1. completion(默认设置补全要按TAB触发,不像company那样就地触发)

image

  1. Tetris(传 统 艺 能)

随便玩玩

  1. rust-mode

除了CL和Scheme以外,还支持OCaml C Diff Rust JS Markdown Nim等语言的高亮,支持LSP,不过我并不是LSP fan所以没有实际测试。

所有内置的mode可以在这里

或者在编辑器里用M-x探索。

个人体感 & 小结

很有趣的尝试,不过完成度不高(比如describe-function describe-variable 等没有实现,我愿称这两个命令为Emacs之魂)。而且CL社区少人,也没有特别好的前景展望。对CL真爱/对Emacs某些设计痛恨的同学可以考虑折腾一下,这个编辑器可hack程度还是很高的,而且hack起来和Emacs一样简单(在buffer写code然后eval就完事了),基于这个来扩展总比从0写编辑器要强。

5赞

Cool!

不知道社区支持能不能到kakoune的程度,

elisp跑得慢和没并发两个问题能解决一个都是体验的极大改进,cl起码前者好很多.

这个和 native-comp 之后的 elisp 比性能怎么样?

放心,吊起来打

但看起来全是 CL 啊,相比于 Emacs 靠 C 写的内核,实现同等的功能会更快吗?在功能比较少的时候性能有优势是可以理解的。

SBCL 高性能部分还是用 x86 ASM 擼出来的,C 写的內核有啥可比的(

1赞

比如 native comp 跑的 elisp-benchmarks,改一下到 Common Lisp 上

(defvar elb-bubble-len 1000)
(defvar elb-bubble-list (mapcar #'random (make-list elb-bubble-len
                                                    :initial-element
                                                    most-positive-fixnum)))
(defun elb-bubble-no-cons (list)
  (loop repeat (length list)
        do
           (loop for x on list
                 for a = (car x)
                 for b = (cadr x)
                 do (when (and b (> a b))
                      (setf (car x) b)
                      (setf (car (cdr x)) a))
                 return list)))

(defun elb-bubble-no-cons-entry ()
  (loop repeat 200
        for l = (copy-seq elb-bubble-list)
        do (elb-bubble-no-cons l)))

在 Clozure CL 上,没开优化结果,根本没得比。

CL-USER> (time (elb-bubble-no-cons-entry))
(ELB-BUBBLE-NO-CONS-ENTRY)
took 5,605 microseconds (0.005605 seconds) to run.
       233 microseconds (0.000233 seconds, 4.16%) of which was spent in GC.
During that period, and with 8 available CPU cores,
     4,568 microseconds (0.004568 seconds) were spent in user mode
     1,184 microseconds (0.001184 seconds) were spent in system mode
 3,200,000 bytes of memory allocated.
NIL

哈哈哈,不过我最喜欢的实现是ECL。ECL的思路类似native-comp,不过更简洁,calling convetion和C一致,有点类似C+一个轻量runtime+糖了。直接用GCC就可以编译,不需要翻译成libgccjit IR然后codegen

测了下,ECL在GCC compile后也很快

CL-USER> (ext:install-c-compiler)
NIL
CL-USER> (compile-file #P"~/tmp/bubble-cons.lisp" :load t)
;;;
;;; Compiling /home/chino/tmp/bubble-cons.lisp.
;;; OPTIMIZE levels: Safety=2, Space=0, Speed=3, Debug=3
;;;
;;; End of Pass 1.
;;; Finished compiling /home/chino/tmp/bubble-cons.lisp.
;;;
;;; Loading "/home/chino/tmp/bubble-cons.fas"

#P"/home/chino/tmp/bubble-cons.fas"
NIL
NIL
CL-USER> (time (elb-bubble-no-cons-entry))
real time : 0.008 secs
run time  : 0.008 secs
gc count  : 1 times
consed    : 3196688 bytes
NIL

作者好像是日本人,从2015年开始开发,star不少,但是看起来还是个人项目

日本玩CL的好像挺多的,单说我知道的

  1. Eitaro Fukamachi(https://github.com/fukamachi ):CL web开发轮子狂魔
  2. 这个作者
  3. g000001.cddddr.org 这个网站的博主,据说在某公司用LispWork做Lisp开发

另外,我刚才提到的ECL,其前身的名字叫Kyoto Common Lisp(京都Common Lisp,KCL),是Taiichi Yuasa和Masami Hagiya在京都大学开发的。KCL的代码派生出了很多CL实现(包括GNU Common Lisp,GCL)

https://en.wikipedia.org/wiki/Kyoto_Common_Lisp

2赞

http://museum.ipsj.or.jp/en/pioneer/gotou.html

还有个因为名字是 goto 而很著名?的计算机科学家,第一个实现了 lisp 上的 hash cons

1赞

Lisp实现的runtime一般都是用C撸的。看起来Lisp多是因为一般喜欢用Lisp写Lisp的compiler. Emacs的byte compiler也是Elisp写的。

其实很多Lisp的interpreter是只能读字节码的。eval sexp必须先compile成bytecode然后eval. 但是这样还需要一个旧版本的实现来编译代码才能运行(比如Clozure CL已经没法full source bootstrap了,因为最原始的没有用Lisp做compiler的代码已经丢了,除非用其他CL实现写一个CCL compiler,但也有像 Gauche 这种邪道把Lisp转译成C然后用C编译器编译一个compiler出来的)

Elisp的interpreter支持直接读入sexp来直接eval求值,但是注意看Emacs编译第一步就是byte compile bytecomp.el cconv.el 等几个关键文件然后替换非bytecode的版本。

看了下汇编部分主要是寄存器分配,算术操作,多值返回等。这个其实和C写的runtime不冲突,毕竟C runtime更多是掌管堆分配,垃圾回收,FFI,Backtrace,Multi-threading.

3赞