Commit 0d2cedd8 authored by Jacek Sowiński's avatar Jacek Sowiński

Expression-mode for del, depri, do, pri, postpone.

This required some refactoring in MultiCommand and ExpressionCommand.

Whole part about processing flags was refactored. Code related to flags
from DCommand was moved into MultiCommand and reused from there in all
"multi" commands.

New attribute: ExpressionCommand.last_argument. Should be set to True if
command is using the last argument as something other than todo ID or
part of an expression (as in case of postpone or pri). By default set to
False.

New method: MultiCommand.execute_not_multi(): wrapper for functionality
not connected with todo IDs (like `topydo edit` or `topydo edit -d`).

New attribute: MultiCommand.multi_mode: Should be set to True if user
wants to operate on multiple todo items. True by default.

New method: MultiCommand.get_todos_from_expr(): gets todo IDs based on
expression and puts it in MultiCommand.todos.

EditCommand._open_in_editor() now accepts only one argument - file to
editing. It handles now also OSError exceptions. It is used also to
opening todo.txt and done.txt.

MultiCommand.get_todos() doesn't accept anymore todo IDs as an argument.
Instead it's using inherited Expression.last_argument` to decide upon
where to find todo IDs.
parent b9615d52
......@@ -25,8 +25,6 @@ class DepriCommand(MultiCommand):
super(DepriCommand, self).__init__(
p_args, p_todolist, p_out, p_err, p_prompt)
self.get_todos(self.args)
def execute_multi_specific(self):
try:
self.printer.add_filter(PrettyPrinterNumbers(self.todolist))
......
......@@ -36,9 +36,13 @@ class DoCommand(DCommand):
def get_flags(self):
""" Additional flags. """
return ("d:s", ["date=", "strict"])
opts, long_opts = super(DoCommand, self).get_flags()
return ("d:s" + opts, ["date=", "strict"] + long_opts)
def process_flag(self, p_opt, p_value):
super(DoCommand, self).process_flag(p_opt, p_value)
if p_opt == "-s" or p_opt == "--strict":
self.strict_recurrence = True
elif p_opt == "-d" or p_opt == "--date":
......
......@@ -34,26 +34,25 @@ DEFAULT_EDITOR = 'vi'
# cannot use super() inside the class itself
BASE_TODOLIST = lambda tl: super(TodoList, tl)
class EditCommand(MultiCommand, ExpressionCommand):
class EditCommand(MultiCommand):
def __init__(self, p_args, p_todolist, p_output, p_error, p_input):
super(EditCommand, self).__init__(p_args, p_todolist, p_output,
p_error, p_input)
if len(self.args) == 0:
self.multi_mode = False
self.is_expression = False
self.edit_archive = False
self.last_argument = False
def _process_flags(self):
opts, args = self.getopt('xed')
for opt, value in opts:
if opt == '-d':
self.edit_archive = True
elif opt == '-x':
self.show_all = True
elif opt == '-e':
self.is_expression = True
def get_flags(self):
return ("d", [])
self.args = args
def process_flag(self, p_opt, p_value):
if p_opt == '-d':
self.edit_archive = True
self.multi_mode = False
def _todos_to_temp(self):
f = tempfile.NamedTemporaryFile()
......@@ -102,51 +101,35 @@ class EditCommand(MultiCommand, ExpressionCommand):
else:
return None
def execute(self):
if not super(EditCommand, self).execute():
return False
def execute_multi_specific(self):
self.printer.add_filter(PrettyPrinterNumbers(self.todolist))
if len(self.args) < 1:
todo = config().todotxt()
temp_todos = self._todos_to_temp()
return self._open_in_editor(todo) == 0
if not self._open_in_editor(temp_todos.name):
new_todos = self._todos_from_temp(temp_todos)
if len(new_todos) == len(self.todos):
for todo in self.todos:
BASE_TODOLIST(self.todolist).delete(todo)
for todo in new_todos:
self.todolist.add_todo(todo)
self.out(self.printer.print_todo(todo))
else:
self.error('Number of edited todos is not equal to '
'number of supplied todo IDs.')
else:
self._process_flags()
self.error(self.usage())
if self.edit_archive:
archive = config().archive()
def execute_not_multi(self):
if self.edit_archive:
archive = config().archive()
return self._open_in_editor(archive) == 0
return self._open_in_editor(archive) == 0
else:
todo = config().todotxt()
if self.is_expression:
self.todos = self._view().todos
else:
self.get_todos(self.args)
todo_errors = self._catch_todo_errors()
if not todo_errors:
temp_todos = self._todos_to_temp()
if not self._open_in_editor(temp_todos):
new_todos = self._todos_from_temp(temp_todos)
if len(new_todos) == len(self.todos):
for todo in self.todos:
BASE_TODOLIST(self.todolist).delete(todo)
for todo in new_todos:
self.todolist.add_todo(todo)
self.out(self.printer.print_todo(todo))
else:
self.error('Number of edited todos is not equal to '
'number of supplied todo IDs.')
else:
self.error(self.usage())
else:
for error in todo_errors:
self.error(error)
return self._open_in_editor(todo) == 0
def usage(self):
return """Synopsis:
......
......@@ -32,17 +32,14 @@ class PostponeCommand(MultiCommand):
p_args, p_todolist, p_out, p_err, p_prompt)
self.move_start_date = False
self._process_flags()
self.get_todos(self.args[:-1])
self.last_argument = True
def _process_flags(self):
opts, args = self.getopt('s')
def get_flags(self):
return("s", [])
for opt, _ in opts:
if opt == '-s':
self.move_start_date = True
self.args = args
def process_flag(self, p_opt, p_value):
if p_opt == '-s':
self.move_start_date = True
def execute_multi_specific(self):
def _get_offset(p_todo):
......
......@@ -26,7 +26,7 @@ class PriorityCommand(MultiCommand):
super(PriorityCommand, self).__init__(
p_args, p_todolist, p_out, p_err, p_prompt)
self.get_todos(self.args[:-1])
self.last_argument = True
def execute_multi_specific(self):
priority = None
......
......@@ -35,29 +35,14 @@ class DCommand(MultiCommand):
self.force = False
self.process_flags()
self.length = len(self.todolist.todos()) # to determine newly activated todos
self.get_todos(self.args)
def get_flags(self):
""" Default implementation of getting specific flags. """
return ("", [])
return ("f", ["force"])
def process_flag(self, p_option, p_value):
""" Default implementation of processing specific flags. """
pass
def process_flags(self):
opts, long_opts = self.get_flags()
opts, args = self.getopt("f" + opts, ["force"] + long_opts)
for opt, value in opts:
if opt == "-f" or opt == "--force":
self.force = True
else:
self.process_flag(opt, value)
self.args = args
def process_flag(self, p_opt, p_value):
if p_opt == "-f" or p_opt == "--force":
self.force = True
def _uncompleted_children(self, p_todo):
return sorted(
......
......@@ -35,13 +35,22 @@ class ExpressionCommand(Command):
self.sort_expression = config().sort_string()
self.show_all = False
# Commands using last argument differently (i.e as something other than
# todo ID/expression) have to set attribute below to True.
self.last_argument = False
def _filters(self):
filters = []
def arg_filters():
result = []
for arg in self.args:
if self.last_argument:
args = self.args[:-1]
else:
args = self.args
for arg in args:
if re.match(Filter.ORDINAL_TAG_MATCH, arg):
argfilter = Filter.OrdinalTagFilter(arg)
elif len(arg) > 1 and arg[0] == '-':
......
......@@ -16,10 +16,10 @@
from six import u
from topydo.lib.Command import Command
from topydo.lib.ExpressionCommand import ExpressionCommand
from topydo.lib.TodoListBase import InvalidTodoException
class MultiCommand(Command):
class MultiCommand(ExpressionCommand):
"""
A common class for operations that can work with multiple todo IDs.
"""
......@@ -33,14 +33,49 @@ class MultiCommand(Command):
self.todos = []
self.invalid_numbers = []
self.is_expression = False
self.multi_mode = True
def get_todos(self, p_numbers):
def get_flags(self):
""" Default implementation of getting specific flags. """
return ("", [])
def process_flag(self, p_option, p_value):
""" Default implementation of processing specific flags. """
pass
def _process_flags(self):
opts, long_opts = self.get_flags()
opts, args = self.getopt("xe" + opts, long_opts)
for opt, value in opts:
if opt == '-x':
self.show_all = True
elif opt == '-e':
self.is_expression = True
else:
self.process_flag(opt, value)
self.args = args
def get_todos_from_expr(self):
self.todos = self._view().todos
def get_todos(self):
""" Gets todo objects from supplied todo IDs """
for number in p_numbers:
try:
self.todos.append(self.todolist.todo(number))
except InvalidTodoException:
self.invalid_numbers.append(number)
if self.is_expression:
self.get_todos_from_expr()
else:
if self.last_argument:
numbers = self.args[:-1]
else:
numbers = self.args
for number in numbers:
try:
self.todos.append(self.todolist.todo(number))
except InvalidTodoException:
self.invalid_numbers.append(number)
def _catch_todo_errors(self):
"""
......@@ -72,16 +107,29 @@ class MultiCommand(Command):
"""
pass
def execute_not_multi(self):
"""
Some commands can do something else besides operating on multiple todo
IDs. This method is a wrapper for those other operations.
"""
pass
def execute(self):
if not super(MultiCommand, self).execute():
return False
todo_errors = self._catch_todo_errors()
self._process_flags()
if not todo_errors:
self.execute_multi_specific()
if not self.multi_mode:
self.execute_not_multi()
else:
for error in todo_errors:
self.error(error)
self.get_todos()
todo_errors = self._catch_todo_errors()
if not todo_errors:
self.execute_multi_specific()
else:
for error in todo_errors:
self.error(error)
return True
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