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): ...@@ -25,8 +25,6 @@ class DepriCommand(MultiCommand):
super(DepriCommand, self).__init__( super(DepriCommand, self).__init__(
p_args, p_todolist, p_out, p_err, p_prompt) p_args, p_todolist, p_out, p_err, p_prompt)
self.get_todos(self.args)
def execute_multi_specific(self): def execute_multi_specific(self):
try: try:
self.printer.add_filter(PrettyPrinterNumbers(self.todolist)) self.printer.add_filter(PrettyPrinterNumbers(self.todolist))
......
...@@ -36,9 +36,13 @@ class DoCommand(DCommand): ...@@ -36,9 +36,13 @@ class DoCommand(DCommand):
def get_flags(self): def get_flags(self):
""" Additional flags. """ """ 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): 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": if p_opt == "-s" or p_opt == "--strict":
self.strict_recurrence = True self.strict_recurrence = True
elif p_opt == "-d" or p_opt == "--date": elif p_opt == "-d" or p_opt == "--date":
......
...@@ -34,26 +34,25 @@ DEFAULT_EDITOR = 'vi' ...@@ -34,26 +34,25 @@ DEFAULT_EDITOR = 'vi'
# cannot use super() inside the class itself # cannot use super() inside the class itself
BASE_TODOLIST = lambda tl: super(TodoList, tl) 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): def __init__(self, p_args, p_todolist, p_output, p_error, p_input):
super(EditCommand, self).__init__(p_args, p_todolist, p_output, super(EditCommand, self).__init__(p_args, p_todolist, p_output,
p_error, p_input) p_error, p_input)
if len(self.args) == 0:
self.multi_mode = False
self.is_expression = False self.is_expression = False
self.edit_archive = False self.edit_archive = False
self.last_argument = False
def _process_flags(self): def get_flags(self):
opts, args = self.getopt('xed') return ("d", [])
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
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): def _todos_to_temp(self):
f = tempfile.NamedTemporaryFile() f = tempfile.NamedTemporaryFile()
...@@ -102,51 +101,35 @@ class EditCommand(MultiCommand, ExpressionCommand): ...@@ -102,51 +101,35 @@ class EditCommand(MultiCommand, ExpressionCommand):
else: else:
return None return None
def execute(self): def execute_multi_specific(self):
if not super(EditCommand, self).execute():
return False
self.printer.add_filter(PrettyPrinterNumbers(self.todolist)) self.printer.add_filter(PrettyPrinterNumbers(self.todolist))
if len(self.args) < 1: temp_todos = self._todos_to_temp()
todo = config().todotxt()
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: else:
self._process_flags() self.error(self.usage())
if self.edit_archive: def execute_not_multi(self):
archive = config().archive() 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: return self._open_in_editor(todo) == 0
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)
def usage(self): def usage(self):
return """Synopsis: return """Synopsis:
......
...@@ -32,17 +32,14 @@ class PostponeCommand(MultiCommand): ...@@ -32,17 +32,14 @@ class PostponeCommand(MultiCommand):
p_args, p_todolist, p_out, p_err, p_prompt) p_args, p_todolist, p_out, p_err, p_prompt)
self.move_start_date = False self.move_start_date = False
self._process_flags() self.last_argument = True
self.get_todos(self.args[:-1])
def _process_flags(self): def get_flags(self):
opts, args = self.getopt('s') return("s", [])
for opt, _ in opts: def process_flag(self, p_opt, p_value):
if opt == '-s': if p_opt == '-s':
self.move_start_date = True self.move_start_date = True
self.args = args
def execute_multi_specific(self): def execute_multi_specific(self):
def _get_offset(p_todo): def _get_offset(p_todo):
......
...@@ -26,7 +26,7 @@ class PriorityCommand(MultiCommand): ...@@ -26,7 +26,7 @@ class PriorityCommand(MultiCommand):
super(PriorityCommand, self).__init__( super(PriorityCommand, self).__init__(
p_args, p_todolist, p_out, p_err, p_prompt) 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): def execute_multi_specific(self):
priority = None priority = None
......
...@@ -35,29 +35,14 @@ class DCommand(MultiCommand): ...@@ -35,29 +35,14 @@ class DCommand(MultiCommand):
self.force = False self.force = False
self.process_flags()
self.length = len(self.todolist.todos()) # to determine newly activated todos self.length = len(self.todolist.todos()) # to determine newly activated todos
self.get_todos(self.args)
def get_flags(self): def get_flags(self):
""" Default implementation of getting specific flags. """ return ("f", ["force"])
return ("", [])
def process_flag(self, p_option, p_value): def process_flag(self, p_opt, p_value):
""" Default implementation of processing specific flags. """ if p_opt == "-f" or p_opt == "--force":
pass self.force = True
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 _uncompleted_children(self, p_todo): def _uncompleted_children(self, p_todo):
return sorted( return sorted(
......
...@@ -35,13 +35,22 @@ class ExpressionCommand(Command): ...@@ -35,13 +35,22 @@ class ExpressionCommand(Command):
self.sort_expression = config().sort_string() self.sort_expression = config().sort_string()
self.show_all = False 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): def _filters(self):
filters = [] filters = []
def arg_filters(): def arg_filters():
result = [] 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): if re.match(Filter.ORDINAL_TAG_MATCH, arg):
argfilter = Filter.OrdinalTagFilter(arg) argfilter = Filter.OrdinalTagFilter(arg)
elif len(arg) > 1 and arg[0] == '-': elif len(arg) > 1 and arg[0] == '-':
......
...@@ -16,10 +16,10 @@ ...@@ -16,10 +16,10 @@
from six import u from six import u
from topydo.lib.Command import Command from topydo.lib.ExpressionCommand import ExpressionCommand
from topydo.lib.TodoListBase import InvalidTodoException from topydo.lib.TodoListBase import InvalidTodoException
class MultiCommand(Command): class MultiCommand(ExpressionCommand):
""" """
A common class for operations that can work with multiple todo IDs. A common class for operations that can work with multiple todo IDs.
""" """
...@@ -33,14 +33,49 @@ class MultiCommand(Command): ...@@ -33,14 +33,49 @@ class MultiCommand(Command):
self.todos = [] self.todos = []
self.invalid_numbers = [] 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 """ """ Gets todo objects from supplied todo IDs """
for number in p_numbers: if self.is_expression:
try: self.get_todos_from_expr()
self.todos.append(self.todolist.todo(number)) else:
except InvalidTodoException: if self.last_argument:
self.invalid_numbers.append(number) 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): def _catch_todo_errors(self):
""" """
...@@ -72,16 +107,29 @@ class MultiCommand(Command): ...@@ -72,16 +107,29 @@ class MultiCommand(Command):
""" """
pass 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): def execute(self):
if not super(MultiCommand, self).execute(): if not super(MultiCommand, self).execute():
return False return False
todo_errors = self._catch_todo_errors() self._process_flags()
if not todo_errors: if not self.multi_mode:
self.execute_multi_specific() self.execute_not_multi()
else: else:
for error in todo_errors: self.get_todos()
self.error(error) 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 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