一直以来都是使用 Corfu 的 TAB-and-Go 模式自动补全,但有时发现自动补全有点干扰输入,所以最近打算尝试手动按需启动补全。
但是直接使用 TAB 键触发 completion-at-point 的话,就没法使用 TAB 触发 Yasnippet 的 snippet 展开,也无法使用 Emacs 默认的 TAB 缩进 (indent-for-tab-command)。
参考了帖子 解决Yasnippet和Company的TAB冲突问题 中大佬们分享的方案, 还有 Emacs TG 中文群中群友的帮助,目前整合为以下方案, yas-expand,缩进(indentation)和补全都可以用 TAB来触发。
欢迎大家指点和帮忙改进。
(defun smarter-yas-expand-indent-or-complete ()
"Try to `yas-expand' and `yas-next-field' at current cursor position.
If failed, try indent command, then try `completion-at-point'"
(interactive)
(cond
((and yas-minor-mode (yas-active-snippets))
(yas-next-field))
(t
(let ((old-point (point))
(old-tick (buffer-chars-modified-tick)))
(yas-expand)
(when (and (eq old-point (point))
(eq old-tick (buffer-chars-modified-tick)))
(if (derived-mode-p 'c-mode 'c++-mode)
(call-interactively 'c-indent-line-or-region)
(unless (derived-mode-p 'haskell-mode)
(indent-for-tab-command)))
(when (and (eq old-point (point))
(eq old-tick (buffer-chars-modified-tick))
(not (region-active-p)))
(if (check-expansion)
(completion-at-point))))))))
(defun check-expansion ()
(save-excursion
(if (looking-at "\\_>") t
(backward-char 1)
(if (looking-at "\\.") t
(backward-char 1)
(if (or (looking-at "->")
(looking-at "::"))
t nil)))))
(define-key prog-mode-map (kbd "<tab>") 'smarter-yas-expand-indent-or-complete)
indent-for-tab-command 在 haskell-mode中无法正常使用,目前还没找到方案。C/C++ 中保留了使用 c-indent-line-or-region 进行缩进。

