举例说明, 有如下三个候选项:
aaabbbaaa
aaaccc
aaaddd
输入aa aa
后, 等效于aa.*aa
, 能唯一匹配第一行, 而不是像orderless或者helm三行都匹配. 他们匹配输入的每个"component" 都是从候选字符串的开头开始, 很不方便.
期望的匹配算法如下:
比如针对第一行的aaabbbaaa
, 用户输入aa
后空格, 算法就把最左匹配(即候选项开头的aa
)去掉不再考虑, 剩余"abbbaaa", 然后用户又输入了第二个aa
, 那么就从剩余的abbbaaa
中搜索第二个aa
, 这样就唯一匹配到了第一行的候选项.
lynnux
2023 年11 月 16 日 15:03
2
consult rg默认风格不就是吗,虽然我不用,不过它是#分割
我说的不是这个搜索外部文件, 而是emacs内的补全界面, 比如切换buffer, M-x等.
helm 把输入的匹配字符串按空格分割,分成n个独立的部分,每个部分都去匹配候选项。这么做的优点是,可以忽略输入字符的顺序,例如 cc aa
可以匹配 aaaccc
,缺点是 aa aa
效果等同于 aa
,而你要得效果其实是把 aa aa
转换成 aa.*aa
,在 helm 上可以这样实现:
(cl-letf (((symbol-function 'helm-mm-3-get-patterns-internal)
(lambda (pattern)
(cl-loop for pat in (helm-mm-split-pattern pattern)
collect pat into pats
finally return (list (cons 'identity (string-join pats ".*")))))))
(completing-read "> " '("aaabbbaaa" "aaaccc" "aaaddd")))
2 个赞
fuzzy matching 的話, 我推薦 flx . magit
的維護者 @tarsius
認為這是 elisp 包裡唯一聰明的 演算法. 我自己也很喜歡用.
2 个赞
这个 flx 好像作者都不怎么维护了。能用在 Emacs 29 和 Emacs master 上吗? 和 orderless 相比有什么特点呢?
可以用啊~ 依照作者本人的意思. 這個插件已經接近完美了, 所以不需要更新! 我自己也蠻認同的!
aqua0210:
和 orderless 相比有什么特点呢?
orderless 可以配置的東西比較多. 但我怎麼配, 都沒有 flx 好用. 我因為開發 company-fuzzy 用了大概 10 幾種模糊匹配 (包含 completion-styles
) 的演算法; 最後總結, flx 比較好用.
不過這個本身就很吃使用習慣, 所以自己用的習慣就行! flx 的特色就是聰明 和短 , 但沒有配置選項.
2 个赞
flx 只支持 ido,没法和 vertico 配合。还是需要更新维护的。
还有个新的 hotfuzz, readme 中有 orderless 和 flx 的比对。这个比 orderless 多了排序,不用空格,比较像内置的 flex。
参考:https://github.com/minad/vertico/issues/177#issuecomment-1008182328
1 个赞
我用了很久的 orderless,习惯了。但最近发现左手拇指按太多 Meta 和 空格,开始痛了。所以我打算换掉 orderless。 对 fix 还是比较感兴趣的,可惜我不知道怎么让它在 Emacs 30中支持 completing-read
PS:原来可以通过 fussy 支持 flx:
用上了大佬写的 flx-rs + fussy, 体验很好。
1 个赞
xiyang
2023 年11 月 22 日 02:49
12
现在大家都用 consult
了吗?如果用的 counsel-*
,可以使用
(setq ivy-re-builders-alist
'((t . ivy--regex-plus)))
1 个赞
对, 就是这个意思, 以前用ido的时候, 就把它改成这样了, 感觉非常好用.
你这是怎么做到不高亮中间文本(abbb
)的? 中间匹配.*
的内容应该也会被高亮吧?
这个插件作者好像是国内的emacs早期玩家. 我看下这个插件能否实现我想要的功能
现在估计很多都用的virtio+consult, 我也是用的这个.
这个匹配算法接口如果遵循emacs内置的completion style, 好像是可以通用的, 类似orderless.
看了下ivy的好像不是这么设计的.
在我电脑上测试了下, 跟预期不一样, 匹配方式依然是老的方式, 可能是我的helm版本太老.
另外, 现在不怎么用helm, 主要用consult了.
@jcs090218 大佬,请问下用 fussy + flx 时下面这个结果是正常的吗?为什么 message-supersede
是第一候选,而不是 message
.
我的配置:
(use-package fussy
:custom
(completion-styles '(fussy basic))
(completion-category-defaults nil)
(completion-category-overrides '((file (styles basic partial-completion))
(eglot (styles fussy basic))))
(fussy-filter-fn 'fussy-filter-default)
(fussy-use-cache t)
:config
(advice-add 'corfu--capf-wrapper :before 'fussy-wipe-cache)
(add-hook 'corfu-mode-hook
(lambda ()
(setq-local fussy-max-candidate-limit 5000
fussy-default-regex-fn 'fussy-pattern-first-letter
fussy-prefer-prefix nil))))
目前没法用 flx-rs,因为我这边开开启 flx-rs 时,有些后选会丢失。可能和下面这个 PR有关。
jojojames:main
← jimeh:clean-flx-rs-score-strings
opened 07:01PM - 20 Nov 23 UTC
When using the `flx-rs` scoring backend, we need to run given string values thro… ugh `fussy-remove-bad-char-fn` to match the behavior of using the flx scoring backend.
Without cleaning up bad characters, `flx-rs` seems like it works, but a lot of result candidates do not appear, yielding a much smaller result set compared to using `flx`. This fixes that, so results for both match.
是正常的唷!
(flx-rs-score "message-supersede" "mes") ; (220 0 1 8)
(flx-rs-score "message" "mes") ; (214 0 1 2)
flx
的首字比重比較高.
[me]ssage-[s]upersede
大於,
[mes]sage-supersede
1 个赞
大佬,fussy 用 flx-rs 这个后端时会丢候选,我已经在 fussy 报了 issue. 有空帮忙看看是什么问题。
opened 12:58AM - 10 Dec 23 UTC
@jojojames and @jcs090218
When using the default backend `flx`, everthing is … working well, but when the number of candidates is large (such as 10000 and more), it is slow. So I tried to use the faster backend `flx-rs`.
But Some result candidates do not appear when using `flx-rs` with `M-x consult-imenu` or `M-x consult-line` .
steps to reprodue:
1. create and empty file `~/.emacs.d/init.el`
2. put the below minimal code in the `init.el` file
```emacs-lisp
;;; init.el --- user-init-file -*- lexical-binding: t -*-
(require 'package)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/"))
(package-initialize)
(package-refresh-contents)
(eval-and-compile
(setq use-package-enable-imenu-support t)
(setq use-package-expand-minimally t)
(require 'use-package))
(use-package flx-rs
:load-path "~/src/packages/flx-rs/"
:config
(setq fussy-score-fn 'fussy-flx-rs-score)
(flx-rs-load-dyn))
(use-package fussy
:ensure t
:custom
(completion-styles '(fussy basic))
(completion-category-defaults nil)
(completion-category-overrides '((file (styles basic partial-completion))
(eglot (styles fussy basic))))
(fussy-score-fn 'fussy-flx-rs-score)
(fussy-filter-fn 'fussy-filter-default)
(fussy-use-cache t)
:config
(advice-add 'corfu--capf-wrapper :before 'fussy-wipe-cache)
(add-hook 'corfu-mode-hook
(lambda ()
(setq-local fussy-max-candidate-limit 5000
fussy-default-regex-fn 'fussy-pattern-first-letter
fussy-prefer-prefix nil))))
(use-package vertico
:ensure t
:demand t
:bind (:map vertico-map
([tab] . vertico-next)
([backtab] . vertico-previous))
:custom (vertico-cycle t)
:config (vertico-mode))
;; Example configuration for Consult
(use-package consult
:ensure t
:bind (;; C-c bindings in `mode-specific-map'
("C-c M-x" . consult-mode-command)
("C-c h" . consult-history)
("C-c k" . consult-kmacro)
("C-c m" . consult-man)
("C-c i" . consult-info)
([remap Info-search] . consult-info)
;; C-x bindings in `ctl-x-map'
("C-x M-:" . consult-complex-command) ;; orig. repeat-complex-command
("C-x b" . consult-buffer) ;; orig. switch-to-buffer
("C-x 4 b" . consult-buffer-other-window) ;; orig. switch-to-buffer-other-window
("C-x 5 b" . consult-buffer-other-frame) ;; orig. switch-to-buffer-other-frame
("C-x t b" . consult-buffer-other-tab) ;; orig. switch-to-buffer-other-tab
("C-x r b" . consult-bookmark) ;; orig. bookmark-jump
("C-x p b" . consult-project-buffer) ;; orig. project-switch-to-buffer
;; Custom M-# bindings for fast register access
("M-#" . consult-register-load)
("M-'" . consult-register-store) ;; orig. abbrev-prefix-mark (unrelated)
("C-M-#" . consult-register)
;; Other custom bindings
("M-y" . consult-yank-pop) ;; orig. yank-pop
;; M-g bindings in `goto-map'
("M-g e" . consult-compile-error)
("M-g f" . consult-flymake) ;; Alternative: consult-flycheck
("M-g g" . consult-goto-line) ;; orig. goto-line
("M-g M-g" . consult-goto-line) ;; orig. goto-line
("M-g o" . consult-outline) ;; Alternative: consult-org-heading
("M-g m" . consult-mark)
("M-g k" . consult-global-mark)
("M-g i" . consult-imenu)
("M-g I" . consult-imenu-multi)
;; M-s bindings in `search-map'
("M-s d" . consult-find) ;; Alternative: consult-fd
("M-s c" . consult-locate)
("M-s g" . consult-grep)
("M-s G" . consult-git-grep)
("M-s r" . consult-ripgrep)
("M-s l" . consult-line)
("M-s L" . consult-line-multi)
("M-s k" . consult-keep-lines)
("M-s u" . consult-focus-lines))
```
3. clone flx-rs to `~/src/packages/`
```bash
git clone https://github.com/jcs-elpa/flx-rs.git ~/src/packages/flx-rs
```
4. start Emacs,it will install the related packages
5. open the init.el file by `C-x C-f ~/.emacs.d/init.el`
6. `M-x consult-imenu` you will see all the candidates as below, so far so good.
<img width="476" alt="image" src="https://github.com/jojojames/fussy/assets/47546452/c9f1598c-442c-4b98-bb81-da509b658a07">
7. Then you type a character `c` in the minibuffer prompt, you will get no candiates. This is the issue.
<img width="394" alt="image" src="https://github.com/jojojames/fussy/assets/47546452/269a23a2-6efa-432e-a6c8-23e2c2225584">
if I disable the flx-rs and use flx, the result is as below:
I don't known why the "fussy" can match the `c`??
<img width="411" alt="image" src="https://github.com/jojojames/fussy/assets/47546452/12f37b73-bbd5-42f1-9652-0e0b2d435d33">
when input `co`, the result is expected:
<img width="398" alt="image" src="https://github.com/jojojames/fussy/assets/47546452/648c8fe2-68b7-4476-8e7f-cfb3efdcc35b">