[PATCH] hgext/win32chcp: switches the console into an encoding actually used (issue2926)

Andrei Polushin polushin at gmail.com
Fri Jul 29 12:25:22 CDT 2011


# HG changeset patch
# User Andrei Polushin <polushin at gmail.com>
# Date 1311959786 -25200
# Branch stable
# Node ID 44c770e07cc734071c834ab70fa0fbfaa714ba34
# Parent  56848e2bb0c5a43b580dd2ca7ce1e781d4e75b2b
hgext/win32chcp: switches the console into an encoding actually used (issue2926)

The encoding of the Windows console is switched temporarily, for the time the
Mercurial is running, and restored to the previous value on exit.

This solution is backward compatible, it changes almost nothing, i.e. neither
stdout/pipe encoding, nor internal string handling are affected anyway.
For maximum compatibility, it is implemented as an optional extension.
Adrian Buehlmann has implemented it in pure Python with ctypes module.

One problem still remains: `hg log | more' doesn't produce readable output on
OEM console, because `more' resets the encoding itself, and it happens at an
arbitrary time.

One problem possibly introduced: killing hg process may not restore previous
console encoding. I'm unable to reproduce the problem, however.

diff -r 56848e2bb0c5 -r 44c770e07cc7 hgext/win32chcp.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hgext/win32chcp.py	Sat Jul 30 00:16:26 2011 +0700
@@ -0,0 +1,49 @@
+# Copyright 2011 Andrei Polushin <polushin at gmail.com>
+# Copyright 2011 Adrian Buehlmann <adrian at cadifra.com>
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+
+'''switches the Windows console into an encoding actually used on output'''
+
+import os, codecs, ctypes, atexit
+from mercurial.i18n import _
+from mercurial import encoding
+
+_cpaliases = {
+    'utf-8': 'cp65001',
+}
+
+_inputcp = 0
+_outputcp = 0
+
+def restoreconsoleencoding():
+    _kernel32 = ctypes.windll.kernel32
+    _kernel32.SetConsoleCP(_inputcp)
+    _kernel32.SetConsoleOutputCP(_outputcp)
+
+def forceconsoleencoding(cp):
+    global _inputcp
+    global _outputcp
+    _kernel32 = ctypes.windll.kernel32
+    _inputcp  = _kernel32.GetConsoleCP()
+    _outputcp = _kernel32.GetConsoleOutputCP()
+    _kernel32.SetConsoleCP(cp)
+    _kernel32.SetConsoleOutputCP(cp)
+    atexit.register(restoreconsoleencoding)
+
+def uisetup(ui):
+    if os.name != 'nt':
+        ui.warn(_("[win32chcp] is not supported on this platform.\n"))
+        return
+
+    cp = encoding.encoding
+    try:
+        cp = codecs.lookup(cp).name
+        cp = _cpaliases.get(cp, cp)
+        if cp.startswith('cp'):
+            cp = cp[2:]
+        forceconsoleencoding(int(cp))
+    except (LookupError, ValueError):
+        ui.warn(_("[win32chcp] unknown encoding: %s\n") % cp)
+        pass


More information about the Mercurial-devel mailing list