Commit 2add29e3 authored by Jacek Sowiński's avatar Jacek Sowiński Committed by Bram Schoenmakers

Slightly modify grammar of ls_format

- From now on literal `%` signs always have to be escaped with `\` (`\%`),
even inside conditional braces.
- `%%` won't work anymore.
- Nonexistent placeholders (for example`%&`) will be expanded to empty
  strings (`''`).

This change fixes also some bugs:
- inappropriate output width when \t was used without %S
  (example: `%p{ }\t%{ }p`)
- curly braces inside conditional braces (example: `%{{}p{}}`)

Minor: recognize literal `\t` in list_format config option and in `-F`.
parent 1aa59ca0
...@@ -68,20 +68,9 @@ def strip_placeholder_braces(p_matchobj): ...@@ -68,20 +68,9 @@ def strip_placeholder_braces(p_matchobj):
into: into:
(%B) (%B)
""" """
try: before = p_matchobj.group('before') or ''
before = p_matchobj.group('before').strip('{}')
except AttributeError:
before = ''
placeholder = p_matchobj.group('placeholder') placeholder = p_matchobj.group('placeholder')
after = p_matchobj.group('after') or ''
try:
after = p_matchobj.group('after').strip('{}')
except AttributeError:
after = ''
whitespace = p_matchobj.group('whitespace') or '' whitespace = p_matchobj.group('whitespace') or ''
start = p_matchobj.group('start') or ''
end = p_matchobj.group('end') or ''
return start + before + '%' + placeholder + after + whitespace + end return before + '%' + placeholder + after + whitespace
...@@ -174,39 +174,51 @@ class PrettyPrinterFormatFilter(PrettyPrinterFilter): ...@@ -174,39 +174,51 @@ class PrettyPrinterFormatFilter(PrettyPrinterFilter):
# relative completion date # relative completion date
placeholders['X'] = lambda t: 'x ' + humanize_date(t.completion_date()) if t.is_completed() else '' placeholders['X'] = lambda t: 'x ' + humanize_date(t.completion_date()) if t.is_completed() else ''
# literal %
placeholders['%'] = lambda _: '%'
# text (truncated if necessary) # text (truncated if necessary)
placeholders['S'] = lambda t: t.text() placeholders['S'] = lambda t: t.text()
p_todo_str = re.sub(r'\\t', '\t', self.format)
p_todo_str = self.format p_todo_str_list = re.split(r'(?<!\\)%', p_todo_str)
main_pattern = (r'^({{(?P<before>.+?)}})?'
for placeholder, getter in placeholders.items(): r'(?P<placeholder>{ph}|\[{ph}\])'
repl = getter(p_todo) r'({{(?P<after>.+?)}})?'
pattern = (r'(?P<start>.*)' r'(?P<whitespace> *)')
r'%(?P<before>{{.+?}})?' truncate = False
r'(?P<placeholder>{ph}|\[{ph}\])'
r'(?P<after>{{.+?}})?' for index, substr in enumerate(p_todo_str_list):
r'(?P<whitespace> *)' if index == 0:
r'(?P<end>.*)').format(ph=placeholder) continue # first item in p_todo_str_list is surely not a placeholder
match = re.match(pattern, p_todo_str) if not re.match(main_pattern.format(ph='['+''.join(placeholders.keys()) + ']'), substr):
if match: substr = re.sub(main_pattern.format(ph='.'), '', substr) # remove nonexistent placeholder
if repl == '': p_todo_str_list[index] = substr
p_todo_str = re.sub(pattern, match.group('start') + match.group('end'), p_todo_str) continue
else: for placeholder, getter in placeholders.items():
repl = getter(p_todo)
p_todo_str = re.sub(pattern, strip_placeholder_braces, p_todo_str) pattern = main_pattern.format(ph=placeholder)
p_todo_str = re.sub(r'%({ph}|\[{ph}\])'.format(ph=placeholder), repl, p_todo_str) match = re.match(pattern, substr)
p_todo_str = p_todo_str.rstrip() if match:
if repl == '':
if placeholder == 'S': substr = re.sub(pattern, '', substr)
p_todo_str = re.sub(' *\t *', '\t', p_todo_str) else:
line_width = get_terminal_size().columns substr = re.sub(pattern, strip_placeholder_braces, substr)
if len(p_todo_str) >= line_width: substr = re.sub(r'(?<!\\)%({ph}|\[{ph}\])'.format(ph=placeholder), repl, substr)
text_lim = line_width - len(p_todo_str) - 4
p_todo_str = re.sub(re.escape(repl), repl[:text_lim] + '...', p_todo_str) if placeholder == 'S':
truncate = True
repl_S = repl # copy for truncating final p_todo_str
p_todo_str_list[index] = substr
break
p_todo_str = ''.join(p_todo_str_list)
p_todo_str = re.sub(r'\\%', '%', p_todo_str)
p_todo_str = re.sub(' *\t *', '\t', p_todo_str)
if truncate:
line_width = get_terminal_size().columns
if len(p_todo_str) >= line_width:
text_lim = line_width - len(p_todo_str) - 4
p_todo_str = re.sub(re.escape(repl_S), repl_S[:text_lim] + '...', p_todo_str)
# cut trailing space left when last placeholder in p_todo_str is empty and its predecessor is not # cut trailing space left when last placeholder in p_todo_str is empty and its predecessor is not
return p_todo_str.rstrip() return p_todo_str.rstrip()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment