Commit 4cd1fbbc authored by Bram Schoenmakers's avatar Bram Schoenmakers

Merge pull request #62 from mruwek/ls-format-S

Add %S - truncated version of %s
parents bb126f00 64c57dbc
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import os import os
import shlex
from six import iteritems from six import iteritems
from six.moves import configparser from six.moves import configparser
...@@ -301,7 +302,7 @@ class _Config: ...@@ -301,7 +302,7 @@ class _Config:
alias_dict = dict() alias_dict = dict()
for alias, meaning in aliases: for alias, meaning in aliases:
meaning = meaning.split() meaning = shlex.split(meaning)
real_subcommand = meaning[0] real_subcommand = meaning[0]
alias_args = meaning[1:] alias_args = meaning[1:]
alias_dict[alias] = (real_subcommand, alias_args) alias_dict[alias] = (real_subcommand, alias_args)
......
...@@ -29,3 +29,26 @@ def humanize_date(p_datetime): ...@@ -29,3 +29,26 @@ def humanize_date(p_datetime):
now = arrow.now() now = arrow.now()
date = now.replace(day=p_datetime.day, month=p_datetime.month, year=p_datetime.year) date = now.replace(day=p_datetime.day, month=p_datetime.month, year=p_datetime.year)
return date.humanize() return date.humanize()
def humanize_dates(p_due=None, p_start=None, p_creation=None):
"""
Returns string with humanized versions of p_due, p_start and p_creation.
Examples:
- all dates: "16 days ago, due in a month, started 2 days ago"
- p_due and p_start: "due in a month, started 2 days ago"
- p_creation and p_due: "16 days ago, due in a month"
"""
dates_list = []
if p_creation:
dates_list.append(humanize_date(p_creation))
if p_due:
dates_list.append('due ' + humanize_date(p_due))
if p_start:
now = arrow.now().date()
start = humanize_date(p_start)
if p_start <= now:
dates_list.append('started ' + start)
else:
dates_list.append('starts in ' + start)
return ', '.join(dates_list)
...@@ -18,11 +18,13 @@ ...@@ -18,11 +18,13 @@
import re import re
from collections import OrderedDict
from six import u from six import u
from topydo.lib.Colors import NEUTRAL_COLOR, Colors from topydo.lib.Colors import NEUTRAL_COLOR, Colors
from topydo.lib.Config import config from topydo.lib.Config import config
from topydo.lib.ListFormat import filler, humanize_date from topydo.lib.ListFormat import filler, humanize_date, humanize_dates
from topydo.lib.Utils import get_terminal_size
class PrettyPrinterFilter(object): class PrettyPrinterFilter(object):
...@@ -135,53 +137,62 @@ class PrettyPrinterFormatFilter(PrettyPrinterFilter): ...@@ -135,53 +137,62 @@ class PrettyPrinterFormatFilter(PrettyPrinterFilter):
self.format = p_format or config().list_format() self.format = p_format or config().list_format()
def filter(self, p_todo_str, p_todo): def filter(self, p_todo_str, p_todo):
placeholders = { placeholders = OrderedDict()
# absolute creation date # absolute creation date
'c': lambda t: t.creation_date().isoformat() if t.creation_date() else '', placeholders['c'] = lambda t: t.creation_date().isoformat() if t.creation_date() else ''
# relative creation date # relative creation date
'C': lambda t: humanize_date(t.creation_date()) if t.creation_date() else '', placeholders['C'] = lambda t: humanize_date(t.creation_date()) if t.creation_date() else ''
# absolute due date # absolute due date
'd': lambda t: t.due_date().isoformat() if t.due_date() else '', placeholders['d'] = lambda t: t.due_date().isoformat() if t.due_date() else ''
# relative due date # relative due date
'D': lambda t: humanize_date(t.due_date()) if t.due_date() else '', placeholders['D'] = lambda t: humanize_date(t.due_date()) if t.due_date() else ''
# todo ID # relative dates: due, start
'i': lambda t: str(self.todolist.number(t)), placeholders['h'] = lambda t: humanize_dates(t.due_date(), t.start_date())
# todo ID pre-filled with 1 or 2 spaces if its length is <3 # relative dates in form: creation, due, start
'I': lambda t: filler(str(self.todolist.number(t)), 3), placeholders['H'] = lambda t: humanize_dates(t.due_date(), t.start_date(), t.creation_date())
# list of tags (spaces) # todo ID
'K': lambda t: ' '.join([u('{}:{}').format(tag, value) placeholders['i'] = lambda t: str(self.todolist.number(t))
for tag, value in sorted(p_todo.tags()) if
tag not in config().hidden_tags()]),
# list of tags (spaces) without due: and t: # todo ID pre-filled with 1 or 2 spaces if its length is <3
'k': lambda t: ' '.join([u('{}:{}').format(tag, value) placeholders['I'] = lambda t: filler(str(self.todolist.number(t)), 3)
for tag, value in sorted(p_todo.tags()) if
tag not in config().hidden_tags() + [config().tag_start(), config().tag_due()]]),
# priority # list of tags (spaces) without due: and t:
'p': lambda t: t.priority() if t.priority() else '', placeholders['k'] = lambda t: ' '.join([u('{}:{}').format(tag, value)
for tag, value in sorted(p_todo.tags()) if
tag not in config().hidden_tags() + [config().tag_start(), config().tag_due()]])
# text # list of tags (spaces)
's': lambda t: t.text(), placeholders['K'] = lambda t: ' '.join([u('{}:{}').format(tag, value)
for tag, value in sorted(p_todo.tags()) if
tag not in config().hidden_tags()])
# absolute start date # priority
't': lambda t: t.start_date().isoformat() if t.start_date() else '', placeholders['p'] = lambda t: t.priority() if t.priority() else ''
# relative start date # text
'T': lambda t: humanize_date(t.start_date()) if t.start_date() else '', placeholders['s'] = lambda t: t.text()
# completed # absolute start date
'x': lambda t: 'x ' + t.completion_date().isoformat() if t.is_completed() else '', placeholders['t'] = lambda t: t.start_date().isoformat() if t.start_date() else ''
# relative start date
placeholders['T'] = lambda t: humanize_date(t.start_date()) if t.start_date() else ''
# completed
placeholders['x'] = lambda t: 'x ' + t.completion_date().isoformat() if t.is_completed() else ''
# literal %
placeholders['%'] = lambda _: '%'
# text (truncated if necessary)
placeholders['S'] = lambda t: t.text()
# literal %
'%': lambda _: '%',
}
p_todo_str = self.format p_todo_str = self.format
...@@ -219,6 +230,13 @@ class PrettyPrinterFormatFilter(PrettyPrinterFilter): ...@@ -219,6 +230,13 @@ class PrettyPrinterFormatFilter(PrettyPrinterFilter):
p_todo_str = re.sub(pattern, strip_braces, p_todo_str) p_todo_str = re.sub(pattern, strip_braces, p_todo_str)
p_todo_str = re.sub(r'%{}'.format(placeholder), repl, p_todo_str) p_todo_str = re.sub(r'%{}'.format(placeholder), repl, p_todo_str)
p_todo_str = p_todo_str.rstrip()
if placeholder == 'S':
line_width = get_terminal_size().columns -1
if len(p_todo_str) > line_width:
text_lim = line_width - len(p_todo_str) - 3
p_todo_str = re.sub(re.escape(repl), repl[:text_lim] + '...', p_todo_str)
return p_todo_str.rstrip() return p_todo_str
...@@ -19,6 +19,8 @@ Various utility functions. ...@@ -19,6 +19,8 @@ Various utility functions.
""" """
import re import re
from collections import namedtuple
from datetime import date from datetime import date
...@@ -51,3 +53,25 @@ def escape_ansi(p_string): ...@@ -51,3 +53,25 @@ def escape_ansi(p_string):
return escape_ansi.pattern.sub('', p_string) return escape_ansi.pattern.sub('', p_string)
escape_ansi.pattern = re.compile(r'\x1b[^m]*m') escape_ansi.pattern = re.compile(r'\x1b[^m]*m')
def get_terminal_size():
"""
Try to determine terminal size at run time. If that is not possible,
returns the default size of 80x24.
"""
try:
from shutil import get_terminal_size # pylint: disable=no-name-in-module
except ImportError:
from backports.shutil_get_terminal_size import get_terminal_size
try:
sz = get_terminal_size()
except ValueError:
"""
This can result from the 'underlying buffer being detached', which
occurs during running the unittest on Windows (but not on Linux?)
"""
terminal_size = namedtuple('Terminal_Size', 'columns lines')
sz = terminal_size((80, 24))
return sz
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