Windows 环境里 projectile-find-file (counsel-projectile-find-file) 文件列表中中文路径和中文文件名乱码

请问 projectile-find-file 得到的文件列表中遇到中文路径和中文文件名都显示为乱码是怎么回事呢?我把 projectile-generic-command 设置为 “fd …” 和 “rg …” 都不行。fd.exe 和 rg.exe 都已加入环境变量,并能够正常使用,其中很多其它使用 rg.exe 的命令都能够正确处理中文,如 rg.el counsel-rg.el 以及 color-rg.el,就是这个 projectile-find-file 不行。

如下面的 projectile-find-file (counsel-projectile-find-file) 结果框中,原本 \344\270 的地方都是中文。

image

环境:Windows 10、Emacs 28.1

(decode-coding-string "\344\270\211" 'utf-8)
;; => "三"

projectile用shell-command来运行这些xxx-command,在windows默认的GBK环境下,就会有编码的问题。

内置的project.el,对于git的仓库,直接用vc-git的命令,没有经过shell,emacs-Q的情况下,C-x p f正常显示中文。

(defun projectile-get-ext-command (vcs)
  "Determine which external command to invoke based on the project's VCS.
Fallback to a generic command when not in a VCS-controlled project."
  (pcase vcs
    ('git projectile-git-command)
    ('hg projectile-hg-command)
    ('fossil projectile-fossil-command)
    ('bzr projectile-bzr-command)
    ('darcs projectile-darcs-command)
    ('pijul projectile-pijul-command)
    ('svn projectile-svn-command)
    (_ projectile-generic-command)))

嗯嗯,是没有问题的,完整的那几个字符是 “上传”,就是不知道怎么解决这个问题,而且搜索也是匹配不到这个的

(decode-coding-string "\344\270\212\344\274\240" 'utf-8)
;; => "上传"

我没在用 windows,不知道是不是可以直接从命令行返回 utf-8 编码的内容,可以的话就从命令行着手。

如果不可以的话,试试重载 projectile-files-via-ext-command 函数,处理命令行输出:

(defun projectile-files-via-ext-command@decode-utf-8 (root command)
  "Advice override `projectile-files-via-ext-command' to decode shell output."
  (when (stringp command)
    (let ((default-directory root))
      (with-temp-buffer
        (shell-command command t "*projectile-files-errors*")
        (decode-coding-region (point-min) (point-max) 'utf-8) ;; ++
        (let ((shell-output (buffer-substring (point-min) (point-max))))
          (split-string (string-trim shell-output) "\0" t))))))

(advice-add 'projectile-files-via-ext-command
            :override 'projectile-files-via-ext-command@decode-utf-8)

改完了重启 Emacs 或清除 projectile 的缓存。

1 个赞

嗯嗯,是的,project.el 是没有问题的,就是感觉 projectile 还是生态完善一些,而且用习惯了,不知道有没有办法解决这个编码问题 :joy:

大佬,你太强了,测试了一下搜索和显示都没有问题

image

建议这里使用 coding-system-for-read ,而不要直接覆盖函数实现, 如果只用Git的话,还建议只修改Git命令的输出,如下:

(with-eval-after-load 'projectile
  (defun my/projectile-fix-decoding-for-ls-files (orig-fun root command)
    "Fix the decoding of git --ls-files output (invoke via cmdproxy)."
    (if (and (stringp command) (string-prefix-p "git " command t)) ; 如果还用Git外的其他的命令,可以加额外的判断
        (let ((coding-system-for-read 'utf-8))
          (funcall orig-fun root command))
      (funcall orig-fun root command)))
  (advice-add #'projectile-files-via-ext-command :around #'my/projectile-fix-decoding-for-ls-files))

谢谢!

请问这里只用 git 的意思是只用 git-for-windows 里的 git.exe 吗?包括 git 里的 git grep 还有其它有关的命令不?

你这个的建议的意思就是直接覆盖函数实现可能会影响或污染其它命令的结果,所以仅限制这些命令 (如这里的 git)使用 utf-8 读入吧?

这里只advice了 projectile-files-via-ext-command 函数,该函数仅用于获取项目文件列表, 具体的,只有在projectile执行 git ls-files 才起作用。

不完全准确。

建议不要覆盖函数实现的目的是,避免作者修改函数实现时,你的实现还是旧的,这里仅加了个around advice,让其针对Git命令的进程输出使用UTF-8 coding system进行解码,实际工作还是由原函数来完成。

建议仅针对Git进行修改是因为,projectile-files-via-ext-command 根据不同的项目类型,执行不同的命令获取项目文件列表,涉及如下命令:

(defun projectile-get-ext-command (vcs)
  "Determine which external command to invoke based on the project's VCS.
Fallback to a generic command when not in a VCS-controlled project."
  (pcase vcs
    ('git projectile-git-command)
    ('hg projectile-hg-command)
    ('fossil projectile-fossil-command)
    ('bzr projectile-bzr-command)
    ('darcs projectile-darcs-command)
    ('pijul projectile-pijul-command)
    ('svn projectile-svn-command)
    (_ projectile-generic-command)))

我对上面的其他项目类型不了解,不清楚它们在Windows下的进程输出的编码是否为UTF-8, 所以我才建议如果你仅用Git的话,那就仅针对Git使用UTF-8 coding system进行解码,或者分情况处理(等到你用到其他项目类型的时候)。

1 个赞

明白了,感谢!