calibredb list: Handle multibyte chars

calibredb list: When outputting data in columns, handle multibyte and
east asian characters correctly. Fixes #1190476 [calibredb list series result into multilines when series length > 4](https://bugs.launchpad.net/calibre/+bug/1190476)
This commit is contained in:
Kovid Goyal 2013-06-13 16:11:06 +05:30
parent 9992d4f1cb
commit 836b955571

View File

@ -8,6 +8,7 @@ Command line interface to the calibre database.
''' '''
import sys, os, cStringIO, re import sys, os, cStringIO, re
import unicodedata
from textwrap import TextWrapper from textwrap import TextWrapper
from calibre import preferred_encoding, prints, isbytestring from calibre import preferred_encoding, prints, isbytestring
@ -98,9 +99,14 @@ def do_list(db, fields, afields, sort_by, ascending, search_text, line_width, se
else: else:
record[f] = unicode(record[f]) record[f] = unicode(record[f])
record[f] = record[f].replace('\n', ' ') record[f] = record[f].replace('\n', ' ')
def chr_width(x):
return 1 + unicodedata.east_asian_width(x).startswith('W')
def str_width(x):
return sum(map(chr_width, x))
for i in data: for i in data:
for j, field in enumerate(fields): for j, field in enumerate(fields):
widths[j] = max(widths[j], len(unicode(i[field]))) widths[j] = max(widths[j], str_width(i[field]))
screen_width = geometry()[0] if line_width < 0 else line_width screen_width = geometry()[0] if line_width < 0 else line_width
if not screen_width: if not screen_width:
@ -128,14 +134,14 @@ def do_list(db, fields, afields, sort_by, ascending, search_text, line_width, se
o = cStringIO.StringIO() o = cStringIO.StringIO()
for record in data: for record in data:
text = [wrappers[i].wrap(unicode(record[field]).encode('utf-8')) for i, field in enumerate(fields)] text = [wrappers[i].wrap(unicode(record[field])) for i, field in enumerate(fields)]
lines = max(map(len, text)) lines = max(map(len, text))
for l in range(lines): for l in range(lines):
for i, field in enumerate(text): for i, field in enumerate(text):
ft = text[i][l] if l < len(text[i]) else '' ft = text[i][l] if l < len(text[i]) else u''
filler = '%*s'%(widths[i]-len(ft)-1, '') filler = u'%*s'%(widths[i]-str_width(ft)-1, u'')
o.write(ft) o.write(ft.encode('utf-8'))
o.write(filler+separator) o.write((filler+separator).encode('utf-8'))
print >>o print >>o
return o.getvalue() return o.getvalue()