Commit 7e9f954c authored by Bram Schoenmakers's avatar Bram Schoenmakers

Embed colors in strings

TopydoString is a string descendent that maintains information where
colors should be applied in a string. A user interface can pass a
function that transforms a color to a color representation that is
relevant there. That way, the topydo library does not make any
assumptions anymore on where colors should be applied.
parent 58079b25
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
from topydo.lib.prettyprinters.Colors import PrettyPrinterColorFilter from topydo.lib.prettyprinters.Colors import PrettyPrinterColorFilter
from topydo.lib.prettyprinters.Numbers import PrettyPrinterNumbers from topydo.lib.prettyprinters.Numbers import PrettyPrinterNumbers
from topydo.lib.TopydoString import TopydoString
class Printer(object): class Printer(object):
...@@ -68,7 +69,11 @@ class PrettyPrinter(Printer): ...@@ -68,7 +69,11 @@ class PrettyPrinter(Printer):
for ppf in self.filters: for ppf in self.filters:
todo_str = ppf.filter(todo_str, p_todo) todo_str = ppf.filter(todo_str, p_todo)
return todo_str # transform color annotations to ANSI codes
if isinstance(todo_str, TopydoString):
return todo_str.with_colors(lambda c: c.as_ansi())
else:
return todo_str
def pretty_printer_factory(p_todolist, p_additional_filters=None): def pretty_printer_factory(p_todolist, p_additional_filters=None):
......
# Topydo - A todo.txt client written in Python.
# Copyright (C) 2016 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/>.
""" This module provides TopydoString to embed colors in a string. """
import collections
class TopydoString(collections.UserString):
"""
Represents a string that also contains color information. A combination of
(position, color) is maintained, where the position is the start position
where a certain color should start.
"""
def __init__(self, p_content):
super().__init__(p_content)
self.colors = {}
def append(self, p_string, p_color):
""" Append a string with the given color. """
self.colors[len(self.data)] = p_color
self.data += p_string
def set_color(self, p_pos, p_color):
""" Start using a color at the given position. """
self.colors[p_pos] = p_color
def with_colors(self, p_transform_fn):
"""
Returns a string with color information at the right positions.
p_transform_fn is a function that takes a Color object and returns a
string representing the color (e.g. "#ff0000").
"""
result = self.data
for pos, color in sorted(self.colors.items(), reverse=True):
result = result[:pos] + p_transform_fn(color) + result[pos:]
return result
...@@ -21,6 +21,7 @@ import re ...@@ -21,6 +21,7 @@ import re
from topydo.lib.Color import Color from topydo.lib.Color import Color
from topydo.lib.Config import config from topydo.lib.Config import config
from topydo.lib.PrettyPrinterFilter import PrettyPrinterFilter from topydo.lib.PrettyPrinterFilter import PrettyPrinterFilter
from topydo.lib.TopydoString import TopydoString
class PrettyPrinterColorFilter(PrettyPrinterFilter): class PrettyPrinterColorFilter(PrettyPrinterFilter):
...@@ -33,35 +34,27 @@ class PrettyPrinterColorFilter(PrettyPrinterFilter): ...@@ -33,35 +34,27 @@ class PrettyPrinterColorFilter(PrettyPrinterFilter):
def filter(self, p_todo_str, p_todo): def filter(self, p_todo_str, p_todo):
""" Applies the colors. """ """ Applies the colors. """
if config().colors(): if config().colors():
p_todo_str = TopydoString(p_todo_str)
priority_color = config().priority_color(p_todo.priority()) priority_color = config().priority_color(p_todo.priority())
project_color = config().project_color()
context_color = config().context_color()
metadata_color = config().metadata_color()
link_color = config().link_color()
neutral_color = Color('NEUTRAL') neutral_color = Color('NEUTRAL')
# color projects / contexts colors = [
p_todo_str = re.sub( (r'\B@(\S*\w)', config().context_color()),
r'\B(\+|@)(\S*\w)', (r'\B\+(\S*\w)', config().project_color()),
lambda m: ( (r'\b\S+:[^/\s]\S*\b', config().metadata_color()),
context_color.as_ansi() if m.group(0)[0] == "@" (r'(^|\s)(\w+:){1}(//\S+)', config().link_color()),
else project_color.as_ansi()) + m.group(0) + priority_color.as_ansi(), ]
p_todo_str)
# tags
p_todo_str = re.sub(r'\b\S+:[^/\s]\S*\b',
metadata_color.as_ansi() + r'\g<0>' + priority_color.as_ansi(),
p_todo_str)
# add link_color to any valid URL specified outside of the tag. for pattern, color in colors:
p_todo_str = re.sub(r'(^|\s)(\w+:){1}(//\S+)', for match in re.finditer(pattern, p_todo_str.data):
r'\1' + link_color.as_ansi() + r'\2\3' + priority_color.as_ansi(), p_todo_str.set_color(match.start(), color)
p_todo_str) p_todo_str.set_color(match.end(), priority_color)
p_todo_str += neutral_color.as_ansi() p_todo_str.append('', neutral_color)
# color by priority # color by priority
p_todo_str = priority_color.as_ansi() + p_todo_str p_todo_str.set_color(0, priority_color)
return p_todo_str return p_todo_str
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