diff --git a/features/steps/core.py b/features/steps/core.py index 1204381e..ab9b90c6 100644 --- a/features/steps/core.py +++ b/features/steps/core.py @@ -8,7 +8,6 @@ from dateutil import parser as date_parser from ansiwrap import strip_color from collections import defaultdict import os -import re import json import yaml import keyring diff --git a/jrnl/Entry.py b/jrnl/Entry.py index a3fea34d..18187a43 100755 --- a/jrnl/Entry.py +++ b/jrnl/Entry.py @@ -5,7 +5,7 @@ from __future__ import unicode_literals import re import ansiwrap from datetime import datetime -from .util import split_title, bold, colorize_red +from .util import split_title, colorize class Entry: @@ -79,10 +79,10 @@ class Entry: else: indent = "" if not short and self.journal.config['linewrap']: - # Color date red and make sure first line of title is bolded - title = ansiwrap.fill(colorize_red(date_str) + " " + bold(self.title), self.journal.config['linewrap']) - # Make sure all lines after the first are bolded, too - title = "".join([bold(part) + "\n" for part in title.split("\n")]).strip() + # Color date and color / bold title and make sure first line of title is bolded + title = ansiwrap.fill(colorize(date_str, self.journal.config['colors']['date']) + " " + + colorize(self.title, self.journal.config['colors']['title'], bold=True), + self.journal.config['linewrap']) body = "\n".join([ ansiwrap.fill( line, @@ -93,7 +93,8 @@ class Entry: for line in self.body.rstrip(" \n").splitlines() ]) else: - title = colorize_red(date_str) + " " + bold(self.title.rstrip("\n ")) + title = colorize(date_str, self.journal.config['colors']['date']) + " " +\ + colorize(self.title.rstrip("\n"), self.journal.config['colors']['title'], bold=True) body = self.body.rstrip("\n ") # Suppress bodies that are just blanks and new lines. diff --git a/jrnl/Journal.py b/jrnl/Journal.py index 4bbc8e5f..886045a6 100644 --- a/jrnl/Journal.py +++ b/jrnl/Journal.py @@ -152,12 +152,12 @@ class Journal(object): for tag in self.search_tags: tagre = re.compile(re.escape(tag), re.IGNORECASE) pp = re.sub(tagre, - lambda match: util.colorize_cyan(match.group(0)), + lambda match: util.colorize(match.group(0), "CYAN"), pp, re.UNICODE) else: pp = re.sub( Entry.Entry.tag_regex(self.config['tagsymbols']), - lambda match: util.colorize_cyan(match.group(0)), + lambda match: util.colorize(match.group(0), "CYAN"), pp ) return pp diff --git a/jrnl/install.py b/jrnl/install.py index 5a80562f..c0fc7dd6 100644 --- a/jrnl/install.py +++ b/jrnl/install.py @@ -12,7 +12,7 @@ from . import upgrade from . import __version__ from .Journal import PlainJournal from .EncryptedJournal import EncryptedJournal -from .util import UserAbort +from .util import UserAbort, verify_config import yaml import logging import sys @@ -42,6 +42,7 @@ def module_exists(module_name): else: return True + default_config = { 'version': __version__, 'journals': { @@ -57,6 +58,10 @@ default_config = { 'highlight': True, 'linewrap': 79, 'indent_character': '|', + 'colors': { + 'date': 'red', + 'title': 'blue', + }, } @@ -98,6 +103,7 @@ def load_or_install_jrnl(): sys.exit(1) upgrade_config(config) + verify_config(config) return config else: diff --git a/jrnl/util.py b/jrnl/util.py index e284b857..e96fd220 100644 --- a/jrnl/util.py +++ b/jrnl/util.py @@ -8,8 +8,8 @@ import sys import os import getpass as gp import yaml +import colorama if "win32" in sys.platform: - import colorama colorama.init() import re import tempfile @@ -30,9 +30,9 @@ STDOUT = sys.stdout TEST = False __cached_tz = None -WARNING_COLOR = "\033[33m" -ERROR_COLOR = "\033[31m" -RESET_COLOR = "\033[0m" +WARNING_COLOR = colorama.Fore.YELLOW +ERROR_COLOR = colorama.Fore.RED +RESET_COLOR = colorama.Fore.RESET # Based on Segtok by Florian Leitner # https://github.com/fnl/segtok @@ -162,6 +162,21 @@ def scope_config(config, journal_name): return config +def verify_config(config): + """ + Ensures the keys set for colors are valid colorama.Fore attributes. + :return: True if all keys are set correctly, False otherwise + """ + all_valid_colors = True + for key, color in config["colors"].items(): + if not getattr(colorama.Fore, color.upper(), None): + # TODO: Not sure whether both of these should stay or not. + print("[{2}ERROR{3}: {0} set to invalid color: {1}]".format(key, color, ERROR_COLOR, RESET_COLOR)) + log.error("Invalid color configuration value for '{0}'.".format(key)) + all_valid_colors = False + return all_valid_colors + + def get_text_from_editor(config, template=""): filehandle, tmpfile = tempfile.mkstemp(prefix="jrnl", text=True, suffix=".txt") with codecs.open(tmpfile, 'w', "utf-8") as f: @@ -180,20 +195,15 @@ def get_text_from_editor(config, template=""): return raw -def colorize_cyan(string): - """Returns the string wrapped in cyan ANSI escape""" - return u"\033[36m{}\033[39m".format(string) - - -def colorize_red(string): - """Returns the string wrapped in red ANSI escape""" - return u"\033[91m{}\033[0m".format(string) - - -def bold(string): - """Returns the string wrapped in bold ANSI escape. Bug / feature that it - also colors the text blue, for some unknown reason.""" - return u"\033[1m{}\033[0m".format(string) +def colorize(string, color, bold=False): + """Returns the string colored with colorama.Fore.color. If the color set + by the user doesn't exist in the colorama.Fore attributes, the colorization + is done with WHITE.""" + color_escape = getattr(colorama.Fore, color.upper(), colorama.Fore.WHITE) + if not bold: + return color_escape + string + colorama.Fore.RESET + else: + return colorama.Style.BRIGHT + color_escape + string + colorama.Style.RESET_ALL def slugify(string):