Skip to content

Commit 1298255

Browse files
committed
implemented unicode support
1 parent 36be7d0 commit 1298255

File tree

1 file changed

+37
-14
lines changed

1 file changed

+37
-14
lines changed

bpython/cli.py

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@
2727
# Debian/Ubuntu: aptitude install python-pyments python-pyparsing
2828
#
2929

30+
from __future__ import with_statement
31+
32+
import codecs
3033
import os
3134
import sys
3235
import curses
@@ -45,7 +48,9 @@
4548
import socket
4649
import pydoc
4750
import types
51+
import unicodedata
4852
from cStringIO import StringIO
53+
from locale import LC_ALL, getpreferredencoding, setlocale
4954
from optparse import OptionParser
5055
from urlparse import urljoin
5156
from xmlrpclib import ServerProxy, Error as XMLRPCError
@@ -88,6 +93,7 @@ def __init__(self, interface):
8893
"""Take the curses Repl on init and assume it provides a get_key method
8994
which, fortunately, it does."""
9095

96+
self.encoding = getpreferredencoding()
9197
self.interface = interface
9298

9399
def readline(self):
@@ -325,7 +331,9 @@ def __init__(self, scr, interp, statusbar=None, idle=None):
325331

326332
pythonhist = os.path.expanduser('~/.pythonhist')
327333
if os.path.exists(pythonhist):
328-
self.rl_hist = open(pythonhist, 'r').readlines()
334+
with codecs.open(pythonhist, 'r', getpreferredencoding(),
335+
'ignore') as hfile:
336+
self.rl_hist = hfile.readlines()
329337

330338
pexp = Forward()
331339
chars = printables.replace('(', '')
@@ -855,7 +863,10 @@ def push(self, s):
855863
self.buffer.append(s)
856864

857865
try:
858-
more = self.interp.runsource("\n".join(self.buffer))
866+
encoding = getpreferredencoding()
867+
source = '# coding: %s\n' % (encoding, )
868+
source += '\n'.join(self.buffer).encode(encoding)
869+
more = self.interp.runsource(source)
859870
except SystemExit:
860871
# Avoid a traceback on e.g. quit()
861872
self.do_exit = True
@@ -950,7 +961,7 @@ def reevaluate(self):
950961

951962
self.iy, self.ix = self.scr.getyx()
952963
for line in self.history:
953-
self.stdout_hist += line + '\n'
964+
self.stdout_hist += line.encode(getpreferredencoding()) + '\n'
954965
self.print_line(line)
955966
self.s_hist[-1] += self.f_string
956967
# I decided it was easier to just do this manually
@@ -1024,7 +1035,7 @@ def repl(self):
10241035
self.h_i = 0
10251036
self.history.append(inp)
10261037
self.s_hist[-1] += self.f_string
1027-
self.stdout_hist += inp + '\n'
1038+
self.stdout_hist += inp.encode(getpreferredencoding()) + '\n'
10281039
# Keep two copies so you can go up and down in the hist:
10291040
if inp:
10301041
self.rl_hist.append(inp + '\n')
@@ -1061,8 +1072,7 @@ def write(self, s):
10611072
t = s
10621073

10631074
if isinstance(t, unicode):
1064-
t = (t.encode(getattr(orig_stdout, 'encoding', None) or
1065-
sys.getdefaultencoding()))
1075+
t = t.encode(getpreferredencoding())
10661076

10671077
if not self.stdout_hist:
10681078
self.stdout_hist = t
@@ -1097,8 +1107,7 @@ def echo(self, s, redraw=True):
10971107
srings. It won't update the screen if it's reevaluating the code (as it
10981108
does with undo)."""
10991109
if isinstance(s, unicode):
1100-
s = (s.encode(getattr(orig_stdout, 'encoding', None)
1101-
or sys.getdefaultencoding()))
1110+
s = s.encode(getpreferredencoding())
11021111

11031112
a = curses.color_pair(0)
11041113
if '\x01' in s:
@@ -1322,7 +1331,8 @@ def p_key(self):
13221331
elif self.c == '\t':
13231332
return self.tab()
13241333

1325-
elif len(self.c) == 1 and self.c in string.printable:
1334+
elif (not self.c.startswith('KEY_')
1335+
and not unicodedata.category(self.c) == 'Cc'):
13261336
self.addstr(self.c)
13271337
self.print_line(self.s)
13281338

@@ -1506,19 +1516,29 @@ def clear_current_line(self):
15061516
self.s = ''
15071517

15081518
def get_key(self):
1519+
key = ''
15091520
while True:
15101521
if self.idle:
15111522
self.idle(self)
15121523
try:
1513-
key = self.scr.getkey()
1524+
key += self.scr.getkey()
1525+
key = key.decode(getpreferredencoding())
1526+
self.scr.nodelay(False)
1527+
except UnicodeDecodeError:
1528+
# Yes, that actually kind of sucks, but I don't see another way to get
1529+
# input right
1530+
self.scr.nodelay(True)
15141531
except curses.error:
15151532
# I'm quite annoyed with the ambiguity of this exception handler. I previously
15161533
# caught "curses.error, x" and accessed x.message and checked that it was "no
15171534
# input", which seemed a crappy way of doing it. But then I ran it on a
15181535
# different computer and the exception seems to have entirely different
15191536
# attributes. So let's hope getkey() doesn't raise any other crazy curses
15201537
# exceptions. :)
1521-
continue
1538+
self.scr.nodelay(False)
1539+
# XXX What to do here? Raise an exception?
1540+
if key:
1541+
return key
15221542
else:
15231543
return key
15241544

@@ -1885,9 +1905,10 @@ def main_curses(scr):
18851905

18861906
repl.repl()
18871907
if OPTS.hist_length:
1888-
f = open(os.path.expanduser('~/.pythonhist'), 'w')
1889-
f.writelines(repl.rl_hist[-OPTS.hist_length:])
1890-
f.close()
1908+
histfilename = os.path.expanduser('~/.pythonhist')
1909+
with codecs.open(histfilename, 'w', getpreferredencoding(),
1910+
'ignore') as hfile:
1911+
hfile.writelines(repl.rl_hist[-OPTS.hist_length:])
18911912

18921913
return repl.getstdout()
18931914

@@ -1915,6 +1936,8 @@ def main(args=None):
19151936
interpreter.runsource(sys.stdin.read())
19161937
return
19171938

1939+
setlocale(LC_ALL, '')
1940+
19181941
tb = None
19191942

19201943
path = os.path.expanduser('~/.bpythonrc') # migrating old configuration file

0 commit comments

Comments
 (0)