基于 Company 编写了一个带中文注释的英文补全助手

  (setup (:pkg corfu)
    (:option
     ;; Optional customizations
     corfu-cycle t                ;; Enable cycling for `corfu-next/previous'
     corfu-auto t                 ;; Enable auto completion
     corfu-preselect-first nil    ;; Disable candidate preselection
     )
    (:with-map corfu-map
      (:bind "TAB" corfu-next
             "S-TAB" corfu-previous))
    (corfu-global-mode))
  ;; Enable Corfu completion UI
  (setup (:pkg corfu-doc :host github :repo "galeo/corfu-doc")
    (:hook-into corfu-mode))

  ;; (setup (:pkg svg-lib :type built-in)) ;; built-in has little icons
  (setup (:pkg kind-icon)
    (:load-after corfu)
    (:option kind-icon-default-face 'corfu-default) ; to compute blended backgrounds correctly
    (:when-loaded
      (add-to-list 'corfu-margin-formatters #'kind-icon-margin-formatter)
      ))

这是我关于corfu的全部代码,你可以参考一下。主要实现了补全、文档展示、svg icons等功能,orderless直接不用改就能用,模糊补全啥的都有。

别忘了注释掉所有的company代码哈哈。

补充:想起来这是corfu首页的那一堆代码,你直接复制官方的就用,我的这个多余了 :rofl:

多谢,我参考官网的先试试,你的也可以参考一下 :grinning_face_with_smiling_eyes:

搞出来发出来,让我们抄抄啊。

得益于English-helper的精简,简单注释几行就能用了,目前还缺一点对齐。等晚上有空搞吧,这会比较忙没时间搞这个

(defun english-helper-annotation (s)
  (let* ((translation (get-text-property 0 :initials s))
         (translation-format-string (replace-regexp-in-string "\\cc" "" translation))
         ;; (max-translation-length (+ 1 (apply 'max (mapcar 'length company-candidates))))
         (candidate-length (length s))
         (translation-length (length translation))
         (translation-format-length (length translation-format-string))
         ;; (blank-length (max 0 (- max-translation-length candidate-length)))
         (dot-length (max 0 (- company-english-helper-candidate-max-width (- translation-length translation-format-length)))))
    ;; (format "%s" (concat (make-string blank-length ?\ )
    (format "%s" (concat
                         translation
                         (make-string dot-length ?\.)))))

(setq completion-at-point-functions
      (list (cape-company-to-capf #'company-english-helper-search)))

1 个赞

水平太菜写了一点半成品。不需要改english-helper代码,把下面几行代码找个文件加载进emacs,然后用的时候M-x toggle-corfu-english-helper 就可以了。目前我不知道怎么恢复completion-at-point-functions原来的内容,所以只能用buffer-local这种work-around方法,保证不影响其他buffer的使用。求大佬指点一下

(defvaralias 'company-candidates 'corfu--candidates)
(defun company-grab-symbol ()
  "If point is at the end of a symbol, return it.
Otherwise, if point is not inside a symbol, return an empty string."
  (if (looking-at "\\_>")
      (buffer-substring (point) (save-excursion (skip-syntax-backward "w_")
                                                (point)))
    (unless (and (char-after) (memq (char-syntax (char-after)) '(?w ?_)))
      "")))

(defun toggle-corfu-english-helper ()
  (interactive)
  (if (not (featurep 'company-english-helper))
      (require 'company-english-helper))
  (if (not corfu-mode)
      (corfu-mode t))
  (make-variable-buffer-local 'completion-at-point-functions)
  (setq completion-at-point-functions
	(list (cape-company-to-capf #'company-english-helper-search)))
    (message "English helper has enable."))

(provide 'company)

匹配和对齐都是english-helper做好的(这个包接口写的干净,都不用改)。corfu补全效果如下:

可以无视顺序模糊匹配,比如图中的 r 和 o 交换毫无影响

2 个赞

这个代码我试了好多次都没成功 除了这段代码还有其他的处理嘛 :rofl:

不好意思今天刚看到,我冷启动emacs试了一下是可以的:

Untitled

是不是你没安装cape?这个我漏讲了

和English helper有关的代码就在上面。至于corfu的配置我的都在这里,不过大部分都是个人偏好的选项,你直接使用默认配置应该也能用的

  (setup (:pkg corfu)
    (:option
     ;; Optional customizations
     corfu-cycle t                ;; Enable cycling for `corfu-next/previous'
     corfu-auto t                 ;; Enable auto completion
     ;; (corfu-quit-at-boundary t)     ;; Automatically quit at word boundary
     corfu-quit-no-match t        ;; Automatically quit if there is no match
     corfu-preview-current nil    ;; Disable current candidate preview
     corfu-echo-documentation nil ;; Disable documentation in the echo area
     corfu-auto-prefix 2
     )
    (:with-map corfu-map
      (:bind [tab] corfu-next
             [backtab] corfu-previous
             "<escape>" corfu-quit))
        (corfu-global-mode)
    )
  ;; corfu backend
  (setup (:pkg cape)
    (add-to-list 'completion-at-point-functions #'cape-file)
    (add-to-list 'completion-at-point-functions #'cape-tex)
    (add-to-list 'completion-at-point-functions #'cape-dabbrev)
    (add-to-list 'completion-at-point-functions #'cape-keyword))

  ;; Enable Corfu completion UI
  (setup (:pkg corfu-doc :host github :repo "galeo/corfu-doc")
    (:hook-into corfu-mode))

  ;; (setup (:pkg svg-lib :type built-in)) ;; built-in has little icons
  (setup (:pkg kind-icon)
    (:load-after corfu)
    (:option kind-icon-default-face 'corfu-default) ; to compute blended backgrounds correctly
    (:when-loaded
      (add-to-list 'corfu-margin-formatters #'kind-icon-margin-formatter)
      ))

setup里面的那一堆宏,你也可以忽略直接去用各自包的github readme的实例代码,跟我的基本一致。

1 个赞

其实English helper的代码很简练明白,直接重写一个corfu的版本会很快。现在这种dirty的方法的好处是如果english helper更新了,就可以很方便的跟进

1 个赞

我和你不同的地方是 我是用的原生的方式管理的 也可能是因为Emacs版本不同导致的

这个代码对我来说够复杂啦 :joy:

哦哦,我贴一个原生的你试试,你是用package.el吗,那个会自动管理autoload,我不太清楚这些包有没有上melpa,如果没有你可能的git下来,几个包手动require一下。

(eval-after-load 'corfu
  #'(lambda nil
      (progn
	(setq corfu-cycle t)
	(setq corfu-auto t)
	(setq corfu-quit-no-match t)
	(setq corfu-preview-current nil)
	(setq corfu-echo-documentation nil)
	(setq corfu-auto-prefix 2)

	(define-key corfu-map [tab] #'corfu-next)
	(define-key corfu-map [backtab] #'corfu-previous)
	(define-key corfu-map [escape] #'corfu-quit))))
(corfu-global-mode)
;; corfu backend
(add-to-list 'completion-at-point-functions #'cape-file)
(add-to-list 'completion-at-point-functions #'cape-tex)
(add-to-list 'completion-at-point-functions #'cape-dabbrev)
(add-to-list 'completion-at-point-functions #'cape-keyword)

(add-hook 'corfu-mode-hook #'corfu-doc-mode)

(eval-after-load 'corfu
  #'(lambda nil
      (require 'kind-icon)
      (setq kind-icon-default-face 'corfu-default)
      (add-to-list 'corfu-margin-formatters #'kind-icon-margin-formatter)))
1 个赞

我遇到的问题是这样的:

(require 'corfu)
(require 'corfu-doc)
(require 'cape)
(require 'company-english-helper)
(defvaralias 'company-candidates 'corfu--candidates)

到这里就报错error: Don’t know how to make a localized variable an alias

我用的是最新的master,native compile。请大佬指导一下 :kissing_heart:

自问自答:顺序很重要,这样是可以的:

(defvaralias 'company-candidates 'corfu--candidates)
(require 'corfu)
(require 'corfu-doc)
(require 'cape)
(require 'company-english-helper)

简单试用了下corfu,没有感受到明显的优点,性能好像差不多。原来简单配置就行,现在反而一大堆包 :joy:

默认配置好像不支持自动补全?试用过程中我只要自己用快捷键或者命令来弹出,是哪里姿势不对吗?有一个致命问题是,corfu只支持27+。另外要加图标也得自己搞一把,有时间再研究下。

(setq corfu-auto t)不过corfu的自动补全默认是不管候选项有没有上屏,回车都会自动输入第一个候选,除非用C-g退出或者hack一下corfu-insert。 感觉corfu跟orderless一起用挺爽的,company虽然也能用orderless,但是不像corfu能直接用空格分词,需要换成比如&

我配置了下面几个项,跟 company 体验就比较像了, 我还不习惯空格分词。

(use-package corfu
  :init
  (setq corfu-cycle t)
  (setq corfu-auto t)
  (setq corfu-quit-at-boundary t)
  (setq corfu-quit-no-match t)
  (setq corfu-preview-current nil)
  (corfu-global-mode))

我今天写了一个新的,主要的作用是把english-helper这类包里对company的依赖模拟了出来。解决了之前遗留的当前buffer没办法退出的问题。现在有几个优点:

  1. 通过模拟api的方式,使得依赖company的包可以在不修改源码的情况下直接运行在corfu上,包括可以使用模拟补全等功能,
  2. advice,可以完整支持 English-helper-company-togggle之类的包方法,而无需像之前那样单独写一个corfu-toggle。也就是说,之前激活和关闭使用toggle-company-english-helper, 现在也可以直接用这个命令切换,无需写额外的配置,支持了包自带的方法。
  3. 理论上其他依赖company的第三方包也能够直接使用,甚至无需什么额外配置。

使用方法,将下面的代码load进emacs。

  (defvaralias 'company-candidates 'corfu--candidates)
  (defalias 'company-mode 'corfu-mode) ;; should be deleted
  (defvaralias 'company-mode 'corfu-mode) ;; should be deleted
  (setq company-backends '())
  (setq completion-at-point-functions-backup completion-at-point-functions)
  (provide 'company)

  (defun set-completion-functions ()
    (setq completion-at-point-functions (cl-concatenate 'list (mapcar #'cape-company-to-capf company-backends) completion-at-point-functions-backup)))

  (defun company-grab-symbol ()
    "If point is at the end of a symbol, return it.
    Otherwise, if point is not inside a symbol, return an empty string."
    (if (looking-at "\\_>")
        (buffer-substring (point) (save-excursion (skip-syntax-backward "w_")
                                                  (point)))
      (unless (and (char-after) (memq (char-syntax (char-after)) '(?w ?_)))
        "")))
  (advice-add 'toggle-company-english-helper :after #'set-completion-functions)

关键是对需要使用的包的激活函数添加一句advice,用法就像上面的最后一行,比如我要使用一个名为“graphviz-company-mode‘ 的函数,那就写成:

(advice-add 'graphviz-company-mode :after #'set-completion-functions)

相当于骗了这些包:“我装了company,你随意运行吧”,其实只装了corfu哈哈哈

1 个赞

Untitled

这张图展示了几种状态:

  1. 没有启动English-helper,这个时候是corfu的补全
  2. 调用English-helper自带的toggle-company-english-helper,可以看到包激活了,并且在下方打印了enable
  3. 测试补全,能看到英文的中文提示了 4.继续调用 toggle-company-english-helper,功能被正确的关闭,打印了disable,然后补全恢复启用前的状态

我之前很少写elisp代码,这些都是东拼西凑的,也不知道对不对,大佬们如果愿意指点一下就太好了。我后面就更新在自己的配置文件里,尽量不让话题偏离english-helper了,会放到这个org文件的最后一个小节“simulate company with corfu”。使用corfu的感兴趣的童鞋可以参考一下啦

1 个赞

其实 company 挺好的,corfu 的优点好像是代码比较简单,貌似直接就是自带 capf 的一个 ui 一样的存在。

用 company 的话可以多个 capf 后端进行轮询,确定后是否直接通过 company-capf 使用,还是继续跟 company 自己的其他后端组合,可能性要更高一点,覆盖的使用领域也明显更广一点(至少对我来说是这样的,特别是现在很多应用接入 capf 后)。

2 个赞

我看corfu 的 wiki 中说,因为 Corfu 可以集成 Orderless ,对候选的过滤和选择是在 Emacs 即时完成的,不需要重新请求 LSP sever。这对于速度慢的 lsp server 来说,可能会快很多。

不知道各位用 Corfu 的有没有感觉快了 :smile:

原文:

速度没感觉,功能还少了不少