写 elisp 不可避免用到宏,一些习以为常的东西都是宏,比如 defun / when / unless / dolist / with-eval-after-load / ...
。
那些很好用/方便的的“函数”,大胆怀疑它们是宏就对了,基本没跑。
定义了一大堆宏还不够,后来又引入 cl
。可以说,没用宏就不能愉快地写 elisp。
如果对宏那么排斥,就不应该这样定义函数:
(defun foo ()
(message "foo"))
应该写成这样:
(defalias (quote foo)
(function
(lambda nil
(message "foo"))))
3 个赞
LdBeth
17
不好意思,lambda
也是宏。
lambda is a Lisp macro in ‘subr.el’.
(lambda ARGS [DOCSTRING] [INTERACTIVE] BODY)
(defalias (quote foo)
(list (quote lambda) nil
(quote (message "foo"))))
4 个赞
我是能用内置都就尽量用内置的,可惜flymake实在不给力。
假如一个函数或者宏内部可以定义函数, 定义的函数名字根据输入的参数来定, 比如参数是: prefix和name, 最终他定义的函数名是prefix和name的值合起来转换为符号名, 这样的函数能搜索吗?
(my-define-function (“hello” “world”)) 会定义一个函数, 名字为hello-world, 如何查看这个函数的定义? 如何找到hello-world是在哪定义的?
LdBeth
20
可以,至少可以定位到具体是在哪个文件定义的。宏最终都是要展开成函数的,展开的函数并不会跨文件。有 60 年历史的 Lisp 不可能没人想到这种问题。
你可以自己试试,用 C-h f 完全可以查到这种方式定制的函数。
dufun 自己就是宏,defun 定义的函数可以在 Emacs 中查到定义位置,没有道理别的宏不行。
至于不能具体定位,只是写的宏不够精致而已,像是 eieio 这种“第三方”定义的宏,也能用 Emacs 自带的 describe-function 查询定义位置。
你这个问题我以前也提到过。
我现在配置文件基本是这样的:
;; misc.el
(definitfun foo
:pre
(progn ...)
:post
(progn ...))
解析的时侯原地展开为:
;; misc.el
(defun misc--pre-init-foo ()
(progn ...))
(defun misc--post-init-foo ()
(progn ...))
这两个函数仍然在 misc.el 文件中,所以 describe-function
可以跳到 misc.el 文件头。如果我再实现一个跨行匹配 (definitfun pkg\n :pre
的方法,就能准确跳到 :pre
的位置。
然而实际上我并没有实现那个跳转方法(暂时没这个需求),而是给 imenu regex 加了一条规则用来定位整个 (definitfun pkg ...)
。
1 个赞
比如cquery的lsp-cquery-enable, 用describe-function可以打开cquery.el文件, 光标在文件开头, 具体定义还要自己找, 甚至看很多代码
对, 试了一下lsp-cquery-enable, 是跳到cquery.el文件开头, 但这还不够啊, 还要看很多代码才行
看了一下, 就是这个情况, 就是感觉这个不方便. 特别是跟踪调试的时候, 想起以前有一个c语言用宏实现的hash table, 虽然可能效率很高, 但是调试太麻烦了, 也很难看懂, 要么就展开再调试, 感觉麻烦
lsp-mode 的做法是更进一步,它把整个函数的实现都放在另一个宏里面,无数个 lsp-<language>-enable
都对应这同一块代码。我上边的例子,函数的主体其实还在声明的这一端,比较有存在感。
然而 eglot 项目也不是为了解决这个问题而成立的。作者只是想用一个统一的 eglot
函数作为入口,而非每一种语言对应一个 eglot-<language>
。把整个函数的实现放在另一个宏里面,目前的代码里已经有了,以后随着项目越来越完善,这种情况只会更多:
其实调试不必纠结 lsp-<language>-enable
能不能定位到,直接看它后边的函数 lsp--enable-stdio-client
。把它看作跟 eglot
一样,是统一的入口。lsp-<language>-enable
和 lsp--enable-stdio-client
之间几乎只是参数传递。
eglot 绝对比 lsp-mode 好用
lsp-mode 一旦 Kill buffer 就会导致各种报错, eglot 可以保持后台重新连接, 没有各种奇怪的报错.
eglot 的作者写出的代码开箱即用, 插件要看实际运行的效果, 而不是只看代码本身, 如果代码写的再好, 但是用户体验和质量做的一团糟, 我想没人想敲几个字符就 backtrace 吧?
ztlevi
30
lsp-mode
有imenu,find-references之类的功能。imenu index的支持对js开发者简直是福音。不过希望大神提出的这些问题lsp-mode
能够早日解决吧。
https://github.com/emacs-lsp/lsp-mode/blob/master/lsp-methods.el#L877
(add-hook 'kill-buffer-hook #'lsp--text-document-did-close nil t)
kill-buffer
會發送當前document的textDocument/didClose
notification,solargraph (Ruby language server)在這種情況下會斷線?
还没有深入研究, kill-buffer 会导致 solargraph 的端口被占用, 因为 lsp-ruby 是写死端口号的.
應該用 stdin/stdout,stdin/stdout用fifo (emacs)
yicao
34
都不怎么滴,没nvim好用。我全都测过。同一份代码。nvim瞬间补全,而且我看过cquery cpu,触发补全时,cpu非常低。用emacs时,cpu就会非常高,而且持续好几秒,最终的表现就是补全速度非常慢。估计是发消息太太太频繁了。不如nvim客户端优化的好。
yicao
35
lcn cpu最低10%,eglot其次30%。lsp mode最高,能达到70%。
所以补全速度的体验也是天壤之别。有空我👆个图,让大家看看