Commit 211d1277 authored by Bram Schoenmakers's avatar Bram Schoenmakers

Add 'tag' subcommand.

parent 671c2aee
......@@ -35,6 +35,7 @@ from ListProjectCommand import ListProjectCommand
from PrettyPrinter import *
from PriorityCommand import PriorityCommand
from SortCommand import SortCommand
from TagCommand import TagCommand
import TodoFile
import TodoList
from Utils import escape_ansi
......@@ -121,6 +122,7 @@ class CLIApplication(object):
'pri': PriorityCommand,
'rm': DeleteCommand,
'sort': SortCommand,
'tag': TagCommand,
}
args = arguments()
......
# Topydo - A todo.txt client written in Python.
# Copyright (C) 2014 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/>.
from Command import *
import TodoList
from PrettyPrinter import pretty_print
from Utils import convert_todo_number, InvalidTodoNumberException
class TagCommand(Command):
def __init__(self, p_args, p_todolist,
p_out=lambda a: None,
p_err=lambda a: None,
p_prompt=lambda a: None):
super(TagCommand, self).__init__(p_args, p_todolist, p_out, p_err, p_prompt)
self.subsubcommand = None
self.todo = None
self.tag = None
self.value = None
self.values = []
try:
self.subsubcommand = self.argument(0)
number = convert_todo_number(self.argument(1))
self.todo = self.todolist.todo(number)
self.tag = self.argument(2)
self.current_values = self.todo.tag_values(self.tag)
self.value = self.argument(3)
except (InvalidCommandArgument, InvalidTodoNumberException, TodoList.InvalidTodoException):
pass
def _print(self):
self.out(pretty_print(self.todo, [self.todolist.pp_number()]))
def _choose(self):
"""
Returns the chosen number of the tag value to process (or "all")
"""
for i, value in enumerate(self.current_values):
self.out("%2d. %s" % (i + 1, value))
answer = self.prompt('Which value to remove? Enter number or "all": ')
if answer != "all":
try:
answer = int(answer) - 1
if answer < 0 or answer >= len(self.current_values):
answer = None
except ValueError:
answer = None
return answer
def _add(self):
self._set(True)
def _set_helper(self, p_force, p_old_value=""):
old_src = self.todo.source()
self.todo.set_tag(self.tag, self.value, p_force, p_old_value)
if old_src != self.todo.source():
self.todolist.set_dirty()
def _set(self, p_force_add=False):
if self.value == None:
self.error("Missing value for tag.")
self.error(self.usage())
else:
if len(self.current_values) > 1:
answer = self._choose()
if answer == "all":
for value in self.current_values:
self._set_helper(False, value)
elif answer != None and self.value != self.current_values[answer]:
self._set_helper(False, self.current_values[answer])
else: # if not self.todo.has_tag(self.tag, self.value):
self._set_helper(p_force_add)
self._print()
def _rm(self):
self.value = ""
self._set()
def execute(self):
if not super(TagCommand, self).execute():
return False
dispatch = {
"add": self._add,
"set": self._set,
"del": self._rm,
"rm": self._rm,
}
if self.subsubcommand in dispatch and self.todo and self.tag:
dispatch[self.subsubcommand]()
elif self.subsubcommand not in dispatch:
self.error(self.usage())
elif not self.todo:
self.error("Invalid todo number.")
def usage(self):
return """Synopsis:
tag (add|set) <NUMBER> <tag> <value>
tag rm <NUMBER> <tag> [value]"""
def help(self):
return """* add: Add a tag to the given todo.
* set: Changes a tag of the given todo.
* rm: Removes a tag from the given todo."""
......@@ -301,6 +301,9 @@ class TodoList(object):
def is_dirty(self):
return self.dirty
def set_dirty(self):
self.dirty = True
def todos(self):
return self._todos
......
# Topydo - A todo.txt client written in Python.
# Copyright (C) 2014 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 CommandTest
import TagCommand
import TodoList
class TagCommandTest(CommandTest.CommandTest):
def setUp(self):
todos = [
"Foo",
"Bar due:2014-10-22",
"Baz due:2014-10-20",
"Fnord due:2014-10-20 due:2014-10-22",
]
self.todolist = TodoList.TodoList(todos)
def test_add_tag1(self):
command = TagCommand.TagCommand(["add", "1", "due", "2014-10-22"], self.todolist, self.out, self.error)
command.execute()
self.assertEquals(self.todolist.todo(1).source(), "Foo due:2014-10-22")
self.assertEquals(self.output, " 1 Foo due:2014-10-22\n")
self.assertEquals(self.errors, "")
self.assertTrue(self.todolist.is_dirty())
def test_add_tag2(self):
command = TagCommand.TagCommand(["add", "1", "due"], self.todolist, self.out, self.error)
command.execute()
self.assertEquals(self.output, "")
self.assertEquals(self.errors, "Missing value for tag.\n" + command.usage() + "\n")
self.assertFalse(self.todolist.is_dirty())
def test_add_tag3(self):
command = TagCommand.TagCommand(["add", "2", "due", "2014-10-19"], self.todolist, self.out, self.error)
command.execute()
self.assertEquals(self.todolist.todo(2).source(), "Bar due:2014-10-22 due:2014-10-19")
self.assertEquals(self.output, " 2 Bar due:2014-10-22 due:2014-10-19\n")
self.assertEquals(self.errors, "")
self.assertTrue(self.todolist.is_dirty())
def test_add_tag4(self):
command = TagCommand.TagCommand(["add", "1", "due"], self.todolist, self.out, self.error)
command.execute()
self.assertEquals(self.output, "")
self.assertEquals(self.errors, "Missing value for tag.\n" + command.usage() + "\n")
self.assertFalse(self.todolist.is_dirty())
def test_set_tag1(self):
command = TagCommand.TagCommand(["set", "1", "due", "2014-10-22"], self.todolist, self.out, self.error)
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertEquals(self.output, " 1 Foo due:2014-10-22\n")
self.assertEquals(self.errors, "")
def test_set_tag2(self):
command = TagCommand.TagCommand(["set", "1", "due"], self.todolist, self.out, self.error)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertEquals(self.output, "")
self.assertEquals(self.errors, "Missing value for tag.\n" + command.usage() + "\n")
def test_set_tag3(self):
command = TagCommand.TagCommand(["set", "2", "due", "2014-10-20"], self.todolist, self.out, self.error)
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertEquals(self.output, " 2 Bar due:2014-10-20\n")
self.assertEquals(self.errors, "")
def test_set_tag4(self):
command = TagCommand.TagCommand(["set", "3", "due", "2014-10-20"], self.todolist, self.out, self.error)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertEquals(self.output, " 3 Baz due:2014-10-20\n")
self.assertEquals(self.errors, "")
def test_set_tag5(self):
command = TagCommand.TagCommand(["set", "4", "due", "2014-10-20"], self.todolist, self.out, self.error, lambda t: "all")
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertEquals(self.output, " 1. 2014-10-20\n 2. 2014-10-22\n 4 Fnord due:2014-10-20 due:2014-10-20\n")
self.assertEquals(self.errors, "")
def test_set_tag6(self):
command = TagCommand.TagCommand(["set", "4", "due", "2014-10-20"], self.todolist, self.out, self.error, lambda t: "1")
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertEquals(self.output, " 1. 2014-10-20\n 2. 2014-10-22\n 4 Fnord due:2014-10-20 due:2014-10-22\n")
self.assertEquals(self.errors, "")
def test_set_tag7(self):
command = TagCommand.TagCommand(["set", "4", "due", "2014-10-20"], self.todolist, self.out, self.error, lambda t: "2")
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertEquals(self.output, " 1. 2014-10-20\n 2. 2014-10-22\n 4 Fnord due:2014-10-20 due:2014-10-20\n")
self.assertEquals(self.errors, "")
def test_set_tag8(self):
command = TagCommand.TagCommand(["set", "4", "due", "2014-10-20"], self.todolist, self.out, self.error, lambda t: "")
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertEquals(self.output, " 1. 2014-10-20\n 2. 2014-10-22\n 4 Fnord due:2014-10-20 due:2014-10-22\n")
self.assertEquals(self.errors, "")
def test_set_tag9(self):
command = TagCommand.TagCommand(["set", "4", "due", "2014-10-20"], self.todolist, self.out, self.error, lambda t: "99")
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertEquals(self.output, " 1. 2014-10-20\n 2. 2014-10-22\n 4 Fnord due:2014-10-20 due:2014-10-22\n")
self.assertEquals(self.errors, "")
def test_rm_tag1(self):
command = TagCommand.TagCommand(["rm", "1", "due"], self.todolist, self.out, self.error)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertEquals(self.output, " 1 Foo\n")
self.assertEquals(self.errors, "")
def test_rm_tag2(self):
command = TagCommand.TagCommand(["rm", "2", "due"], self.todolist, self.out, self.error)
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertEquals(self.output, " 2 Bar\n")
self.assertEquals(self.errors, "")
def test_rm_tag3(self):
command = TagCommand.TagCommand(["rm", "4", "due"], self.todolist, self.out, self.error, lambda t: "all")
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertEquals(self.output, " 1. 2014-10-20\n 2. 2014-10-22\n 4 Fnord\n")
self.assertEquals(self.errors, "")
def test_rm_tag4(self):
command = TagCommand.TagCommand(["rm", "4", "due"], self.todolist, self.out, self.error, lambda t: "1")
command.execute()
self.assertTrue(self.todolist.is_dirty())
self.assertEquals(self.output, " 1. 2014-10-20\n 2. 2014-10-22\n 4 Fnord due:2014-10-22\n")
self.assertEquals(self.errors, "")
def test_rm_tag6(self):
command = TagCommand.TagCommand(["rm", "4", "due"], self.todolist, self.out, self.error, lambda t: "99")
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertEquals(self.output, " 1. 2014-10-20\n 2. 2014-10-22\n 4 Fnord due:2014-10-20 due:2014-10-22\n")
self.assertEquals(self.errors, "")
def test_rm_tag7(self):
command = TagCommand.TagCommand(["rm", "4", "due"], self.todolist, self.out, self.error, lambda t: "A")
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertEquals(self.output, " 1. 2014-10-20\n 2. 2014-10-22\n 4 Fnord due:2014-10-20 due:2014-10-22\n")
self.assertEquals(self.errors, "")
def test_rm_tag8(self):
command = TagCommand.TagCommand(["rm", "5", "due"], self.todolist, self.out, self.error)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertEquals(self.output, "")
self.assertEquals(self.errors, "Invalid todo number.\n")
def test_rm_tag9(self):
command = TagCommand.TagCommand(["rm", "A", "due"], self.todolist, self.out, self.error)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertEquals(self.output, "")
self.assertEquals(self.errors, "Invalid todo number.\n")
def test_invalid_subsubcommand(self):
command = TagCommand.TagCommand(["foo", "bar"], self.todolist, self.out, self.error)
command.execute()
self.assertFalse(self.todolist.is_dirty())
self.assertEquals(self.output, "")
self.assertEquals(self.errors, command.usage() + "\n")
def test_help(self):
command = TagCommand.TagCommand(["help"], self.todolist, self.out, self.error)
command.execute()
self.assertEquals(self.output, "")
self.assertEquals(self.errors, command.usage() + "\n\n" + command.help() + "\n")
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