First cut on lsp-mode restructoring

lsp

#1

yyoncho想大刀闊斧改lsp-mode,會吸收一些eglot好的地方。

大家可以到 https://github.com/emacs-lsp/lsp-mode/pull/469 看。

  • session機制
  • lsp-restart
  • lsp-auto-guess-root。自動猜project root,大多數時候這是期望行爲,但是他用lsp-java很想要workspace folders。
  • lsp-auto-configure。向M-x eglot靠攏,自動啓動lsp-uicompany-mode

演化的方向應該是workspace folders+每個workspace多server。我有點擔憂實作複雜性。大家多給出反饋意見吧。

另外lsp-mode前陣子5.0了,我有一些重的翻新:

* Rename lsp-symbol-highlight to lsp-document-highlight
  We should keep consistency with LSP names
* Delete lsp-enable-codeaction
  It does not make sense to update codeAction again and again in eldoc
  They can add it to lsp-eldoc-hook if they really want the feature
* Delete lsp-hover-text-function, lsp-enable-eldoc, lsp-highlight-symbol-at-point in favor of lsp-eldoc-hooks
  lsp-ui-doc users are not affected.
* Add defcustom lsp-eldoc-hook to customize requests to send (default: documentHighlight, hover)
* Use add-function instead of setq to set eldoc-documentation-function

* Bump to 5.0

挺心累的,現在不得不盯着看有沒有悄悄溜進來的PR加default-directory損害C/C++的體驗。有這麼一類檔案,比如/usr/include/stdio.h,他們被打開時自身不應該啓動language server。而是使用爭搶制,看那個project的buffer第一個跳到他們,把workspace資訊populate到/usr/include/stdio.h。對於這類檔案,lsp--suggest-project-root返回nil(不啓動language server)是最合適的。

eglot實現了一個有趣的LSP UTF-16移動: https://github.com/joaotavora/eglot/commit/7b4ed9736f8ab21adeee0205546d160313ab8b8f


lsp-mode新接口lsp.el
#2

ou xiang


#3

@seagle0128 Please read https://github.com/emacs-lsp/lsp-mode/pull/474


#4

我在 github 上回复你了。 我明白你的 concern 了,主要是 C/C++ 头文件中不想启用 lsp。似乎也算一种特例。其他编程语言尤其是脚本单独使用的情况也很多,所以像之前提到的需要 trade-off。我个人在本地作了 hack,可以针对单个文件启用 lsp。 说老实话,怎么看起来都不是很完美的解决方案,也许可以参考下其他编辑器比如 vscode 怎么处理的。 这个话题也许还要深入讨论下去。


#5

謝謝你明白我說的什麼。這裏yyoncho沒有表態,lsp-mode owner經常處於裝死狀態,如果你不主動提出要revert /改owner會把這個拖很久的。你可以叫他儘快開publicly editable wiki (我看上去是個"Member"但在lsp-mode沒有任何權限,包括改wiki)

這個沒必要參考vscode怎麼處理。他們的做法不見得好/對,它的workspace folders使用起來過分透明,經常在使用者不知情的情況下做出(經常是愚蠢的)選擇。

yyoncho不想force push是擔心Melpa,你隨便找個什麼地方弄個乾淨的改動,讓它重置那7個commit,加上這個新日期的commit,Melpa就正常了

把一個隨意的directory當作project是個不好的行爲。特別在現在的lsp-mode model,選錯project根本無法方便地撤回。在workspace folder和session management引入後情況也許能好轉一些,但注意yyoncho主要考慮地是lsp-java使用情景。

lsp-mode上很多提問的人只是想着自己方便就隨便提個issue/PR(當然我也是這樣,主要想C++,但還是會考慮其他語言的)。否則也不會發 https://github.com/emacs-lsp/lsp-ruby/pull/6 這些(沒被理睬,我也沒力氣繼續和他們爭辯。在這裏費些精力和你爭辯,你可以幫忙去上游討論,這個owner判斷力不夠)eglot作者判斷力明顯好很多,但他在很多地方也有(我覺得奇怪的)見解。因爲慣性我繼續用lsp-mode

(a): 我之前提的,直接去改那個語言的client (像是lsp-python),不過我也不希望直接在client裡面寫死(以前lsp-python就是直接寫死),應該教導user使用advice去改變行為(可以把相關的advice寫在readme裡面),或是也在client裡面做一個feature,讓使用者自己去選擇要不要在return nil的時候用default directory當root

(b): 在lsp-mode裡面多加一個feature, 像是lsp-if-nil-use-default-dir-as-root (抱歉想不到什麼好名字XD), 然後用個list紀錄這些有特別行為的language server ,像是lsp-if-nil-use-default-dir-as-root-list。然後每次開啟找root的時,如果 (1) return nil (2) lsp-if-nil-default-as-root 是 t (3) 那個language server有在 lsp-if-nil-use-default-dir-as-root-list裡面,滿足這三個條件才把 當下的directory設成root


#6

我用lsp-mode很多的地方是Org Mode Babel source block的代码补全。多是javascript,python,ruby,php之类的脚本代码。

以下有一些相关的链接:


#7

项目讨论争辩是在所难免的。lsp-mode很多 feature 还是很不错的,owner 也许有他自己的一些考虑。我觉得你提的方案 b 比较可行。很多脚本语言单独使用的情况确实很多,所以在 lsp client 中加入默认project root 其实也是可以的。这也是为什么你修改了 lsp-python 之后我发现不工作才提交 PR 给lsp-mode。对我而言,其实两种方案都是可以的。刚发现其实其他 client 也没有用默认的 project root detection,所以这里其实存在很大的 gap。我已经删除 fork 的库,不知道你希望怎么操作,如果可能讨论完你直接改就好了。或者你告诉我详细步骤,我再提交比较稳妥。

说到eglot,我也使用过。Centuar Emacs 中可以选择。配置很方便,跟 flymake 设计理念相同。不过目前功能还比较孱弱,而且与 flymake 默认绑定。我主要使用 flycheck,还放不下 lsp-ui 这样的功能,所以还是坚持在用 lsp-mode。希望两者互相促进发展吧。目前这两个性能都不算太好,似乎都比不上 vim-lsp,更不用说 vscode 啦。都是后台解析 REST JSON,不知道改用 emacs 默认的解析库是否有改善。希望后续有所改进。


#8

是的,这也是为什么这个 PR 争论很久的原因。@MaskRay 主要考虑 C++,@yyoncho 主要考虑 Java,我呢,Python,Ruby,Go 用得比较多,C/C++也用但现在相对少些。org src block 的使用场景就是典型的单个临时文件,但希望有补全、跳转等功能。相信你以前用了我提供的方案,应该是可以工作的。我后来又做了一些优化包装,可以参考 https://github.com/seagle0128/.emacs.d/blob/master/lisp/init-lsp.el#L63 ,已经解决所有问题。


#9

你畢竟還是弄壞了東西,然後你只發了一個"Two cents here."。你不去https://github.com/emacs-lsp/lsp-mode/pull/470 主動說你想revert lsp-mode owner會繼續裝死的。

owner 也许有他自己的一些考虑。

我幾乎想說你想得太美好了,owner很多情況就是不會做出合適的選擇,或者不管不問。


#10

我想说明下,我理解你的 concern,但是并不代表认可你的 solution。之前你对lsp-mode 和lsp-python的改动造成了行为的变化,在文档中也未有说明,而且对projectile 和 project 两者的行为也没有统一。这也是我提这个 PR 的初衷,我在提交过程中也有明确说明,yyoncho 也认可这个方案,所以 owner approve。至于你的 concern,主要是认为打开系统的 C++头文件不方便。我在讨论中也明确说了,这点上目前方案确实不完美,所以需要折衷考虑,能解决大部分场景是可以的。yyoncho也指出后续会有backlist之类的功能,加入到就完美解决了。如果不想启动 lsp 也可以临时关闭 lsp-mode。因此,我找不出一定要去主动 revert的理由。

另外,在讨论过程中你数次指责 owner 装死,做的决定不合理。我们建议参考其他项目的实现比如 eglot、vscode,你都不屑一顾。这种态度和语气也是我不敢苟同的。难道你每次的选择就一定是最合理最完美的?做项目还是要听取多方意见综合考虑,有时是需要妥协的。如果真的不认可大可以另起炉灶,没必要公开指责。至少在这个case 中,我认为你的方案就不是很好。除了上述描述外,还有一个问题,你的改动还要求所有 client 作相应适配,但我没有看到其他 client 作者收到通知。我相信也很难说服他们主动修改。当然我提交的 PR 方案也不完美,但是能应付大多数场景,应该算 better solution,有其他新 feature 支撑就能更完善,这也是我和@yyoncho的观点。心平气和参与项目,相信会更好的,希望这次不要更生气呀。


#11

right.


#12

Thanks. I will check out this in some languages.


#13

作为这个pr无关者,这里我是支持@MaskRay的,至少他给出了具体的(在我看来合理的)方案以及论述。至于对owner的指责,他确实已经很长时间处于不作为的状态了.或许如他自己所说,现实繁忙,没有精力。但是这并不影响我们的判断,如果不是@MaskRay@yyoncho,或许lsp mode已经处于一个半死亡状态,另外说到revert的理由,我觉得至少squash应该算一个,当然决定权在于@seagle0128,最后说一点,开源项目中一味做个老好人,想来对项目是弊大于利的。


#14

I some thought and suggestion or the lsp-org-babel-enbale macro. Bellowing list is from my original task list thought:

  • [X] detect ~:file~ header argument exist?
  • [X] if not exist, create a fake one ~:file /tmp/tmp.(lang ext)~
  • [X] detect ~lsp-mode~ enable?
  • [ ] Detect function ~org-babel-edit-prep:lang~ exists first.
  • [ ] Then create it if not exist.
  • [ ] If exists already, advice before original function.
  • [X] Echo message lsp-java setup
  • [X] add support to Org source code ~:file~

#15

@MaskRay 在PR里tag的BooAA就是我,在这边我也想发表一些意见。

就技术上来说,我也不支持这次改动。在return nil的时候把当下的directory设成root虽然对很多script language很方便,但是对C/C++的header会有问题(我不确定会不会有其他语言也受到影响)。如果要接受这个改动,势必某些client一定要对这种情况做处理(e.g. emacs-ccls就可能要对header的情况自己处理)。

相比之下,原先的作法只是会对某些client带来不便,你永远可以自己开一个资料夹然后把东西放进去,在建一个.projectile之类的,这只是会带来不方便,但是不一定要动到client端(eg lsp-python),我自己权衡之下我觉得以前的作法可能稍微好一点。 (不过我的说法也不一定对,这也是为什么我们需要在这边讨论的原因)

而就专案的协作上,我觉得owner的作法确实不妥当,在大家还没有讨论出一个共识的情况下就轻率的merge(我什至怀疑他有没有仔细的看过改动的内容),如果接下来出现了一连串新的PR,然后他也继续这样merge,那到时候想改回来就为时已晚了。

所以我认为revert的最大理由不光是到底这样的改动好不好,而是我们根本还没有明确的共识,为何不好好讨论之后再做决定?

令外 @Maskray 同时作为language server 跟client的作者(ccls跟emacs-ccls),我相信他一定有参考过其他的专案,以前他也在论坛上发表过学习eglot的心得,同时在vscode上也有vscode -ccls,他应该是参考之后觉得vscode的作法没有比较好才这么说的,不是单纯的自大狂妄。

当然他的措辞确实不当,在公开场合批评别人确实不应该,但正如上面 @lambdacn 所说的,如果只想一味的当老好人那专案很难进步的。所以还是希望大家可以着重在技术的讨论而不要模糊焦点。

另外 @seagle0128 无论最后要不要revert PR,你提出的改动都是很有意义的, 至少让其他人知道很多script language有这样的需求,而lsp-mode作为一个library性质的专案也确实应该要考虑到不同语言之间的需求。


#16

谢谢这么中肯而且客观的评论。个人也不是推崇做老好人,该争论就争论,就事论事作为技术从业者其实都没有什么问题。但是也不能偏激,一味指责也是没有意义的。Owner 的做派其实我不是非常了解,接触不算多。但是对@yyoncho 印象还是不错的,反馈积极及时,也会跟你沟通方案。我在其他几个 issue 里其实也看到不少人在积极讨论开发对于workspace folder 的方案。如果 owner 忙,其实可以委托几位信任的开发者进行review 和 merge。我想yyoncho和 MaskRay应该就在其中吧,个中辛酸我想他们更有发言权。所以讨论技术问题我个人是很支持的。如果还是觉得 owner 不作为或者阻力大,不如大家重新 fork 继续开发,岂不是更好?

这点我非常赞成。因为我只是提出了一个问题,yyoncho也赞成,让我提交一个 PR。后边为什么 approve 我就不是很清楚了。如果没有讨论清楚确实不应该 merge。当然,回到这个问题本身,我说了两个方案都不完美。这又回到一个鸡生蛋蛋生鸡的问题上了,既然上一个方案也有问题,当初又是怎么通过的呢?不是在引战,这点确实是有问题的。因为我看到各种 client 现在做法都不统一(比如lsp-python, lsp-java, lsp-ruby, lsp-go),我自己使用时需要各种 hack。所以我非常赞成你说的这句话。

现在改动 server,需要考虑到各种语言,包括编译型、脚本类,所以没有一个开发者能完全清楚,这点大家讨论甚至争论都是很正常的,不存在谁弄坏了东西。现在这个 PR 让大家意识到这点就已经达到目的了。另外,我还是想说一点,有时靠创建一个类似于.projectile 文件来指定项目也是不行的,比如上面提到的org babel src block。另外,projectile 和 project 的行为还是没有统一,既然引入了就必须考虑这点。

BTW,我个人目前配置文件采用了如下 hack,所以如果revert 回去也是没有问题的。对于不同的语言也可以在这个 advice 中处理。

     ;; HACK: Project detection
     ;; If nil, use the current directory
     ;; https://github.com/emacs-lsp/lsp-python/issues/28
     (defun my-default-directory ()
       "Returns the current directory."
       default-directory)
     (advice-add #'lsp--suggest-project-root :after-until #'my-default-directory)

#17

谢谢你的建议,不错的想法,我会考虑加进去,但不一定是全部 feature。我们可以一起讨论。 有个问题:

这个有什么意义呢?这个宏的目的就是想启用 lsp 啊。

我已经更新了一个版本,如果函数存在就add advice。


#18

FYI,VS Code在这里的做法其实反而是非常不透明,不“智能”的:所有 project root 必须手动指定。即有一个打开文件夹的功能,凡是在这里打开过的就会被认为是 project root,没有的就不会。(实际用的时候还得结合那个“保存workspace”,即保存某个 project root 集合的功能来用,不然如果开的多的话打开会烦死)


#19

是的。它的Open Workspace Open Folder我從來沒有弄懂過,所以我也問過幾次workspace folders是怎麼運作的,但依然很模糊。

自動選project root仍然是個很棒的、適合多數人的設計。yyoncho改lsp-mode我得堤防他不要把這個常見功能改得難以使用了。

對於樓上的人,我還是希望你主動提出這個改回來。注意到vibhavp現在確實很少管理了,merge時可能根本沒仔細看,yyoncho也不是依賴自動選project root功能的,他Approve可能是當時失手了。他不用這個功能,所以470不置可否,對473也懶得搭理。

还有一个问题,你的改动还要求所有 client 作相应适配,但我没有看到其他 client 作者收到通知。我相信也很难说服他们主动修改

對emacs-lsp organization想象得太美好了,大多數repo只有vibhavp一人可以merge。我之前還有心情的時候想把:get-root改對他除了lsp-python都沒理睬。

这点上目前方案确实不完美,所以需要折衷考虑,能解决大部分场景是可以的。

不僅僅是是否你的改動解決了絕大多數需求。還有:

  • 是否引入了新的選項
  • 新的選項是否和已有功能重疊(projectile-require-project-root)
  • 是否對未來改進造成困擾
  • 不加到lsp-mode,加到client / user config是否可行

之前你对lsp-mode 和lsp-python的改动造成了行为的变化,在文档中也未有说明,而且对projectile 和 project 两者的行为也没有统一。

“在文档中也未有说明”我不認同。

我在無數場合說過我沒有編輯權限了,哪怕是改wiki的權限。我也數次給你提到過你可以表態讓vibhavp把wiki變得publicly editable。

我想yyoncho和 MaskRay应该就在其中吧

前面說過了,我不在其中。

剛剛在gitter上問yyoncho

I approved it before reading your comment about about header files and then I commented that what you are saying make sence

希望这次不要更生气呀

說不生氣只能是我騙自己。在這件事情上已經浪費了我至少三個小時。


#20

大家要认真看待一个问题, 全世界编写 elisp 插件的黑客, 90%都不是全职的, 都是利用自己的下班时间在做贡献.

lsp-mode 的作者肯定是发现LSP以后, 很兴奋的实现这个插件, 给自己用也给别人分享快乐.

但是 LSP 不管怎么说, 撇开 server 的不均衡发展, lsp-mode 要面对所有具有 lsp server 的编程语言, 这个难度和工作量已经远远超过一个业余贡献开发者的精力.

面对这样爆炸性需求的问题, 只有几个方案:

  1. 像微软VScode那样, 提供财力全职开发
  2. 强力hacker提供大范围重构, 满足需求 (这个也很难, 因为能够大范围重构要求对项目很熟悉)
  3. 实在看不惯, 自己重新设计和写一个, 只要做的好, 社区的人会用脚投票的

我想表达什么?

  • 如果目标一致, 大家都想改进 LSP, 不管遇到什么困难, 沟通是解决问题的方法
  • 如果看不惯, 自己重新写一个

但是千万不要为了补丁细节, 互相指责, 不管创建者还是贡献者都是牺牲自己业余时间贡献代码方便大家, 在我看来不管做的怎么样都是值得赞扬的事情.