lsp-bridge -- 速度最快的语法补全插件

@manateelazycat 大佬你用smerge的功能嘛?

  <<<<<<<
  UUU
  =======
  LLL
  >>>>>>>

lsp-bridge没开的时候(smerge-keep-upper)的输出是正确的,是UUU

开了lsp-bridge之后smerge会有遗留一些marker变成

  <<<<<<<
  UUU

你说的是 lsp-bridge 和 smerge 冲突? 还是 lsp-mode?

这张架构图底部和左上角替换 tramp 的功能已经完成, 还差右上角和 lsp-bridge 交互的地方。

交互的地方完成以后, lsp-bridge 结合 nova 就可以实现 VSCode 远程实时补全了。

先分享给大家, 有好的建议, 大家一起讨论。 :wink:

2 个赞

不好意思,手滑打错了,是lsp-bridge和smerge冲突

有些插件依赖于 after-change-functions 比如 org 的命令, 会和 lsp-bridge 冲突。

你把 smerge 的命令加入到上面连接的地方试一下, 就是符合 this-command-string 如果是 smerge- 开头的字符串就不执行连接下面的代码。

你试一下, 应该可以解决你的问题。

提一个issue吧, 我看看怎么融合 lsp, snippet, tabnine 等补全内容, 又不要把配置搞的太复杂了。

原来没有开放这一块API的原因就是 capf 那些多后端融合因为自定义搞的具复杂无比。

diff --git a/lsp-bridge.el b/lsp-bridge.el
index 4b07814..71e2262 100644
--- a/lsp-bridge.el
+++ b/lsp-bridge.el
@@ -1157,7 +1157,7 @@ So we build this macro to restore postion after code format."
     (let ((this-command-string (format "%s" this-command)))
       ;; Record last command to `lsp-bridge-last-change-command'.
       (setq lsp-bridge-last-change-command (format "%s" this-command))
-
+      (print (format "running: %s" this-command-string))
       ;; Record last change position to avoid popup outdate completions.
       (setq lsp-bridge-last-change-position (list (current-buffer) (buffer-chars-modified-tick) (point)))
 
@@ -1179,8 +1179,10 @@ So we build this macro to restore postion after code format."
                  ;; Most org-mode commands will make lsp-bridge failed that casue (thing-at-point 'symbol t).
                  ;; We only allow `org-self-insert-command' trigger lsp-bridge action.
                  (not (and (or (string-prefix-p "org-" this-command-string)
-                               (string-prefix-p "+org/" this-command-string))
+                               (string-prefix-p "+org/" this-command-string)
+                               (string-prefix-p "smerge-" this-command-string))
                            (not (string-equal this-command-string "org-self-insert-command")))))
+        (print "execution")
         (let* ((current-word (thing-at-point 'word t))
                (current-symbol (thing-at-point 'symbol t)))
           ;; TabNine search.

加了一些print,看起来像是skip了但是还有是问题


"running: smerge-keep-upper"


"running: undo-tree-undo"

"execution"

(smerge-keep-lower)的时候会看到以下log,不知是否有帮助

Debugger entered--Lisp error: (wrong-type-argument integer-or-marker-p nil)
  #<subr delete-region>(5774 nil)
  ad-Advice-delete-region(#<subr delete-region> 5774 nil)
  apply(ad-Advice-delete-region #<subr delete-region> (5774 nil))
  delete-region(5774 nil)
  smerge-keep-n(3)
  smerge-keep-lower()
  funcall-interactively(smerge-keep-lower)
  command-execute(smerge-keep-lower)

你要自己看了,欢迎发补丁。

应该是这段引起的,注释掉就没事了 :sweat_smile:

我想想怎么改

;; lsp-bridge/lsp-bridge.el:1166

;; Send change_file request to trigger LSP completion.
(when (lsp-bridge-call-file-api-p)
  (lsp-bridge-call-file-api "change_file"
                            lsp-bridge--before-change-begin-pos
                            lsp-bridge--before-change-end-pos
                            length
                            (buffer-substring-no-properties begin end)
                            (lsp-bridge--position)
                            (acm-char-before)
                            (buffer-name)
                            (acm-get-input-prefix)))

你这个看起来像一个补丁插件, 为啥要开 lsp-bridge ? 关闭可以吗?

不是呀,合并的时候有conflict,那些mark都是在源文件里的呀。用smerge可以快速选择保留哪一份

lsp-bridge 和 nova 已经对接起来了, 已经实现了Emacs中远程补全的方案。

上图就是直接编辑远程服务器的文件, lsp-bridge 的Python模块和LSP Server 运行在服务器上, 由服务器来计算远程文件的补全信息, 然后实时传送补全菜单数据会本地, 再由 lsp-bridge 的 elisp 模块进行补全菜单渲染。

我晚上测试的性能和本地一样, 完全感觉不到是远程服务器在计算, 性能比 VSCode 那种网页渲染的还要快很多。

lsp-bridge 和 nova 都写了大量补丁才搞定, 太晚了, 先睡觉了, 明天补一下怎么配置远程服务器的文档。

26 个赞

lsp-bridge 也可以像 VSCode 那样对远程服务器的文件提供代码语法补全。 对于那些资源要求过高或者运行环境配置复杂, 不方便在本地开发的大型复杂软件,提供远程代码补全的功能是很有用的。以下是配置远程代码补全的步骤:

  1. 下载 nova: nova 是一个多线程的远程文件编辑和同步插件, 利用多线程技术保证编辑远程文件时不会卡住 Emacs
  2. novaserver.py 拷贝到远程服务器,并执行命令 python3 server.py 启动 nova 的服务端
  3. 在远程服务器上安装 LSP Server、lsp-bridge 和 Emacs
  4. 在远程 Emacs 中配置默认加载 lsp-bridge 插件, 并自动启动lsp-bridge服务(lsp-bridge-start-process)
  5. 使用命令 nova-open-file 打开远程文件,输入远程服务器 IP 和文件路径,比如 xxx.xxx.xxx.xxx:/path/file

远程文件打开后,lsp-bridge会自动弹出补全菜单。lsp-bridgenova协同工作的原理是:

  1. nova通过 SSH 认证的方式登录远程服务器, 并访问和编辑远程文件
  2. 在本地编辑远程文件时,lsp-bridge会实时发送 diff 序列给 nova 服务端, nova 会根据 diff 序列在服务端重建文件的最新内容
  3. 编辑远程文件产生的 LSP 请求转发到服务器端的lsp-bridgelsp-bridge会根据远程文件最新内容和服务器里的 LSP Server 进行语法补全计算
  4. lsp-bridge在远端计算好 LSP 补全菜单项后,发送补全数据到本机,再由本机的 lsp-bridge 进行补全菜单渲染

如果补全菜单没有弹出,请登录远程服务器,打开 Emacs,查看 *lsp-bridge* 缓冲区的内容。一般情况下,都是由于服务端的 Emacs 插件或者 LSP Server 没有安装完整导致的。

6 个赞

lsp-bridge 的所有补全后端 lsp, file words, path, sdcv, tailwindcss, tabnine, 已经支持远程服务器了。

大家可以更新体验下。

4 个赞

lsp-bridge 和 nova 都更新到最新版, 才把远程服务器的LSP文档查看的功能补上, 昨天忘记这个API了。

1 个赞

Done, 用这个选项吧, 现在更灵活了。

1 个赞

谢谢大佬,已经调好了!

不过能不能在文档中说明一下 candidate 的枚举值和含义是什么?不然配置的时候还是要摸索一下的……

比如我是想把 yas-snippet 的补全放在首位,我先看了下代码里可能包含的 candidates :

lsp-candidates
path-candidates
yas-candidates
tabnine-candidates
tempel-candidates
mode-candidates
mode-first-part-candidates
mode-second-part-candidates
mode-candidates-split-index
template-candidates
template-first-part-candidates
template-second-part-candidates
citre-candidates

首先我下意识把 yas-candidates 排在了最前面,但是使用的时候依然发现 yas 的结果不在第一位,然后又尝试了把 template-first-part-candidates 放在了第一位就好了。

这里如果能说明一下就会更容易配置了 :grin:

1 个赞

这个地方就是不好解释呀, 因为其实大家希望多个补全后端在第一屏快速混合, 至于第一屏以后, 大家其实不是很关心。

我之前不想暴露这个接口的目的就是不想重蹈 capf 的覆辙: 后端都装好了, 各种折腾, 快折腾死了, 多个后端还没法融合显示。

今天其实也没有想的太好, 主要临时改一下让你先用着(前几天在开发 nova 没顾上), 等过段时间没有那么疲劳了再看看怎么设计这个接口。

1 个赞

好的好的,谢谢大佬。能用上我就知足了 :joy:

今天写了一个新的补丁 Start lsp-bridge only need python, don't need Emacs. · manateelazycat/lsp-bridge@fd80ffa · GitHub

现在远程补全不需要在服务端启动Emacs, 直接启动 lsp-bridge 的Python模块就好了:

  1. 在远程服务器上安装 lsp-bridge 以及对应的LSP Server
  2. 启动lsp-bridge 服务: python3 lsp-bridge/lsp_bridge.py
  3. 使用命令 lsp-bridge-open-remote-file 打开远程文件,输入远程服务器 IP 和文件路径,比如 xxx.xxx.xxx.xxx:/path/file

lsp-bridge依赖的elisp代码, 我想了办法, 让lsp-bridge服务端通过SSH隧道反向来本机查找Elisp变量和函数值。

最新的设计的好处是:

  1. 用户只用在服务器安装 lsp-bridge 和 LSP Server就行了, 不需要在远端安装编辑插件
  2. Emacs插件和配置全部在本地
  3. lsp-bridge会自动探测所处的环境, 选择用本地还是远端 lsp-bridge 代码去计算补全菜单
10 个赞