codeLens: 如何固定在行末顯示字串 (附codeAction/codeLens介紹)

今天翻新了一下ccls的codeLens和codeAction。下面簡單介紹下這兩個LSP requests

  • textDocument/codeAction: clang FixIt,如void main(){}自動更正爲int main(){} textDocument/codeAction可返回 (Command | CodeAction)[] | null,目前lsp-mode僅處理Command[],這個PR添加edit?: WorkspaceEdit;的支持。

    • 插入void main() {}
    • textDocument/publishDiagnosticsvoid處warning
    • M-x lsp-execute-code-action and select the action
    • ccls返回CodeAction[]
    • lsp-mode自動更正爲int main() {}
  • textDocument/codeLens: 原來cquery的做法,codeLens返回值包含所有refs/derived/bases/vars的Location[],因爲三種原因會造成緩慢:

    • 消息很大。如果有1000 refs那麼就返回1000 Location[]。服務端要計算一會兒
    • Emacs JSON deserialize慢
    • 把LSP的Location (line/character)翻譯成(point)慢。大量(goto-char 1) (forward-line l) (forward-char c)操作。根據我的理解,移動操作的時間和移動距離正相關。

現在改成ccls僅返回

"command":{
  "title":"1 var",
  "command":"ccls.xref",
  "arguments":["{\"usr\":16926293689053220079,\"kind\":2,\"field\":\"instances\"}"]}}

取代原來的1000 Location[]。點擊1000 refs overlay時,發送workspace/executeCommand,帶上"arguments",ccls返回1000 Location[]。參照下圖理解。

我另外加了ccls-code-lens-position,預設爲'end,用overlay after-string放置到行末。但無法防止point移動到overlay右邊,如何避免呢?

        (-let (([l0 c0 l1 c1 command] lens))
          (forward-line (- l1 line))
          (let ((ov (pcase ccls-code-lens-position
                      ('end
                       (let ((p (line-end-position)))
                         (make-overlay p p)))
                      ('inplace
                       (forward-char c1)
                       (make-overlay (point) (point))))))
            (overlay-put ov 'ccls-code-lens t)
            (overlay-put ov 'after-string (ccls--make-code-lens-string (if (= l1 line) "|" " ") command)))
          (setq line l1)
          )

point移動到overlay右邊可以打字,不過好在這個是暫時的,textDocument/didChange觸發diagnostics更新後,emacs-ccls會重新請求codeLens,overlay又會被重新放置到行末。

放到右邊不inplace干擾後我打算預設開啓了 (add-hook 'lsp-after-open-hook #'ccls-code-lens-mode)。如果這個能改好體驗會更棒一些。

另外改進lsp-ui-sideline.el顯示code lens也是個好主意。等人來實現~

4 个赞

但無法防止point移動到overlay右邊,如何避免呢?

可以用 display overlay 放到 \n 上,不过只能放一个overlay

'display "asd\n"放在\n上,還是能移動到asd右邊。

(make-overlay p (+ 1 p) nil t nil)

感謝。修好了

(let ((line 0) (col 0) ov)
      (seq-doseq (lens result)
        (-let (([l0 c0 l1 c1 command] lens) (pad " "))
          (pcase ccls-code-lens-position
            ('end
             (forward-line (- l0 line))
             (if (and ov (= l0 line))
                 (overlay-put ov 'display
                              (concat (overlay-get ov 'display)
                                      (ccls--make-code-lens-string (if (/= c1 col) "|" " ") command)))
               (when ov
                 (overlay-put ov 'display (concat (overlay-get ov 'display) "\n")))
               (let ((p (point-at-eol)))
                 (setq ov (make-overlay p (1+ p) nil 'front-advance))
                 (overlay-put ov 'ccls-code-lens t)
                 (overlay-put ov 'display (ccls--make-code-lens-string " " command))))
             (setq line l0 col c0))
            ('inplace
             (forward-line (- l1 line))
             (forward-char c1)
             (setq line l1)
             (setq ov (make-overlay (point) (point)))
             (overlay-put ov 'ccls-code-lens t)
             (overlay-put ov 'after-string (ccls--make-code-lens-string " " command)))))
        )
      (when (and (eq ccls-code-lens-position 'end) ov)
        (overlay-put ov 'display (concat (overlay-get ov 'display) "\n"))))

仍然有問題。在一個有overlay的行如void foo() { 1 ref按 evil 的 o 打開新行,會把overlay拖到下一行

我只想问一下,textDocument_codeLens.cc 那张图用的是什么主题?看起来配色很好啊 :star_struck:

;;; 本文預設開啓codeLens
  (add-hook 'lsp-after-open-hook #'ccls-code-lens-mode)

;;; rainbow semantic highlighting
  (setq ccls-sem-highlight-method 'font-lock)
  (ccls-use-default-rainbow-sem-highlight)

有篇舊文 改进 cquery rainbow semantic highlighting和推進feature/noverlay分支開發 我用ccls後又加了一些優化,比如把line/character改成Emacs-style point減少response體積

歪个题,字体和主题很赞