Merge pull request #1775 from ZyX-I/bash-pipestatus

Add support for pipestatus in bash
This commit is contained in:
Nikolai Aleksandrovich Pavlov 2017-05-16 20:07:58 +03:00 committed by GitHub
commit b5fe29eff5
10 changed files with 128 additions and 21 deletions

View File

@ -143,6 +143,40 @@ started from.*
Shell issues
============
Pipe status segment displays only last value in bash
----------------------------------------------------
Make sure that powerline command that sets prompt appears the very first in
``$PROMPT_COMMAND``. To do this ``powerline.sh`` needs to be sourced the very
last, after all other users of ``$PROMPT_COMMAND``.
Bash prompt stopped updating
----------------------------
Make sure that powerline commands appear in ``$PROMPT_COMMAND``: some users of
``$PROMPT_COMMAND`` have a habit of overwriting the value instead of
prepending/appending to it. All powerline commands start with ``_powerline`` or
``powerline``, e.g. ``_powerline_set_prompt``.
Bash prompt does not show last exit code
----------------------------------------
There are two possibilities here:
* You are using ``default`` theme in place of ``default_leftonly``. Unlike
``default_leftonly`` ``default`` theme was designed for shells with right
prompt support (e.g. zsh, tcsh, fish) and status in question is supposed to be
shown on the right side which bash cannot display.
* There is some other user of ``$PROMPT_COMMAND`` which prepended to this
variable, but did not bother keeping the exit code. For the best experience
powerline must appear first in ``$PROMPT_COMMAND`` which may be achieved by
sourcing powerline bindings the last.
.. note::
Resourcing bash bindings will not resolve the problem unless you clear
powerline commands from ``$PROMPT_COMMAND`` first.
When sourcing shell bindings it complains about missing command or file
-----------------------------------------------------------------------

View File

@ -27,6 +27,31 @@ _powerline_tmux_set_pwd() {
fi
}
_powerline_return() {
return $1
}
_powerline_status_wrapper() {
local last_exit_code=$? last_pipe_status=( "${PIPESTATUS[@]}" )
if test "$last_exit_code" != "${last_pipe_status[-1]}" ; then
last_pipe_status=()
fi
"$@" $last_exit_code "${last_pipe_status[*]}"
return $last_exit_code
}
_powerline_add_status_wrapped_command() {
local action="$1" ; shift
local cmd="$1" ; shift
full_cmd="_powerline_status_wrapper $cmd"
if test "$action" = "append" ; then
PROMPT_COMMAND="$PROMPT_COMMAND"$'\n'"$full_cmd"
else
PROMPT_COMMAND="$full_cmd"$'\n'"$PROMPT_COMMAND"
fi
}
_powerline_tmux_set_columns() {
_powerline_tmux_setenv COLUMNS "${COLUMNS:-`_powerline_columns_fallback`}"
}
@ -40,41 +65,53 @@ _powerline_init_tmux_support() {
_powerline_tmux_set_columns
test "$PROMPT_COMMAND" != "${PROMPT_COMMAND/_powerline_tmux_set_pwd}" \
|| PROMPT_COMMAND="${PROMPT_COMMAND}"$'\n_powerline_tmux_set_pwd'
|| _powerline_add_status_wrapped_command append _powerline_tmux_set_pwd
fi
}
_powerline_local_prompt() {
# Arguments: side, renderer_module arg, last_exit_code, jobnum, local theme
# Arguments:
# 1: side
# 2: renderer_module arg
# 3: last_exit_code
# 4: last_pipe_status
# 5: jobnum
# 6: local theme
"$POWERLINE_COMMAND" $POWERLINE_COMMAND_ARGS shell $1 \
$2 \
--last-exit-code=$3 \
--jobnum=$4 \
--last-pipe-status="$4" \
--jobnum=$5 \
--renderer-arg="client_id=$$" \
--renderer-arg="local_theme=$5"
--renderer-arg="local_theme=$6"
}
_powerline_prompt() {
# Arguments: side, last_exit_code, jobnum
# Arguments:
# 1: side
# 2: last_exit_code
# 3: last_pipe_status
# 4: jobnum
"$POWERLINE_COMMAND" $POWERLINE_COMMAND_ARGS shell $1 \
--width="${COLUMNS:-$(_powerline_columns_fallback)}" \
-r.bash \
--last-exit-code=$2 \
--jobnum=$3 \
--last-pipe-status="$3" \
--jobnum=$4 \
--renderer-arg="client_id=$$"
}
_powerline_set_prompt() {
local last_exit_code=$?
local last_exit_code=$1 ; shift
local last_pipe_status=$1 ; shift
local jobnum="$(jobs -p|wc -l)"
PS1="$(_powerline_prompt aboveleft $last_exit_code $jobnum)"
PS1="$(_powerline_prompt aboveleft $last_exit_code "$last_pipe_status" $jobnum)"
if test -n "$POWERLINE_SHELL_CONTINUATION$POWERLINE_BASH_CONTINUATION" ; then
PS2="$(_powerline_local_prompt left -r.bash $last_exit_code $jobnum continuation)"
PS2="$(_powerline_local_prompt left -r.bash $last_exit_code "$last_pipe_status" $jobnum continuation)"
fi
if test -n "$POWERLINE_SHELL_SELECT$POWERLINE_BASH_SELECT" ; then
PS3="$(_powerline_local_prompt left '' $last_exit_code $jobnum select)"
PS3="$(_powerline_local_prompt left '' $last_exit_code "$last_pipe_status" $jobnum select)"
fi
return $last_exit_code
}
_powerline_setup_prompt() {
@ -83,9 +120,9 @@ _powerline_setup_prompt() {
POWERLINE_COMMAND="$("$POWERLINE_CONFIG_COMMAND" shell command)"
fi
test "$PROMPT_COMMAND" != "${PROMPT_COMMAND%_powerline_set_prompt*}" \
|| PROMPT_COMMAND=$'_powerline_set_prompt\n'"${PROMPT_COMMAND}"
PS2="$(_powerline_local_prompt left -r.bash 0 0 continuation)"
PS3="$(_powerline_local_prompt left '' 0 0 select)"
|| _powerline_add_status_wrapped_command prepend _powerline_set_prompt
PS2="$(_powerline_local_prompt left -r.bash 0 0 0 continuation)"
PS3="$(_powerline_local_prompt left '' 0 0 0 select)"
}
if test -z "${POWERLINE_CONFIG_COMMAND}" ; then

View File

@ -26,7 +26,7 @@
"priority": 20
},
{
"function": "powerline.segments.shell.last_status",
"function": "powerline.segments.shell.last_pipe_status",
"priority": 10
}
]

View File

@ -39,7 +39,10 @@ def last_pipe_status(pl, segment_info):
Highlight groups used: ``exit_fail``, ``exit_success``
'''
last_pipe_status = segment_info['args'].last_pipe_status
last_pipe_status = (
segment_info['args'].last_pipe_status
or (segment_info['args'].last_exit_code,)
)
if any(last_pipe_status):
return [
{

View File

@ -125,6 +125,11 @@ class TestParser(TestCase):
'side': 'left',
'config_override': {'common': {}},
}),
(['shell', 'left', '--last-pipe-status='], {
'ext': ['shell'],
'side': 'left',
'last_pipe_status': [],
}),
]:
args = parser.parse_args(argv)
finish_args(parser, {}, args)

View File

@ -138,7 +138,7 @@ class TestConfig(TestCase):
def test_bash(self):
from powerline.shell import ShellPowerline
args = Args(last_exit_code=1, jobnum=0, ext=['shell'], renderer_module='.bash', config_override={'ext': {'shell': {'theme': 'default_leftonly'}}})
args = Args(last_exit_code=1, last_pipe_status=[], jobnum=0, ext=['shell'], renderer_module='.bash', config_override={'ext': {'shell': {'theme': 'default_leftonly'}}})
with ShellPowerline(args, logger=get_logger(), run_once=False) as powerline:
powerline.render(segment_info={'args': args})
with ShellPowerline(args, logger=get_logger(), run_once=False) as powerline:

View File

@ -52,15 +52,35 @@ class TestShell(TestCase):
def test_last_pipe_status(self):
pl = Pl()
segment_info = {'args': Args(last_pipe_status=[])}
segment_info = {'args': Args(last_pipe_status=[], last_exit_code=0)}
self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), None)
segment_info['args'].last_pipe_status = [0, 0, 0]
self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), None)
segment_info['args'].last_pipe_status = [0, 0]
self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), None)
segment_info['args'].last_pipe_status = [0]
self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), None)
segment_info['args'].last_pipe_status = [0, 2, 0]
self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), [
{'contents': '0', 'highlight_groups': ['exit_success'], 'draw_inner_divider': True},
{'contents': '2', 'highlight_groups': ['exit_fail'], 'draw_inner_divider': True},
{'contents': '0', 'highlight_groups': ['exit_success'], 'draw_inner_divider': True}
{'contents': '0', 'highlight_groups': ['exit_success'], 'draw_inner_divider': True},
])
segment_info['args'].last_pipe_status = [2, 0, 0]
self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), [
{'contents': '2', 'highlight_groups': ['exit_fail'], 'draw_inner_divider': True},
{'contents': '0', 'highlight_groups': ['exit_success'], 'draw_inner_divider': True},
{'contents': '0', 'highlight_groups': ['exit_success'], 'draw_inner_divider': True},
])
segment_info['args'].last_pipe_status = [0, 0, 2]
self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), [
{'contents': '0', 'highlight_groups': ['exit_success'], 'draw_inner_divider': True},
{'contents': '0', 'highlight_groups': ['exit_success'], 'draw_inner_divider': True},
{'contents': '2', 'highlight_groups': ['exit_fail'], 'draw_inner_divider': True},
])
segment_info['args'].last_pipe_status = [2]
self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), [
{'contents': '2', 'highlight_groups': ['exit_fail'], 'draw_inner_divider': True},
])
segment_info['args'].last_pipe_status = [0, 'sigsegv', 'sigsegv+core']
self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), [
@ -80,6 +100,11 @@ class TestShell(TestCase):
{'contents': 'sigsegv+core', 'highlight_groups': ['exit_fail'], 'draw_inner_divider': True},
{'contents': '0', 'highlight_groups': ['exit_success'], 'draw_inner_divider': True}
])
segment_info['args'].last_pipe_status = []
segment_info['args'].last_exit_code = 5
self.assertEqual(shell.last_pipe_status(pl=pl, segment_info=segment_info), [
{'contents': '5', 'highlight_groups': ['exit_fail'], 'draw_inner_divider': True},
])
def test_jobnum(self):
pl = Pl()

View File

@ -55,6 +55,7 @@ cd ../'(echo)'
cd ../'$(echo)'
cd ../'`echo`'
cd ../'«Unicode!»'
(exit 42)|(exit 43)
set_theme_option default_leftonly.segments.above "$ABOVE_LEFT"
export DISPLAYED_ENV_VAR=foo
unset DISPLAYED_ENV_VAR

View File

@ -26,7 +26,8 @@ def
  BRANCH  …  shell  3rd  (echo)  cd ../'$(echo)'
  BRANCH  …  shell  3rd  $(echo)  cd ../'`echo`'
  BRANCH  …  shell  3rd  `echo`  cd ../'«Unicode!»'
  BRANCH  …  shell  3rd  «Unicode!»  set_theme_option default_leftonly.segments.above "$ABOVE_LEFT"
  BRANCH  …  shell  3rd  «Unicode!»  (exit 42)|(exit 43)
  BRANCH  …  shell  3rd  «Unicode!»  42  43  set_theme_option default_leftonly.segments.above "$ABOVE_LEFT"
  BRANCH  …  shell  3rd  «Unicode!»  export DISPLAYED_ENV_VAR=foo
 foo  
  BRANCH  …  shell  3rd  «Unicode!»  unset DISPLAYED_ENV_VAR

View File

@ -26,7 +26,8 @@ def
  BRANCH  …  shell  3rd  (echo)  cd ../'$(echo)'
  BRANCH  …  shell  3rd  $(echo)  cd ../'`echo`'
  BRANCH  …  shell  3rd  `echo`  cd ../'«Unicode!»'
  BRANCH  …  shell  3rd  «Unicode!»  set_theme_option default_leftonly.segments.above "$ABOVE_LEFT"
  BRANCH  …  shell  3rd  «Unicode!»  (exit 42)|(exit 43)
  BRANCH  …  shell  3rd  «Unicode!»  42  43  set_theme_option default_leftonly.segments.above "$ABOVE_LEFT"
  BRANCH  …  shell  3rd  «Unicode!»  export DISPLAYED_ENV_VAR=foo
 foo  
  BRANCH  …  shell  3rd  «Unicode!»  unset DISPLAYED_ENV_VAR