我正在尝试将一些 Windows PowerShell 脚本存储在 Mercurial 存储库中。PowerShell 编辑器似乎喜欢将文件保存为 UTF-16 Unicode。这意味着有很多\0
字节,这是 Mercurial 用来区分“文本”和“二进制”文件的。我知道这对 Mercurial 存储数据的方式没有影响,但这确实意味着它会显示二进制差异,这有点难以阅读。有没有办法告诉 Mercurial 这些真的是文本文件?大概我需要说服 Mercurial 对特定文件类型使用外部 Unicode 感知差异程序。
3 回答
这可能与您无关;如果听起来不像,请阅读最后一段。
我不确定这是否是您所需要的,但我需要 UTF-16LE 内容的差异,而不仅仅是“二进制文件不同” - 当我大约几个月前搜索它时,我发现了一个线程和讨论它的错误;这是它的一部分。我现在找不到这个迷你扩展的原始来源(虽然它正在做那个补丁所做的事情),但我得到的是一个扩展,BOM.py
:
#!/usr/bin/env python
from mercurial import hg, util
import codecs
boms = [
codecs.BOM_UTF8,
codecs.BOM_UTF16_BE, codecs.BOM_UTF16_LE,
codecs.BOM_UTF32_BE, codecs.BOM_UTF32_LE
]
def binary(s):
if s:
for bom in boms:
if s.startswith(bom):
return False
return '\0' in s
return False
def reposetup(ui, repo):
util.binary = binary
这会像这样加载到 .hgrc(或您的 users\username\mercurial.ini)中:
[extensions]
bom = ~/.hgexts/BOM.py
请注意,Windows 和 Linux 之间的路径会有所不同;在我的 Windows 副本上,我将路径设置为\...\whatever
(它位于驱动器号可以更改的 USB 磁盘上)。不幸的是,相对路径是相对于当前工作目录而不是存储库根目录或任何类似的东西,但如果你将它保存在 C: 驱动器上,你可以只放置完整路径。
在 Linux(我的主要开发环境)中,这很好用;在命令提示符(我仍然经常使用)中,它通常运行良好。我从未在 PowerShell 中尝试过它,但我希望它比命令提示符更好,因为它支持命令行中的任意空字节。
我不确定这是否是您想要的。顺便说一句,您说过“二进制差异”,我怀疑您可能已经拥有这个或正在做hg diff -a
的事情是实现相同的目标。在这种情况下,我能想到的就是编写另一个扩展,它采用 UTF-16LE 并尝试将其解码为 UTF-8。我不确定这种扩展的语法,但我可能会尝试一下。
编辑:现在通过 commands.py、cmdutil.py、patch.py 和 mdiff.py 搜索了 mercurial 源,我看到二进制差异是使用 base85 编码(patch.b85diff)而不是普通差异完成的。我没有意识到这一点,我认为它只是强迫它区分它。在那种情况下,也许这个文本毕竟是相关的。我等待回复,看看是不是!
我通过使用 NotePad++ 创建一个新文件并将其保存为 PowerShell 文件(.ps1 扩展名)来解决此问题。NotePad++ 会将文件创建为纯文本 ANSI 文件。创建后,我可以在 PowerShell 编辑器中打开文件并根据需要进行任何更改,而无需编辑器修改文件编码。
免责声明:我刚刚遇到这个问题,所以我不确定是否有任何影响,但到目前为止,我的脚本似乎正常工作,我的差异也很好地显示出来。
如果我的另一个答案不能满足您的要求,我认为这个答案可能;虽然我还没有在 Windows 上测试过它,但它在 Linux 上运行良好。它做了一件可能令人讨厌的事情,包装mercurial.mdiff.unidiff
了一个将 utf-16le 转换为 utf-8 的新函数。这不会影响hg st
,但会影响hg diff
。一个潜在的陷阱是 BOM 也会从 UTF-16LE BOM 更改为 UTF-8 BOM。
无论如何,我认为它可能对您有用,所以在这里。
扩展文件utf16decodediff.py
:
import codecs
from mercurial import mdiff
unidiff = mdiff.unidiff
def new_unidiff(a, ad, b, bd, fn1, fn2, r=None, opts=mdiff.defaultopts):
"""
A simple wrapper around mercurial.mdiff.unidiff which first decodes
UTF-16LE text.
"""
if a.startswith(codecs.BOM_UTF16_LE):
try:
# Gets reencoded as utf-8 to be a str rather than a unicode; some
# extensions may expect a str and may break if it's wrong.
a = a.decode('utf-16le').encode('utf-8')
except UnicodeDecodeError:
pass
if b.startswith(codecs.BOM_UTF16_LE):
try:
b = b.decode('utf-16le').encode('utf-8')
except UnicodeDecodeError:
pass
return unidiff(a, ad, b, bd, fn1, fn2, r, opts)
mdiff.unidiff = new_unidiff
在.hgrc
:
[extensions]
utf16decodediff = ~/.hgexts/utf16decodediff.py
(或等效路径。)