Commit a414f07d authored by Bram Schoenmakers's avatar Bram Schoenmakers

Merge branch 'master' into groups

parents 3bb55c37 c9e1cd0d
......@@ -4,3 +4,5 @@ project_color =
context_color =
link_color =
metadata_color =
focus_background_color =
marked_background_color =
......@@ -24,3 +24,5 @@ project_color = junk
context_color = junk
metadata_color = junk
link_color = junk
focus_background_color = junk
marked_background_color = junk
(A) Foo
2014-06-14 Last
First
first
......@@ -154,6 +154,14 @@ class ColorsTest(TopydoTest):
self.assertEqual(color_b, '')
self.assertEqual(color_c, '')
def test_focus_color(self):
config(p_overrides={('colorscheme', 'focus_background_color'): 'gray'})
self.assertEqual(config().focus_background_color().as_ansi(), '\033[0;37m')
def test_mark_color(self):
config(p_overrides={('colorscheme', 'marked_background_color'): 'blue'})
self.assertEqual(config().marked_background_color().as_ansi(), '\033[0;34m')
def test_empty_color_values(self):
config("test/data/ColorsTest5.conf")
project_color = config().project_color().as_ansi(p_decoration='bold')
......
......@@ -128,6 +128,18 @@ class ConfigTest(TopydoTest):
self.assertEqual(config("test/data/ConfigTest5.conf").link_color().color, 6)
def test_config24(self):
""" No focus background color value. """
self.assertEqual(config("test/data/ConfigTest5.conf").focus_background_color().color, 7)
def test_config25(self):
""" No mark background color value. """
self.assertEqual(config("test/data/ConfigTest5.conf").marked_background_color().color, 4)
def test_config26(self):
self.assertTrue(config("test/data/ConfigTest4.conf").focus_background_color().is_neutral())
self.assertTrue(config("test/data/ConfigTest4.conf").marked_background_color().is_neutral())
def test_config27(self):
""" column_keymap test. """
keymap, keystates = config("test/data/ConfigTest6.conf").column_keymap()
......
......@@ -295,6 +295,39 @@ class DepCommandTest(CommandTest):
self.assertEqual(self.output, "")
self.assertEqual(self.errors, command.usage() + "\n")
def test_dot1(self):
command = DepCommand(["dot"], self.todolist, self.out, self.error)
command.execute()
self.assertFalse(self.todolist.dirty)
self.assertEqual(self.output, "")
self.assertEqual(self.errors, command.usage() + "\n")
def test_dot2(self):
self.maxDiff = None
command = DepCommand(["dot", "1"], self.todolist, self.out, self.error)
command.execute()
self.assertFalse(self.todolist.dirty)
self.assertEqual(self.output, """digraph topydo {
node [ shape="none" margin="0" fontsize="9" fontname="Helvetica" ]
_2 [label=<<TABLE CELLBORDER="0" CELLSPACING="1" VALIGN="top"><TR><TD><B>2</B></TD><TD BALIGN="LEFT"><B>Bar</B></TD></TR></TABLE>> style=filled fillcolor="#008000" fontcolor="#ffffff"]
_3 [label=<<TABLE CELLBORDER="0" CELLSPACING="1" VALIGN="top"><TR><TD><B>3</B></TD><TD BALIGN="LEFT"><B>Baz</B></TD></TR></TABLE>> style=filled fillcolor="#008000" fontcolor="#ffffff"]
_1 [label=<<TABLE CELLBORDER="0" CELLSPACING="1" VALIGN="top"><TR><TD><B>1</B></TD><TD BALIGN="LEFT"><B>Foo</B></TD></TR></TABLE>> style=filled fillcolor="#008000" fontcolor="#ffffff"]
_1 -> _2
_1 -> _3
}\n
""")
self.assertEqual(self.errors, "")
def test_dot3(self):
command = DepCommand(["dot", "99"], self.todolist, self.out, self.error)
command.execute()
self.assertFalse(self.todolist.dirty)
self.assertEqual(self.output, "")
self.assertEqual(self.errors, "Invalid todo number given." + "\n")
def gc_helper(self, p_subcommand):
command = DepCommand([p_subcommand], self.todolist, self.out,
self.error)
......
......@@ -33,14 +33,14 @@ class SortCommandTest(CommandTest):
command.execute()
self.assertEqual(self.todolist.print_todos(),
"First\n(A) Foo\n2014-06-14 Last")
"first\n(A) Foo\n2014-06-14 Last")
def test_sort2(self):
command = SortCommand([], self.todolist, self.out, self.error)
command.execute()
self.assertEqual(self.todolist.print_todos(),
"(A) Foo\n2014-06-14 Last\nFirst")
"(A) Foo\n2014-06-14 Last\nfirst")
def test_sort3(self):
""" Check that order does not influence the UID of a todo. """
......
......@@ -50,6 +50,8 @@ append_parent_contexts = 0
; context_color = magenta
; metadata_color = green
; link_color = light-cyan
; focus_background_color = gray
; marked_background_color = blue
[aliases]
;showall = ls -x
......
......@@ -135,17 +135,20 @@ class DepCommand(Command):
""" Handles the dot subsubcommand. """
self.printer = DotPrinter(self.todolist)
arg = self.argument(1)
try:
arg = self.argument(1)
todo = self.todolist.todo(arg)
arg = self.argument(1)
todos = set([self.todolist.todo(arg)])
todos |= set(self.todolist.children(todo))
todos |= set(self.todolist.parents(todo))
todos = sorted(todos, key=lambda t: t.text())
self.out(self.printer.print_list(todos))
except InvalidTodoException:
self.error("Invalid todo number given.")
except InvalidCommandArgument:
self.error(self.usage())
def execute(self):
......
......@@ -107,6 +107,8 @@ class _Config:
'metadata_color': 'green',
'link_color': 'cyan',
'priority_colors': 'A:cyan,B:yellow,C:blue',
'focus_background_color': 'gray',
'marked_background_color': 'blue'
},
'aliases': {
......@@ -371,6 +373,18 @@ class _Config:
except ValueError:
return Color(self.cp.get('colorscheme', 'link_color'))
def focus_background_color(self):
try:
return Color(self.cp.getint('colorscheme', 'focus_background_color'))
except ValueError:
return Color(self.cp.get('colorscheme', 'focus_background_color'))
def marked_background_color(self):
try:
return Color(self.cp.getint('colorscheme', 'marked_background_color'))
except ValueError:
return Color(self.cp.get('colorscheme', 'marked_background_color'))
def auto_creation_date(self):
try:
return self.cp.getboolean('add', 'auto_creation_date')
......
......@@ -28,42 +28,8 @@ class TodoFile(object):
to.
"""
def __init__(self, p_path, p_on_update=None):
def __init__(self, p_path):
self.path = os.path.abspath(p_path)
self.write_lock = False
if p_on_update:
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler, FileModifiedEvent, FileCreatedEvent
class EventHandler(FileSystemEventHandler):
"""
Event handler to catch modifications (or creations) of the
current todo.txt file.
"""
def __init__(self, p_file):
super().__init__()
self.file = p_file
def _handle(self, p_event):
right_type = isinstance(p_event, FileModifiedEvent) or isinstance(p_event, FileCreatedEvent)
if not self.file.write_lock and right_type and p_event.src_path == self.file.path:
p_on_update()
def on_created(self, p_event):
"""
Because vim deletes and creates a file on buffer save, also
catch a creation event.
"""
self._handle(p_event)
def on_modified(self, p_event):
self._handle(p_event)
observer = Observer()
observer.schedule(EventHandler(self), os.path.dirname(self.path))
observer.start()
def read(self):
""" Reads the todo.txt file and returns a list of todo items. """
......@@ -85,10 +51,6 @@ class TodoFile(object):
to the file.
"""
# make sure not to reread the todo file because this instance is
# actually writing it
self.write_lock = True
todofile = codecs.open(self.path, 'w', encoding="utf-8")
if p_todos is list:
......@@ -100,4 +62,3 @@ class TodoFile(object):
todofile.write("\n")
todofile.close()
self.write_lock = False
# Topydo - A todo.txt client written in Python.
# Copyright (C) 2014 - 2016 Bram Schoenmakers <bram@topydo.org>
#
# 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/>.
"""
This module deals with todo.txt files while putting a watch on them for file
changes.
"""
import os.path
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler, FileModifiedEvent, FileCreatedEvent
from topydo.lib.TodoFile import TodoFile
class TodoFileWatched(TodoFile):
"""
This class represents a todo.txt file, which can be read from or written
to.
"""
def __init__(self, p_path, p_on_update):
super().__init__(p_path)
class EventHandler(FileSystemEventHandler):
"""
Event handler to catch modifications (or creations) of the
current todo.txt file.
"""
def __init__(self, p_file):
super().__init__()
self.file = p_file
def _handle(self, p_event):
right_type = isinstance(p_event, FileModifiedEvent) or isinstance(p_event, FileCreatedEvent)
should_trigger = right_type and p_event.src_path == self.file.path
if self.file.self_write and should_trigger:
# the file was written by topydo, unmark that so we can
# record external writes again.
self.file.self_write = False
elif should_trigger:
p_on_update()
def on_created(self, p_event):
"""
Because vim deletes and creates a file on buffer save, also
catch a creation event.
"""
self._handle(p_event)
def on_modified(self, p_event):
self._handle(p_event)
observer = Observer()
observer.schedule(EventHandler(self), os.path.dirname(self.path))
observer.start()
def write(self, p_todos):
# make sure not to reread the todo file because this instance is
# actually writing it
self.self_write = True
super().write(p_todos)
......@@ -111,7 +111,7 @@ class DotPrinter(Printer):
children = set(p_todos) & set(self.todolist.children(todo,
p_only_direct=True))
for child in children:
for child in sorted(list(children), key=lambda t: t.text()):
result += ' {} -> {}\n'.format(
node_name(todo),
node_name(child)
......
......@@ -44,13 +44,13 @@ def main():
from topydo.ui.prompt.Prompt import PromptApplication
PromptApplication().run()
except ImportError:
error("You have to install prompt-toolkit to run prompt mode.")
error("Some additional dependencies for prompt mode were not installed, please install with 'pip install topydo[prompt]'")
elif args[0] == 'columns':
try:
from topydo.ui.columns.Main import UIApplication
UIApplication().run()
except ImportError:
error("You have to install urwid to run column mode.")
error("Some additional dependencies for column mode were not installed, please install with 'pip install topydo[columns]'")
else:
CLIApplication().run()
except IndexError:
......
......@@ -30,7 +30,7 @@ from topydo.lib.Sorter import Sorter
from topydo.lib.Filter import get_filter_list, RelevanceFilter, DependencyFilter
from topydo.lib.Utils import get_terminal_size
from topydo.lib.View import View
from topydo.lib import TodoFile
from topydo.lib.TodoFileWatched import TodoFileWatched
from topydo.lib import TodoList
from topydo.ui.CLIApplicationBase import CLIApplicationBase, error
from topydo.ui.columns.CommandLineWidget import CommandLineWidget
......@@ -115,7 +115,7 @@ class UIApplication(CLIApplicationBase):
self._redraw()
self.column_width = config().column_width()
self.todofile = TodoFile.TodoFile(config().todotxt(), callback)
self.todofile = TodoFileWatched(config().todotxt(), callback)
self.todolist = TodoList.TodoList(self.todofile.read())
self.marked_todos = []
......@@ -193,18 +193,20 @@ class UIApplication(CLIApplicationBase):
context_color = to_urwid_color(config().context_color())
metadata_color = to_urwid_color(config().metadata_color())
link_color = to_urwid_color(config().link_color())
focus_background_color = to_urwid_color(config().focus_background_color())
marked_background_color = to_urwid_color(config().marked_background_color())
palette = [
(PaletteItem.PROJECT, '', '', '', project_color, ''),
(PaletteItem.PROJECT_FOCUS, '', 'light gray', '', project_color, None),
(PaletteItem.PROJECT_FOCUS, '', 'light gray', '', project_color, focus_background_color),
(PaletteItem.CONTEXT, '', '', '', context_color, ''),
(PaletteItem.CONTEXT_FOCUS, '', 'light gray', '', context_color, None),
(PaletteItem.CONTEXT_FOCUS, '', 'light gray', '', context_color, focus_background_color),
(PaletteItem.METADATA, '', '', '', metadata_color, ''),
(PaletteItem.METADATA_FOCUS, '', 'light gray', '', metadata_color, None),
(PaletteItem.METADATA_FOCUS, '', 'light gray', '', metadata_color, focus_background_color),
(PaletteItem.LINK, '', '', '', link_color, ''),
(PaletteItem.LINK_FOCUS, '', 'light gray', '', link_color, None),
(PaletteItem.DEFAULT_FOCUS, 'black', 'light gray'),
(PaletteItem.MARKED, '', 'light blue'),
(PaletteItem.LINK_FOCUS, '', 'light gray', '', link_color, focus_background_color),
(PaletteItem.DEFAULT_FOCUS, '', 'light gray', '', '', focus_background_color),
(PaletteItem.MARKED, '', 'light blue', '', '', marked_background_color),
]
for C in ascii_uppercase:
......@@ -217,7 +219,7 @@ class UIApplication(CLIApplicationBase):
'pri_' + C, '', '', '', pri_color, ''
))
palette.append((
'pri_' + C + '_focus', '', 'light gray', '', pri_color_focus, None
'pri_' + C + '_focus', '', 'light gray', '', pri_color_focus, focus_background_color
))
return palette
......
......@@ -37,7 +37,7 @@ except ConfigError as config_error:
sys.exit(1)
from topydo.Commands import get_subcommand
from topydo.lib import TodoFile
from topydo.lib.TodoFileWatched import TodoFileWatched
from topydo.lib import TodoList
......@@ -52,7 +52,7 @@ class PromptApplication(CLIApplicationBase):
self._process_flags()
self.completer = None
self.todofile = TodoFile.TodoFile(config().todotxt(), self._load_file)
self.todofile = TodoFileWatched(config().todotxt(), self._load_file)
def _load_file(self):
"""
......
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