由于内置的 ielm 会污染当前 Emacs,所以想要一个比较“卫生”的 repl。简单用用还可以:
感谢 @xuchunyang batch 模式下如何 read 多行字符? - #8,来自 xuchunyang 帮我解决关键问题。
由于内置的 ielm 会污染当前 Emacs,所以想要一个比较“卫生”的 repl。简单用用还可以:
感谢 @xuchunyang batch 模式下如何 read 多行字符? - #8,来自 xuchunyang 帮我解决关键问题。
感觉有些用处,有时需要从 Emacs -Q 试下代码。
反馈一个问题:我这边只按换行会卡死,一直输出 "ELPL> "
好像就没事:
(if (string= s "")
"ELPL> "
"")
刚刚修复了。
当 s 内容只有 “\n” 的时候 (eval (read s))
就会卡死。
感觉不是这个原因,(eval (read "\n"))
不会卡死:
(eval (read "\n"))
;; error-> End of file during parsing
下面这里按换行也会卡死:
ELPL> (+ 1
我把测试用例补上了,包括单行/多行/未闭合的字符串和 sexp。
发现问题出在 candition-case
第二个参数,这里本应该是一个 HANDLER:
(condition-case err
(progn
(unless (string= s "\n")
(print (eval (read s))))
(setq s ""))
(end-of-file) ;; <<-----------
(error
(setq s "")
(print err)))
正是这第二个参数,使得多行表达式能成功执行。也使得未闭合表达式卡死。
(end-of-file)
其实是 eval 输出的错误信息,如果把这句屏蔽:
(condition-case err
(progn
(unless (string= s "\n")
(print (eval (read s))))
(setq s ""))
;; (end-of-file) ;; <<-----------
(error
(setq s "")
(print err)))
问题似乎回到了原点:
未闭合的字符串/表达式
ELPL> "foo<RET>
(end-of-file)
ELPL>
续行
ELPL> "foo<C-j>
bar"<RET>
(end-of-file)
ELPL>
(void-variable bar)
ELPL>
第 1 种比较好理解,没闭合就是 end-of-file
了。
第 2 种情况比较复杂,因为两个错误是分别产生、但几乎同时打印出来。在 (end-of-file)
的时候无法预料后面是否 (void-variable bar)
。
目前只能顾第 2 种错误,放任第 1 种错误了。
去读一读源代码,看看是否能找到完美解决方案。
或许可以在 comint-send-input
判断字符串/表达式是否闭合,以阻止发送不完整的表达式。参考 eilm-return
增加了一个 elpl-return
函数并绑定到回车键。当表达式未闭合的时候,按回车不是提交,而改为插入新行。避免了求值出错造成卡死的问题。
这样好像就可以用了(不会卡死)?
(apply #'make-comint "ELPL" elpl-cli-file-path nil elpl-cli-arguments)
我改用 elpl-return
提交数据可以避免卡死,ielm 也是这样做的,感觉这种方案更好。
剩下其他错误在 condition-case
里面处理。
看起来挺有用,会上melpa吗?
上面提到的问题差不多已经解决了。
等我把测试补完,没测出新问题就上 melpa。
嗯,elpl-return
应该也行,但我这边下面这样不会卡:
(apply #'make-comint "ELPL" elpl-cli-file-path nil elpl-cli-arguments)
(换行是我👋打的)
ELPL> (+
1
2
3
4
5
)
15
ELPL>
ELPL>
ELPL>
ELPL>
也是一个思路,稍后我也验证一下。
输出开头不知道为什么多个换行?
增加了 edit-direct
支持,大大降低误操作率。
在交互式状态下,按回车键有两种响应:
看起来挺简单,实际中却常常因为这个小小的差别而受挫:为了少打括号,我开启了括号、引号补全。但这样一来表达式始终都是闭合的,想换行就必须用 C-j
代替,稍不留神就直接按了 RET
,把未输入完的表达式提交执行了。
关闭括号、引号的补全显然也是不可取的。所以,既然想不到什么好的解决方案,不如跳出 comint-mode
的限制,一可以真正杜绝误提交, 二可以享受在一个正常的 emacs-lisp-mode
中编辑代码的畅快。
可以仿照lisp-interaction-mode
里的eval-print-last-sexp
(C-j)不过改成用单独的Emacs执行
增加了对 completion-at-point
的支持。
之前一直没想明白应该怎么写,而且只要设置了 completion-at-point-functions
就能补全当前 Emacs 的符号,算是有些帮助。但实际上这是不对的,应该补全 elpl
进程内部的符号。
现在简单实现了 elpl
进程内部符号的补全,效果如下:
C-M-i
)