Skip to content

Commit

Permalink
Release 1.3.1
Browse files Browse the repository at this point in the history
- Fixed Command-T finder labels: now `CommandT::` and  `Finder::` parts are
  removed because all finders were moved to `CommandT::Finder` module in place
  of just `CommandT`.
- Fixed dbus players support: it is now OK not to have album title.
- Characters that form the surrogate pair that represents some character above
  U+10000 in UCS-2 Python builds are no longer considered non-printable.
- Added support for calculating lengths of the characters above U+10000 in UCS-2
  Python builds.
- Made linter support characters above U+10000 if they are represented as
  a `\uXXXX\uXXXX` surrogate pair in JSON.
- Made linter validate that all characters in some strings are printable.
- Made `powerline-daemon` work in FreeBSD: only use abstract socket namespace on
  linux systems.
- Fixed `string` and `safe_unicode` functions in Python-3.
  • Loading branch information
ZyX-I committed Dec 6, 2014
2 parents 5154dcb + 3a175fe commit 6eaa640
Show file tree
Hide file tree
Showing 25 changed files with 536 additions and 95 deletions.
8 changes: 4 additions & 4 deletions client/powerline.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,12 @@ void do_write(int sd, const char *raw, size_t len) {
}
}

#ifdef __APPLE__
# define ADDRESS_TEMPLATE "/tmp/powerline-ipc-%d"
# define A
#else
#ifdef __linux__
# define ADDRESS_TEMPLATE "powerline-ipc-%d"
# define A +1
#else
# define ADDRESS_TEMPLATE "/tmp/powerline-ipc-%d"
# define A
#endif

#define ADDRESS_SIZE sizeof(ADDRESS_TEMPLATE) + (sizeof(uid_t) * 4)
Expand Down
4 changes: 1 addition & 3 deletions client/powerline.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,7 @@
print('Must provide at least one argument.', file=sys.stderr)
raise SystemExit(1)

platform = sys.platform.lower()
use_filesystem = 'darwin' in platform
del platform
use_filesystem = not sys.platform.lower().startswith('linux')

if sys.argv[1] == '--socket':
address = sys.argv[2]
Expand Down
25 changes: 22 additions & 3 deletions client/powerline.sh
Original file line number Diff line number Diff line change
@@ -1,20 +1,39 @@
#!/bin/sh

test "${OSTYPE#darwin}" = "${OSTYPE}" && darwin=n || darwin=y
use_filesystem=1
darwin=
if test -n "$OSTYPE" ; then
# OSTYPE variable is a shell feature. supported by bash and zsh, but not
# dash, busybox or (m)ksh.
if test "${OSTYPE#linux}" '!=' "${OSTYPE}" ; then
use_filesystem=
elif test "${OSTYPE#darwin}" ; then
darwin=1
fi
elif which uname >/dev/null ; then
if uname -o | grep -iqF linux ; then
use_filesystem=
elif uname -o | grep -iqF darwin ; then
darwin=1
fi
fi

if test "$1" = "--socket" ; then
shift
ADDRESS="$1"
shift
else
ADDRESS="powerline-ipc-${UID:-`id -u`}"
test "$darwin" = y && ADDRESS="/tmp/$ADDRESS"
test -n "$use_filesystem" && ADDRESS="/tmp/$ADDRESS"
fi

if test "$darwin" = y; then
if test -n "$darwin" ; then
ENV=genv
else
ENV=env
fi

if test -z "$use_filesystem" ; then
ADDRESS="abstract-client:$ADDRESS"
fi

Expand Down
11 changes: 10 additions & 1 deletion docs/source/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@ Generic requirements

* Python 2.6 or later, 3.2 or later, PyPy 2.0 or later. It is the only
non-optional requirement.

.. warning:
It is highly advised to use UCS-4 version of Python because UCS-2 version
uses significantly slower text processing (length determination and
non-printable character replacement) functions due to the need of
supporting unicode characters above U+FFFF which are represented as
surrogate pairs. This price will be paid even if configuration has no such
characters.
* C compiler. Required to build powerline client on linux. If it is not present
then powerline will fall back to shell script or python client.
* ``socat`` program. Required for shell variant of client which runs a bit
Expand Down Expand Up @@ -43,7 +52,7 @@ powerline with ``pip``:

.. code-block:: sh
pip install -e --user {path_to_powerline}
pip install --user --editable={path_to_powerline}
, but note that in this case ``pip`` will not install ``powerline`` executable
and you will have to do something like
Expand Down
2 changes: 2 additions & 0 deletions powerline/bindings/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,8 @@ def get_highlighting(group):
left_dividers = powerline.renderer.theme.dividers['left']
set_tmux_environment('_POWERLINE_LEFT_HARD_DIVIDER', left_dividers['hard'])
set_tmux_environment('_POWERLINE_LEFT_SOFT_DIVIDER', left_dividers['soft'])
set_tmux_environment('_POWERLINE_LEFT_HARD_DIVIDER_SPACES', (
' ' * powerline.renderer.strwidth(left_dividers['hard'])))


def get_main_config(args):
Expand Down
2 changes: 1 addition & 1 deletion powerline/bindings/tmux/powerline-base.conf
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ set -g status-interval 2
set -g status-left-length 20
set -g status-right '#(eval $POWERLINE_COMMAND tmux right -R pane_id=`tmux display -p "#D"`)'
set -g status-right-length 150
set -g window-status-format "#[$_POWERLINE_WINDOW_COLOR] #I #[$_POWERLINE_WINDOW_DIVIDER_COLOR]$_POWERLINE_LEFT_SOFT_DIVIDER#[default]#W "
set -g window-status-format "#[$_POWERLINE_WINDOW_COLOR]$_POWERLINE_LEFT_HARD_DIVIDER_SPACES#I #[$_POWERLINE_WINDOW_DIVIDER_COLOR]$_POWERLINE_LEFT_SOFT_DIVIDER#[default]#W $_POWERLINE_LEFT_HARD_DIVIDER_SPACES"
set -g window-status-current-format "#[$_POWERLINE_WINDOW_CURRENT_HARD_DIVIDER_COLOR]$_POWERLINE_LEFT_HARD_DIVIDER#[$_POWERLINE_WINDOW_CURRENT_COLOR]#I $_POWERLINE_LEFT_SOFT_DIVIDER#[$_POWERLINE_WINDOW_NAME_COLOR]#W #[$_POWERLINE_WINDOW_CURRENT_HARD_DIVIDER_NEXT_COLOR]$_POWERLINE_LEFT_HARD_DIVIDER"

# Legacy status-left definition to be overwritten for tmux Versions 1.8+
Expand Down
4 changes: 2 additions & 2 deletions powerline/config_files/colorschemes/tmux/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
"window_status": {"fg": "gray70", "bg": "gray0", "attr": []},
"activity_status": {"fg": "yellow", "bg": "gray0", "attr": []},
"bell_status": {"fg": "red", "bg": "gray0", "attr": []},
"window": {"fg": "gray6", "bg": "gray11", "attr": []},
"window:divider": {"fg": "gray4", "bg": "gray11", "attr": []},
"window": {"fg": "gray6", "bg": "gray0", "attr": []},
"window:divider": {"fg": "gray4", "bg": "gray0", "attr": []},
"window:current": {"fg": "mediumcyan", "bg": "darkblue", "attr": []},
"window_name": {"fg": "white", "bg": "darkblue", "attr": ["bold"]},
"session": {"fg": "black", "bg": "gray90", "attr": ["bold"]},
Expand Down
1 change: 0 additions & 1 deletion powerline/lib/debug.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#!/usr/bin/env python
# vim:fileencoding=utf-8:noet
from __future__ import (unicode_literals, division, absolute_import, print_function)

Expand Down
169 changes: 161 additions & 8 deletions powerline/lib/unicode.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import sys
import codecs

from unicodedata import east_asian_width, combining

from powerline.lib.encoding import get_preferred_output_encoding


Expand All @@ -19,6 +21,17 @@
unichr = chr


if sys.maxunicode < 0x10FFFF:
_unichr = unichr

def unichr(ch):
if ch <= sys.maxunicode:
return _unichr(ch)
else:
ch -= 0x10000
return _unichr((ch >> 10) + 0xD800) + _unichr((ch & ((1 << 10) - 1)) + 0xDC00)


def u(s):
'''Return unicode instance assuming UTF-8 encoded string.
'''
Expand Down Expand Up @@ -56,6 +69,27 @@ def powerline_decode_error(e):


def register_strwidth_error(strwidth):
'''Create new encode errors handling method similar to ``replace``
Like ``replace`` this method uses question marks in place of the characters
that cannot be represented in the requested encoding. Unlike ``replace`` the
amount of question marks is identical to the amount of display cells
offending character occupies. Thus encoding ``…`` (U+2026, HORIZONTAL
ELLIPSIS) to ``latin1`` will emit one question mark, but encoding ``A``
(U+FF21, FULLWIDTH LATIN CAPITAL LETTER A) will emit two question marks.
Since width of some characters depends on the terminal settings and
powerline knows how to respect them a single error handling method cannot be
used. Instead of it the generator function is used which takes ``strwidth``
function (function that knows how to compute string width respecting all
needed settings) and emits new error handling method name.
:param function strwidth:
Function that computs string width measured in display cells the string
occupies when displayed.
:return: New error handling method name.
'''
global last_swe_idx
last_swe_idx += 1

Expand Down Expand Up @@ -98,7 +132,10 @@ def safe_unicode(s):
'''
try:
try:
return unicode(s)
if type(s) is bytes:
return unicode(s, 'ascii')
else:
return unicode(s)
except UnicodeDecodeError:
try:
return unicode(s, 'utf-8')
Expand All @@ -111,8 +148,7 @@ def safe_unicode(s):


class FailedUnicode(unicode):
'''Builtin ``unicode`` (``str`` in python 3) subclass indicating fatal
error.
'''Builtin ``unicode`` subclass indicating fatal error
If your code for some reason wants to determine whether `.render()` method
failed it should check returned string for being a FailedUnicode instance.
Expand All @@ -123,8 +159,125 @@ class FailedUnicode(unicode):
pass


def string(s):
if type(s) is not str:
return s.encode('utf-8')
else:
return s
if sys.version_info < (3,):
def string(s):
if type(s) is not str:
return s.encode('utf-8')
else:
return s
else:
def string(s):
if type(s) is not str:
return s.decode('utf-8')
else:
return s


string.__doc__ = (
'''Transform ``unicode`` or ``bytes`` object into ``str`` object
On Python-2 this encodes ``unicode`` to ``bytes`` (which is ``str``) using
UTF-8 encoding; on Python-3 this decodes ``bytes`` to ``unicode`` (which is
``str``) using UTF-8 encoding.
Useful for functions that expect an ``str`` object in both unicode versions,
not caring about the semantic differences between them in Python-2 and
Python-3.
'''
)


def surrogate_pair_to_character(high, low):
'''Transform a pair of surrogate codepoints to one codepoint
'''
return 0x10000 + ((high - 0xD800) << 10) + (low - 0xDC00)


_strwidth_documentation = (
'''Compute string width in display cells
{0}
:param dict width_data:
Dictionary which maps east_asian_width property values to strings
lengths. It is expected to contain the following keys and values (from
`East Asian Width annex <http://www.unicode.org/reports/tr11/>`_):
=== ====== ===========================================================
Key Value Description
=== ====== ===========================================================
F 2 Fullwidth: all characters that are defined as Fullwidth in
the Unicode Standard [Unicode] by having a compatibility
decomposition of type <wide> to characters elsewhere in the
Unicode Standard that are implicitly narrow but unmarked.
H 1 Halfwidth: all characters that are explicitly defined as
Halfwidth in the Unicode Standard by having a compatibility
decomposition of type <narrow> to characters elsewhere in
the Unicode Standard that are implicitly wide but unmarked,
plus U+20A9 ₩ WON SIGN.
W 2 Wide: all other characters that are always wide. These
characters occur only in the context of East Asian
typography where they are wide characters (such as the
Unified Han Ideographs or Squared Katakana Symbols). This
category includes characters that have explicit halfwidth
counterparts.
Na 1 Narrow: characters that are always narrow and have explicit
fullwidth or wide counterparts. These characters are
implicitly narrow in East Asian typography and legacy
character sets because they have explicit fullwidth or wide
counterparts. All of ASCII is an example of East Asian
Narrow characters.
A 1 or 2 Ambigious: characters that may sometimes be wide and
sometimes narrow. Ambiguous characters require additional
information not contained in the character code to further
resolve their width. This information is usually defined in
terminal setting that should in turn respect glyphs widths
in used fonts. Also see :ref:`ambiwidth configuration
option <config-common-ambiwidth>`.
N 1 Neutral characters: character that does not occur in legacy
East Asian character sets.
=== ====== ===========================================================
:param unicode string:
String whose width will be calculated.
:return: unsigned integer.''')


def strwidth_ucs_4(width_data, string):
return sum(((
(
0
) if combining(symbol) else (
width_data[east_asian_width(symbol)]
)
) for symbol in string))


strwidth_ucs_4.__doc__ = _strwidth_documentation.format(
'''This version of function expects that characters above 0xFFFF are
represented using one symbol. This is only the case in UCS-4 Python builds.
.. note:
Even in UCS-4 Python builds it is possible to represent characters above
0xFFFF using surrogate pairs. Characters represented this way are not
supported.''')


def strwidth_ucs_2(width_data, string):
return sum(((
(
width_data[east_asian_width(string[i - 1] + symbol)]
) if 0xDC00 <= ord(symbol) <= 0xDFFF else (
0
) if combining(symbol) or 0xD800 <= ord(symbol) <= 0xDBFF else (
width_data[east_asian_width(symbol)]
)
) for i, symbol in enumerate(string)))


strwidth_ucs_2.__doc__ = _strwidth_documentation.format(
'''This version of function expects that characters above 0xFFFF are
represented using two symbols forming a surrogate pair, which is the only
option in UCS-2 Python builds. It still works correctly in UCS-4 Python
builds, but is slower then its UCS-4 counterpart.''')
14 changes: 7 additions & 7 deletions powerline/lint/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def load_json_config(config_file_path, load=load, open_file=open_file):
function_name_re = '^(\w+\.)*[a-zA-Z_]\w*$'


divider_spec = Spec().type(unicode).len(
divider_spec = Spec().printable().len(
'le', 3, (lambda value: 'Divider {0!r} is too large!'.format(value))).copy
ext_theme_spec = Spec().type(unicode).func(lambda *args: check_config('themes', *args)).copy
top_theme_spec = Spec().type(unicode).func(check_top_theme).copy
Expand Down Expand Up @@ -211,12 +211,12 @@ def load_json_config(config_file_path, load=load, open_file=open_file):
display=Spec().type(bool).optional(),
module=segment_module_spec(),
priority=Spec().type(int, float, type(None)).optional(),
after=Spec().type(unicode).optional(),
before=Spec().type(unicode).optional(),
after=Spec().printable().optional(),
before=Spec().printable().optional(),
width=Spec().either(Spec().unsigned(), Spec().cmp('eq', 'auto')).optional(),
align=Spec().oneof(set('lr')).optional(),
args=args_spec().func(lambda *args, **kwargs: check_args(get_one_segment_function, *args, **kwargs)),
contents=Spec().type(unicode).optional(),
contents=Spec().printable().optional(),
highlight_group=Spec().list(
highlight_group_spec().re(
'^(?:(?!:divider$).)+$',
Expand All @@ -243,11 +243,11 @@ def load_json_config(config_file_path, load=load, open_file=open_file):
soft=divider_spec(),
).copy
segment_data_value_spec = Spec(
after=Spec().type(unicode).optional(),
before=Spec().type(unicode).optional(),
after=Spec().printable().optional(),
before=Spec().printable().optional(),
display=Spec().type(bool).optional(),
args=args_spec().func(lambda *args, **kwargs: check_args(get_all_possible_functions, *args, **kwargs)),
contents=Spec().type(unicode).optional(),
contents=Spec().printable().optional(),
).copy
dividers_spec = Spec(
left=divside_spec(),
Expand Down
Loading

0 comments on commit 6eaa640

Please sign in to comment.