summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Geier <geier@lostpackets.de>2023-06-24 23:56:09 +0200
committerChristian Geier <geier@lostpackets.de>2023-10-27 14:09:22 +0200
commit5ee70b576b9f3b37a73f2b93b64209297f46a6e4 (patch)
tree03830f40e9335c6c7cb7163de18fe42a7d737e02
parent25c5c2671908a72f82f4d2add02068374ffb3242 (diff)
support for color theme plugins
-rw-r--r--khal/api.py1
-rw-r--r--khal/cli.py35
-rw-r--r--khal/settings/khal.spec2
-rw-r--r--khal/ui/__init__.py14
-rw-r--r--khal/ui/colors.py4
5 files changed, 46 insertions, 10 deletions
diff --git a/khal/api.py b/khal/api.py
new file mode 100644
index 00000000..7664b86d
--- /dev/null
+++ b/khal/api.py
@@ -0,0 +1 @@
+from .ui.colors import register_color_theme # noqa
diff --git a/khal/cli.py b/khal/cli.py
index 538ff9d4..0c6132b3 100644
--- a/khal/cli.py
+++ b/khal/cli.py
@@ -29,6 +29,7 @@ from shutil import get_terminal_size
import click
import click_log
+import xdg
from . import __version__, controllers, khalendar
from .exceptions import FatalError
@@ -252,6 +253,7 @@ def _get_cli():
logger = logging.getLogger('khal')
logger.handlers = [logging.FileHandler(ctx.logfilepath)]
prepare_context(ctx, config)
+ find_load_plugins()
@cli.command()
@multi_calendar_option
@@ -512,15 +514,21 @@ def _get_cli():
def interactive_cli(ctx, config, include_calendar, exclude_calendar, mouse):
'''Interactive UI. Also launchable via `khal interactive`.'''
prepare_context(ctx, config)
+ find_load_plugins()
if mouse is not None:
ctx.obj['conf']['default']['enable_mouse'] = mouse
- controllers.interactive(
- build_collection(
- ctx.obj['conf'],
- multi_calendar_select(ctx, include_calendar, exclude_calendar)
- ),
- ctx.obj['conf']
- )
+ try:
+ controllers.interactive(
+ build_collection(
+ ctx.obj['conf'],
+ multi_calendar_select(ctx, include_calendar, exclude_calendar)
+ ),
+ ctx.obj['conf']
+ )
+ except FatalError as error:
+ logger.debug(error, exc_info=True)
+ logger.fatal(error)
+ sys.exit(1)
@cli.command()
@multi_calendar_option
@@ -698,5 +706,18 @@ def _get_cli():
return cli, interactive_cli
+def find_load_plugins():
+ """Find and load all plugins in the plugin directory."""
+ # check all folders in $XDG_DATA_HOME/khal/plugins if they contain a
+ # __init__.py file. If so, import them.
+ plugin_dir = os.path.join(xdg.BaseDirectory.xdg_data_home, 'khal', 'plugins')
+ if not os.path.isdir(plugin_dir):
+ return
+ sys.path.append(plugin_dir)
+ for plugin in os.listdir(plugin_dir):
+ if os.path.isfile(os.path.join(plugin_dir, plugin, '__init__.py')):
+ logger.debug(f'loading plugin {plugin}')
+ __import__(plugin)
+
main_khal, main_ikhal = _get_cli()
diff --git a/khal/settings/khal.spec b/khal/settings/khal.spec
index ec4e8eef..951a169a 100644
--- a/khal/settings/khal.spec
+++ b/khal/settings/khal.spec
@@ -258,7 +258,7 @@ blank_line_before_day = boolean(default=False)
#
# __ http://urwid.org/manual/displayattributes.html
# .. _github: https://github.com/pimutils/khal/issues
-theme = option('dark', 'light', default='dark')
+theme = string(default='dark')
# Whether to show a visible frame (with *box drawing* characters) around some
# (groups of) elements or not. There are currently several different frame
diff --git a/khal/ui/__init__.py b/khal/ui/__init__.py
index 806501b4..cb7e222a 100644
--- a/khal/ui/__init__.py
+++ b/khal/ui/__init__.py
@@ -31,7 +31,7 @@ import urwid
from .. import utils
from ..khalendar import CalendarCollection
-from ..khalendar.exceptions import ReadOnlyCalendarError
+from ..khalendar.exceptions import FatalError, ReadOnlyCalendarError
from . import colors
from .base import Pane, Window
from .editor import EventEditor, ExportDialog
@@ -1356,6 +1356,17 @@ def start_pane(
color_mode: Literal['rgb', '256colors']='rgb',
):
"""Open the user interface with the given initial pane."""
+
+ # we can't use configobj to do validation of theme for us, because when the
+ # config is passed, we haven't loaded plugins yet. We could load plugins
+ # earlier, but then logging wouldn't work at plugin loading time.
+ # We do this early, so that logger messages still get shown in a regular way
+ theme = colors.themes.get(pane._conf['view']['theme'])
+ if theme is None:
+ logger.fatal(f'Invalid theme {pane._conf["view"]["theme"]} configured')
+ logger.fatal(f'Available themes are: {", ".join(colors.themes.keys())}')
+ raise FatalError
+
quit_keys = quit_keys or ['q']
frame = Window(
@@ -1406,7 +1417,6 @@ def start_pane(
logger.addHandler(header_handler)
frame.open(pane, callback)
- theme = getattr(colors, pane._conf['view']['theme'])
palette = _add_calendar_colors(
theme, pane.collection, color_mode=color_mode,
base='calendar', attr_template='calendar {}',
diff --git a/khal/ui/colors.py b/khal/ui/colors.py
index 5cffb116..055a5636 100644
--- a/khal/ui/colors.py
+++ b/khal/ui/colors.py
@@ -107,3 +107,7 @@ light = [
]
themes: Dict[str, List[Tuple[str, ...]]] = {'light': light, 'dark': dark}
+
+
+def register_color_theme(name: str, theme: List[Tuple[str, ...]]):
+ themes[name] = theme