helm-mode打开文件支持中文搜索
Table of Contents
由于helm的很多功能比较好用,于是把所有的ido全部用helm替代了。但是,其中少了使用拼音首字母进行搜索的功能,于是自己捣鼓着弄出来。
1 pinyin-search
首先,这个功能是基于pinyin-search里面的函数来创建pinyin字母到汉字的正则表达式创建。
(setq helm-pinyin-search-p t) (when helm-pinyin-search-p (require ‘pinyin-search))
2 helm-find-files中的拼音搜索
将原来的创建搜索的正则表达式由纯英文的改为中英文混合: helm–mapconcat-pattern:
he => [h]*h[e]*e
helm–mapconcat-pinyin-pattern:
he => [h哈]*[h哈][e额]*[e额]
(defsubst helm--mapconcat-pinyin-pattern (pattern) "Transform string PATTERN in regexp for further fuzzy matching. e.g helm.el$ => \"[^h哈]*[h哈][^e额]*[e额][^l]*l[^m]*m[^.]*[.][^e]*e[^l]*l$\" ^helm.el$ => \"helm[.]el$\"." (let ((ls (split-string-and-unquote pattern ""))) (if (string= "^" (car ls)) ;; Exact match. (mapconcat (lambda (c) (if (and (string= c "$") (string-match "$\\‘" pattern)) c (regexp-quote c))) (cdr ls) "") ;; Fuzzy match. (mapconcat (lambda (c) (if (and (string= c "$") (string-match "$\\‘" pattern)) c (let ((pinyin-pattern (pinyinlib-build-regexp-string c))) (if (< (length pinyin-pattern) 3) c (format "[^%s]*%s" (substring pinyin-pattern 1 -1) pinyin-pattern))))) ls ""))))
再把查找文件函数里面的helm–mapconcat-pattern替换为helm–mapconcat-pinyin-pattern:
(defun helm-ff--transform-pattern-for-completion (pattern) "Maybe return PATTERN with it‘s basename modified as a regexp. This happen only when `helm-ff-fuzzy-matching‘ is enabled. This provide a similar behavior as `ido-enable-flex-matching‘. See also `helm--mapconcat-pinyin-pattern‘ If PATTERN is an url returns it unmodified. When PATTERN contain a space fallback to multi-match. If basename contain one or more space fallback to multi-match. If PATTERN is a valid directory name,return PATTERN unchanged." ;; handle bad filenames containing a backslash. (setq pattern (helm-ff-handle-backslash pattern)) (let ((bn (helm-basename pattern)) (bd (or (helm-basedir pattern) "")) ;; Trigger tramp connection with file-directory-p. (dir-p (file-directory-p pattern)) (tramp-p (cl-loop for (m . f) in tramp-methods thereis (string-match m pattern)))) ;; Always regexp-quote base directory name to handle ;; crap dirnames such e.g bookmark+ (cond ((or (and dir-p tramp-p (string-match ":\\‘" pattern)) (string= pattern "") (and dir-p (<= (length bn) 2)) ;; Fix Issue #541 when BD have a subdir similar ;; to BN, don‘t switch to match plugin ;; which will match both. (and dir-p (string-match (regexp-quote bn) bd))) ;; Use full PATTERN on e.g "/ssh:host:". (regexp-quote pattern)) ;; Prefixing BN with a space call multi-match completion. ;; This allow showing all files/dirs matching BN (Issue #518). ;; FIXME: some multi-match methods may not work here. (dir-p (concat (regexp-quote bd) " " (regexp-quote bn))) ((or (not (helm-ff-fuzzy-matching-p)) (string-match "\\s-" bn)) ; Fall back to multi-match. (concat (regexp-quote bd) bn)) ((or (string-match "[*][.]?.*" bn) ; Allow entering wilcard. (string-match "/$" pattern) ; Allow mkdir. (string-match helm-ff-url-regexp pattern) (and (string= helm-ff-default-directory "/") tramp-p)) ;; Don‘t treat wildcards ("*") as regexp char. ;; (e.g ./foo/*.el => ./foo/[*].el) (concat (regexp-quote bd) (replace-regexp-in-string "[*]" "[*]" bn))) (t (concat (regexp-quote bd) (if (>= (length bn) 2) ; wait 2nd char before concating. (progn ;; (print (helm--mapconcat-pinyin-pattern bn)) (helm--mapconcat-pinyin-pattern bn)) (concat ".*" (regexp-quote bn))))))))
将下面文件名的正则表达式修改成中英文混合就可以实现了。
3 helm-multi-files和helm-projectile中的拼音搜索
这两个模式里面的搜索不一样,因为包含全路径。
3.1 match
用来判断模式pattern和string是否匹配。
3.2 search是用于真正的搜索过滤的函数
用来搜索和过滤candidates。
(cl-defun helm-mm-3-match (str &optional (pattern helm-pattern)) "Check if PATTERN match STR. When PATTERN contain a space, it is splitted and matching is done with the several resulting regexps against STR. e.g \"bar foo\" will match \"foobar\" and \"barfoo\". Argument PATTERN, a string, is transformed in a list of cons cell with `helm-mm-3-get-patterns‘ if it contain a space. e.g \"foo bar\"=>((identity . \"foo\") (identity . \"bar\")). Then each predicate of cons cell(s) is called with regexp of same cons cell against STR (a candidate). i.e (identity (string-match \"foo\" \"foo bar\")) => t." (let ((pat (helm-mm-3-get-patterns pattern))) (let ((source-name (assoc-default ‘name (helm-get-current-source)))) ;; (print (concat "8 " source-name)) (if (string= source-name "Recentf") (cl-loop for (predicate . regexp) in pat always (funcall predicate (condition-case _err ;; FIXME: Probably do nothing when ;; using fuzzy leaving the job ;; to the fuzzy fn. (string-match (concat "\\(" regexp "\\)\\|\\(" (pinyin-search--pinyin-to-regexp regexp) "\\)") str) (invalid-regexp nil)))) (cl-loop for (predicate . regexp) in pat always (funcall predicate (condition-case _err ;; FIXME: Probably do nothing when ;; using fuzzy leaving the job ;; to the fuzzy fn. (string-match regexp str) (invalid-regexp nil))))))))