diff --git a/src/braindrop/app/braindrop.py b/src/braindrop/app/braindrop.py index bd69297..da1f18f 100644 --- a/src/braindrop/app/braindrop.py +++ b/src/braindrop/app/braindrop.py @@ -12,7 +12,13 @@ ############################################################################## # Local imports. from ..raindrop import API -from .data import ExitState, load_configuration, save_configuration, token_file +from .data import ( + ExitState, + load_configuration, + save_configuration, + token_file, + update_configuration, +) from .screens import Main, TokenInput @@ -79,9 +85,8 @@ def __init__(self) -> None: def watch_theme(self) -> None: """Save the application's theme when it's changed.""" - configuration = load_configuration() - configuration.theme = self.theme - save_configuration(configuration) + with update_configuration() as config: + config.theme = self.theme @staticmethod def environmental_token() -> str | None: diff --git a/src/braindrop/app/data/__init__.py b/src/braindrop/app/data/__init__.py index 2944b77..c910e65 100644 --- a/src/braindrop/app/data/__init__.py +++ b/src/braindrop/app/data/__init__.py @@ -2,7 +2,12 @@ ############################################################################## # Local imports. -from .config import configuration_file, load_configuration, save_configuration +from .config import ( + configuration_file, + load_configuration, + save_configuration, + update_configuration, +) from .exit_state import ExitState from .local import LocalData, Raindrops, local_data_file from .token import token_file @@ -18,6 +23,7 @@ "Raindrops", "save_configuration", "token_file", + "update_configuration", ] diff --git a/src/braindrop/app/data/config.py b/src/braindrop/app/data/config.py index a14c238..820945e 100644 --- a/src/braindrop/app/data/config.py +++ b/src/braindrop/app/data/config.py @@ -2,10 +2,12 @@ ############################################################################## # Python imports. +from contextlib import contextmanager from dataclasses import asdict, dataclass from functools import lru_cache from json import dumps, loads from pathlib import Path +from typing import Iterator ############################################################################## # Local imports. @@ -81,4 +83,25 @@ def load_configuration() -> Configuration: ) +############################################################################## +@contextmanager +def update_configuration() -> Iterator[Configuration]: + """Context manager for updating the configuration. + + Loads the configuration and makes it available, then ensures it is + saved. + + Example: + ```python + with update_configuration() as config: + config.meaning = 42 + ``` + """ + configuration = load_configuration() + try: + yield configuration + finally: + save_configuration(configuration) + + ### config.py ends here diff --git a/src/braindrop/app/screens/main.py b/src/braindrop/app/screens/main.py index c22df84..846199a 100644 --- a/src/braindrop/app/screens/main.py +++ b/src/braindrop/app/screens/main.py @@ -62,6 +62,7 @@ local_data_file, save_configuration, token_file, + update_configuration, ) from ..messages import ShowCollection, ShowTagged from ..providers import CollectionCommands, CommandsProvider, MainCommands, TagCommands @@ -379,9 +380,8 @@ def action_tag_order_command(self) -> None: self.query_one(Navigation).tags_by_count = ( by_count := not self.query_one(Navigation).tags_by_count ) - config = load_configuration() - config.show_tags_by_count = by_count - save_configuration(config) + with update_configuration() as config: + config.show_tags_by_count = by_count @on(ShowAll) def action_show_all_command(self) -> None: @@ -426,9 +426,8 @@ def action_escape_command(self) -> None: def action_details_command(self) -> None: """Toggle the details of the raindrop details view.""" self.toggle_class("details-hidden") - config = load_configuration() - config.details_visible = not self.has_class("details-hidden") - save_configuration(config) + with update_configuration() as config: + config.details_visible = not self.has_class("details-hidden") @on(CompactMode) def action_compact_mode_command(self) -> None: @@ -436,9 +435,8 @@ def action_compact_mode_command(self) -> None: self.query_one(RaindropsView).compact = not self.query_one( RaindropsView ).compact - config = load_configuration() - config.compact_mode = self.query_one(RaindropsView).compact - save_configuration(config) + with update_configuration() as config: + config.compact_mode = self.query_one(RaindropsView).compact @on(Search) @work