summaryrefslogtreecommitdiffstats
path: root/powerline/segments/shell.py
blob: 66991c7f99978476cfb363fd3e18ed2020da2732 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# vim:fileencoding=utf-8:noet
from __future__ import (unicode_literals, division, absolute_import, print_function)

from powerline.theme import requires_segment_info
from powerline.segments import with_docstring
from powerline.segments.common.env import CwdSegment
from powerline.lib.unicode import out_u


@requires_segment_info
def jobnum(pl, segment_info, show_zero=False):
	'''Return the number of jobs.

	:param bool show_zero:
		If False (default) shows nothing if there are no jobs. Otherwise shows
		zero for no jobs.
	'''
	jobnum = segment_info['args'].jobnum
	if jobnum is None or (not show_zero and jobnum == 0):
		return None
	else:
		return str(jobnum)

try:
	import signal
	exit_codes = dict((k, v) for v, k in reversed(sorted(signal.__dict__.items())) \
		if v.startswith('SIG') and not v.startswith('SIG_'))
except ImportError:
	exit_codes = dict()

@requires_segment_info
def last_status(pl, segment_info, signal_names=True):
	'''Return last exit code.

	:param bool signal_names:
		If True (default), translate signal numbers to human-readable names.

	Highlight groups used: ``exit_fail``
	'''
	if not segment_info['args'].last_exit_code:
		return None

	try:
		if signal_names and segment_info['args'].last_exit_code - 128 in exit_codes:
			return [{'contents': exit_codes[segment_info['args'].last_exit_code - 128], 'highlight_groups': ['exit_fail']}]
	except TypeError:
		pass
	return [{'contents': str(segment_info['args'].last_exit_code), 'highlight_groups': ['exit_fail']}]


@requires_segment_info
def last_pipe_status(pl, segment_info, signal_names=True):
	'''Return last pipe status.

	:param bool signal_names:
		If True (default), translate signal numbers to human-readable names.

	Highlight groups used: ``exit_fail``, ``exit_success``
	'''
	last_pipe_status = (
		segment_info['args'].last_pipe_status
		or (segment_info['args'].last_exit_code,)
	)
	if any(last_pipe_status):
		try:
			return [{
				'contents': exit_codes[status - 128] if signal_names and \
					status - 128 in exit_codes else str(status),
				'highlight_groups': ['exit_fail' if status else 'exit_success'],
				'draw_inner_divider': True
			} for status in last_pipe_status]
		except TypeError:
			return [{
				'contents': str(status),
				'highlight_groups': ['exit_fail' if status else 'exit_success'],
				'draw_inner_divider': True
			} for status in last_pipe_status]
	else:
		return None

@requires_segment_info
def mode(pl, segment_info, override={'vicmd': 'COMMND', 'viins': 'INSERT'}, default=None):
	'''Return the current mode.

	:param dict override:
		dict for overriding mode strings.
	:param str default:
		If current mode is equal to this string then this segment will not get
		displayed. If not specified the value is taken from
		``$POWERLINE_DEFAULT_MODE`` variable. This variable is set by zsh
		bindings for any mode that does not start from ``vi``.
	'''
	mode = segment_info.get('mode', None)
	if not mode:
		pl.debug('No mode specified')
		return None
	default = default or segment_info.get('default_mode', None)
	if mode == default:
		return None
	try:
		return override[mode]
	except KeyError:
		# Note: with zsh line editor you can emulate as much modes as you wish.
		# Thus having unknown mode is not an error: maybe just some developer
		# added support for his own zle widgets. As there is no built-in mode()
		# function like in VimL and mode is likely be defined by our code or by
		# somebody knowing what he is doing there is absolutely no need in
		# keeping translations dictionary.
		return mode.upper()


@requires_segment_info
def continuation(pl, segment_info, omit_cmdsubst=True, right_align=False, renames={}):
	'''Display parser state.

	:param bool omit_cmdsubst:
		Do not display cmdsubst parser state if it is the last one.
	:param bool right_align:
		Align to the right.
	:param dict renames:
		Rename states: ``{old_name : new_name}``. If ``new_name`` is ``None``
		then given state is not displayed.

	Highlight groups used: ``continuation``, ``continuation:current``.
	'''
	if not segment_info.get('parser_state'):
		return [{
			'contents': '',
			'width': 'auto',
			'highlight_groups': ['continuation:current', 'continuation'],
		}]
	ret = []

	for state in segment_info['parser_state'].split():
		state = renames.get(state, state)
		if state:
			ret.append({
				'contents': state,
				'highlight_groups': ['continuation'],
				'draw_inner_divider': True,
			})

	if omit_cmdsubst and ret[-1]['contents'] == 'cmdsubst':
		ret.pop(-1)

	if not ret:
		ret.append({
			'contents': ''
		})

	if right_align:
		ret[0].update(width='auto', align='r')
		ret[-1]['highlight_groups'] = ['continuation:current', 'continuation']
	else:
		ret[-1].update(width='auto', align='l', highlight_groups=['continuation:current', 'continuation'])

	return ret


@requires_segment_info
class ShellCwdSegment(CwdSegment):
	def get_shortened_path(self, pl, segment_info, use_shortened_path=True, **kwargs):
		if use_shortened_path:
			try:
				return out_u(segment_info['shortened_path'])
			except KeyError:
				pass
		return super(ShellCwdSegment, self).get_shortened_path(pl, segment_info, **kwargs)


cwd = with_docstring(ShellCwdSegment(),
'''Return the current working directory.

Returns a segment list to create a breadcrumb-like effect.

:param int dir_shorten_len:
	shorten parent directory names to this length (e.g.
	:file:`/long/path/to/powerline` → :file:`/l/p/t/powerline`)
:param int dir_limit_depth:
	limit directory depth to this number (e.g.
	:file:`/long/path/to/powerline` → :file:`⋯/to/powerline`)
:param bool use_path_separator:
	Use path separator in place of soft divider.
:param bool use_shortened_path:
	Use path from shortened_path ``--renderer-arg`` argument. If this argument
	is present ``shorten_home`` argument is ignored.
:param bool shorten_home:
	Shorten home directory to ``~``.
:param str ellipsis:
	Specifies what to use in place of omitted directories. Use None to not
	show this subsegment at all.

Divider highlight group used: ``cwd:divider``.

Highlight groups used: ``cwd:current_folder`` or ``cwd``. It is recommended to define all highlight groups.
''')