改进 cquery rainbow semantic highlighting和推進feature/noverlay分支開發

我今天給 emacs-cquery 加了實驗性的 rainbow semantic highlighting 。順便說下,已嘗試添加 cquery.el 到 Melpa,等待維護者批准。

cquery 是一個 C/C++/Obj-C language server,實現查找定義、引用、符號搜索、顯示光標處符號類型簽名等功能。 semantic highlighting 是cquery擴展功能,LSP協議中未定義。

原理是索引 C/C++ 文件時記錄符號(var/func/type)的 ClangSymbolKind,如:Struct Variable Parameter EnumConstant等。

文檔新打開或保存時,cquery會發送semantic highlighting信息。EmitSemanticHighlighting 製作信息後發給 language client。Semantic highlighting 功能 cquery原本就有,VSCode 的插件支持,但Emacs裏用得人很少,只有單色。這次我把符號種類從原來的 {member,free}{function,variable}/type 5種細分了下,再把VSCode用的配色方案導入到cquery.el,根據stableId渲染符號,把 face 的:foreground設置爲colors[stableId % len(colors)]。我的elisp技能有限,各位感興趣的話求幫忙改進

Emacs cquery 安裝配置參見 wiki Emacs · jacobdufault/cquery Wiki · GitHub , 啓用彩虹只需

(cquery-use-default-rainbow-sem-highlight)

另:渲染這個10000多行的文件,不管用 (setq cquery-sem-highlight-method 'overlay)還是'font-lock ,都很慢的。使用 'overlay 的話用Emacs noverlay分支能改善。

(defun cquery--make-sem-highlight (region buffer face)
  "."
  (pcase cquery-sem-highlight-method
    ('overlay
     (let ((ov (make-overlay (car region) (cdr region) buffer)))
       (overlay-put ov 'face face)
       (overlay-put ov 'cquery-sem-highlight t)))
    ('font-lock
     (put-text-property (car region) (cdr region) 'font-lock-face face buffer))))

(defun cquery--publish-semantic-highlighting (_workspace params)
  "."
  (when cquery-enable-sem-highlight
    (let* ((file (cquery--uri-to-file (gethash "uri" params)))
           (buffer (find-buffer-visiting file))
           (symbols (gethash "symbols" params)))
      (when buffer
        (with-current-buffer buffer
          (save-excursion
           (with-silent-modifications
             (cquery--clear-sem-highlights)
             (dolist (symbol symbols)
               (-when-let (face (funcall cquery-sem-face-function symbol))
                 (dolist (range
                          (mapcar 'cquery--read-range (gethash "ranges" symbol)))
                     (cquery--make-sem-highlight range buffer face)))))))))))

Rainbow semantic highlighting樣式:func/var/type 各預設了10種顏色,member func/var用相應顏色的斜體。

現在 (defcustom cquery-sem-member-func-faces [cquery-sem-member-func-face] 這樣的定製方式是很笨拙的。我的這種根據 ClangSymbolKind 劃分色譜區間取色的方式對於顏色定製也不夠方便:

    (pcase kind
      ;; var
      (4 (funcall fn0 cquery-sem-free-var-faces 600 700)) ; Macro
      (13 (funcall fn0 cquery-sem-free-var-faces 0 600)) ; Variable
      (25 (funcall fn0 cquery-sem-free-var-faces 700 1000)) ; Parameter
      (14 (funcall fn0 cquery-sem-member-var-faces 400 1000)) ; Field
      (15 (funcall fn0 cquery-sem-member-var-faces 200 400)) ; EnumConstant
      (21 (funcall fn0 cquery-sem-member-var-faces 0 200)) ; StaticProperty

      ;; func
      (12 (funcall fn0 cquery-sem-free-func-faces 0 800)) ; Function
      (18 (funcall fn0 cquery-sem-free-func-faces 800 1000)) ; StaticMethod
      (22 (funcall fn0 cquery-sem-member-func-faces 800 1000)) ; Constructor
      (23 (funcall fn0 cquery-sem-member-func-faces 1000 1000)) ; Destructor
      (24 (funcall fn0 cquery-sem-member-func-faces 1000 1000)) ; ConversionFunction
      (16 (funcall fn0 cquery-sem-member-func-faces 0 800)) ; InstanceMethod

      ;; type
      ((or 6 7) (funcall fn0 cquery-sem-type-faces 0 700)) ; Struct | Class
      (10 (funcall fn0 cquery-sem-type-faces 1000 1000)) ; Union
      (11 (funcall fn0 cquery-sem-type-faces 700 1000)) ; TypeAlias
5 个赞

希望能讓這個東西方便地定製,比如有些人希望 InstanceMethod (C++ member function) 斜體 (:slant 'italics) 有些人希望 underline ;希望 Macro 粗體等;怎麼復用現在的調色盤 https://github.com/cquery-project/emacs-cquery/blob/master/cquery.el#L147 把幾種 face 合併起來。

越来越现代化了

我应当怎么改默认的样式呢,比如

(defface cquery-sem-member-face
  '((t :slant italic))
  "The extra face applied to member functions/variables."
  :group 'cquery-sem)

我想不要加斜体,我试了在 spacemacs 里面的 user-init 先定义

(defface cquery-sem-member-face
      nil
      "The extra face applied to member functions/variables.")

也去不掉。

通过

  (face-spec-set 'cquery-sem-member-face
                 '((t :slant "normal"))
                 'face-defface-spec)

解决了

我很久以前也改進過 'font-lock 性能了(給emacs-cquery的最後一個commit,以後不可能再push了,因爲用自己的 https://github.com/MaskRay/emacs-ccls 了)。我現在也在用 font-lock,因爲 feature/noverlay 不更新很久了