又有人给emacs开发了一个lsp客户端

好像是flymake的作者, flymake虽然内置于emacs里, 但是好像没什么人用, 在emacs26里面, 作者来了个大更新, 然后现在又自己搞了个lsp客户端, 原因之一是为了和flymake集成.

lsp-mode里面宏用的挺多, 代码不容易搜索(describe-function), 印象不太好, 这个不知道会怎么样, 拭目以待.

http://lists.gnu.org/archive/html/emacs-devel/2018-05/msg00201.html

稍微看了一下它好像是只有一个单一的包,而不是像 lsp-mode 那样需要各种语言的适配器

Emacs 要求至少 26 才行

看了一下作者在 reddit 上的留言,作者之所以又搞了一个 lsp 客户端的原因是当他开始搞的时候还不知道 lsp-mode 的存在,我看了一些这个项目去年 8 月份就开始了,两个项目的思路差别还是蛮大的,我觉得没有必要过分的排斥 https://www.reddit.com/r/emacs/comments/8ijoem/eglot_emacs_polyglot_an_emacs_client_to_language/

Flymake 是重写一遍,不算大更新。

Flymake has been completely redesigned

Flymake now annotates arbitrary buffer regions, not just lines. It supports arbitrary diagnostic types, not just errors and warnings (see variable ‘flymake-diagnostic-types-alist’).

It also supports multiple simultaneous backends, meaning that you can check your buffer from different perspectives (see variable ‘flymake-diagnostic-functions’). Backends for Emacs Lisp mode are provided.

The old Flymake behavior is preserved in the so-called “legacy backend”, which has been updated to benefit from the new UI features.

Emacs 社区的目标就是让 LSP 内置到 Emacs 中,现在 Flymake 作者自己不仅写 LSP 客户端,又重写了一遍 Flymake ,让两者更好的整合在一起,你们不觉得这个才是被教主钦定的 LSP 客户端吗?

最后八卦一下,Flycheck 的原作者转投 Vim 了。

原作者是谁,为何跑了

内部几乎完全重新设计了一遍, 还不算大更新?

其实lsp-mode的作者也有意愿将lsp-mode集成到emacs里, 基础功能分离就是为这个目标, 没想到现在又出了一个, 挺热闹的.

lsp-mode 代码不好搜索,部分原因也是因为它比较完善代码量大了。

这个 eglot 这样做法不太好吧,选用什么 ls 组织上钦定了,无视各种 ls 还在竞争当中,没有完全定型吗?它打算内置多少种语言呢,还是仅仅写个例子做参考而已:

(defvar eglot-server-programs '((rust-mode . ("rls"))
                                (python-mode . ("pyls"))
                                (js-mode . ("javascript-typescript-stdio"))
                                (sh-mode . ("bash-language-server" "start")))
  "Alist mapping major modes to server executables.")
  
...

;;; Rust-specific
;;;
(defun eglot--rls-probably-ready-for-p (what proc)
  "Guess if the RLS running in PROC is ready for WHAT."
  (or (eq what :textDocument/completion) ; RLS normally ready for this
                                        ; one, even if building ;
      (pcase-let ((`(,_id ,what ,done ,_detail) (eglot--spinner proc)))
        (and (equal "Indexing" what) done))))

...

除了 lsp-mode 之外,还有个 lsp-ui,是不是也再造一遍?

这个问题不大, 自己修改一下eglot-server-programs的值就可以了, 我更喜欢这种方式, 修改的地方比较集中, 反倒感觉挺方便.

看文件只有1000多行, 就实现了常用的lsp的功能

不应该说代码量太大, 还是因为宏用的太多了, 仅仅代码量大不影响describe-function

ui这种本来就是多种多样, 不同的人喜欢不同的风格.

没有看出“集中”在哪里,这些代码放在用户配置里,也不会造成不集中。何况作者想要把它提交为内置包,我不认为 Emacs 开发者能接受这种把某个特定 ls 的配置写进基础包的做法。

不能这么看。验证核心功的时侯可以写得简洁一点,要达到可用的程度,处理各种枝末细节的问题,代码自然就多了,然后开始抽象/复用。。也少不了会用到宏。

lsp-mode 现在 1100 多次提交,代码 2500 多行,注释近 500 行,测试近 300 行,似乎也没有很臃肿。


一些函数不能跳转,确实有点烦,不过在 lsp-mode 中没那么严重吧,大家还是对 spacemacs 吐槽比较多。

不能跳转也不是因为它是宏,而是因为没有实现相应的查找规则。宏没什么特别的 (最常用的 defun 就是宏),都是文本查找而已:

  • find-function-regexp

    "^\\s-*(\\(def\\(ine-skeleton\\|ine-generic-mode\\|ine-derived-mode\\|ine\\(?:-global\\)?-minor-mode\\|ine-compilation-mode\\|un-cvs-mode\\|foo\\|\\(?:[^icfgv]\\|g[^r]\\)\\(\\w\\|\\s_\\)+\\*?\\)\\|easy-mmode-define-[a-z-]+\\|easy-menu-define\\|menu-bar-make-toggle\\)\\(?:\\s-\\|
    \\|;.*
    \\)+\\('\\|(quote \\)?%s\\(\\s-\\|$\\|[()]\\)"
    
  • find-function-regexp-alist

    ((define-mode-local-override . xref-mode-local-find-override)
     (define-overloadable-function . xref-mode-local-find-overloadable-regexp)
     (flycheck-checker . flycheck-find-checker-regexp)
     (define-type . cl--typedef-regexp)
     (cl-defgeneric . cl--generic-find-defgeneric-regexp)
     (cl-defmethod . cl--generic-search-method)
     (nil . find-function-regexp)
     (defvar . find-variable-regexp)
     (defface . find-face-regexp)
     (feature . find-feature-regexp)
     (defalias . find-alias-regexp))
    

lsp是干嘛使的?

作者是此人,有没有跑,我不知道。

https://twitter.com/lunaryorn/status/792644690797625344

个人觉得flycheck比flymake好用多了,为什么不能内置呢?

貌似是因为原作者不愿意

https://github.com/flycheck/flycheck/issues/1177#issuecomment-267445833

emacs 的邮件列表里也有关于这个问题的讨论

https://lists.gnu.org/archive/html/emacs-devel/2017-10/msg00499.html

emacs 现任维护者 John Wiegley 也对 flycheck 的作者发出过邀请,希望可以将 flycheck 加入 elpa 进而成为 emacs 的一部分,不过可惜被拒绝了

https://github.com/flycheck/flycheck/issues/801

flymake 完全重写了,到时候也可以重新试试看。 其实现在安装软件都是包管理,即便不内置安装起来也不是太麻烦,选择自己喜欢的用就可以了。

2 个赞

宏太多,不会测试… 没法测试是配置的lsp server有问题,还是lsp-mode有问题,还是lsp server的哪个步骤出了问题

写 elisp 不可避免用到宏,一些习以为常的东西都是宏,比如 defun / when / unless / dolist / with-eval-after-load / ...

那些很好用/方便的的“函数”,大胆怀疑它们是宏就对了,基本没跑。

定义了一大堆宏还不够,后来又引入 cl。可以说,没用宏就不能愉快地写 elisp。

如果对宏那么排斥,就不应该这样定义函数:

(defun foo ()
  (message "foo"))

应该写成这样:

(defalias (quote foo)
  (function
   (lambda nil
     (message "foo"))))
3 个赞

不好意思,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是在哪定义的?

可以,至少可以定位到具体是在哪个文件定义的。宏最终都是要展开成函数的,展开的函数并不会跨文件。有 60 年历史的 Lisp 不可能没人想到这种问题。

你可以自己试试,用 C-h f 完全可以查到这种方式定制的函数。

dufun 自己就是宏,defun 定义的函数可以在 Emacs 中查到定义位置,没有道理别的宏不行。

至于不能具体定位,只是写的宏不够精致而已,像是 eieio 这种“第三方”定义的宏,也能用 Emacs 自带的 describe-function 查询定义位置。