Commit 09208067 authored by Kirill Smelkov's avatar Kirill Smelkov

edit: Don't move modified todo items to the end of file

Before this patch a `t edit ...` will remove todo items selected by
`...` and then do equivalent of `t add` with input from result of
editing. This works, but has the property that whenever a todo item is
edited, it is always moved till the end of todo.txt file.

This property creates noise and makes synchronization harder to implement for
some of us who uses VCS and different machines to maintain todo.txt .

-> Teach edit to preserve todo items in their places. Adjust existing
tests and add a couple more exercising cases where either new todo
items are added in the editor, or vice versa, removed in the editor.

/cc @mruwek
parent b59fcfca
......@@ -58,7 +58,7 @@ class EditCommandTest(CommandTest):
self.assertEqual(self.errors, "")
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.todolist.print_todos(), u"Bar p:1 @test\nBaz @test\nFo\u00f3B\u0105\u017a\nFoo id:1")
self.assertEqual(self.todolist.print_todos(), u"Foo id:1\nBar p:1 @test\nBaz @test\nFo\u00f3B\u0105\u017a")
@mock.patch('topydo.commands.EditCommand._is_edited')
@mock.patch('topydo.commands.EditCommand.EditCommand._todos_from_temp')
......@@ -75,7 +75,7 @@ class EditCommandTest(CommandTest):
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.errors, "")
self.assertEqual(self.todolist.print_todos(), u"Foo id:1\nBaz @test\nFo\u00f3B\u0105\u017a\nLazy Cat")
self.assertEqual(self.todolist.print_todos(), u"Foo id:1\nLazy Cat\nBaz @test\nFo\u00f3B\u0105\u017a")
def test_edit03(self):
""" Throw an error after invalid todo number given as argument. """
......@@ -156,12 +156,49 @@ class EditCommandTest(CommandTest):
self.error, None)
command.execute()
expected = u"| 3| Lazy Cat\n| 4| Lazy Dog\n"
expected = u"| 2| Lazy Cat\n| 3| Lazy Dog\n"
self.assertEqual(self.errors, "")
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.output, expected)
self.assertEqual(self.todolist.print_todos(), u"Foo id:1\nFo\u00f3B\u0105\u017a\nLazy Cat\nLazy Dog")
self.assertEqual(self.todolist.print_todos(), u"Foo id:1\nLazy Cat\nLazy Dog\nFo\u00f3B\u0105\u017a")
@mock.patch('topydo.commands.EditCommand._is_edited')
@mock.patch('topydo.commands.EditCommand.EditCommand._todos_from_temp')
@mock.patch('topydo.commands.EditCommand.EditCommand._open_in_editor')
def test_edit_addnew(self, mock_open_in_editor, mock_todos_from_temp, mock_is_edited):
""" New todos are added in the process of editing. """
mock_open_in_editor.return_value = 0
mock_todos_from_temp.return_value = [Todo('Bar (edited)'),
Todo('New1'),
Todo('New 2')]
mock_is_edited.return_value = True
command = EditCommand(["2"], self.todolist, self.out, self.error, None)
command.execute()
self.assertEqual(self.errors, "")
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.todolist.print_todos(), u"Foo id:1\nBar (edited)\nBaz @test\nFo\u00f3B\u0105\u017a\nNew1\nNew 2")
@mock.patch('topydo.commands.EditCommand._is_edited')
@mock.patch('topydo.commands.EditCommand.EditCommand._todos_from_temp')
@mock.patch('topydo.commands.EditCommand.EditCommand._open_in_editor')
def test_edit_remove(self, mock_open_in_editor, mock_todos_from_temp, mock_is_edited):
""" Some todos are removed in the process of editing. """
mock_open_in_editor.return_value = 0
mock_todos_from_temp.return_value = [Todo('Foo (edited)')]
mock_is_edited.return_value = True
command = EditCommand(["1", "2"], self.todolist, self.out, self.error, None)
command.execute()
self.assertEqual(self.errors, "")
self.assertTrue(self.todolist.dirty)
self.assertEqual(self.todolist.print_todos(), u"Foo (edited)\nBaz @test\nFo\u00f3B\u0105\u017a")
@mock.patch.dict(os.environ, {'EDITOR': 'vi'})
@mock.patch('topydo.commands.EditCommand.check_call')
......
......@@ -117,10 +117,15 @@ class EditCommand(MultiCommand):
new_todos = EditCommand._todos_from_temp(temp_todos)
if _is_edited(orig_mtime, temp_todos):
for todo in self.todos:
modified = list(zip(self.todos, new_todos))
for (todo, new_todo) in modified:
self.todolist.modify_todo(todo, new_todo.src)
self.out(self.printer.print_todo(todo))
for todo in self.todos[len(modified):]:
self.todolist.delete(todo, p_leave_tags=True)
for todo in new_todos:
for todo in new_todos[len(modified):]:
self.todolist.add_todo(todo)
self.out(self.printer.print_todo(todo))
else:
......
......@@ -173,6 +173,13 @@ class TodoListBase(object):
# todo item couldn't be found, ignore
pass
def modify_todo(self, p_todo, p_new_source):
""" Modify source of a Todo item from the list. """
assert p_todo in self._todos
p_todo.set_source_text(p_new_source)
self._update_todo_ids()
self.dirty = True
def erase(self):
""" Erases all todos from the list. """
self._todos = []
......
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