Emacs C mode 的一个#if 代码高亮问题

#if 0
...
#endif

代码块的颜色变灰以后,改成 #if 1 也不恢复代码高亮。 如图: emacs-c-question font-lock-fontify-buffer 也不行。

只有关掉buffer,重新打开文件才能恢复

font-lock-flush 试试

没有这个函数, 26已经移除这个函数了吗。 toggle font-lock-mode 也不行

redraw display呢 和这个差不多名字的函数

我认为修改 font lock 不应该是首先考虑,解决问题思路应该是这样的:

  1. 先检查 lsp 是否安装&配置正确。

    如果 lsp 配置都不正确了,此时修改 font lock 就舍本求末了。

  2. 是否 ls 本身的 bug。

    如果 ls 安装&配置正确且已经启用, #if ... 条件成立,其包裹的代码是可以跳转和高亮的。

    我之前也遇到类似问题:#if 条件成立,代码仍然是灰色 -->> 幫忙改進 C++ LSP 體驗 #58,选用正确 libclang 重编之后就正常了 -->> 幫忙改進 C++ LSP 體驗 #63。 虽然不完全一样,但说明 ls 存在 bug 的可能性。

    按理说,只要修改源代码&存盘,ls 立即就会解析。可以编译 debug 版本,把 log 抓出来看看,ls 是否有立即响应代码变更。


APPEND 2018-09-06 18.40.43

把以前的测试代码翻出来,录了一组动图:

emacs-lsp-cquery-detect-if-macro-change

那确实可能是llvm的问题,lsp应该配置正确,可以正常补全,高亮同名符号。 如果的你的ccls是静态编译的话请发我一份,我回去用mac试一试,不是静态就算了。

也没有效果,可能是llvm的问题。

cc-mode的#if高亮不瞭解。我知道GNU Global也有類似於碰到#if 0就停止索引的邏輯,但不準確,使用lsp是比較推薦的。

clang 5.0.0的libclang有#ifdef無法索引的重大缺陷。4.0 5.0 5.0.1的libclang都有default template template argument的SIGSEGV bug (因爲crash recovery保護,只有一個檔案有問題,會無法索引)。clang 6很穩定。

  1. after-save-hooklsp-on-save (lsp-mode)發送textDocument/didSave給language server (ccls)
  2. ccls更新改檔案的索引,發送$ccls/setSkippedRanges (cquery爲$cquery/setInactiveRegions)和$ccls/publishSemanticHighlighting
  3. lsp-mode收到後交給adapter ccls.el處理,後者更新font-lock / overlay (取決於ccls-sem-highlight-method)

惊现ccls作者。 使用的就是 lsp-mode,还有你的ccls。系统是archlinux,用的是你特意说明修复 SIGSEGV bug 的版本。 #if 0 之后确实无法索引,但是改成 #if 1 后虽然代码高亮没有恢复,但此时是可以索引的。 所以问题出在第三步??

strace -s9999 -f -e write -p $(pgrep -fn ccls) or sysdig -As9999 --unbuffered "proc.exe contains ccls and fd.type=pipe"$ccls/setSkippedRanges是否包含#if 1 #endif區域。行列號從0開始

新建了个 test.c 测试一下。

YY%E6%88%AA%E5%9B%BE20180908205016

#if 0 的时候:

\"skippedRanges\":[{\"start\":{\"line\":2,\"character\":0},\"end\":{\"line\":5,\"character\":0}}]}}", 220) = 220

#if 1的时候:

\"skippedRanges\":[]}}", 155) = 155

没有包含 #if 1 #endif 的区域

那麼很清晰,language server (ccls)在這裏是好的。你需要看看爲什麼

https://github.com/maskray/emacs-ccls/blob/master/ccls-semantic-highlighting.el#L309

(defun ccls--clear-skipped-ranges ()
  "Clean up overlays."
  (while ccls--inactive-overlays
    (delete-overlay (pop ccls--inactive-overlays))))

你可以看下這個defun是不是沒生效

  • $ccls/setSkippedRangesccls--handlers
  • ccls.el初始化自身時向lsp-mode註冊ccls--handlers
  • 收到language server的$ccls/setSkippedRanges後,ccls--clear-skipped-ranges被間接呼叫清除舊的font-lock/overlay

确实是这个函数没有生效,添加(interactive)手动执行这个函数后代码高亮恢复。