Use proper encoding to convert values in various places

Fixes #1072
This commit is contained in:
ZyX 2014-09-14 13:45:19 +04:00
parent fa217185cf
commit d14aecbc0a
10 changed files with 43 additions and 26 deletions

View File

@ -371,6 +371,10 @@ Vim ``segment_info`` argument is a dictionary with the following keys:
``mode`` ``mode``
Current mode. Current mode.
``encoding``
Value of ``&encoding`` from the time when powerline was initialized. It
should be used to convert return values.
.. note:: .. note::
Your segment generally should not assume that it is run for the current Your segment generally should not assume that it is run for the current
window, current buffer or current tabpage. “Current window” and “current window, current buffer or current tabpage. “Current window” and “current

View File

@ -13,13 +13,20 @@ if not hasattr(vim, 'bindeval'):
import json import json
try:
vim_encoding = vim.eval('&encoding')
except AttributeError:
vim_encoding = 'utf-8'
if hasattr(vim, 'bindeval'): if hasattr(vim, 'bindeval'):
def vim_get_func(f, rettype=None): def vim_get_func(f, rettype=None):
'''Return a vim function binding.''' '''Return a vim function binding.'''
try: try:
func = vim.bindeval('function("' + f + '")') func = vim.bindeval('function("' + f + '")')
if sys.version_info >= (3,) and rettype is str: if sys.version_info >= (3,) and rettype is str:
return (lambda *args, **kwargs: func(*args, **kwargs).decode('utf-8', errors='replace')) return (lambda *args, **kwargs: func(*args, **kwargs).decode(
vim_encoding, errors='powerline_vim_strtrans_error'))
return func return func
except vim.error: except vim.error:
return None return None
@ -102,7 +109,7 @@ else:
if sys.version_info < (3,): if sys.version_info < (3,):
getbufvar = _getbufvar getbufvar = _getbufvar
else: else:
_vim_to_python_types[bytes] = lambda value: value.decode('utf-8') _vim_to_python_types[bytes] = lambda value: value.decode(vim_encoding)
def getbufvar(*args): def getbufvar(*args):
return _vim_to_python(_getbufvar(*args)) return _vim_to_python(_getbufvar(*args))
@ -256,18 +263,18 @@ class VimEnviron(object):
if sys.version_info < (3,): if sys.version_info < (3,):
def buffer_name(buf): def buffer_name(segment_info):
return buf.name return segment_info['buffer'].name
else: else:
vim_bufname = vim_get_func('bufname') vim_bufname = vim_get_func('bufname')
def buffer_name(buf): def buffer_name(segment_info):
try: try:
name = buf.name name = segment_info['buffer'].name
except UnicodeDecodeError: except UnicodeDecodeError:
return vim_bufname(buf.number) return vim_bufname(segment_info['bufnr'])
else: else:
return name.encode('utf-8') if name else None return name.encode(segment_info['encoding']) if name else None
vim_strtrans = vim_get_func('strtrans') vim_strtrans = vim_get_func('strtrans')

View File

@ -4,6 +4,7 @@ from __future__ import (unicode_literals, division, absolute_import, print_funct
import atexit import atexit
from weakref import WeakValueDictionary, ref from weakref import WeakValueDictionary, ref
from locale import getpreferredencoding
import zsh import zsh
@ -65,7 +66,7 @@ class Args(object):
def string(s): def string(s):
if type(s) is bytes: if type(s) is bytes:
return s.decode('utf-8', 'replace') return s.decode(getpreferredencoding(), 'replace')
else: else:
return str(s) return str(s)
@ -154,9 +155,9 @@ class Prompt(object):
) )
if type(r) is not str: if type(r) is not str:
if type(r) is bytes: if type(r) is bytes:
return r.decode('utf-8') return r.decode(getpreferredencoding(), 'replace')
else: else:
return r.encode('utf-8') return r.encode(getpreferredencoding(), 'replace')
return r return r
def __del__(self): def __del__(self):

View File

@ -123,8 +123,6 @@ class INotify(object):
self._buf = ctypes.create_string_buffer(5000) self._buf = ctypes.create_string_buffer(5000)
self.fenc = sys.getfilesystemencoding() or 'utf-8' self.fenc = sys.getfilesystemencoding() or 'utf-8'
self.hdr = struct.Struct(b'iIII') self.hdr = struct.Struct(b'iIII')
if self.fenc == 'ascii':
self.fenc = 'utf-8'
# We keep a reference to os to prevent it from being deleted # We keep a reference to os to prevent it from being deleted
# during interpreter shutdown, which would lead to errors in the # during interpreter shutdown, which would lead to errors in the
# __del__ method # __del__ method

View File

@ -6,6 +6,7 @@ import os
import re import re
from io import StringIO from io import StringIO
from locale import getpreferredencoding
from bzrlib import (workingtree, status, library_state, trace, ui) from bzrlib import (workingtree, status, library_state, trace, ui)
@ -15,7 +16,7 @@ from powerline.lib.vcs import get_branch_name, get_file_status
class CoerceIO(StringIO): class CoerceIO(StringIO):
def write(self, arg): def write(self, arg):
if isinstance(arg, bytes): if isinstance(arg, bytes):
arg = arg.decode('utf-8', 'replace') arg = arg.decode(getpreferredencoding(), 'replace')
return super(CoerceIO, self).write(arg) return super(CoerceIO, self).write(arg)
@ -29,7 +30,7 @@ def branch_name_from_config_file(directory, config_file):
for line in f: for line in f:
m = nick_pat.match(line) m = nick_pat.match(line)
if m is not None: if m is not None:
ans = m.group(1).strip().decode('utf-8', 'replace') ans = m.group(1).strip().decode(getpreferredencoding(), 'replace')
break break
except Exception: except Exception:
pass pass

View File

@ -5,6 +5,8 @@ import os
import sys import sys
import re import re
from locale import getpreferredencoding
from powerline.lib.vcs import get_branch_name, get_file_status from powerline.lib.vcs import get_branch_name, get_file_status
from powerline.lib.shell import readlines from powerline.lib.shell import readlines
@ -20,7 +22,7 @@ def branch_name_from_config_file(directory, config_file):
return os.path.basename(directory) return os.path.basename(directory)
m = _ref_pat.match(raw) m = _ref_pat.match(raw)
if m is not None: if m is not None:
return m.group(1).decode('utf-8', 'replace') return m.group(1).decode(getpreferredencoding(), 'replace')
return raw[:7] return raw[:7]

View File

@ -3,6 +3,8 @@ from __future__ import (unicode_literals, division, absolute_import, print_funct
import os import os
from locale import getpreferredencoding
from mercurial import hg, ui, match from mercurial import hg, ui, match
from powerline.lib.vcs import get_branch_name, get_file_status from powerline.lib.vcs import get_branch_name, get_file_status
@ -12,7 +14,7 @@ def branch_name_from_config_file(directory, config_file):
try: try:
with open(config_file, 'rb') as f: with open(config_file, 'rb') as f:
raw = f.read() raw = f.read()
return raw.decode('utf-8', 'replace').strip() return raw.decode(getpreferredencoding(), 'replace').strip()
except Exception: except Exception:
return 'default' return 'default'

View File

@ -42,6 +42,7 @@ class VimRenderer(Renderer):
self.hl_groups = {} self.hl_groups = {}
self.prev_highlight = None self.prev_highlight = None
self.strwidth_error_name = register_strwidth_error(self.strwidth) self.strwidth_error_name = register_strwidth_error(self.strwidth)
self.encoding = vim.eval('&encoding')
def shutdown(self): def shutdown(self):
self.theme.shutdown() self.theme.shutdown()
@ -72,11 +73,10 @@ class VimRenderer(Renderer):
if hasattr(vim, 'strwidth'): if hasattr(vim, 'strwidth'):
if sys.version_info < (3,): if sys.version_info < (3,):
@staticmethod def strwidth(self, string):
def strwidth(string):
# Does not work with tabs, but neither is strwidth from default # Does not work with tabs, but neither is strwidth from default
# renderer # renderer
return vim.strwidth(string.encode('utf-8')) return vim.strwidth(string.encode(self.encoding, 'replace'))
else: else:
@staticmethod @staticmethod
def strwidth(string): def strwidth(string):
@ -102,6 +102,7 @@ class VimRenderer(Renderer):
winnr=winnr, winnr=winnr,
buffer=window.buffer, buffer=window.buffer,
tabpage=current_tabpage(), tabpage=current_tabpage(),
encoding=self.encoding,
) )
segment_info['tabnr'] = segment_info['tabpage'].number segment_info['tabnr'] = segment_info['tabpage'].number
segment_info['bufnr'] = segment_info['buffer'].number segment_info['bufnr'] = segment_info['buffer'].number
@ -116,7 +117,7 @@ class VimRenderer(Renderer):
segment_info=segment_info, segment_info=segment_info,
matcher_info=(None if is_tabline else segment_info), matcher_info=(None if is_tabline else segment_info),
) )
statusline = statusline.encode(vim.eval('&encoding'), self.strwidth_error_name) statusline = statusline.encode(self.encoding, self.strwidth_error_name)
return statusline return statusline
def reset_highlight(self): def reset_highlight(self):

View File

@ -225,7 +225,7 @@ def file_scheme(pl, segment_info):
name will look like :file:`zipfile:/path/to/archive.zip::file.txt`. name will look like :file:`zipfile:/path/to/archive.zip::file.txt`.
``file_scheme`` segment will catch ``zipfile`` part here. ``file_scheme`` segment will catch ``zipfile`` part here.
''' '''
name = buffer_name(segment_info['buffer']) name = buffer_name(segment_info)
if not name: if not name:
return None return None
match = SCHEME_RE.match(name) match = SCHEME_RE.match(name)
@ -254,7 +254,7 @@ def file_directory(pl, segment_info, remove_scheme=True, shorten_user=True, shor
Shorten all directories in :file:`/home/` to :file:`~user/` instead of Shorten all directories in :file:`/home/` to :file:`~user/` instead of
:file:`/home/user/`. Does not work for files with scheme present. :file:`/home/user/`. Does not work for files with scheme present.
''' '''
name = buffer_name(segment_info['buffer']) name = buffer_name(segment_info)
if not name: if not name:
return None return None
match = SCHEME_RE.match(name) match = SCHEME_RE.match(name)
@ -271,7 +271,7 @@ def file_directory(pl, segment_info, remove_scheme=True, shorten_user=True, shor
return None return None
if shorten_home and file_directory.startswith('/home/'): if shorten_home and file_directory.startswith('/home/'):
file_directory = b'~' + file_directory[6:] file_directory = b'~' + file_directory[6:]
file_directory = file_directory.decode('utf-8', 'powerline_vim_strtrans_error') file_directory = file_directory.decode(segment_info['encoding'], 'powerline_vim_strtrans_error')
return file_directory + os.sep return file_directory + os.sep
@ -286,7 +286,7 @@ def file_name(pl, segment_info, display_no_file=False, no_file_text='[No file]')
Highlight groups used: ``file_name_no_file`` or ``file_name``, ``file_name``. Highlight groups used: ``file_name_no_file`` or ``file_name``, ``file_name``.
''' '''
name = buffer_name(segment_info['buffer']) name = buffer_name(segment_info)
if not name: if not name:
if display_no_file: if display_no_file:
return [{ return [{
@ -295,7 +295,7 @@ def file_name(pl, segment_info, display_no_file=False, no_file_text='[No file]')
}] }]
else: else:
return None return None
return os.path.basename(name).decode('utf-8', 'powerline_vim_strtrans_error') return os.path.basename(name).decode(segment_info['encoding'], 'powerline_vim_strtrans_error')
@window_cached @window_cached

View File

@ -651,6 +651,7 @@ def _get_segment_info():
'tabnr': tabpage.number, 'tabnr': tabpage.number,
'window_id': window._window_id, 'window_id': window._window_id,
'mode': mode, 'mode': mode,
'encoding': options['encoding'],
} }