Commit d62f5d02 authored by Bram Schoenmakers's avatar Bram Schoenmakers

Merge branch 'ls-format'

Conflicts:
	setup.py
parents 75adf777 f856c006
......@@ -31,13 +31,19 @@ setup(
url = "https://github.com/bram85/topydo",
install_requires = [
'six >= 1.9.0',
'arrow >= 0.7.0',
],
extras_require = {
':sys_platform=="win32"': ['colorama>=0.2.5'],
':python_version=="2.7"': ['ushlex'],
# shutil.get_terminal_size() was introduced in Python 3.3
':python_version=="2.7"': [
'backports.shutil_get_terminal_size>=1.0.0',
'ushlex',
],
':python_version=="3.2"': ['backports.shutil_get_terminal_size>=1.0.0'],
'ical': ['icalendar'],
'prompt-toolkit': ['prompt-toolkit >= 0.53'],
'test': ['freezegun', 'coverage', 'green'],
'test': ['coverage', 'freezegun', 'green', ],
'test:python_version=="2.7"': ['mock'],
'test:python_version!="3.2"': ['pylint'],
},
......
[{"completed": false, "completion_date": null, "contexts": ["Context2"], "creation_date": null, "priority": "C", "projects": ["Project1"], "source": "(C) Foo @Context2 Not@Context +Project1 Not+Project", "tags": [], "text": "Foo @Context2 Not@Context +Project1 Not+Project"}, {"completed": false, "completion_date": null, "contexts": [], "creation_date": null, "priority": "C", "projects": [], "source": "(C) Drink beer @ home", "tags": [], "text": "Drink beer @ home"}, {"completed": false, "completion_date": null, "contexts": [], "creation_date": null, "priority": "C", "projects": [], "source": "(C) 13 + 29 = 42", "tags": [], "text": "13 + 29 = 42"}, {"completed": false, "completion_date": null, "contexts": ["Context1"], "creation_date": null, "priority": "D", "projects": ["Project2"], "source": "(D) Bar @Context1 +Project2 p:1", "tags": [["p", "1"]], "text": "Bar @Context1 +Project2"}]
[{"completed": false, "completion_date": null, "contexts": ["Context2"], "creation_date": "2015-11-05", "priority": "C", "projects": ["Project1"], "source": "(C) 2015-11-05 Foo @Context2 Not@Context +Project1 Not+Project", "tags": [], "text": "Foo @Context2 Not@Context +Project1 Not+Project"}, {"completed": false, "completion_date": null, "contexts": [], "creation_date": null, "priority": "C", "projects": [], "source": "(C) Drink beer @ home", "tags": [], "text": "Drink beer @ home"}, {"completed": false, "completion_date": null, "contexts": [], "creation_date": null, "priority": "C", "projects": [], "source": "(C) 13 + 29 = 42", "tags": [], "text": "13 + 29 = 42"}, {"completed": false, "completion_date": null, "contexts": ["Context1"], "creation_date": null, "priority": "D", "projects": ["Project2"], "source": "(D) Bar @Context1 +Project2 p:1", "tags": [["p", "1"]], "text": "Bar @Context1 +Project2"}]
(C) Foo @Context2 Not@Context +Project1 Not+Project
(C) 2015-11-05 Foo @Context2 Not@Context +Project1 Not+Project
(D) Bar @Context1 +Project2 p:1
(C) Baz @Context1 +Project1 key:value id:1
(C) Drink beer @ home
......
(D) 2015-08-31 Bar @Context1 +Project2 due:2015-09-30 t:2015-09-29
(Z) 2015-11-06 Lorem ipsum dolorem sit amet. Red @fox +jumped over the lazy:bar and jar due:2015-11-08 t:2015-11-07
(C) 2015-07-12 Foo @Context2 Not@Context +Project1 Not+Project
(C) Baz @Context1 +Project1 key:value
Drink beer @ home id:1 p:2 ical:foobar
x 2014-12-12 Completed but with date:2014-12-12
[ls]
list_format = |%I| %x %{(}p{)} %c %S\t%K
......@@ -36,7 +36,7 @@ class ListCommandTest(CommandTest):
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertEqual(self.output, "| 1| (C) Foo @Context2 Not@Context +Project1 Not+Project\n| 4| (C) Drink beer @ home\n| 5| (C) 13 + 29 = 42\n| 2| (D) Bar @Context1 +Project2\n")
self.assertEqual(self.output, "| 1| (C) 2015-11-05 Foo @Context2 Not@Context +Project1 Not+Project\n| 4| (C) Drink beer @ home\n| 5| (C) 13 + 29 = 42\n| 2| (D) Bar @Context1 +Project2\n")
self.assertEqual(self.errors, "")
def test_list03(self):
......@@ -62,7 +62,7 @@ class ListCommandTest(CommandTest):
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertEqual(self.output, "| 1| (C) Foo @Context2 Not@Context +Project1 Not+Project\n| 3| (C) Baz @Context1 +Project1 key:value\n| 4| (C) Drink beer @ home\n| 5| (C) 13 + 29 = 42\n| 2| (D) Bar @Context1 +Project2\n| 6| x 2014-12-12 Completed but with date:2014-12-12\n")
self.assertEqual(self.output, "| 1| (C) 2015-11-05 Foo @Context2 Not@Context +Project1 Not+Project\n| 3| (C) Baz @Context1 +Project1 key:value\n| 4| (C) Drink beer @ home\n| 5| (C) 13 + 29 = 42\n| 2| (D) Bar @Context1 +Project2\n| 6| x 2014-12-12 Completed but with date:2014-12-12\n")
self.assertEqual(self.errors, "")
def test_list06(self):
......@@ -80,7 +80,7 @@ class ListCommandTest(CommandTest):
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertEqual(self.output, "| 3| (C) Baz @Context1 +Project1 key:value\n| 1| (C) Foo @Context2 Not@Context +Project1 Not+Project\n")
self.assertEqual(self.output, "| 3| (C) Baz @Context1 +Project1 key:value\n| 1| (C) 2015-11-05 Foo @Context2 Not@Context +Project1 Not+Project\n")
self.assertEqual(self.errors, "")
def test_list08(self):
......@@ -117,7 +117,7 @@ class ListCommandTest(CommandTest):
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertEqual(self.output, "| 1| (C) Foo @Context2 Not@Context +Project1 Not+Project\n")
self.assertEqual(self.output, "| 1| (C) 2015-11-05 Foo @Context2 Not@Context +Project1 Not+Project\n")
self.assertEqual(self.errors, "")
def test_list12(self):
......@@ -128,7 +128,7 @@ class ListCommandTest(CommandTest):
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertEqual(self.output, "| 1| (C) Foo @Context2 Not@Context +Project1 Not+Project\n| 3| (C) Baz @Context1 +Project1 key:value\n| 2| (D) Bar @Context1 +Project2\n")
self.assertEqual(self.output, "| 1| (C) 2015-11-05 Foo @Context2 Not@Context +Project1 Not+Project\n| 3| (C) Baz @Context1 +Project1 key:value\n| 2| (D) Bar @Context1 +Project2\n")
self.assertEqual(self.errors, "")
def test_list13(self):
......@@ -137,7 +137,7 @@ class ListCommandTest(CommandTest):
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertEqual(self.output, "| 1| (C) Foo @Context2 Not@Context +Project1 Not+Project\n| 3| (C) Baz @Context1 +Project1 key:value\n| 4| (C) Drink beer @ home\n| 5| (C) 13 + 29 = 42\n| 6| x 2014-12-12 Completed but with date:2014-12-12\n")
self.assertEqual(self.output, "| 1| (C) 2015-11-05 Foo @Context2 Not@Context +Project1 Not+Project\n| 3| (C) Baz @Context1 +Project1 key:value\n| 4| (C) Drink beer @ home\n| 5| (C) 13 + 29 = 42\n| 6| x 2014-12-12 Completed but with date:2014-12-12\n")
self.assertEqual(self.errors, "")
def test_list14(self):
......@@ -147,7 +147,7 @@ class ListCommandTest(CommandTest):
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertEqual(self.output, " | 1| (C) Foo @Context2 Not@Context +Project1 Not+Project\n | 4| (C) Drink beer @ home\n | 5| (C) 13 + 29 = 42\n | 2| (D) Bar @Context1 +Project2\n")
self.assertEqual(self.output, " | 1| (C) 2015-11-05 Foo @Context2 Not@Context +Project1 Not+Project\n | 4| (C) Drink beer @ home\n | 5| (C) 13 + 29 = 42\n | 2| (D) Bar @Context1 +Project2\n")
self.assertEqual(self.errors, "")
def test_list15(self):
......@@ -165,7 +165,7 @@ class ListCommandTest(CommandTest):
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertEqual(self.output, "|t5c| (C) Foo @Context2 Not@Context +Project1 Not+Project\n|wa5| (C) Drink beer @ home\n|z63| (C) 13 + 29 = 42\n|mfg| (D) Bar @Context1 +Project2\n")
self.assertEqual(self.output, "|t5c| (C) 2015-11-05 Foo @Context2 Not@Context +Project1 Not+Project\n|wa5| (C) Drink beer @ home\n|z63| (C) 13 + 29 = 42\n|mfg| (D) Bar @Context1 +Project2\n")
self.assertEqual(self.errors, "")
def test_list17(self):
......@@ -195,7 +195,7 @@ class ListCommandTest(CommandTest):
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertEqual(self.output, "| 3| (C) Baz @Context1 +Project1 key:value id:1\n| 1| (C) Foo @Context2 Not@Context +Project1 Not+Project\n")
self.assertEqual(self.output, "| 3| (C) Baz @Context1 +Project1 id:1 key:value\n| 1| (C) 2015-11-05 Foo @Context2 Not@Context +Project1 Not+Project\n")
self.assertEqual(self.errors, "")
def test_list20(self):
......@@ -203,7 +203,7 @@ class ListCommandTest(CommandTest):
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertEqual(self.output, "| 1| (C) Foo @Context2 Not@Context +Project1 Not+Project\n| 4| (C) Drink beer @ home\n| 5| (C) 13 + 29 = 42\n| 2| (D) Bar @Context1 +Project2\n")
self.assertEqual(self.output, "| 1| (C) 2015-11-05 Foo @Context2 Not@Context +Project1 Not+Project\n| 4| (C) Drink beer @ home\n| 5| (C) 13 + 29 = 42\n| 2| (D) Bar @Context1 +Project2\n")
self.assertEqual(self.errors, "")
def test_list21(self):
......@@ -212,7 +212,7 @@ class ListCommandTest(CommandTest):
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertEqual(self.output, "| 1| (C) Foo @Context2 Not@Context +Project1 Not+Project\n| 4| (C) Drink beer @ home\n| 5| (C) 13 + 29 = 42\n| 2| (D) Bar @Context1 +Project2\n")
self.assertEqual(self.output, "| 1| (C) 2015-11-05 Foo @Context2 Not@Context +Project1 Not+Project\n| 4| (C) Drink beer @ home\n| 5| (C) 13 + 29 = 42\n| 2| (D) Bar @Context1 +Project2\n")
self.assertEqual(self.errors, "")
def test_list22(self):
......@@ -239,7 +239,7 @@ class ListCommandTest(CommandTest):
command = ListCommand(["-n", "1"], self.todolist, self.out, self.error)
command.execute()
self.assertEqual(self.output, "| 1| (C) Foo @Context2 Not@Context +Project1 Not+Project\n")
self.assertEqual(self.output, "| 1| (C) 2015-11-05 Foo @Context2 Not@Context +Project1 Not+Project\n")
self.assertEqual(self.errors, "")
def test_list33(self):
......@@ -247,7 +247,7 @@ class ListCommandTest(CommandTest):
command = ListCommand(["-n", "-1"], self.todolist, self.out, self.error)
command.execute()
self.assertEqual(self.output, "| 1| (C) Foo @Context2 Not@Context +Project1 Not+Project\n| 4| (C) Drink beer @ home\n| 5| (C) 13 + 29 = 42\n| 2| (D) Bar @Context1 +Project2\n")
self.assertEqual(self.output, "| 1| (C) 2015-11-05 Foo @Context2 Not@Context +Project1 Not+Project\n| 4| (C) Drink beer @ home\n| 5| (C) 13 + 29 = 42\n| 2| (D) Bar @Context1 +Project2\n")
self.assertEqual(self.errors, "")
def test_list34(self):
......@@ -257,7 +257,7 @@ class ListCommandTest(CommandTest):
command = ListCommand(["-n", "foo"], self.todolist, self.out, self.error)
command.execute()
self.assertEqual(self.output, "| 1| (C) Foo @Context2 Not@Context +Project1 Not+Project\n| 4| (C) Drink beer @ home\n")
self.assertEqual(self.output, "| 1| (C) 2015-11-05 Foo @Context2 Not@Context +Project1 Not+Project\n| 4| (C) Drink beer @ home\n")
self.assertEqual(self.errors, "")
def test_list35(self):
......@@ -265,7 +265,7 @@ class ListCommandTest(CommandTest):
command = ListCommand(["-x", "-n", "foo"], self.todolist, self.out, self.error)
command.execute()
self.assertEqual(self.output, "| 1| (C) Foo @Context2 Not@Context +Project1 Not+Project\n| 3| (C) Baz @Context1 +Project1 key:value\n| 4| (C) Drink beer @ home\n| 5| (C) 13 + 29 = 42\n| 2| (D) Bar @Context1 +Project2\n| 6| x 2014-12-12 Completed but with date:2014-12-12\n")
self.assertEqual(self.output, "| 1| (C) 2015-11-05 Foo @Context2 Not@Context +Project1 Not+Project\n| 3| (C) Baz @Context1 +Project1 key:value\n| 4| (C) Drink beer @ home\n| 5| (C) 13 + 29 = 42\n| 2| (D) Bar @Context1 +Project2\n| 6| x 2014-12-12 Completed but with date:2014-12-12\n")
self.assertEqual(self.errors, "")
def test_help(self):
......
# Topydo - A todo.txt client written in Python.
# Copyright (C) 2014 - 2015 Bram Schoenmakers <me@bramschoenmakers.nl>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import unittest
from collections import namedtuple
from freezegun import freeze_time
from test.command_testcase import CommandTest
from test.facilities import load_file_to_todolist
from topydo.commands.ListCommand import ListCommand
from topydo.lib.Config import config
# We're searching for 'mock'
# pylint: disable=no-name-in-module
try:
from unittest import mock
except ImportError:
import mock
@freeze_time("2015, 11, 06")
class ListFormatTest(CommandTest):
def setUp(self):
super(ListFormatTest, self).setUp()
self.todolist = load_file_to_todolist("test/data/ListFormat.txt")
self.terminal_size = namedtuple('terminal_size', ['columns', 'lines'])
def test_list_format01(self):
config(p_overrides={('ls', 'list_format'): '|%I| %x %{(}p{)} %c %s %K'})
command = ListCommand(["-x"], self.todolist, self.out, self.error)
command.execute()
result = u"""| 1| (D) 2015-08-31 Bar @Context1 +Project2 due:2015-09-30 t:2015-09-29
| 2| (Z) 2015-11-06 Lorem ipsum dolorem sit amet. Red @fox +jumped over the and jar due:2015-11-08 lazy:bar t:2015-11-07
| 3| (C) 2015-07-12 Foo @Context2 Not@Context +Project1 Not+Project
| 4| (C) Baz @Context1 +Project1 key:value
| 5| Drink beer @ home ical:foobar id:1 p:2
| 6| x 2014-12-12 Completed but with date:2014-12-12
"""
self.assertEqual(self.output, result)
@mock.patch('topydo.lib.ListFormat.get_terminal_size')
def test_list_format02(self, mock_terminal_size):
mock_terminal_size.return_value = self.terminal_size(80, 25)
config(p_overrides={('ls', 'list_format'): '|%I| %x %{(}p{)} %c %S %K'})
command = ListCommand(["-x"], self.todolist, self.out, self.error)
command.execute()
result = u"""| 1| (D) 2015-08-31 Bar @Context1 +Project2 due:2015-09-30 t:2015-09-29
| 2| (Z) 2015-11-06 Lorem ipsum dolore... due:2015-11-08 lazy:bar t:2015-11-07
| 3| (C) 2015-07-12 Foo @Context2 Not@Context +Project1 Not+Project
| 4| (C) Baz @Context1 +Project1 key:value
| 5| Drink beer @ home ical:foobar id:1 p:2
| 6| x 2014-12-12 Completed but with date:2014-12-12
"""
self.assertEqual(self.output, result)
@mock.patch('topydo.lib.ListFormat.get_terminal_size')
def test_list_format03(self, mock_terminal_size):
mock_terminal_size.return_value = self.terminal_size(100, 25)
config(p_overrides={('ls', 'list_format'): '|%I| %x %{(}p{)} %c %S %K'})
command = ListCommand(["-x"], self.todolist, self.out, self.error)
command.execute()
result = u"""| 1| (D) 2015-08-31 Bar @Context1 +Project2 due:2015-09-30 t:2015-09-29
| 2| (Z) 2015-11-06 Lorem ipsum dolorem sit amet. Red @fox... due:2015-11-08 lazy:bar t:2015-11-07
| 3| (C) 2015-07-12 Foo @Context2 Not@Context +Project1 Not+Project
| 4| (C) Baz @Context1 +Project1 key:value
| 5| Drink beer @ home ical:foobar id:1 p:2
| 6| x 2014-12-12 Completed but with date:2014-12-12
"""
self.assertEqual(self.output, result)
@mock.patch('topydo.lib.ListFormat.get_terminal_size')
def test_list_format04(self, mock_terminal_size):
mock_terminal_size.return_value = self.terminal_size(100, 25)
config(p_overrides={('ls', 'list_format'): '|%I| %x %{(}p{)} %c %S %K'})
command = ListCommand(["-x"], self.todolist, self.out, self.error)
command.execute()
result = u"""| 1| (D) 2015-08-31 Bar @Context1 +Project2 due:2015-09-30 t:2015-09-29
| 2| (Z) 2015-11-06 Lorem ipsum dolorem sit amet. Red @fox... due:2015-11-08 lazy:bar t:2015-11-07
| 3| (C) 2015-07-12 Foo @Context2 Not@Context +Project1 Not+Project
| 4| (C) Baz @Context1 +Project1 key:value
| 5| Drink beer @ home ical:foobar id:1 p:2
| 6| x 2014-12-12 Completed but with date:2014-12-12
"""
self.assertEqual(self.output, result)
@mock.patch('topydo.lib.ListFormat.get_terminal_size')
def test_list_format05(self, mock_terminal_size):
mock_terminal_size.return_value = self.terminal_size(80, 25)
config(p_overrides={('ls', 'list_format'): '|%I| %x %{(}p{)} %c %S %K'})
command = ListCommand(["-x"], self.todolist, self.out, self.error)
command.execute()
result = u"""| 1| (D) 2015-08-31 Bar @Context1 +Project2 due:2015-09-30 t:2015-09-29
| 2| (Z) 2015-11-06 Lorem ipsum dolore... due:2015-11-08 lazy:bar t:2015-11-07
| 3| (C) 2015-07-12 Foo @Context2 Not@Context +Project1 Not+Project
| 4| (C) Baz @Context1 +Project1 key:value
| 5| Drink beer @ home ical:foobar id:1 p:2
| 6| x 2014-12-12 Completed but with date:2014-12-12
"""
@mock.patch('topydo.lib.ListFormat.get_terminal_size')
def test_list_format06(self, mock_terminal_size):
mock_terminal_size.return_value = self.terminal_size(100, 25)
config(p_overrides={('ls', 'list_format'): '|%I| %x %p %S %k %{(}H{)}'})
command = ListCommand(["-x"], self.todolist, self.out, self.error)
command.execute()
result = u"""| 1| D Bar @Context1 +Project2 (3 months ago, due a month ago, started a month ago)
| 2| Z Lorem ipsum dolorem sit amet. Red @f... lazy:bar (just now, due in 2 days, starts in a day)
| 3| C Foo @Context2 Not@Context +Project1 Not+Project (4 months ago)
| 4| C Baz @Context1 +Project1 key:value
| 5| Drink beer @ home
| 6| x 2014-12-12 Completed but with date:2014-12-12
"""
self.assertEqual(self.output, result)
@mock.patch('topydo.lib.ListFormat.get_terminal_size')
def test_list_format07(self, mock_terminal_size):
mock_terminal_size.return_value = self.terminal_size(100, 25)
config(p_overrides={('ls', 'list_format'): '|%I| %x %p %S %k %{(}h{)}'})
command = ListCommand(["-x"], self.todolist, self.out, self.error)
command.execute()
result = u"""| 1| D Bar @Context1 +Project2 (due a month ago, started a month ago)
| 2| Z Lorem ipsum dolorem sit amet. Red @fox +jumped... lazy:bar (due in 2 days, starts in a day)
| 3| C Foo @Context2 Not@Context +Project1 Not+Project
| 4| C Baz @Context1 +Project1 key:value
| 5| Drink beer @ home
| 6| x 2014-12-12 Completed but with date:2014-12-12
"""
self.assertEqual(self.output, result)
@mock.patch('topydo.lib.ListFormat.get_terminal_size')
def test_list_format08(self, mock_terminal_size):
mock_terminal_size.return_value = self.terminal_size(100, 25)
config(p_overrides={('ls', 'list_format'): '%c %d %t %x'})
command = ListCommand(["-x"], self.todolist, self.out, self.error)
command.execute()
result = u"""2015-08-31 2015-09-30 2015-09-29
2015-11-06 2015-11-08 2015-11-07
2015-07-12
x 2014-12-12
"""
self.assertEqual(self.output, result)
@mock.patch('topydo.lib.ListFormat.get_terminal_size')
def test_list_format09(self, mock_terminal_size):
mock_terminal_size.return_value = self.terminal_size(100, 25)
config(p_overrides={('ls', 'list_format'): '%C | %D | %T | %X'})
command = ListCommand(["-x"], self.todolist, self.out, self.error)
command.execute()
result = u"""3 months ago | a month ago | a month ago |
just now | in 2 days | in a day |
4 months ago | | |
| | |
| | |
| | | x 11 months ago
"""
self.assertEqual(self.output, result)
def test_list_format10(self):
config(p_overrides={('ls', 'list_format'): '|%i| %k'})
command = ListCommand(["-x"], self.todolist, self.out, self.error)
command.execute()
result = u"""|1|
|2| lazy:bar
|3|
|4| key:value
|5|
|6| date:2014-12-12
"""
self.assertEqual(self.output, result)
def test_list_format11(self):
config(p_overrides={('ls', 'list_format'): '|%I| %K'})
command = ListCommand(["-x"], self.todolist, self.out, self.error)
command.execute()
result = u"""| 1| due:2015-09-30 t:2015-09-29
| 2| due:2015-11-08 lazy:bar t:2015-11-07
| 3|
| 4| key:value
| 5| ical:foobar id:1 p:2
| 6| date:2014-12-12
"""
self.assertEqual(self.output, result)
def test_list_format12(self):
config(p_overrides={('ls', 'list_format'): '|%I| \%'})
command = ListCommand(["-x"], self.todolist, self.out, self.error)
command.execute()
result = u"""| 1| %
| 2| %
| 3| %
| 4| %
| 5| %
| 6| %
"""
self.assertEqual(self.output, result)
def test_list_format13(self):
command = ListCommand(["-x", "-F", "|%I| %x %{(}p{)} %c %s %K"],
self.todolist, self.out, self.error)
command.execute()
result = u"""| 1| (D) 2015-08-31 Bar @Context1 +Project2 due:2015-09-30 t:2015-09-29
| 2| (Z) 2015-11-06 Lorem ipsum dolorem sit amet. Red @fox +jumped over the and jar due:2015-11-08 lazy:bar t:2015-11-07
| 3| (C) 2015-07-12 Foo @Context2 Not@Context +Project1 Not+Project
| 4| (C) Baz @Context1 +Project1 key:value
| 5| Drink beer @ home ical:foobar id:1 p:2
| 6| x 2014-12-12 Completed but with date:2014-12-12
"""
self.assertEqual(self.output, result)
@mock.patch('topydo.lib.ListFormat.get_terminal_size')
def test_list_format14(self, mock_terminal_size):
mock_terminal_size.return_value = self.terminal_size(40, 25)
command = ListCommand(["-x", "-F", "|%I| %x %{(}p{)} %c %s %K", "@Context1"],
self.todolist, self.out, self.error)
command.execute()
result = u"""| 1| (D) 2015-08-31 Bar @Context1 +Project2 due:2015-09-30 t:2015-09-29
| 4| (C) Baz @Context1 +Project1 key:value
"""
self.assertEqual(self.output, result)
def test_list_format15(self):
command = ListCommand(["-x", "-F", "%c"], self.todolist, self.out, self.error)
command.execute()
result = u"""2015-08-31
2015-11-06
2015-07-12
"""
self.assertEqual(self.output, result)
def test_list_format16(self):
command = ListCommand(["-x", "-F", "%C"], self.todolist, self.out, self.error)
command.execute()
result = u"""3 months ago
just now
4 months ago
"""
self.assertEqual(self.output, result)
def test_list_format17(self):
command = ListCommand(["-x", "-F", "%d"], self.todolist, self.out, self.error)
command.execute()
result = u"""2015-09-30
2015-11-08
"""
self.assertEqual(self.output, result)
def test_list_format18(self):
command = ListCommand(["-x", "-F", "%D"], self.todolist, self.out, self.error)
command.execute()
result = u"""a month ago
in 2 days
"""
self.assertEqual(self.output, result)
def test_list_format19(self):
command = ListCommand(["-x", "-F", "%h"], self.todolist, self.out, self.error)
command.execute()
result = u"""due a month ago, started a month ago
due in 2 days, starts in a day
"""
self.assertEqual(self.output, result)
def test_list_format20(self):
command = ListCommand(["-x", "-F", "%H"], self.todolist, self.out, self.error)
command.execute()
result = u"""3 months ago, due a month ago, started a month ago
just now, due in 2 days, starts in a day
4 months ago
"""
self.assertEqual(self.output, result)
def test_list_format21(self):
command = ListCommand(["-x", "-F", "%i"], self.todolist, self.out, self.error)
command.execute()
result = u"""1
2
3
4
5
6
"""
self.assertEqual(self.output, result)
def test_list_format22(self):
command = ListCommand(["-x", "-F", "%I"], self.todolist, self.out, self.error)
command.execute()
result = u""" 1
2
3
4
5
6
"""
self.assertEqual(self.output, result)
def test_list_format23(self):
command = ListCommand(["-x", "-F", "%k"], self.todolist, self.out, self.error)
command.execute()
result = u"""
lazy:bar
key:value
date:2014-12-12
"""
self.assertEqual(self.output, result)
def test_list_format24(self):
command = ListCommand(["-x", "-F", "%K"], self.todolist, self.out, self.error)
command.execute()
result = u"""due:2015-09-30 t:2015-09-29
due:2015-11-08 lazy:bar t:2015-11-07
key:value
ical:foobar id:1 p:2
date:2014-12-12
"""
self.assertEqual(self.output, result)
def test_list_format25(self):
command = ListCommand(["-x", "-F", "%p"], self.todolist, self.out, self.error)
command.execute()
result = u"""D
Z
C
C
"""
self.assertEqual(self.output, result)
def test_list_format26(self):
command = ListCommand(["-x", "-F", "%s"], self.todolist, self.out, self.error)
command.execute()
result = u"""Bar @Context1 +Project2
Lorem ipsum dolorem sit amet. Red @fox +jumped over the and jar
Foo @Context2 Not@Context +Project1 Not+Project
Baz @Context1 +Project1
Drink beer @ home
Completed but with
"""
self.assertEqual(self.output, result)
@mock.patch('topydo.lib.ListFormat.get_terminal_size')
def test_list_format27(self, mock_terminal_size):
mock_terminal_size.return_value = self.terminal_size(50, 25)
command = ListCommand(["-x", "-F", "%S"], self.todolist, self.out, self.error)
command.execute()
result = u"""Bar @Context1 +Project2
Lorem ipsum dolorem sit amet. Red @fox +jumped...
Foo @Context2 Not@Context +Project1 Not+Project
Baz @Context1 +Project1
Drink beer @ home
Completed but with
"""
self.assertEqual(self.output, result)
def test_list_format28(self):
command = ListCommand(["-x", "-F", "%t"], self.todolist, self.out, self.error)
command.execute()
result = u"""2015-09-29
2015-11-07
"""
self.assertEqual(self.output, result)
def test_list_format29(self):
command = ListCommand(["-x", "-F", "%T"], self.todolist, self.out, self.error)
command.execute()
result = u"""a month ago
in a day
"""
self.assertEqual(self.output, result)
def test_list_format30(self):
command = ListCommand(["-x", "-F", "%x"], self.todolist, self.out, self.error)
command.execute()
result = u"""
x 2014-12-12
"""
self.assertEqual(self.output, result)
def test_list_format31(self):
command = ListCommand(["-x", "-F", "%X"], self.todolist, self.out, self.error)
command.execute()
result = u"""
x 11 months ago
"""
self.assertEqual(self.output, result)
def test_list_format32(self):
command = ListCommand(["-x", "-s", "desc:priority", "-F", "%{{}p{}}"], self.todolist, self.out, self.error)
command.execute()
result = u"""{C}
{C}
{D}
{Z}
"""
self.assertEqual(self.output, result)
def test_list_format33(self):
command = ListCommand(["-x", "-s", "desc:priority", "-F", "%{\%p}p{\%p}"], self.todolist, self.out, self.error)
command.execute()
result = u"""%pC%p
%pC%p
%pD%p
%pZ%p
"""
self.assertEqual(self.output, result)
def test_list_format34(self):
command = ListCommand(["-x", "-s", "desc:priority", "-F", "%p%p"], self.todolist, self.out, self.error)
command.execute()
result = u"""CC
CC
DD
ZZ
"""
self.assertEqual(self.output, result)
@mock.patch('topydo.lib.ListFormat.get_terminal_size')
def test_list_format35(self, mock_terminal_size):
mock_terminal_size.return_value = self.terminal_size(5, 25)
command = ListCommand(["-x", "-s", "desc:priority", "-F", "%p{ } %{ }p"], self.todolist, self.out, self.error)
command.execute()
result = u"""C C
C C
D D
Z Z
"""
self.assertEqual(self.output, result)
@mock.patch('topydo.lib.ListFormat.get_terminal_size')
def test_list_format36(self, mock_terminal_size):
"""Tab expands to 1 character."""
mock_terminal_size.return_value = self.terminal_size(6, 25)
command = ListCommand(["-x", "-s", "desc:priority", "-F", "%p{ } %{ }p"], self.todolist, self.out, self.error)
command.execute()
result = u"""C C
C C
D D
Z Z
"""
self.assertEqual(self.output, result)
@mock.patch('topydo.lib.ListFormat.get_terminal_size')
def test_list_format37(self, mock_terminal_size):
mock_terminal_size.return_value = self.terminal_size(5, 25)
command = ListCommand(["-x", "-s", "desc:priority", "-F", " %{ }p"], self.todolist, self.out, self.error)
command.execute()
result = u""" C
C
D
Z
"""
self.assertEqual(self.output, result)
def test_list_format38(self):
"""
Invalid placeholders should expand to an empty string.
"""
command = ListCommand(["-x", "-s", "desc:priority", "-F", "%&"], self.todolist, self.out, self.error)
command.execute()
result = u"""
"""
self.assertEqual(self.output, result)
def test_list_format39(self):
"""
Invalid placeholders without a character should expand to an empty
string.
"""
command = ListCommand(["-x", "-s", "desc:priority", "-F", "%"], self.todolist, self.out, self.error)
command.execute()
result = u"""
"""
self.assertEqual(self.output, result)
@mock.patch('topydo.lib.ListFormat.get_terminal_size')
def test_list_format40(self, mock_terminal_size):
mock_terminal_size.return_value = self.terminal_size(100, 25)
config('test/data/listformat.conf')
command = ListCommand(["-x"], self.todolist, self.out, self.error)
command.execute()
result = u"""| 1| (D) 2015-08-31 Bar @Context1 +Project2 due:2015-09-30 t:2015-09-29
| 2| (Z) 2015-11-06 Lorem ipsum dolorem sit amet. Red @fox... due:2015-11-08 lazy:bar t:2015-11-07
| 3| (C) 2015-07-12 Foo @Context2 Not@Context +Project1 Not+Project
| 4| (C) Baz @Context1 +Project1 key:value
| 5| Drink beer @ home ical:foobar id:1 p:2
| 6| x 2014-12-12 Completed but with date:2014-12-12
"""
self.assertEqual(self.output, result)
@mock.patch('topydo.lib.ListFormat.get_terminal_size')
def test_list_format41(self, mock_terminal_size):
mock_terminal_size.return_value = self.terminal_size(100, 25)
command = ListCommand(["-x", "-F", "|%I| %x %{(}p{)} %c %S\\t%K"], self.todolist, self.out, self.error)
command.execute()
result = u"""| 1| (D) 2015-08-31 Bar @Context1 +Project2 due:2015-09-30 t:2015-09-29
| 2| (Z) 2015-11-06 Lorem ipsum dolorem sit amet. Red @fox... due:2015-11-08 lazy:bar t:2015-11-07
| 3| (C) 2015-07-12 Foo @Context2 Not@Context +Project1 Not+Project
| 4| (C) Baz @Context1 +Project1 key:value
| 5| Drink beer @ home ical:foobar id:1 p:2
| 6| x 2014-12-12 Completed but with date:2014-12-12
"""
self.assertEqual(self.output, result)
@mock.patch('topydo.lib.ListFormat.get_terminal_size')
def test_list_format42(self, mock_terminal_size):
mock_terminal_size.return_value = self.terminal_size(100, 25)
config('test/data/listformat.conf', p_overrides={('ls', 'indent'): '3'})
command = ListCommand(["-x"], self.todolist, self.out, self.error)
command.execute()
result = u""" | 1| (D) 2015-08-31 Bar @Context1 +Project2 due:2015-09-30 t:2015-09-29
| 2| (Z) 2015-11-06 Lorem ipsum dolorem sit amet. Red @... due:2015-11-08 lazy:bar t:2015-11-07
| 3| (C) 2015-07-12 Foo @Context2 Not@Context +Project1 Not+Project
| 4| (C) Baz @Context1 +Project1 key:value
| 5| Drink beer @ home ical:foobar id:1 p:2
| 6| x 2014-12-12 Completed but with date:2014-12-12
"""
self.assertEqual(self.output, result)
if __name__ == '__main__':
unittest.main()
......@@ -16,6 +16,7 @@ auto_creation_date = 1
hide_tags = id,p,ical
indent = 0
list_limit = -1
list_format = |%I| %x %{(}p{)} %c %s %k %{due:}d %{t:}t
[tags]
tag_start = t
......@@ -51,6 +52,7 @@ append_parent_contexts = 0
[aliases]
;showall = ls -x
;next = ls -n 1
;top = ls -F '|%I| %x %p %S %k %{(}H{)}'
;lsproj = lsprj
;listprj = lsprj
;listproj = lsprj
......
......@@ -17,15 +17,20 @@
""" Entry file for the topydo Prompt interface (CLI). """
import os.path
import shlex
import sys
from topydo.cli.CLIApplicationBase import CLIApplicationBase, error, usage
from topydo.cli.TopydoCompleter import TopydoCompleter
from prompt_toolkit.shortcuts import prompt
from prompt_toolkit.history import InMemoryHistory
from six import PY2
from topydo.lib.Config import config, ConfigError
if PY2:
import ushlex as shlex
# First thing is to poke the configuration and check whether it's sane
# The modules below may already read in configuration upon import, so
# make sure to bail out if the configuration is invalid.
......@@ -94,7 +99,8 @@ class PromptApplication(CLIApplicationBase):
try:
user_input = prompt(u'topydo> ', history=history,
completer=self.completer,
complete_while_typing=False).split()
complete_while_typing=False)
user_input = shlex.split(user_input)
except (EOFError, KeyboardInterrupt):
sys.exit(0)
......
......@@ -16,9 +16,9 @@
from topydo.lib.Config import config
from topydo.lib.ExpressionCommand import ExpressionCommand
from topydo.lib.ListFormat import ListFormatParser
from topydo.lib.PrettyPrinter import pretty_printer_factory
from topydo.lib.PrettyPrinterFilter import (PrettyPrinterHideTagFilter,
PrettyPrinterIndentFilter)
from topydo.lib.PrettyPrinterFilter import PrettyPrinterFormatFilter
class ListCommand(ExpressionCommand):
......@@ -32,6 +32,7 @@ class ListCommand(ExpressionCommand):
self.printer = None
self.sort_expression = config().sort_string()
self.show_all = False
self.format = config().list_format()
def _poke_icalendar(self):
"""
......@@ -47,7 +48,7 @@ class ListCommand(ExpressionCommand):
return True
def _process_flags(self):
opts, args = self.getopt('f:n:s:x')
opts, args = self.getopt('f:F:n:s:x')
for opt, value in opts:
if opt == '-x':
......@@ -64,6 +65,8 @@ class ListCommand(ExpressionCommand):
self.printer = IcalPrinter(self.todolist)
else:
self.printer = None
elif opt == '-F':
self.format = value
elif opt == '-n':
try:
self.limit = int(value)
......@@ -83,11 +86,11 @@ class ListCommand(ExpressionCommand):
if self.printer is None:
# create a standard printer with some filters
indent = config().list_indent()
final_format = ' ' * indent + self.format
hidden_tags = config().hidden_tags()
filters = []
filters.append(PrettyPrinterIndentFilter(indent))
filters.append(PrettyPrinterHideTagFilter(hidden_tags))
filters.append(PrettyPrinterFormatFilter(self.todolist, final_format))
self.printer = pretty_printer_factory(self.todolist, filters)
......@@ -108,7 +111,8 @@ class ListCommand(ExpressionCommand):
return True
def usage(self):
return """ Synopsis: ls [-x] [-s <sort_expression>] [-f <format>] [expression]"""
return """Synopsis: ls [-x] [-s <sort_expression>] [-f <output format>]
[-F <format string>] [expression]"""
def help(self):
return """\
......@@ -128,6 +132,36 @@ When an expression is given, only the todos matching that expression are shown.
an 'ical' tag with a unique ID. Completed todo items may be
archived.
* 'json' - Javascript Object Notation (JSON)
-F : Specify the format of the text ('text' format), which may contain
placeholders that may be expanded if the todo has such attribute. If such
attribute does not exist, then it expands to an empty string.
%c: Absolute creation date.
%C: Relative creation date.
%d: Absolute due date.
%D: Relative due date.
%h: Relative due and start date (due in 3 days, started 3 days ago)
%H: Like %h with creation date.
%i: Todo number.
%I: Todo number padded with spaces (always 3 characters wide).
%k: List of tags separated by spaces (excluding hidden tags).
%K: List of all tags separated by spaces.
%p: Priority.
%s: Todo text.
%S: Todo text, truncated such that an item fits on one line.
%t: Absolute creation date.
%T: Relative creation date.
%x: 'x' followed by absolute completion date.
%X: 'x' followed by relative completion date.
\%: Literal percent sign.
Conditional characters can be added with blocks surrounded by curly
braces, they will only appear when a placeholder expanded to a value.
E.g. %{(}p{)} will print (C) when the todo item has priority C, or ''
(empty string) when an item has no priority set.
A tab character serves as a marker to start right alignment.
-s : Sort the list according to a sort expression. Defaults to the expression
in the configuration.
-x : Show all todos (i.e. do not filter on dependencies or relevance).
......
......@@ -74,6 +74,7 @@ class _Config:
'hide_tags': 'id,p,ical',
'indent': '0',
'list_limit': '-1',
'list_format': '|%I| %x %{(}p{)} %c %s %k %{due:}d %{t:}t',
},
'tags': {
......@@ -115,7 +116,7 @@ class _Config:
self.config = {}
self.cp = configparser.ConfigParser()
self.cp = configparser.RawConfigParser()
for section in self.defaults:
self.cp.add_section(section)
......@@ -320,6 +321,11 @@ class _Config:
return alias_dict
def list_format(self):
""" Returns the list format used by `ls` """
return self.cp.get('ls', 'list_format')
def config(p_path=None, p_overrides=None):
"""
Retrieve the config instance.
......
# Topydo - A todo.txt client written in Python.
# Copyright (C) 2014 - 2015 Bram Schoenmakers <me@bramschoenmakers.nl>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
""" Utilities for formatting output with "list_format" option."""
import arrow
import re
from six import u
from topydo.lib.Config import config
from topydo.lib.Utils import get_terminal_size
MAIN_PATTERN = (r'^({{(?P<before>.+?)}})?'
r'(?P<placeholder>{ph}|\[{ph}\])'
r'({{(?P<after>.+?)}})?'
r'(?P<whitespace> *)')
def _columns():
""" Returns the number of columns of the terminal. """
return get_terminal_size().columns
def _filler(p_str, p_len):
"""
Returns p_str preceded by additional spaces if p_str is shorter than p_len.
"""
to_fill = p_len - len(p_str)
return to_fill*' ' + p_str
def humanize_date(p_datetime):
""" Returns a relative date string from a datetime object. """
now = arrow.now()
date = now.replace(day=p_datetime.day, month=p_datetime.month, year=p_datetime.year)
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()
dates_list.append('{} {}'.format(
'started' if p_start <= now else 'starts',
humanize_date(p_start)
))
return ', '.join(dates_list)
def _strip_placeholder_braces(p_matchobj):
"""
Returns string with conditional braces around placeholder stripped and
percent sign glued into placeholder character.
Returned string is composed from 'start', 'before', 'placeholder', 'after',
'whitespace', and 'end' match-groups of p_matchobj. Conditional braces are
stripped from 'before' and 'after' groups. 'whitespace', 'start', and 'end'
groups are preserved without any change.
Using this function as an 'repl' argument in re.sub it is possible to turn:
%{(}B{)}
into:
(%B)
"""
before = p_matchobj.group('before') or ''
placeholder = p_matchobj.group('placeholder')
after = p_matchobj.group('after') or ''
whitespace = p_matchobj.group('whitespace') or ''
return before + '%' + placeholder + after + whitespace
def _unescape_percent_sign(p_str):
""" Strips backslashes from escaped percent signs in p_str. """
unescaped_str = re.sub(r'\\%', '%', p_str)
return unescaped_str
def _remove_redundant_spaces(p_str):
""" Removes spaces surrunding <TAB> character (\t) from p_str. """
clean_str = re.sub(' *\t *', '\t', p_str)
return clean_str
def _truncate(p_str, p_repl):
"""
Returns p_str with truncated and ended with '...' version of p_repl.
Place of the truncation is calculated depending on p_max_width.
"""
# 4 is for '...' and an extra space at the end
text_lim = _columns() - len(p_str) - 4
truncated_str = re.sub(re.escape(p_repl), p_repl[:text_lim] + '...', p_str)
return truncated_str
def _right_align(p_str):
"""
Returns p_str with content after <TAB> character aligned right.
Right alignment is done using proper number of spaces calculated from
'line_width' attribute.
"""
to_fill = _columns() - len(p_str)
if to_fill > 0:
p_str = re.sub('\t', ' '*to_fill, p_str)
else:
p_str = re.sub('\t', ' ', p_str)
return p_str
class ListFormatParser(object):
""" Parser of format string. """
def __init__(self, p_todolist, p_format=None):
self.format_string = re.sub(r'\\t', '\t', p_format or config().list_format())
self.todolist = p_todolist
self.one_line = False
self.placeholders = {
# absolute creation date
'c': lambda t: t.creation_date().isoformat() if t.creation_date() else '',
# relative creation date
'C': lambda t: humanize_date(t.creation_date()) if t.creation_date() else '',
# absolute due date
'd': lambda t: t.due_date().isoformat() if t.due_date() else '',
# relative due date
'D': lambda t: humanize_date(t.due_date()) if t.due_date() else '',
# relative dates: due, start
'h': lambda t: humanize_dates(t.due_date(), t.start_date()),
# relative dates in form: creation, due, start
'H': lambda t: humanize_dates(t.due_date(), t.start_date(), t.creation_date()),
# todo ID
'i': lambda t: str(self.todolist.number(t)),
# todo ID pre-filled with 1 or 2 spaces if its length is <3
'I': lambda t: _filler(str(self.todolist.number(t)), 3),
# list of tags (spaces) without hidden ones and due: and t:
'k': lambda t: ' '.join([u('{}:{}').format(tag, value)
for tag, value in sorted(t.tags()) if
tag not in config().hidden_tags() +
[config().tag_start(), config().tag_due()]]),
# list of all tags (spaces)
'K': lambda t: ' '.join([u('{}:{}').format(tag, value)
for tag, value in sorted(t.tags())]),
# priority
'p': lambda t: t.priority() if t.priority() else '',
# text
's': lambda t: t.text(),
# text (truncated if necessary)
'S': lambda t: t.text(),
# absolute start date
't': lambda t: t.start_date().isoformat() if t.start_date() else '',
# relative start date
'T': lambda t: humanize_date(t.start_date()) if t.start_date() else '',
# absolute completion date
'x': lambda t: 'x ' + t.completion_date().isoformat() if t.is_completed() else '',
# relative completion date
'X': lambda t: 'x ' + humanize_date(t.completion_date()) if t.is_completed() else '',
}
self.format_list = self._preprocess_format()
def _preprocess_format(self):
"""
Preprocess the format_string attribute.
Splits the format string on each placeholder and returns a list of
tuples containing substring, placeholder name, and function
retrieving content for placeholder (getter).
Relevant placeholder functions (getters) are taken from
'placeholders' attribute which is a dict. If no matching placeholder
is found in 'placeholders' getter is set to None. Getter and
placeholder are also always set to None in first element of the
returned list, because it never contain a real placeholder (read
re.split documentation for further information).
"""
format_split = re.split(r'(?<!\\)%', self.format_string)
preprocessed_format = []
for idx, substr in enumerate(format_split):
if idx == 0:
getter = None
placeholder = None
else:
pattern = MAIN_PATTERN.format(ph=r'\S')
try:
placeholder = re.match(pattern, substr).group('placeholder').strip('[]')
except AttributeError:
placeholder = None
if placeholder == 'S':
self.one_line = True
try:
getter = self.placeholders[placeholder]
except KeyError:
getter = None
substr = re.sub(pattern, '', substr)
format_elem = (substr, placeholder, getter)
preprocessed_format.append(format_elem)
return preprocessed_format
def parse(self, p_todo):
"""
Returns fully parsed string from 'format_string' attribute with all
placeholders properly substituted by content obtained from p_todo.
It uses preprocessed form of 'format_string' (result of
ListFormatParser._preprocess_format) stored in 'format_list'
attribute.
"""
parsed_list = []
repl_trunc = None
for substr, placeholder, getter in self.format_list:
repl = getter(p_todo) if getter else ''
pattern = MAIN_PATTERN.format(ph=placeholder)
if placeholder == 'S':
repl_trunc = repl
if repl == '':
substr = re.sub(pattern, '', substr)
else:
substr = re.sub(pattern, _strip_placeholder_braces, substr)
substr = re.sub(r'(?<!\\)%({ph}|\[{ph}\])'.format(ph=placeholder), repl, substr)
parsed_list.append(substr)
parsed_str = _unescape_percent_sign(''.join(parsed_list))
parsed_str = _remove_redundant_spaces(parsed_str)
if self.one_line and len(parsed_str) >= _columns():
parsed_str = _truncate(parsed_str, repl_trunc)
if re.search('.*\t', parsed_str):
parsed_str = _right_align(parsed_str)
return parsed_str.rstrip()
......@@ -18,10 +18,13 @@
import re
from collections import OrderedDict
from six import u
from topydo.lib.Colors import NEUTRAL_COLOR, Colors
from topydo.lib.Config import config
from topydo.lib.ListFormat import ListFormatParser
from topydo.lib.Utils import get_terminal_size
class PrettyPrinterFilter(object):
......@@ -61,9 +64,6 @@ class PrettyPrinterColorFilter(PrettyPrinterFilter):
except KeyError:
pass
# color by priority
p_todo_str = color + p_todo_str
# color projects / contexts
p_todo_str = re.sub(
r'\B(\+|@)(\S*\w)',
......@@ -79,26 +79,17 @@ class PrettyPrinterColorFilter(PrettyPrinterFilter):
# add link_color to any valid URL specified outside of the tag.
p_todo_str = re.sub(r'(^|\s)(\w+:){1}(//\S+)',
' ' + link_color + r'\2\3' + color,
r'\1' + link_color + r'\2\3' + color,
p_todo_str)
p_todo_str += NEUTRAL_COLOR
# color by priority
p_todo_str = color + p_todo_str
return p_todo_str
class PrettyPrinterIndentFilter(PrettyPrinterFilter):
""" Adds indentation to the todo item. """
def __init__(self, p_indent=0):
super(PrettyPrinterIndentFilter, self).__init__()
self.indent = p_indent
def filter(self, p_todo_str, _):
""" Applies the indentation. """
return ' ' * self.indent + p_todo_str
class PrettyPrinterNumbers(PrettyPrinterFilter):
""" Prepends the todo's number, retrieved from the todolist. """
......@@ -111,17 +102,12 @@ class PrettyPrinterNumbers(PrettyPrinterFilter):
return u("|{:>3}| {}").format(self.todolist.number(p_todo), p_todo_str)
class PrettyPrinterHideTagFilter(PrettyPrinterFilter):
""" Removes all occurrences of the given tags from the text. """
def __init__(self, p_hidden_tags):
super(PrettyPrinterHideTagFilter, self).__init__()
self.hidden_tags = p_hidden_tags
class PrettyPrinterFormatFilter(PrettyPrinterFilter):
def __init__(self, p_todolist, p_format=None):
super(PrettyPrinterFormatFilter, self).__init__()
self.parser = ListFormatParser(p_todolist, p_format)
def filter(self, p_todo_str, _):
for hidden_tag in self.hidden_tags:
# inspired from remove_tag in TodoBase
p_todo_str = re.sub(r'\s?\b' + hidden_tag + r':\S+\b', '',
p_todo_str)
def filter(self, p_todo_str, p_todo):
p_todo_str = self.parser.parse(p_todo)
return p_todo_str
......@@ -19,6 +19,8 @@ Various utility functions.
"""
import re
from collections import namedtuple
from datetime import date
......@@ -51,3 +53,25 @@ def escape_ansi(p_string):
return escape_ansi.pattern.sub('', p_string)
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