记录一次 折腾 Windows 下 Shell Command encoding 的问题

Windows 下 emacs 的 M-!call-process,等的 encoding 问题

不想读系列:开启 UTF-8 Beta 保平安 Screenshot 2022-05-16 213826

前言

最近打算把浏览器的书签从浏览器中迁移出来,于是打算转用 buku。Emacs 有一个包 ebuku ,提供了一个前端。

但是在实际使用的时候,在 Windows 里会有编码的问题。具体体现为类似乱码

系统状况

我的系统是英文为主要,然后为非 Unicode 的程序开启了中文编码(GBK)。这个设置应该是为了兼容中英文比较普遍的设置了(如果不设置中文编码,有时候安装软件,或者解压文件的时候会有乱码)

Ebuku 运作原理

Ebuku 是一个比较简易的包,通过 regex 来提取 buku 运行的结果。但这也是问题的源头。

折腾编码

在 Windows 当中,编码的问题由来已久,从最早的完全不支持 utf,到使用自己的 utf-16le。 在测试我的 Emacs 的编码的时候,发现调用 call-processM-! 的时候,编码环境是 gbk (我是通过一个“笨”办法,跑 python -c "import sys;print(sys.stdout.encoding)"来确认的,应该有更好的办法)

在知道编码是 gbk 之后,事情就好办了,可以通过设置一些参数来让 emacs 用合适的编码来处理 buku 的输出。

(set-default 'process-coding-system-alist
             '(("[cC][mM][dD][pP][rR][oO][xX][yY]" gbk-dos . gbk-dos)))

这段设置可以让 emacs 成功识别编码,在这个环境下,如果输出有中文的话,可以成功读取成正确的内容。

Buku gbk 输出乱码

理论上,上一步问题应该已经解决了,可惜的是,在运行 ebuku 的时候还是会提示出错。在手动跑了 ebuku 中的命令之后,发现虽然大多数的输出是没有问题的,但是在有的字符的时候还是会出先乱码

这里我也不知道具体的原因,不过我怀疑罪魁祸首还是 gbk 的问题。顾又开始在网上查阅各种有关 emacs 编码的问题。最后在一篇 reddit 的帖子中看到有一个用户提到可以通过设置本文最开始提到的 Beta UTF-8 支持来解决这一问题。

在设置了这个选项,并且按提示重启电脑之后,终于可以在 M-! 中看到到编码是 UTF-8 了!折腾终于结束了

其他杂记

  • 为何不用 Linux/Mac,我也想,但必须在 windows 环境下干一些事情(玩游戏),同时也想用 Emacs

设置Windows编码为utf-8时在部分软件里面会出现兼容性问题

Locale Emulator 做最后保底 (捂脸)

emacs在windows上运行程序有几种,很多是通过cmdproxy进程代理的,所以设置cmdproxy有效。像consult-ripgreg异步调用rg就不需要cmdproxy,只需要设置

(add-to-list 'process-coding-system-alist 
                        '("[rR][gG]" . (utf-8 . gbk-dos)))

像projectile的fd调用就是cmdproxy,我一般通过advise临时设置process-coding-system-alist,而不是像那样set-default 'process-coding-system-alist,代码如下:

(defadvice projectile-files-via-ext-command (around my-projectile-files-via-ext-command activate)
      (let ((cmdproxy-old-encoding (cdr (assoc "[cC][mM][dD][pP][rR][oO][xX][yY]" process-coding-system-alist))))
	    (modify-coding-system-alist 'process "[cC][mM][dD][pP][rR][oO][xX][yY]" '(utf-8 . gbk-dos))
	    ad-do-it
	    (modify-coding-system-alist 'process "[cC][mM][dD][pP][rR][oO][xX][yY]" cmdproxy-old-encoding)
	    ))

确定Buku是如何调用的(可以用process explorer查看进程树),然后对应设置进程就行了。假设Buku是cmdproxy代理,并且输出utf-8编码,那么按上面你的代码这样设置可能有效:

(set-default 'process-coding-system-alist
             '(("[cC][mM][dD][pP][rR][oO][xX][yY]" utf-8 . gbk-dos)))

不过你这样是全局设置cmdproxy了,最好是找到调用Buku的elisp代码,然后advise临时设置编码。

1 个赞

ebuku 是使用 call-process 来调用 buku 的,我推测和实验的结果 cmdproxy 是生效的。当我当时最后遇到的问题是在 (gbk-dos . gbk-dos) 的情况下 buku 自己的输出会有部分是乱码(90%的中文没问题,但可能我的书签中有其他的文字,比如有个标题中有德文字符)。这个没能找到根本原因,只能推测是在 windows 中 python(buku 是个 python 的包)encoding 处理的兼容性问题。

如果在 powershell 或者 cmd 中直接运行 buku 的话,都是没有这个问题的(当时忘记截图了…)不过我在验证 encoding 时(没设置 utf-8 beta时), powershell 和 cmd 都是使用 utf-8 作为输出。