mirror of
https://github.com/powerline/powerline.git
synced 2025-09-25 10:59:18 +02:00
Release 2.5
- Added IPython-5 support: in new major IPython version prompt code was largerly reworked, resulting in different set of hacks needed for powerline to work. IPython still does not have features needed to avoid using hacks. - Added stash segment. - Fixed trailing whitespace segment: it could incorrectly report trailing whitespace if line ended with `b` or `'` on Python-3. - Fixed weather segment and altered geoip service used. - Fixed escaping used for status-left option on tmux-2.1 and higher.
This commit is contained in:
commit
6e2e0b2f92
@ -12,7 +12,7 @@ Awesome, i3 and Qtile.**
|
||||
* `Support forum`_ (powerline-support@googlegroups.com)
|
||||
* `Development discussion`_ (powerline-dev@googlegroups.com)
|
||||
|
||||
.. image:: https://api.travis-ci.org/powerline/powerline.png?branch=develop
|
||||
.. image:: https://api.travis-ci.org/powerline/powerline.svg?branch=develop
|
||||
:target: `travis-build-status`_
|
||||
:alt: Build status
|
||||
|
||||
@ -52,7 +52,7 @@ hassle for me / what happened to the original vim-powerline project / …*
|
||||
|
||||
You should check out some of the Powerline derivatives. The most lightweight
|
||||
and feature-rich alternative is currently Bailey Ling’s `vim-airline
|
||||
<https://github.com/bling/vim-airline>`_ project.
|
||||
<https://github.com/vim-airline/vim-airline>`_ project.
|
||||
|
||||
------
|
||||
|
||||
@ -92,4 +92,4 @@ Vim statusline
|
||||
|
||||
The font in the screenshots is `Pragmata Pro`_ by Fabrizio Schiavi.
|
||||
|
||||
.. _`Pragmata Pro`: http://www.fsd.it/fonts/pragmatapro.htm
|
||||
.. _`Pragmata Pro`: http://www.fsd.it/shop/fonts/pragmatapro
|
||||
|
@ -2,11 +2,19 @@
|
||||
from __future__ import (unicode_literals, division, absolute_import, print_function)
|
||||
|
||||
from weakref import ref
|
||||
from warnings import warn
|
||||
|
||||
try:
|
||||
from IPython.core.prompts import PromptManager
|
||||
has_prompt_manager = True
|
||||
except ImportError:
|
||||
has_prompt_manager = False
|
||||
from IPython.core.magic import Magics, magics_class, line_magic
|
||||
|
||||
from powerline.ipython import IPythonPowerline, RewriteResult
|
||||
from powerline.ipython import IPythonPowerline, IPythonInfo
|
||||
|
||||
if has_prompt_manager:
|
||||
from powerline.ipython import RewriteResult
|
||||
|
||||
|
||||
@magics_class
|
||||
@ -23,15 +31,23 @@ class PowerlineMagics(Magics):
|
||||
raise ValueError('Expected `reload`, but got {0}'.format(line))
|
||||
|
||||
|
||||
class IPythonInfo(object):
|
||||
def __init__(self, shell):
|
||||
self._shell = shell
|
||||
|
||||
@property
|
||||
def prompt_count(self):
|
||||
return self._shell.execution_count
|
||||
old_prompt_manager = None
|
||||
|
||||
|
||||
class ShutdownHook(object):
|
||||
def __init__(self, ip):
|
||||
self.powerline = lambda: None
|
||||
ip.hooks.shutdown_hook.add(self)
|
||||
|
||||
def __call__(self):
|
||||
from IPython.core.hooks import TryNext
|
||||
powerline = self.powerline()
|
||||
if powerline is not None:
|
||||
powerline.shutdown()
|
||||
raise TryNext()
|
||||
|
||||
|
||||
if has_prompt_manager:
|
||||
class PowerlinePromptManager(PromptManager):
|
||||
def __init__(self, powerline, shell):
|
||||
self.powerline = powerline
|
||||
@ -55,52 +71,53 @@ class PowerlinePromptManager(PromptManager):
|
||||
else:
|
||||
return ret
|
||||
|
||||
|
||||
class ShutdownHook(object):
|
||||
powerline = lambda: None
|
||||
|
||||
def __call__(self):
|
||||
from IPython.core.hooks import TryNext
|
||||
powerline = self.powerline()
|
||||
if powerline is not None:
|
||||
powerline.shutdown()
|
||||
raise TryNext()
|
||||
|
||||
|
||||
class ConfigurableIPythonPowerline(IPythonPowerline):
|
||||
def init(self, ip):
|
||||
config = ip.config.Powerline
|
||||
self.config_overrides = config.get('config_overrides')
|
||||
self.theme_overrides = config.get('theme_overrides', {})
|
||||
self.config_paths = config.get('config_paths')
|
||||
super(ConfigurableIPythonPowerline, self).init()
|
||||
if has_prompt_manager:
|
||||
renderer_module = '.pre_5'
|
||||
else:
|
||||
renderer_module = '.since_5'
|
||||
super(ConfigurableIPythonPowerline, self).init(
|
||||
renderer_module=renderer_module)
|
||||
|
||||
def do_setup(self, ip, shutdown_hook):
|
||||
global old_prompt_manager
|
||||
|
||||
if old_prompt_manager is None:
|
||||
old_prompt_manager = ip.prompt_manager
|
||||
prompt_manager = PowerlinePromptManager(
|
||||
powerline=self,
|
||||
shell=ip.prompt_manager.shell,
|
||||
)
|
||||
ip.prompt_manager = prompt_manager
|
||||
|
||||
magics = PowerlineMagics(ip, self)
|
||||
shutdown_hook.powerline = ref(self)
|
||||
|
||||
ip.prompt_manager = prompt_manager
|
||||
ip.register_magics(magics)
|
||||
|
||||
|
||||
old_prompt_manager = None
|
||||
|
||||
|
||||
def load_ipython_extension(ip):
|
||||
global old_prompt_manager
|
||||
old_prompt_manager = ip.prompt_manager
|
||||
|
||||
if has_prompt_manager:
|
||||
shutdown_hook = ShutdownHook(ip)
|
||||
powerline = ConfigurableIPythonPowerline(ip)
|
||||
shutdown_hook = ShutdownHook()
|
||||
|
||||
powerline.setup(ip, shutdown_hook)
|
||||
|
||||
ip.hooks.shutdown_hook.add(shutdown_hook)
|
||||
else:
|
||||
from powerline.bindings.ipython.since_5 import PowerlinePrompts
|
||||
ip.prompts_class = PowerlinePrompts
|
||||
ip.prompts = PowerlinePrompts(ip)
|
||||
warn(DeprecationWarning(
|
||||
'post_0_11 extension is deprecated since IPython 5, use\n'
|
||||
' from powerline.bindings.ipython.since_5 import PowerlinePrompts\n'
|
||||
' c.TerminalInteractiveShell.prompts_class = PowerlinePrompts\n'
|
||||
))
|
||||
|
||||
|
||||
def unload_ipython_extension(ip):
|
||||
global old_prompt_manager
|
||||
if old_prompt_manager is not None:
|
||||
ip.prompt_manager = old_prompt_manager
|
||||
old_prompt_manager = None
|
||||
|
@ -99,7 +99,7 @@ class ConfigurableIPythonPowerline(IPythonPowerline):
|
||||
self.config_overrides = config_overrides
|
||||
self.theme_overrides = theme_overrides
|
||||
self.config_paths = config_paths
|
||||
super(ConfigurableIPythonPowerline, self).init()
|
||||
super(ConfigurableIPythonPowerline, self).init(renderer_module='.pre_5')
|
||||
|
||||
def ipython_magic(self, ip, parameter_s=''):
|
||||
if parameter_s == 'reload':
|
||||
|
79
powerline/bindings/ipython/since_5.py
Normal file
79
powerline/bindings/ipython/since_5.py
Normal file
@ -0,0 +1,79 @@
|
||||
# vim:fileencoding=utf-8:noet
|
||||
from __future__ import (unicode_literals, division, absolute_import, print_function)
|
||||
|
||||
from weakref import ref
|
||||
|
||||
from IPython.terminal.prompts import Prompts
|
||||
from pygments.token import Token # NOQA
|
||||
|
||||
from powerline.ipython import IPythonPowerline
|
||||
from powerline.renderers.ipython.since_5 import PowerlinePromptStyle
|
||||
from powerline.bindings.ipython.post_0_11 import PowerlineMagics, ShutdownHook
|
||||
|
||||
|
||||
class ConfigurableIPythonPowerline(IPythonPowerline):
|
||||
def init(self, ip):
|
||||
config = ip.config.Powerline
|
||||
self.config_overrides = config.get('config_overrides')
|
||||
self.theme_overrides = config.get('theme_overrides', {})
|
||||
self.config_paths = config.get('config_paths')
|
||||
super(ConfigurableIPythonPowerline, self).init(
|
||||
renderer_module='.since_5')
|
||||
|
||||
def do_setup(self, ip, prompts, shutdown_hook):
|
||||
prompts.powerline = self
|
||||
|
||||
saved_msfn = ip._make_style_from_name
|
||||
|
||||
if hasattr(saved_msfn, 'powerline_original'):
|
||||
saved_msfn = saved_msfn.powerline_original
|
||||
|
||||
def _make_style_from_name(ip, name):
|
||||
prev_style = saved_msfn(name)
|
||||
new_style = PowerlinePromptStyle(lambda: prev_style)
|
||||
return new_style
|
||||
|
||||
_make_style_from_name.powerline_original = saved_msfn
|
||||
|
||||
if not isinstance(ip._style, PowerlinePromptStyle):
|
||||
prev_style = ip._style
|
||||
ip._style = PowerlinePromptStyle(lambda: prev_style)
|
||||
|
||||
if not isinstance(saved_msfn, type(self.init)):
|
||||
_saved_msfn = saved_msfn
|
||||
saved_msfn = lambda: _saved_msfn(ip)
|
||||
|
||||
ip._make_style_from_name = _make_style_from_name
|
||||
|
||||
magics = PowerlineMagics(ip, self)
|
||||
ip.register_magics(magics)
|
||||
|
||||
if shutdown_hook:
|
||||
shutdown_hook.powerline = ref(self)
|
||||
|
||||
|
||||
class PowerlinePrompts(Prompts):
|
||||
'''Class that returns powerline prompts
|
||||
'''
|
||||
def __init__(self, shell):
|
||||
shutdown_hook = ShutdownHook(shell)
|
||||
powerline = ConfigurableIPythonPowerline(shell)
|
||||
self.shell = shell
|
||||
powerline.do_setup(shell, self, shutdown_hook)
|
||||
self.last_output_count = None
|
||||
self.last_output = {}
|
||||
|
||||
for prompt in ('in', 'continuation', 'rewrite', 'out'):
|
||||
exec((
|
||||
'def {0}_prompt_tokens(self, *args, **kwargs):\n'
|
||||
' if self.last_output_count != self.shell.execution_count:\n'
|
||||
' self.last_output.clear()\n'
|
||||
' self.last_output_count = self.shell.execution_count\n'
|
||||
' if "{0}" not in self.last_output:\n'
|
||||
' self.last_output["{0}"] = self.powerline.render('
|
||||
' side="left",'
|
||||
' matcher_info="{1}",'
|
||||
' segment_info=self.shell,'
|
||||
' ) + [(Token.Generic.Prompt, " ")]\n'
|
||||
' return self.last_output["{0}"]'
|
||||
).format(prompt, 'in2' if prompt == 'continuation' else prompt))
|
2
powerline/bindings/tmux/powerline_tmux_2.1_plus.conf
Normal file
2
powerline/bindings/tmux/powerline_tmux_2.1_plus.conf
Normal file
@ -0,0 +1,2 @@
|
||||
# Starting from tmux-2.1 escaping of dollar signs inside #() is harmful
|
||||
set -qg status-left "#{?client_prefix,#[fg=$_POWERLINE_SESSION_PREFIX_FG]#[bg=$_POWERLINE_SESSION_PREFIX_BG]#[$_POWERLINE_SESSION_PREFIX_ATTR],#[fg=$_POWERLINE_SESSION_FG]#[bg=$_POWERLINE_SESSION_BG]#[$_POWERLINE_SESSION_ATTR]} #S #{?client_prefix,#[fg=$_POWERLINE_SESSION_PREFIX_BG],#[fg=$_POWERLINE_SESSION_BG]}#[bg=$_POWERLINE_BACKGROUND_BG]#[nobold]$_POWERLINE_LEFT_HARD_DIVIDER#(env $POWERLINE_COMMAND $POWERLINE_COMMAND_ARGS tmux left --width=`tmux display -p '#{client_width}'` -R width_adjust=`tmux show-options -g status-right-length | cut -d' ' -f2` -R pane_id=\"`tmux display -p '#D'`\")"
|
@ -43,6 +43,8 @@
|
||||
"branch_dirty": { "fg": "brightyellow", "bg": "gray2", "attrs": [] },
|
||||
"branch_clean": { "fg": "gray9", "bg": "gray2", "attrs": [] },
|
||||
"branch:divider": { "fg": "gray7", "bg": "gray2", "attrs": [] },
|
||||
"stash": "branch_dirty",
|
||||
"stash:divider": "branch:divider",
|
||||
"cwd": "information:additional",
|
||||
"cwd:current_folder": "information:regular",
|
||||
"cwd:divider": { "fg": "gray7", "bg": "gray4", "attrs": [] },
|
||||
|
@ -15,6 +15,7 @@
|
||||
"branch": { "fg": "solarized:base1", "bg": "solarized:base02", "attrs": [] },
|
||||
"branch_dirty": { "fg": "solarized:yellow", "bg": "solarized:base02", "attrs": [] },
|
||||
"branch_clean": { "fg": "solarized:base1", "bg": "solarized:base02", "attrs": [] },
|
||||
"stash": "branch_dirty",
|
||||
"email_alert_gradient": { "fg": "solarized:base3", "bg": "yellow_orange_red", "attrs": [] },
|
||||
"email_alert": "warning:regular",
|
||||
"cwd": "information:additional",
|
||||
|
@ -12,6 +12,7 @@
|
||||
"readonly_indicator": { "fg": "solarized:red", "bg": "solarized:base01", "attrs": [] },
|
||||
"branch_dirty": { "fg": "solarized:yellow", "bg": "solarized:base01", "attrs": [] },
|
||||
"branch:divider": { "fg": "solarized:base1", "bg": "solarized:base01", "attrs": [] },
|
||||
"stash:divider": "branch:divider",
|
||||
"file_name": { "fg": "solarized:base3", "bg": "solarized:base01", "attrs": ["bold"] },
|
||||
"window_title": { "fg": "solarized:base3", "bg": "solarized:base01", "attrs": [] },
|
||||
"file_name_no_file": { "fg": "solarized:base3", "bg": "solarized:base01", "attrs": ["bold"] },
|
||||
|
@ -12,6 +12,8 @@
|
||||
"readonly_indicator": { "fg": "solarized:red", "bg": "solarized:base2", "attrs": [] },
|
||||
"branch_dirty": { "fg": "solarized:yellow", "bg": "solarized:base2", "attrs": [] },
|
||||
"branch:divider": { "fg": "solarized:base1", "bg": "solarized:base2", "attrs": [] },
|
||||
"stash": "branch_dirty",
|
||||
"stash:divider": "branch:divider",
|
||||
"file_name": { "fg": "solarized:base03", "bg": "solarized:base2", "attrs": ["bold"] },
|
||||
"window_title": { "fg": "solarized:base03", "bg": "solarized:base2", "attrs": [] },
|
||||
"file_size": { "fg": "solarized:base03", "bg": "solarized:base2", "attrs": [] },
|
||||
|
@ -15,6 +15,9 @@
|
||||
"branch": {
|
||||
"before": "BR "
|
||||
},
|
||||
"stash": {
|
||||
"before": "ST "
|
||||
},
|
||||
"cwd": {
|
||||
"args": {
|
||||
"ellipsis": "..."
|
||||
|
@ -14,6 +14,9 @@
|
||||
"branch": {
|
||||
"before": " "
|
||||
},
|
||||
"stash": {
|
||||
"before": "⌆ "
|
||||
},
|
||||
"cwd": {
|
||||
"args": {
|
||||
"ellipsis": "⋯"
|
||||
|
@ -14,6 +14,9 @@
|
||||
"branch": {
|
||||
"before": "🔀 "
|
||||
},
|
||||
"stash": {
|
||||
"before": "📝"
|
||||
},
|
||||
"cwd": {
|
||||
"args": {
|
||||
"ellipsis": "⋯"
|
||||
|
@ -30,6 +30,10 @@
|
||||
"function": "powerline.segments.shell.last_pipe_status",
|
||||
"priority": 10
|
||||
},
|
||||
{
|
||||
"function": "powerline.segments.common.vcs.stash",
|
||||
"priority": 50
|
||||
},
|
||||
{
|
||||
"function": "powerline.segments.common.vcs.branch",
|
||||
"priority": 40
|
||||
|
@ -14,6 +14,9 @@
|
||||
"branch": {
|
||||
"before": "⎇ "
|
||||
},
|
||||
"stash": {
|
||||
"before": "⌆"
|
||||
},
|
||||
"cwd": {
|
||||
"args": {
|
||||
"ellipsis": "⋯"
|
||||
|
@ -14,6 +14,9 @@
|
||||
"branch": {
|
||||
"before": "BR "
|
||||
},
|
||||
"stash": {
|
||||
"before": "ST "
|
||||
},
|
||||
"cwd": {
|
||||
"args": {
|
||||
"ellipsis": "…"
|
||||
|
@ -14,6 +14,9 @@
|
||||
"branch": {
|
||||
"before": "B "
|
||||
},
|
||||
"stash": {
|
||||
"before": "S "
|
||||
},
|
||||
"cwd": {
|
||||
"args": {
|
||||
"use_path_separator": true,
|
||||
|
@ -6,6 +6,15 @@ from powerline.lib.dict import mergedicts
|
||||
from powerline.lib.unicode import string
|
||||
|
||||
|
||||
class IPythonInfo(object):
|
||||
def __init__(self, shell):
|
||||
self._shell = shell
|
||||
|
||||
@property
|
||||
def prompt_count(self):
|
||||
return self._shell.execution_count
|
||||
|
||||
|
||||
# HACK: ipython tries to only leave us with plain ASCII
|
||||
class RewriteResult(object):
|
||||
def __init__(self, prompt):
|
||||
|
@ -102,6 +102,13 @@ try:
|
||||
def ignore_event(path, name):
|
||||
return False
|
||||
|
||||
def stash(self):
|
||||
try:
|
||||
stashref = git.Repository(git_directory(self.directory)).lookup_reference('refs/stash')
|
||||
except KeyError:
|
||||
return 0
|
||||
return sum(1 for _ in stashref.log())
|
||||
|
||||
def do_status(self, directory, path):
|
||||
if path:
|
||||
try:
|
||||
@ -171,6 +178,9 @@ except ImportError:
|
||||
def _gitcmd(self, directory, *args):
|
||||
return readlines(('git',) + args, directory)
|
||||
|
||||
def stash(self):
|
||||
return sum(1 for _ in self._gitcmd(self.directory, 'stash', 'list'))
|
||||
|
||||
def do_status(self, directory, path):
|
||||
if path:
|
||||
try:
|
||||
|
@ -4,6 +4,7 @@ from __future__ import (unicode_literals, division, absolute_import, print_funct
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
import operator
|
||||
|
||||
from itertools import chain
|
||||
|
||||
@ -310,6 +311,19 @@ class Renderer(object):
|
||||
},
|
||||
}
|
||||
|
||||
hl_join = staticmethod(''.join)
|
||||
'''Join a list of rendered segments into a resulting string
|
||||
|
||||
This method exists to deal with non-string render outputs, so `segments`
|
||||
may actually be not an iterable with strings.
|
||||
|
||||
:param list segments:
|
||||
Iterable containing rendered segments. By “rendered segments”
|
||||
:py:meth:`Renderer.hl` output is meant.
|
||||
|
||||
:return: Results of joining these segments.
|
||||
'''
|
||||
|
||||
def do_render(self, mode, width, side, line, output_raw, output_width, segment_info, theme):
|
||||
'''Like Renderer.render(), but accept theme in place of matcher_info
|
||||
'''
|
||||
@ -323,7 +337,7 @@ class Renderer(object):
|
||||
# No width specified, so we don’t need to crop or pad anything
|
||||
if output_width:
|
||||
current_width = self._render_length(theme, segments, self.compute_divider_widths(theme))
|
||||
return construct_returned_value(''.join([
|
||||
return construct_returned_value(self.hl_join([
|
||||
segment['_rendered_hl']
|
||||
for segment in self._render_segments(theme, segments)
|
||||
]) + self.hlstyle(), segments, current_width, output_raw, output_width)
|
||||
@ -378,7 +392,10 @@ class Renderer(object):
|
||||
elif output_width:
|
||||
current_width = self._render_length(theme, segments, divider_widths)
|
||||
|
||||
rendered_highlighted = ''.join([segment['_rendered_hl'] for segment in self._render_segments(theme, segments)])
|
||||
rendered_highlighted = self.hl_join([
|
||||
segment['_rendered_hl']
|
||||
for segment in self._render_segments(theme, segments)
|
||||
])
|
||||
if rendered_highlighted:
|
||||
rendered_highlighted += self.hlstyle()
|
||||
|
||||
|
@ -1,12 +1,11 @@
|
||||
# vim:fileencoding=utf-8:noet
|
||||
from __future__ import (unicode_literals, division, absolute_import, print_function)
|
||||
|
||||
from powerline.renderers.shell import ShellRenderer
|
||||
from powerline.renderers.shell.readline import ReadlineRenderer
|
||||
from powerline.theme import Theme
|
||||
from powerline.renderers.shell import PromptRenderer
|
||||
|
||||
|
||||
class IPythonRenderer(ShellRenderer):
|
||||
class IPythonRenderer(PromptRenderer):
|
||||
'''Powerline ipython segment renderer.'''
|
||||
def get_segment_info(self, segment_info, mode):
|
||||
r = self.segment_info.copy()
|
||||
@ -33,50 +32,3 @@ class IPythonRenderer(ShellRenderer):
|
||||
for match in self.local_themes.values():
|
||||
if 'theme' in match:
|
||||
match['theme'].shutdown()
|
||||
|
||||
def render(self, **kwargs):
|
||||
# XXX super(ShellRenderer), *not* super(IPythonRenderer)
|
||||
return super(ShellRenderer, self).render(**kwargs)
|
||||
|
||||
def do_render(self, segment_info, **kwargs):
|
||||
segment_info.update(client_id='ipython')
|
||||
return super(IPythonRenderer, self).do_render(
|
||||
segment_info=segment_info,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
|
||||
class IPythonPromptRenderer(IPythonRenderer, ReadlineRenderer):
|
||||
'''Powerline ipython prompt (in and in2) renderer'''
|
||||
pass
|
||||
|
||||
|
||||
class IPythonNonPromptRenderer(IPythonRenderer):
|
||||
'''Powerline ipython non-prompt (out and rewrite) renderer'''
|
||||
pass
|
||||
|
||||
|
||||
class RendererProxy(object):
|
||||
'''Powerline IPython renderer proxy which chooses appropriate renderer
|
||||
|
||||
Instantiates two renderer objects: one will be used for prompts and the
|
||||
other for non-prompts.
|
||||
'''
|
||||
def __init__(self, **kwargs):
|
||||
old_widths = {}
|
||||
self.non_prompt_renderer = IPythonNonPromptRenderer(old_widths=old_widths, **kwargs)
|
||||
self.prompt_renderer = IPythonPromptRenderer(old_widths=old_widths, **kwargs)
|
||||
|
||||
def render_above_lines(self, *args, **kwargs):
|
||||
return self.non_prompt_renderer.render_above_lines(*args, **kwargs)
|
||||
|
||||
def render(self, is_prompt, *args, **kwargs):
|
||||
return (self.prompt_renderer if is_prompt else self.non_prompt_renderer).render(
|
||||
*args, **kwargs)
|
||||
|
||||
def shutdown(self, *args, **kwargs):
|
||||
self.prompt_renderer.shutdown(*args, **kwargs)
|
||||
self.non_prompt_renderer.shutdown(*args, **kwargs)
|
||||
|
||||
|
||||
renderer = RendererProxy
|
||||
|
56
powerline/renderers/ipython/pre_5.py
Normal file
56
powerline/renderers/ipython/pre_5.py
Normal file
@ -0,0 +1,56 @@
|
||||
# vim:fileencoding=utf-8:noet
|
||||
from __future__ import (unicode_literals, division, absolute_import, print_function)
|
||||
|
||||
from powerline.renderers.shell import ShellRenderer
|
||||
from powerline.renderers.shell.readline import ReadlineRenderer
|
||||
from powerline.renderers.ipython import IPythonRenderer
|
||||
|
||||
|
||||
class IPythonPre50Renderer(IPythonRenderer, ShellRenderer):
|
||||
'''Powerline ipython segment renderer for pre-5.0 IPython versions.'''
|
||||
def render(self, **kwargs):
|
||||
# XXX super(ShellRenderer), *not* super(IPythonPre50Renderer)
|
||||
return super(ShellRenderer, self).render(**kwargs)
|
||||
|
||||
def do_render(self, segment_info, **kwargs):
|
||||
segment_info.update(client_id='ipython')
|
||||
return super(IPythonPre50Renderer, self).do_render(
|
||||
segment_info=segment_info,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
|
||||
class IPythonPromptRenderer(IPythonPre50Renderer, ReadlineRenderer):
|
||||
'''Powerline ipython prompt (in and in2) renderer'''
|
||||
pass
|
||||
|
||||
|
||||
class IPythonNonPromptRenderer(IPythonPre50Renderer):
|
||||
'''Powerline ipython non-prompt (out and rewrite) renderer'''
|
||||
pass
|
||||
|
||||
|
||||
class RendererProxy(object):
|
||||
'''Powerline IPython renderer proxy which chooses appropriate renderer
|
||||
|
||||
Instantiates two renderer objects: one will be used for prompts and the
|
||||
other for non-prompts.
|
||||
'''
|
||||
def __init__(self, **kwargs):
|
||||
old_widths = {}
|
||||
self.non_prompt_renderer = IPythonNonPromptRenderer(old_widths=old_widths, **kwargs)
|
||||
self.prompt_renderer = IPythonPromptRenderer(old_widths=old_widths, **kwargs)
|
||||
|
||||
def render_above_lines(self, *args, **kwargs):
|
||||
return self.non_prompt_renderer.render_above_lines(*args, **kwargs)
|
||||
|
||||
def render(self, is_prompt, *args, **kwargs):
|
||||
return (self.prompt_renderer if is_prompt else self.non_prompt_renderer).render(
|
||||
*args, **kwargs)
|
||||
|
||||
def shutdown(self, *args, **kwargs):
|
||||
self.prompt_renderer.shutdown(*args, **kwargs)
|
||||
self.non_prompt_renderer.shutdown(*args, **kwargs)
|
||||
|
||||
|
||||
renderer = RendererProxy
|
130
powerline/renderers/ipython/since_5.py
Normal file
130
powerline/renderers/ipython/since_5.py
Normal file
@ -0,0 +1,130 @@
|
||||
# vim:fileencoding=utf-8:noet
|
||||
from __future__ import (unicode_literals, division, absolute_import, print_function)
|
||||
|
||||
import operator
|
||||
|
||||
from collections import defaultdict
|
||||
|
||||
try:
|
||||
from __builtin__ import reduce
|
||||
except ImportError:
|
||||
from functools import reduce
|
||||
|
||||
from pygments.token import Token
|
||||
from prompt_toolkit.styles import DynamicStyle, Attrs
|
||||
|
||||
from powerline.renderers.ipython import IPythonRenderer
|
||||
from powerline.ipython import IPythonInfo
|
||||
from powerline.colorscheme import ATTR_BOLD, ATTR_ITALIC, ATTR_UNDERLINE
|
||||
|
||||
|
||||
PowerlinePromptToken = Token.Generic.Prompt.Powerline
|
||||
|
||||
|
||||
# Note: since 2.7 there is dict.__missing__ with same purpose. But in 2.6 one
|
||||
# must use defaultdict to get __missing__ working.
|
||||
class PowerlineStyleDict(defaultdict):
|
||||
'''Dictionary used for getting pygments style for Powerline groups
|
||||
'''
|
||||
def __new__(cls, missing_func):
|
||||
return defaultdict.__new__(cls)
|
||||
|
||||
def __init__(self, missing_func):
|
||||
super(PowerlineStyleDict, self).__init__()
|
||||
self.missing_func = missing_func
|
||||
|
||||
def __missing__(self, key):
|
||||
return self.missing_func(key)
|
||||
|
||||
|
||||
class PowerlinePromptStyle(DynamicStyle):
|
||||
def get_attrs_for_token(self, token):
|
||||
if (
|
||||
token not in PowerlinePromptToken
|
||||
or len(token) != len(PowerlinePromptToken) + 1
|
||||
or not token[-1].startswith('Pl')
|
||||
or token[-1] == 'Pl'
|
||||
):
|
||||
return super(PowerlinePromptStyle, self).get_attrs_for_token(token)
|
||||
ret = {
|
||||
'color': None,
|
||||
'bgcolor': None,
|
||||
'bold': None,
|
||||
'underline': None,
|
||||
'italic': None,
|
||||
'reverse': False,
|
||||
'blink': False,
|
||||
}
|
||||
for prop in token[-1][3:].split('_'):
|
||||
if prop[0] == 'a':
|
||||
ret[prop[1:]] = True
|
||||
elif prop[0] == 'f':
|
||||
ret['color'] = prop[1:]
|
||||
elif prop[0] == 'b':
|
||||
ret['bgcolor'] = prop[1:]
|
||||
return Attrs(**ret)
|
||||
|
||||
def get_token_to_attributes_dict(self):
|
||||
dct = super(PowerlinePromptStyle, self).get_token_to_attributes_dict()
|
||||
|
||||
def fallback(key):
|
||||
try:
|
||||
return dct[key]
|
||||
except KeyError:
|
||||
return self.get_attrs_for_token(key)
|
||||
|
||||
return PowerlineStyleDict(fallback)
|
||||
|
||||
def invalidation_hash(self):
|
||||
return super(PowerlinePromptStyle, self).invalidation_hash() + 1
|
||||
|
||||
|
||||
class IPythonPygmentsRenderer(IPythonRenderer):
|
||||
reduce_initial = []
|
||||
|
||||
def get_segment_info(self, segment_info, mode):
|
||||
return super(IPythonPygmentsRenderer, self).get_segment_info(
|
||||
IPythonInfo(segment_info), mode)
|
||||
|
||||
@staticmethod
|
||||
def hl_join(segments):
|
||||
return reduce(operator.iadd, segments, [])
|
||||
|
||||
def hl(self, contents, fg=None, bg=None, attrs=None):
|
||||
'''Output highlighted chunk.
|
||||
|
||||
This implementation outputs a list containing a single pair
|
||||
(:py:class:`pygments.token.Token`,
|
||||
:py:class:`powerline.lib.unicode.unicode`).
|
||||
'''
|
||||
guifg = None
|
||||
guibg = None
|
||||
attrs = []
|
||||
if fg is not None and fg is not False:
|
||||
guifg = fg[1]
|
||||
if bg is not None and bg is not False:
|
||||
guibg = bg[1]
|
||||
if attrs:
|
||||
attrs = []
|
||||
if attrs & ATTR_BOLD:
|
||||
attrs.append('bold')
|
||||
if attrs & ATTR_ITALIC:
|
||||
attrs.append('italic')
|
||||
if attrs & ATTR_UNDERLINE:
|
||||
attrs.append('underline')
|
||||
name = (
|
||||
'Pl'
|
||||
+ ''.join(('_a' + attr for attr in attrs))
|
||||
+ (('_f%6x' % guifg) if guifg is not None else '')
|
||||
+ (('_b%6x' % guibg) if guibg is not None else '')
|
||||
)
|
||||
return [(getattr(Token.Generic.Prompt.Powerline, name), contents)]
|
||||
|
||||
def hlstyle(self, **kwargs):
|
||||
return []
|
||||
|
||||
def get_client_id(self, segment_info):
|
||||
return id(self)
|
||||
|
||||
|
||||
renderer = IPythonPygmentsRenderer
|
@ -13,41 +13,30 @@ def int_to_rgb(num):
|
||||
return r, g, b
|
||||
|
||||
|
||||
class ShellRenderer(Renderer):
|
||||
'''Powerline shell segment renderer.'''
|
||||
escape_hl_start = ''
|
||||
escape_hl_end = ''
|
||||
term_truecolor = False
|
||||
term_escape_style = 'auto'
|
||||
tmux_escape = False
|
||||
screen_escape = False
|
||||
|
||||
character_translations = Renderer.character_translations.copy()
|
||||
class PromptRenderer(Renderer):
|
||||
'''Powerline generic prompt segment renderer'''
|
||||
|
||||
def __init__(self, old_widths=None, **kwargs):
|
||||
super(ShellRenderer, self).__init__(**kwargs)
|
||||
super(PromptRenderer, self).__init__(**kwargs)
|
||||
self.old_widths = old_widths if old_widths is not None else {}
|
||||
|
||||
def render(self, segment_info, **kwargs):
|
||||
local_theme = segment_info.get('local_theme')
|
||||
return super(ShellRenderer, self).render(
|
||||
matcher_info=local_theme,
|
||||
segment_info=segment_info,
|
||||
**kwargs
|
||||
)
|
||||
def get_client_id(self, segment_info):
|
||||
'''Get client ID given segment info
|
||||
|
||||
This is used by daemon to correctly cache widths for different clients
|
||||
using a single renderer instance.
|
||||
|
||||
:param dict segment_info:
|
||||
:ref:`Segment info dictionary <dev-segments-info>`. Out of it only
|
||||
``client_id`` key is used. It is OK for this dictionary to not
|
||||
contain this key.
|
||||
|
||||
:return: Any hashable value or ``None``.
|
||||
'''
|
||||
return segment_info.get('client_id') if isinstance(segment_info, dict) else None
|
||||
|
||||
def do_render(self, output_width, segment_info, side, theme, width=None, **kwargs):
|
||||
if self.term_escape_style == 'auto':
|
||||
if segment_info['environ'].get('TERM') == 'fbterm':
|
||||
self.used_term_escape_style = 'fbterm'
|
||||
else:
|
||||
self.used_term_escape_style = 'xterm'
|
||||
else:
|
||||
self.used_term_escape_style = self.term_escape_style
|
||||
if isinstance(segment_info, dict):
|
||||
client_id = segment_info.get('client_id')
|
||||
else:
|
||||
client_id = None
|
||||
client_id = self.get_client_id(segment_info)
|
||||
if client_id is not None:
|
||||
local_key = (client_id, side, None if theme is self.theme else id(theme))
|
||||
key = (client_id, side, None)
|
||||
@ -70,7 +59,7 @@ class ShellRenderer(Renderer):
|
||||
width -= self.old_widths[(client_id, 'left', local_key[-1])]
|
||||
except KeyError:
|
||||
pass
|
||||
res = super(ShellRenderer, self).do_render(
|
||||
res = super(PromptRenderer, self).do_render(
|
||||
output_width=True,
|
||||
width=width,
|
||||
theme=theme,
|
||||
@ -86,6 +75,36 @@ class ShellRenderer(Renderer):
|
||||
else:
|
||||
return ret
|
||||
|
||||
|
||||
class ShellRenderer(PromptRenderer):
|
||||
'''Powerline shell segment renderer.'''
|
||||
escape_hl_start = ''
|
||||
escape_hl_end = ''
|
||||
term_truecolor = False
|
||||
term_escape_style = 'auto'
|
||||
tmux_escape = False
|
||||
screen_escape = False
|
||||
|
||||
character_translations = Renderer.character_translations.copy()
|
||||
|
||||
def render(self, segment_info, **kwargs):
|
||||
local_theme = segment_info.get('local_theme')
|
||||
return super(ShellRenderer, self).render(
|
||||
matcher_info=local_theme,
|
||||
segment_info=segment_info,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
def do_render(self, segment_info, **kwargs):
|
||||
if self.term_escape_style == 'auto':
|
||||
if segment_info['environ'].get('TERM') == 'fbterm':
|
||||
self.used_term_escape_style = 'fbterm'
|
||||
else:
|
||||
self.used_term_escape_style = 'xterm'
|
||||
else:
|
||||
self.used_term_escape_style = self.term_escape_style
|
||||
return super(ShellRenderer, self).do_render(segment_info=segment_info, **kwargs)
|
||||
|
||||
def hlstyle(self, fg=None, bg=None, attrs=None):
|
||||
'''Highlight a segment.
|
||||
|
||||
|
@ -56,3 +56,34 @@ branch = with_docstring(BranchSegment(),
|
||||
|
||||
Highlight groups used: ``branch_clean``, ``branch_dirty``, ``branch``.
|
||||
''')
|
||||
|
||||
|
||||
@requires_filesystem_watcher
|
||||
@requires_segment_info
|
||||
class StashSegment(Segment):
|
||||
divider_highlight_group = None
|
||||
|
||||
@staticmethod
|
||||
def get_directory(segment_info):
|
||||
return segment_info['getcwd']()
|
||||
|
||||
def __call__(self, pl, segment_info, create_watcher):
|
||||
name = self.get_directory(segment_info)
|
||||
if name:
|
||||
repo = guess(path=name, create_watcher=create_watcher)
|
||||
if repo is not None:
|
||||
stash = getattr(repo, 'stash', None)
|
||||
if stash:
|
||||
stashes = stash()
|
||||
if stashes:
|
||||
return [{
|
||||
'contents': str(stashes),
|
||||
'highlight_groups': ['stash'],
|
||||
'divider_highlight_group': self.divider_highlight_group
|
||||
}]
|
||||
|
||||
stash = with_docstring(StashSegment(),
|
||||
'''Return the number of current VCS stash entries, if any.
|
||||
|
||||
Highlight groups used: ``stash``.
|
||||
''')
|
||||
|
@ -115,19 +115,20 @@ class WeatherSegment(KwThreadedSegment):
|
||||
return self.location_urls[location_query]
|
||||
except KeyError:
|
||||
if location_query is None:
|
||||
location_data = json.loads(urllib_read('http://freegeoip.net/json/'))
|
||||
location_data = json.loads(urllib_read('http://geoip.nekudo.com/api/'))
|
||||
location = ','.join((
|
||||
location_data['city'],
|
||||
location_data['region_name'],
|
||||
location_data['country_code']
|
||||
location_data['country']['name'],
|
||||
location_data['country']['code']
|
||||
))
|
||||
self.info('Location returned by freegeoip is {0}', location)
|
||||
self.info('Location returned by nekudo is {0}', location)
|
||||
else:
|
||||
location = location_query
|
||||
query_data = {
|
||||
'q':
|
||||
'use "https://raw.githubusercontent.com/yql/yql-tables/master/weather/weather.bylocation.xml" as we;'
|
||||
'select * from we where location="{0}" and unit="c"'.format(location).encode('utf-8'),
|
||||
'select * from weather.forecast where woeid in'
|
||||
' (select woeid from geo.places(1) where text="{0}") and u="c"'.format(location).encode('utf-8'),
|
||||
'format': 'json',
|
||||
}
|
||||
self.location_urls[location_query] = url = (
|
||||
@ -143,7 +144,7 @@ class WeatherSegment(KwThreadedSegment):
|
||||
|
||||
response = json.loads(raw_response)
|
||||
try:
|
||||
condition = response['query']['results']['weather']['rss']['channel']['item']['condition']
|
||||
condition = response['query']['results']['channel']['item']['condition']
|
||||
condition_code = int(condition['code'])
|
||||
temp = float(condition['temp'])
|
||||
except (KeyError, ValueError):
|
||||
@ -203,7 +204,7 @@ class WeatherSegment(KwThreadedSegment):
|
||||
weather = with_docstring(WeatherSegment(),
|
||||
'''Return weather from Yahoo! Weather.
|
||||
|
||||
Uses GeoIP lookup from http://freegeoip.net/ to automatically determine
|
||||
Uses GeoIP lookup from http://geoip.nekudo.com to automatically determine
|
||||
your current location. This should be changed if you’re in a VPN or if your
|
||||
IP address is registered at another location.
|
||||
|
||||
|
@ -22,7 +22,7 @@ from powerline.lib import add_divider_highlight_group
|
||||
from powerline.lib.vcs import guess
|
||||
from powerline.lib.humanize_bytes import humanize_bytes
|
||||
from powerline.lib import wraps_saveargs as wraps
|
||||
from powerline.segments.common.vcs import BranchSegment
|
||||
from powerline.segments.common.vcs import BranchSegment, StashSegment
|
||||
from powerline.segments import with_docstring
|
||||
from powerline.lib.unicode import string, unicode
|
||||
|
||||
@ -510,6 +510,25 @@ Divider highlight group used: ``branch:divider``.
|
||||
''')
|
||||
|
||||
|
||||
@requires_filesystem_watcher
|
||||
@requires_segment_info
|
||||
class VimStashSegment(StashSegment):
|
||||
divider_highlight_group = 'stash:divider'
|
||||
|
||||
@staticmethod
|
||||
def get_directory(segment_info):
|
||||
if vim_getbufoption(segment_info, 'buftype'):
|
||||
return None
|
||||
return buffer_name(segment_info)
|
||||
|
||||
|
||||
stash = with_docstring(VimStashSegment(),
|
||||
'''Return the number of stashes in the current working branch.
|
||||
|
||||
Highlight groups used: ``stash``.
|
||||
''')
|
||||
|
||||
|
||||
@requires_filesystem_watcher
|
||||
@requires_segment_info
|
||||
def file_vcs_status(pl, segment_info, create_watcher):
|
||||
@ -559,7 +578,7 @@ def trailing_whitespace(pl, segment_info):
|
||||
else:
|
||||
buf = segment_info['buffer']
|
||||
bws = b' \t'
|
||||
sws = str(bws)
|
||||
sws = str(' \t') # Ignore unicode_literals and use native str.
|
||||
for i in range(len(buf)):
|
||||
try:
|
||||
line = buf[i]
|
||||
|
@ -231,7 +231,7 @@ def do_one(sock, read_sockets, write_sockets, result_map):
|
||||
|
||||
|
||||
def main_loop(sock):
|
||||
sock.listen(1)
|
||||
sock.listen(128)
|
||||
sock.setblocking(0)
|
||||
|
||||
read_sockets, write_sockets = set(), set()
|
||||
|
4
setup.py
4
setup.py
@ -59,7 +59,7 @@ else:
|
||||
|
||||
|
||||
def get_version():
|
||||
base_version = '2.4'
|
||||
base_version = '2.5'
|
||||
base_version += '.dev9999'
|
||||
try:
|
||||
return base_version + '+git.' + str(subprocess.check_output(['git', 'rev-parse', 'HEAD']).strip())
|
||||
@ -70,7 +70,7 @@ def get_version():
|
||||
|
||||
setup(
|
||||
name='powerline-status',
|
||||
version='2.4',
|
||||
version='2.5',
|
||||
description='The ultimate statusline/prompt utility.',
|
||||
long_description=README,
|
||||
classifiers=[
|
||||
|
@ -24,12 +24,19 @@ exit_suite() {
|
||||
}
|
||||
|
||||
fail() {
|
||||
local allow_failure=
|
||||
if test "x$1" = "x--allow-failure" ; then
|
||||
shift
|
||||
allow_failure=A
|
||||
fi
|
||||
local test_name="$1"
|
||||
local fail_char="$2"
|
||||
local fail_char="$allow_failure$2"
|
||||
local message="$3"
|
||||
local full_msg="$fail_char $POWERLINE_CURRENT_SUITE|$test_name :: $message"
|
||||
FAIL_SUMMARY="${FAIL_SUMMARY}${NL}${full_msg}"
|
||||
echo "Failed: $full_msg"
|
||||
echo "$full_msg" >> tests/failures
|
||||
if test "x$allow_failure" = "x" ; then
|
||||
FAILED=1
|
||||
fi
|
||||
}
|
||||
|
@ -44,13 +44,13 @@ def urllib_read(query_url):
|
||||
return '127.0.0.1'
|
||||
elif query_url.startswith('http://ipv4.icanhazip.com'):
|
||||
return '2001:4801:7818:6:abc5:ba2c:ff10:275f'
|
||||
elif query_url.startswith('http://freegeoip.net/json/'):
|
||||
return '{"city": "Meppen", "region_code": "06", "region_name": "Niedersachsen", "areacode": "", "ip": "82.145.55.16", "zipcode": "49716", "longitude": 7.3167, "country_name": "Germany", "country_code": "DE", "metrocode": "", "latitude": 52.6833}'
|
||||
elif query_url.startswith('http://geoip.nekudo.com/api/'):
|
||||
return '{"city":"Meppen","country":{"name":"Germany", "code":"DE"},"location":{"accuracy_radius":100,"latitude":52.6833,"longitude":7.3167,"time_zone":"Europe\/Berlin"},"ip":"82.145.55.16"}'
|
||||
elif query_url.startswith('http://query.yahooapis.com/v1/public/'):
|
||||
if 'Meppen' in query_url:
|
||||
return r'{"query":{"count":1,"created":"2013-03-02T13:20:22Z","lang":"en-US","results":{"weather":{"rss":{"version":"2.0","geo":"http://www.w3.org/2003/01/geo/wgs84_pos#","yweather":"http://xml.weather.yahoo.com/ns/rss/1.0","channel":{"title":"Yahoo! Weather - Russia, RU","link":"http://us.rd.yahoo.com/dailynews/rss/weather/Russia__RU/*http://weather.yahoo.com/forecast/RSXX1511_c.html","description":"Yahoo! Weather for Russia, RU","language":"en-us","lastBuildDate":"Sat, 02 Mar 2013 4:58 pm MSK","ttl":"60","location":{"city":"Russia","country":"Russia","region":""},"units":{"distance":"km","pressure":"mb","speed":"km/h","temperature":"C"},"wind":{"chill":"-9","direction":"0","speed":""},"atmosphere":{"humidity":"94","pressure":"1006.1","rising":"0","visibility":""},"astronomy":{"sunrise":"10:04 am","sunset":"7:57 pm"},"image":{"title":"Yahoo! Weather","width":"142","height":"18","link":"http://weather.yahoo.com","url":"http://l.yimg.com/a/i/brand/purplelogo//uh/us/news-wea.gif"},"item":{"title":"Conditions for Russia, RU at 4:58 pm MSK","lat":"59.45","long":"108.83","link":"http://us.rd.yahoo.com/dailynews/rss/weather/Russia__RU/*http://weather.yahoo.com/forecast/RSXX1511_c.html","pubDate":"Sat, 02 Mar 2013 4:58 pm MSK","condition":{"code":"30","date":"Sat, 02 Mar 2013 4:58 pm MSK","temp":"-9","text":"Partly Cloudy"},"description":"<img src=\"http://l.yimg.com/a/i/us/we/52/30.gif\"/><br />\n<b>Current Conditions:</b><br />\nPartly Cloudy, -9 C<BR />\n<BR /><b>Forecast:</b><BR />\nSat - Partly Cloudy. High: -9 Low: -19<br />\nSun - Partly Cloudy. High: -12 Low: -18<br />\n<br />\n<a href=\"http://us.rd.yahoo.com/dailynews/rss/weather/Russia__RU/*http://weather.yahoo.com/forecast/RSXX1511_c.html\">Full Forecast at Yahoo! Weather</a><BR/><BR/>\n(provided by <a href=\"http://www.weather.com\" >The Weather Channel</a>)<br/>","forecast":[{"code":"29","date":"2 Mar 2013","day":"Sat","high":"-9","low":"-19","text":"Partly Cloudy"},{"code":"30","date":"3 Mar 2013","day":"Sun","high":"-12","low":"-18","text":"Partly Cloudy"}],"guid":{"isPermaLink":"false","content":"RSXX1511_2013_03_03_7_00_MSK"}}}}}}}}'
|
||||
return r'{"query":{"count":1,"created":"2016-05-13T19:43:18Z","lang":"en-US","results":{"channel":{"units":{"distance":"mi","pressure":"in","speed":"mph","temperature":"C"},"title":"Yahoo! Weather - Meppen, NI, DE","link":"http://us.rd.yahoo.com/dailynews/rss/weather/Country__Country/*https://weather.yahoo.com/country/state/city-674836/","description":"Yahoo! Weather for Meppen, NI, DE","language":"en-us","lastBuildDate":"Fri, 13 May 2016 09:43 PM CEST","ttl":"60","location":{"city":"Meppen","country":"Germany","region":" NI"},"wind":{"chill":"55","direction":"350","speed":"25"},"atmosphere":{"humidity":"57","pressure":"1004.0","rising":"0","visibility":"16.1"},"astronomy":{"sunrise":"5:35 am","sunset":"9:21 pm"},"image":{"title":"Yahoo! Weather","width":"142","height":"18","link":"http://weather.yahoo.com","url":"http://l.yimg.com/a/i/brand/purplelogo//uh/us/news-wea.gif"},"item":{"title":"Conditions for Meppen, NI, DE at 08:00 PM CEST","lat":"52.68993","long":"7.29115","link":"http://us.rd.yahoo.com/dailynews/rss/weather/Country__Country/*https://weather.yahoo.com/country/state/city-674836/","pubDate":"Fri, 13 May 2016 08:00 PM CEST","condition":{"code":"23","date":"Fri, 13 May 2016 08:00 PM CEST","temp":"14","text":"Breezy"},"forecast":[{"code":"30","date":"13 May 2016","day":"Fri","high":"71","low":"48","text":"Partly Cloudy"},{"code":"28","date":"14 May 2016","day":"Sat","high":"54","low":"44","text":"Mostly Cloudy"},{"code":"11","date":"15 May 2016","day":"Sun","high":"55","low":"43","text":"Showers"},{"code":"28","date":"16 May 2016","day":"Mon","high":"54","low":"42","text":"Mostly Cloudy"},{"code":"28","date":"17 May 2016","day":"Tue","high":"57","low":"43","text":"Mostly Cloudy"},{"code":"12","date":"18 May 2016","day":"Wed","high":"62","low":"45","text":"Rain"},{"code":"28","date":"19 May 2016","day":"Thu","high":"63","low":"48","text":"Mostly Cloudy"},{"code":"28","date":"20 May 2016","day":"Fri","high":"67","low":"50","text":"Mostly Cloudy"},{"code":"30","date":"21 May 2016","day":"Sat","high":"71","low":"50","text":"Partly Cloudy"},{"code":"30","date":"22 May 2016","day":"Sun","high":"74","low":"54","text":"Partly Cloudy"}],"description":"<![CDATA[<img src=\"http://l.yimg.com/a/i/us/we/52/23.gif\"/>\n<BR />\n<b>Current Conditions:</b>\n<BR />Breezy\n<BR />\n<BR />\n<b>Forecast:</b>\n<BR /> Fri - Partly Cloudy. High: 71Low: 48\n<BR /> Sat - Mostly Cloudy. High: 54Low: 44\n<BR /> Sun - Showers. High: 55Low: 43\n<BR /> Mon - Mostly Cloudy. High: 54Low: 42\n<BR /> Tue - Mostly Cloudy. High: 57Low: 43\n<BR />\n<BR />\n<a href=\"http://us.rd.yahoo.com/dailynews/rss/weather/Country__Country/*https://weather.yahoo.com/country/state/city-674836/\">Full Forecast at Yahoo! Weather</a>\n<BR />\n<BR />\n(provided by <a href=\"http://www.weather.com\" >The Weather Channel</a>)\n<BR />\n]]>","guid":{"isPermaLink":"false"}}}}}}'
|
||||
elif 'Moscow' in query_url:
|
||||
return r'{"query":{"count":1,"created":"2013-03-02T13:20:22Z","lang":"en-US","results":{"weather":{"rss":{"version":"2.0","geo":"http://www.w3.org/2003/01/geo/wgs84_pos#","yweather":"http://xml.weather.yahoo.com/ns/rss/1.0","channel":{"title":"Yahoo! Weather - Russia, RU","link":"http://us.rd.yahoo.com/dailynews/rss/weather/Russia__RU/*http://weather.yahoo.com/forecast/RSXX1511_c.html","description":"Yahoo! Weather for Russia, RU","language":"en-us","lastBuildDate":"Sat, 02 Mar 2013 4:58 pm MSK","ttl":"60","location":{"city":"Russia","country":"Russia","region":""},"units":{"distance":"km","pressure":"mb","speed":"km/h","temperature":"C"},"wind":{"chill":"-9","direction":"0","speed":""},"atmosphere":{"humidity":"94","pressure":"1006.1","rising":"0","visibility":""},"astronomy":{"sunrise":"10:04 am","sunset":"7:57 pm"},"image":{"title":"Yahoo! Weather","width":"142","height":"18","link":"http://weather.yahoo.com","url":"http://l.yimg.com/a/i/brand/purplelogo//uh/us/news-wea.gif"},"item":{"title":"Conditions for Russia, RU at 4:58 pm MSK","lat":"59.45","long":"108.83","link":"http://us.rd.yahoo.com/dailynews/rss/weather/Russia__RU/*http://weather.yahoo.com/forecast/RSXX1511_c.html","pubDate":"Sat, 02 Mar 2013 4:58 pm MSK","condition":{"code":"30","date":"Sat, 02 Mar 2013 4:58 pm MSK","temp":"19","text":"Partly Cloudy"},"description":"<img src=\"http://l.yimg.com/a/i/us/we/52/30.gif\"/><br />\n<b>Current Conditions:</b><br />\nPartly Cloudy, -9 C<BR />\n<BR /><b>Forecast:</b><BR />\nSat - Partly Cloudy. High: -9 Low: -19<br />\nSun - Partly Cloudy. High: -12 Low: -18<br />\n<br />\n<a href=\"http://us.rd.yahoo.com/dailynews/rss/weather/Russia__RU/*http://weather.yahoo.com/forecast/RSXX1511_c.html\">Full Forecast at Yahoo! Weather</a><BR/><BR/>\n(provided by <a href=\"http://www.weather.com\" >The Weather Channel</a>)<br/>","forecast":[{"code":"29","date":"2 Mar 2013","day":"Sat","high":"-9","low":"-19","text":"Partly Cloudy"},{"code":"30","date":"3 Mar 2013","day":"Sun","high":"-12","low":"-18","text":"Partly Cloudy"}],"guid":{"isPermaLink":"false","content":"RSXX1511_2013_03_03_7_00_MSK"}}}}}}}}'
|
||||
return r'{"query":{"count":1,"created":"2016-05-13T19:47:01Z","lang":"en-US","results":{"channel":{"units":{"distance":"mi","pressure":"in","speed":"mph","temperature":"C"},"title":"Yahoo! Weather - Moscow, Moscow Federal City, RU","link":"http://us.rd.yahoo.com/dailynews/rss/weather/Country__Country/*https://weather.yahoo.com/country/state/city-2122265/","description":"Yahoo! Weather for Moscow, Moscow Federal City, RU","language":"en-us","lastBuildDate":"Fri, 13 May 2016 10:47 PM MSK","ttl":"60","location":{"city":"Moscow","country":"Russia","region":" Moscow Federal City"},"wind":{"chill":"45","direction":"80","speed":"11"},"atmosphere":{"humidity":"52","pressure":"993.0","rising":"0","visibility":"16.1"},"astronomy":{"sunrise":"4:19 am","sunset":"8:34 pm"},"image":{"title":"Yahoo! Weather","width":"142","height":"18","link":"http://weather.yahoo.com","url":"http://l.yimg.com/a/i/brand/purplelogo//uh/us/news-wea.gif"},"item":{"title":"Conditions for Moscow, Moscow Federal City, RU at 09:00 PM MSK","lat":"55.741638","long":"37.605061","link":"http://us.rd.yahoo.com/dailynews/rss/weather/Country__Country/*https://weather.yahoo.com/country/state/city-2122265/","pubDate":"Fri, 13 May 2016 09:00 PM MSK","condition":{"code":"33","date":"Fri, 13 May 2016 09:00 PM MSK","temp":"9","text":"Mostly Clear"},"forecast":[{"code":"30","date":"13 May 2016","day":"Fri","high":"62","low":"41","text":"Partly Cloudy"},{"code":"30","date":"14 May 2016","day":"Sat","high":"64","low":"43","text":"Partly Cloudy"},{"code":"30","date":"15 May 2016","day":"Sun","high":"63","low":"44","text":"Partly Cloudy"},{"code":"12","date":"16 May 2016","day":"Mon","high":"60","low":"47","text":"Rain"},{"code":"12","date":"17 May 2016","day":"Tue","high":"64","low":"48","text":"Rain"},{"code":"28","date":"18 May 2016","day":"Wed","high":"67","low":"48","text":"Mostly Cloudy"},{"code":"12","date":"19 May 2016","day":"Thu","high":"68","low":"49","text":"Rain"},{"code":"39","date":"20 May 2016","day":"Fri","high":"66","low":"50","text":"Scattered Showers"},{"code":"39","date":"21 May 2016","day":"Sat","high":"69","low":"49","text":"Scattered Showers"},{"code":"30","date":"22 May 2016","day":"Sun","high":"73","low":"50","text":"Partly Cloudy"}],"description":"<![CDATA[<img src=\"http://l.yimg.com/a/i/us/we/52/33.gif\"/>\n<BR />\n<b>Current Conditions:</b>\n<BR />Mostly Clear\n<BR />\n<BR />\n<b>Forecast:</b>\n<BR /> Fri - Partly Cloudy. High: 62Low: 41\n<BR /> Sat - Partly Cloudy. High: 64Low: 43\n<BR /> Sun - Partly Cloudy. High: 63Low: 44\n<BR /> Mon - Rain. High: 60Low: 47\n<BR /> Tue - Rain. High: 64Low: 48\n<BR />\n<BR />\n<a href=\"http://us.rd.yahoo.com/dailynews/rss/weather/Country__Country/*https://weather.yahoo.com/country/state/city-2122265/\">Full Forecast at Yahoo! Weather</a>\n<BR />\n<BR />\n(provided by <a href=\"http://www.weather.com\" >The Weather Channel</a>)\n<BR />\n]]>","guid":{"isPermaLink":"false"}}}}}}'
|
||||
else:
|
||||
raise NotImplementedError
|
||||
|
||||
|
@ -566,6 +566,32 @@ class TestVCS(TestCase):
|
||||
self.do_branch_rename_test(repo, lambda b: re.match(r'^[a-f0-9]+$', b))
|
||||
finally:
|
||||
call(['git', 'checkout', '-q', 'master'], cwd=GIT_REPO)
|
||||
# Test stashing
|
||||
self.assertEqual(repo.stash(), 0)
|
||||
|
||||
def stash_save():
|
||||
with open(os.path.join(GIT_REPO, 'file'), 'w') as f:
|
||||
f.write('abc')
|
||||
return call(['git', 'stash', '-u'], cwd=GIT_REPO, stdout=PIPE)
|
||||
|
||||
def stash_drop():
|
||||
return call(['git', 'stash', 'drop'], cwd=GIT_REPO, stdout=PIPE)
|
||||
|
||||
def stash_list():
|
||||
return call(['git', 'stash', 'list'], cwd=GIT_REPO, stdout=PIPE)
|
||||
|
||||
try:
|
||||
stash_save()
|
||||
self.assertEqual(repo.stash(), 1)
|
||||
stash_save()
|
||||
self.assertEqual(repo.stash(), 2)
|
||||
stash_drop()
|
||||
self.assertEqual(repo.stash(), 1)
|
||||
stash_drop()
|
||||
self.assertEqual(repo.stash(), 0)
|
||||
finally:
|
||||
while stash_list():
|
||||
stash_drop()
|
||||
|
||||
def test_git_sym(self):
|
||||
create_watcher = get_fallback_create_watcher()
|
||||
|
@ -154,11 +154,11 @@ class TestConfig(TestCase):
|
||||
|
||||
segment_info = Args(prompt_count=1)
|
||||
|
||||
with IpyPowerline(logger=get_logger()) as powerline:
|
||||
with IpyPowerline(logger=get_logger(), renderer_module='.pre_5') as powerline:
|
||||
for prompt_type in ['in', 'in2']:
|
||||
powerline.render(is_prompt=True, matcher_info=prompt_type, segment_info=segment_info)
|
||||
powerline.render(is_prompt=True, matcher_info=prompt_type, segment_info=segment_info)
|
||||
with IpyPowerline(logger=get_logger()) as powerline:
|
||||
with IpyPowerline(logger=get_logger(), renderer_module='.pre_5') as powerline:
|
||||
for prompt_type in ['out', 'rewrite']:
|
||||
powerline.render(is_prompt=False, matcher_info=prompt_type, segment_info=segment_info)
|
||||
powerline.render(is_prompt=False, matcher_info=prompt_type, segment_info=segment_info)
|
||||
|
@ -738,6 +738,29 @@ class TestVcs(TestCommon):
|
||||
'divider_highlight_group': None
|
||||
}])
|
||||
|
||||
def test_stash(self):
|
||||
pl = Pl()
|
||||
create_watcher = get_fallback_create_watcher()
|
||||
stash = partial(self.module.stash, pl=pl, create_watcher=create_watcher, segment_info={'getcwd': os.getcwd})
|
||||
|
||||
def forge_stash(n):
|
||||
return replace_attr(self.module, 'guess', get_dummy_guess(stash=lambda: n, directory='/tmp/tests'))
|
||||
|
||||
with forge_stash(0):
|
||||
self.assertEqual(stash(), None)
|
||||
with forge_stash(1):
|
||||
self.assertEqual(stash(), [{
|
||||
'highlight_groups': ['stash'],
|
||||
'contents': '1',
|
||||
'divider_highlight_group': None
|
||||
}])
|
||||
with forge_stash(2):
|
||||
self.assertEqual(stash(), [{
|
||||
'highlight_groups': ['stash'],
|
||||
'contents': '2',
|
||||
'divider_highlight_group': None
|
||||
}])
|
||||
|
||||
|
||||
class TestTime(TestCommon):
|
||||
module_name = 'time'
|
||||
@ -844,46 +867,46 @@ class TestWthr(TestCommon):
|
||||
pl = Pl()
|
||||
with replace_attr(self.module, 'urllib_read', urllib_read):
|
||||
self.assertEqual(self.module.weather(pl=pl), [
|
||||
{'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_condition_partly_cloudy_day', 'weather_condition_cloudy', 'weather_conditions', 'weather'], 'contents': 'CLOUDS '},
|
||||
{'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_temp_gradient', 'weather_temp', 'weather'], 'contents': '-9°C', 'gradient_level': 30.0}
|
||||
{'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_condition_blustery', 'weather_condition_windy', 'weather_conditions', 'weather'], 'contents': 'WINDY '},
|
||||
{'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_temp_gradient', 'weather_temp', 'weather'], 'contents': '14°C', 'gradient_level': 62.857142857142854}
|
||||
])
|
||||
self.assertEqual(self.module.weather(pl=pl, temp_coldest=0, temp_hottest=100), [
|
||||
{'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_condition_partly_cloudy_day', 'weather_condition_cloudy', 'weather_conditions', 'weather'], 'contents': 'CLOUDS '},
|
||||
{'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_temp_gradient', 'weather_temp', 'weather'], 'contents': '-9°C', 'gradient_level': 0}
|
||||
{'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_condition_blustery', 'weather_condition_windy', 'weather_conditions', 'weather'], 'contents': 'WINDY '},
|
||||
{'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_temp_gradient', 'weather_temp', 'weather'], 'contents': '14°C', 'gradient_level': 14.0}
|
||||
])
|
||||
self.assertEqual(self.module.weather(pl=pl, temp_coldest=-100, temp_hottest=-50), [
|
||||
{'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_condition_partly_cloudy_day', 'weather_condition_cloudy', 'weather_conditions', 'weather'], 'contents': 'CLOUDS '},
|
||||
{'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_temp_gradient', 'weather_temp', 'weather'], 'contents': '-9°C', 'gradient_level': 100}
|
||||
{'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_condition_blustery', 'weather_condition_windy', 'weather_conditions', 'weather'], 'contents': 'WINDY '},
|
||||
{'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_temp_gradient', 'weather_temp', 'weather'], 'contents': '14°C', 'gradient_level': 100}
|
||||
])
|
||||
self.assertEqual(self.module.weather(pl=pl, icons={'cloudy': 'o'}), [
|
||||
{'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_condition_partly_cloudy_day', 'weather_condition_cloudy', 'weather_conditions', 'weather'], 'contents': 'o '},
|
||||
{'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_temp_gradient', 'weather_temp', 'weather'], 'contents': '-9°C', 'gradient_level': 30.0}
|
||||
self.assertEqual(self.module.weather(pl=pl, icons={'blustery': 'o'}), [
|
||||
{'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_condition_blustery', 'weather_condition_windy', 'weather_conditions', 'weather'], 'contents': 'o '},
|
||||
{'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_temp_gradient', 'weather_temp', 'weather'], 'contents': '14°C', 'gradient_level': 62.857142857142854}
|
||||
])
|
||||
self.assertEqual(self.module.weather(pl=pl, icons={'partly_cloudy_day': 'x'}), [
|
||||
{'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_condition_partly_cloudy_day', 'weather_condition_cloudy', 'weather_conditions', 'weather'], 'contents': 'x '},
|
||||
{'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_temp_gradient', 'weather_temp', 'weather'], 'contents': '-9°C', 'gradient_level': 30.0}
|
||||
self.assertEqual(self.module.weather(pl=pl, icons={'windy': 'x'}), [
|
||||
{'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_condition_blustery', 'weather_condition_windy', 'weather_conditions', 'weather'], 'contents': 'x '},
|
||||
{'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_temp_gradient', 'weather_temp', 'weather'], 'contents': '14°C', 'gradient_level': 62.857142857142854}
|
||||
])
|
||||
self.assertEqual(self.module.weather(pl=pl, unit='F'), [
|
||||
{'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_condition_partly_cloudy_day', 'weather_condition_cloudy', 'weather_conditions', 'weather'], 'contents': 'CLOUDS '},
|
||||
{'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_temp_gradient', 'weather_temp', 'weather'], 'contents': '16°F', 'gradient_level': 30.0}
|
||||
{'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_condition_blustery', 'weather_condition_windy', 'weather_conditions', 'weather'], 'contents': 'WINDY '},
|
||||
{'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_temp_gradient', 'weather_temp', 'weather'], 'contents': '57°F', 'gradient_level': 62.857142857142854}
|
||||
])
|
||||
self.assertEqual(self.module.weather(pl=pl, unit='K'), [
|
||||
{'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_condition_partly_cloudy_day', 'weather_condition_cloudy', 'weather_conditions', 'weather'], 'contents': 'CLOUDS '},
|
||||
{'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_temp_gradient', 'weather_temp', 'weather'], 'contents': '264K', 'gradient_level': 30.0}
|
||||
{'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_condition_blustery', 'weather_condition_windy', 'weather_conditions', 'weather'], 'contents': 'WINDY '},
|
||||
{'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_temp_gradient', 'weather_temp', 'weather'], 'contents': '287K', 'gradient_level': 62.857142857142854}
|
||||
])
|
||||
self.assertEqual(self.module.weather(pl=pl, temp_format='{temp:.1e}C'), [
|
||||
{'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_condition_partly_cloudy_day', 'weather_condition_cloudy', 'weather_conditions', 'weather'], 'contents': 'CLOUDS '},
|
||||
{'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_temp_gradient', 'weather_temp', 'weather'], 'contents': '-9.0e+00C', 'gradient_level': 30.0}
|
||||
{'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_condition_blustery', 'weather_condition_windy', 'weather_conditions', 'weather'], 'contents': 'WINDY '},
|
||||
{'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_temp_gradient', 'weather_temp', 'weather'], 'contents': '1.4e+01C', 'gradient_level': 62.857142857142854}
|
||||
])
|
||||
with replace_attr(self.module, 'urllib_read', urllib_read):
|
||||
self.module.weather.startup(pl=pl, location_query='Meppen,06,DE')
|
||||
self.assertEqual(self.module.weather(pl=pl), [
|
||||
{'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_condition_partly_cloudy_day', 'weather_condition_cloudy', 'weather_conditions', 'weather'], 'contents': 'CLOUDS '},
|
||||
{'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_temp_gradient', 'weather_temp', 'weather'], 'contents': '-9°C', 'gradient_level': 30.0}
|
||||
{'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_condition_blustery', 'weather_condition_windy', 'weather_conditions', 'weather'], 'contents': 'WINDY '},
|
||||
{'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_temp_gradient', 'weather_temp', 'weather'], 'contents': '14°C', 'gradient_level': 62.857142857142854}
|
||||
])
|
||||
self.assertEqual(self.module.weather(pl=pl, location_query='Moscow,RU'), [
|
||||
{'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_condition_partly_cloudy_day', 'weather_condition_cloudy', 'weather_conditions', 'weather'], 'contents': 'CLOUDS '},
|
||||
{'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_temp_gradient', 'weather_temp', 'weather'], 'contents': '19°C', 'gradient_level': 70.0}
|
||||
{'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_condition_fair_night', 'weather_condition_night', 'weather_conditions', 'weather'], 'contents': 'NIGHT '},
|
||||
{'divider_highlight_group': 'background:divider', 'highlight_groups': ['weather_temp_gradient', 'weather_temp', 'weather'], 'contents': '9°C', 'gradient_level': 55.714285714285715}
|
||||
])
|
||||
self.module.weather.shutdown()
|
||||
|
||||
@ -1390,6 +1413,30 @@ class TestVim(TestCase):
|
||||
{'divider_highlight_group': 'branch:divider', 'highlight_groups': ['branch_clean', 'branch'], 'contents': 'foo'}
|
||||
])
|
||||
|
||||
def test_stash(self):
|
||||
pl = Pl()
|
||||
create_watcher = get_fallback_create_watcher()
|
||||
with vim_module._with('buffer', '/foo') as segment_info:
|
||||
stash = partial(self.vim.stash, pl=pl, create_watcher=create_watcher, segment_info=segment_info)
|
||||
|
||||
def forge_stash(n):
|
||||
return replace_attr(self.vcs, 'guess', get_dummy_guess(stash=lambda: n))
|
||||
|
||||
with forge_stash(0):
|
||||
self.assertEqual(stash(), None)
|
||||
with forge_stash(1):
|
||||
self.assertEqual(stash(), [{
|
||||
'divider_highlight_group': 'stash:divider',
|
||||
'highlight_groups': ['stash'],
|
||||
'contents': '1'
|
||||
}])
|
||||
with forge_stash(2):
|
||||
self.assertEqual(stash(), [{
|
||||
'divider_highlight_group': 'stash:divider',
|
||||
'highlight_groups': ['stash'],
|
||||
'contents': '2'
|
||||
}])
|
||||
|
||||
def test_file_vcs_status(self):
|
||||
pl = Pl()
|
||||
create_watcher = get_fallback_create_watcher()
|
||||
|
@ -88,6 +88,10 @@ do_run_test() {
|
||||
|| test "$PYTHON_IMPLEMENTATION" = "PyPy" \
|
||||
) \
|
||||
) \
|
||||
|| ( \
|
||||
test "x${SH}" = "xipython" \
|
||||
&& test "$("${PYTHON}" -mIPython --version | head -n1 | cut -d. -f1)" -ge 5 \
|
||||
) \
|
||||
) ; then
|
||||
wait_for_echo_arg="--wait-for-echo"
|
||||
fi
|
||||
@ -363,13 +367,6 @@ if test -z "${ONLY_SHELL}" || test "x${ONLY_SHELL%sh}" != "x${ONLY_SHELL}" || te
|
||||
fi
|
||||
fi
|
||||
SH="${TEST_COMMAND%% *}"
|
||||
# dash tests are not stable, see #931
|
||||
if test x$FAST$SH = x1dash ; then
|
||||
continue
|
||||
fi
|
||||
if test x$FAST$SH = x1fish ; then
|
||||
continue
|
||||
fi
|
||||
if test "x$ONLY_SHELL" != "x" && test "x$ONLY_SHELL" != "x$SH" ; then
|
||||
continue
|
||||
fi
|
||||
@ -378,7 +375,13 @@ if test -z "${ONLY_SHELL}" || test "x${ONLY_SHELL%sh}" != "x${ONLY_SHELL}" || te
|
||||
fi
|
||||
echo ">>> $(readlink "tests/shell/path/$SH")"
|
||||
if ! run_test $TEST_TYPE $TEST_CLIENT $TEST_COMMAND ; then
|
||||
fail "$SH-$TEST_TYPE-$TEST_CLIENT:test" F "Failed checking $TEST_COMMAND"
|
||||
ALLOW_FAILURE_ARG=
|
||||
# dash tests are not stable, see #931
|
||||
# also do not allow fish tests to spoil the build
|
||||
if test x$FAST$SH = x1dash || test x$FAST$SH = x1fish ; then
|
||||
ALLOW_FAILURE_ARG="--allow-failure"
|
||||
fi
|
||||
fail $ALLOW_FAILURE_ARG "$SH-$TEST_TYPE-$TEST_CLIENT:test" F "Failed checking $TEST_COMMAND"
|
||||
fi
|
||||
done
|
||||
done
|
||||
@ -448,7 +451,8 @@ if test "x${ONLY_SHELL}" = "x" || test "x${ONLY_SHELL}" = "xipython" ; then
|
||||
export POWERLINE_THEME_OVERRIDES='in.segments.left=[]'
|
||||
echo "> ipython"
|
||||
if ! run_test ipython ipython ${IPYTHON_PYTHON} -mIPython ; then
|
||||
fail "ipython:test" F "Failed checking ${IPYTHON_PYTHON} -mIPython"
|
||||
# Do not allow ipython tests to spoil the build
|
||||
fail --allow-failure "ipython:test" F "Failed checking ${IPYTHON_PYTHON} -mIPython"
|
||||
fi
|
||||
unset POWERLINE_THEME_OVERRIDES
|
||||
unset POWERLINE_CONFIG_OVERRIDES
|
||||
|
Loading…
x
Reference in New Issue
Block a user