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

dap-mode 依赖 lsp-mode, 需要安装 lsp-mode 才行,然后用下面的 wrapper 可以在不启动 lsp-mode 的情况下使用 dap-mode

  ;; 下面的 wrapper 可以在不启动 lsp-mode 的情况下通过 lsp-workspace-root 获取正确的值
  (eval-and-compile
    (defun my--ensure-lsp-workspace-root()
      "Ensure `lsp-workspace-root' valid."
      (require 'lsp-mode)
      (unless (lsp-workspace-root)
        (let* ((session (lsp-session))
               (lsp-auto-guess-root t)
               (project-root (lsp-f-canonical (lsp--calculate-root session (buffer-file-name)))))
          (unless (-contains? (lsp-session-folders session) project-root)
            (cl-pushnew project-root (lsp-session-folders session))
            (lsp--persist-session session))
          ))))

  (defun my/dap-debug()
    "dap-debug wrapper."
    (interactive)
    (require 'dap-mode)
    (my--ensure-lsp-workspace-root)
    (call-interactively #'dap-debug)
    )

完整的 dap 配置见:GitHub - xhcoding/.emacs.d: A simple Emacs config on Windows

5 个赞

补全可以用了,但是定义跳转不能用,提示没有相关定义,切回lsp-mode是没问题的

最麻烦的地方是 jupyter notebook 的 web 版本的每一个单元格的编辑框就是一个 web 的编辑框,而不是 emacs 的 buffer,因此即使它可以在 eaf 里运行,也是一个普通的网页来运行。

vscode 是重写了整个 jupyter notebook 的前端,所以每一个单元格都可以当作一个正常的 vscode 的文本编辑区域来使用。

原来如此,我还以为 vscode 是用 html + CSS 来实现 jupyter notebook 的呢。

jupyter 就是在 Web 上运行上,现在个人使用体验最好的就是 google 的 colab。

eaf 需要一个额外的 leader key 才能将按键发送到浏览器,我比较习惯在浏览器中也用类 vim-mode 进行浏览,多了个 leader key 总是适应不了。

EAF可以直接用 switch_to_input_mode (Alt + z) 来切换成输入模式, 就不需要 leader key 了。

这样呀,是我蠢了 :dizzy_face:。等我后续再尝试一下 eaf。

eaf-browser访问 localhost:8888 的 jupyter notebook 感觉挺好的

h 可以看看快捷键

没有了解到这一点之前,在用 org-mode 文学编程,也挺不错

破案了,是after-change之后的search-regexp系把smerge依赖的matching-beginningmatch-end给冲走了。

不知道大佬有什么思路去修这个,我手动补了几个save-match-data之后刚修好,pull了master之后又不好用了,因为有新的代码用了search-regexp

1 个赞

你详细写一下这个重现步骤和问题吧,我有点没看懂你说的东西。

在smerge-mode下,在conflict marker里跑smerge-keep-lower

<<<<<<< HEAD
    this.code.doThat(true, false);
=======

    this.code.doThis(true);
    this.var = blah;
>>>>>>> b66071d1 (refactor: fix bug)

这个smerge最后会用到下面的code

;; /usr/local/share/emacs/29.0.90/lisp/vc/smerge-mode.el.gz:299

(defun smerge-keep-n (n)
  (smerge-remove-props (match-beginning 0) (match-end 0))
  ;; We used to use replace-match, but that did not preserve markers so well.
  (delete-region (match-end n) (match-end 0)) ;; lsp-bridge会监控到变化,search-backward-regexp 会代替掉global的matching beginning
  (delete-region (match-beginning 0) (match-beginning n))) ;; match-beginning已经被修改 (match-beginning n)会返回nil, delete-region失败

我在我的旧版本里wrap了几个地方,但是pull了master之后就不work了。这个不能从根本上解决问题

manual上是这么写的,但lsp bridge应该不是process filter functions也不算process sentinels?

Emacs automatically saves and restores the match data when it runs process filter functions (see Process Filter Functions) and process sentinels (see Sentinels: Detecting Process Status Changes).

把这个命令加到 lsp-bridge/lsp-bridge.el at ce463c9fc4137364ff85f89ae44d6762c425f69d · manateelazycat/lsp-bridge · GitHub

这个黑名单试一下?

试过了不work

    ;; Send change_file request to trigger LSP completion.
    (when (or (lsp-bridge-call-file-api-p)
              (lsp-bridge-is-remote-file))
      (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) ;; <====== 这行已经破坏了match
                                (buffer-name)
                                (acm-get-input-prefix)))


    ;; Complete other non-LSP backends.
    (lsp-bridge-complete-other-backends)

看不懂你说的啥意思。

lsp-bridge不是用emacs的子进程,不需要 process filter这些

1 个赞

我整理一下吧

smerge依赖re-search-forward的结果来擦除conflict markers

此时buffer状态

<<<<<<< HEAD
    this.code.doThat(true, false);
=======

    this.code.doThis(true);
    this.var = blah;
>>>>>>> b66071d1 (refactor: fix bug)
  1. smerge跑re-search-forward
  2. smerge先执行一段delete-region (一共两段)
(defun smerge-keep-n (n)
  (smerge-remove-props (match-beginning 0) (match-end 0))
  ;; We used to use replace-match, but that did not preserve markers so well.
  (delete-region (match-end n) (match-end 0)) ;;<=== 这行,执行成功
  (delete-region (match-beginning 0) (match-beginning n)))
  1. lsp-bridge看到buffer变化,进行相应的操作。这些期间调用了search-backward-regexp
  2. match-beginning跟match-end被lsp-bridge修改了
  3. smerge执行第二段delete-region (一共两段),因为match-beginning已经被修改了,(match-beginning n)返回nil,delete-region失败
(defun smerge-keep-n (n)
  (smerge-remove-props (match-beginning 0) (match-end 0))
  ;; We used to use replace-match, but that did not preserve markers so well.
  (delete-region (match-end n) (match-end 0)) 
  (delete-region (match-beginning 0) (match-beginning n))) ;;<=== 这行,失败了

结果上看buffer变成了这样,因为前三行没能被删掉

<<<<<<< HEAD
    this.code.doThat(true, false);
=======

    this.code.doThis(true);
    this.var = blah;

The functions you use in these hooks should save and restore the match data if they do anything that uses regular expressions; otherwise, they will interfere in bizarre ways with the editing operations that call them.

我按照手册建议把lsp-bridge-monitor-before-changelsp-bridge-monitor-after-changesave-match-data包了一下

这个PR ready了

已经合并, 感谢补丁。

1 个赞

泪了,我折腾半天搞好的Eglot,使用Lsp-bridge 就两行代码就解决了。我爱死你了懒猫。!!!

2 个赞