diff --git a/src/csv_overrides.py b/src/csv_overrides.py index 8067fda0..eb945ea7 100644 --- a/src/csv_overrides.py +++ b/src/csv_overrides.py @@ -25,6 +25,7 @@ def init_csv_and_watch_changes( default_list_name: Optional[str] = None, headers: list[str] = [SPOKEN_FORM_HEADER, CURSORLESS_IDENTIFIER_HEADER], ctx: Context = Context(), + no_update_file: bool = False, ): """ Initialize a cursorless settings csv, creating it if necessary, and watch @@ -49,6 +50,8 @@ def init_csv_and_watch_changes( allow_unknown_values bool: If unknown values appear, just put them in the list default_list_name Optional[str]: If unknown values are allowed, put any unknown values in this list + no_update_file Optional[bool]: Set this to `TRUE` to indicate that we should + not update the csv. This is used generally in case there was an issue coming up with the default set of values so we don't want to persist those to disk """ if extra_ignored_values is None: extra_ignored_values = [] @@ -85,6 +88,7 @@ def on_watch(path, flags): super_default_values, extra_ignored_values, allow_unknown_values, + no_update_file, ) update_dicts( default_values, @@ -95,7 +99,8 @@ def on_watch(path, flags): ctx, ) else: - create_file(file_path, headers, super_default_values) + if not no_update_file: + create_file(file_path, headers, super_default_values) update_dicts( default_values, super_default_values, @@ -165,6 +170,7 @@ def update_file( default_values: dict, extra_ignored_values: list[str], allow_unknown_values: bool, + no_update_file: bool, ): current_values, has_errors = read_file( path, @@ -181,7 +187,7 @@ def update_file( missing[key] = value if missing: - if has_errors: + if has_errors or no_update_file: print( "NOTICE: New cursorless features detected, but refusing to update " "csv due to errors. Please fix csv errors above and restart talon" diff --git a/src/marks/mark.py b/src/marks/mark.py index f26a380f..428397c4 100644 --- a/src/marks/mark.py +++ b/src/marks/mark.py @@ -4,7 +4,6 @@ from talon import Module, actions, app, Context, fs, cron from ..csv_overrides import init_csv_and_watch_changes from .lines_number import DEFAULT_DIRECTIONS -from .vscode_settings import vscode_get_setting_with_fallback mod = Module() ctx = Context() @@ -145,23 +144,33 @@ def cursorless_mark(m) -> str: def setup_hat_styles_csv(): global unsubscribe_hat_styles + ( + color_enablement_settings, + is_color_error, + ) = actions.user.vscode_get_setting_with_fallback( + "cursorless.hatEnablement.colors", + default_value={}, + fallback_value=FALLBACK_COLOR_ENABLEMENT, + fallback_message="Error finding color enablement; falling back to full enablement", + ) + + ( + shape_enablement_settings, + is_shape_error, + ) = actions.user.vscode_get_setting_with_fallback( + "cursorless.hatEnablement.shapes", + default_value={}, + fallback_value=FALLBACK_SHAPE_ENABLEMENT, + fallback_message="Error finding shape enablement; falling back to full enablement", + ) + color_enablement = { **DEFAULT_COLOR_ENABLEMENT, - **vscode_get_setting_with_fallback( - "cursorless.hatEnablement.colors", - default_value={}, - fallback_value=FALLBACK_COLOR_ENABLEMENT, - fallback_message="Error finding color enablement; falling back to full enablement", - ), + **color_enablement_settings, } shape_enablement = { **DEFAULT_SHAPE_ENABLEMENT, - **vscode_get_setting_with_fallback( - "cursorless.hatEnablement.shapes", - default_value={}, - fallback_value=FALLBACK_SHAPE_ENABLEMENT, - fallback_message="Error finding shape enablement; falling back to full enablement", - ), + **shape_enablement_settings, } active_hat_colors = { @@ -185,8 +194,12 @@ def setup_hat_styles_csv(): "hat_shape": active_hat_shapes, }, [*hat_colors.values(), *hat_shapes.values()], + no_update_file=is_shape_error or is_color_error, ) + if is_shape_error or is_color_error: + app.notify("Error reading vscode settings. Restart talon; see log") + fast_reload_job = None slow_reload_job = None diff --git a/src/marks/vscode_settings.py b/src/marks/vscode_settings.py index 76b1db53..49bca57c 100644 --- a/src/marks/vscode_settings.py +++ b/src/marks/vscode_settings.py @@ -38,6 +38,30 @@ def vscode_get_setting(key: str, default_value: Any = None): else: return settings[key] + def vscode_get_setting_with_fallback( + key: str, + default_value: Any, + fallback_value: Any, + fallback_message: str, + ) -> tuple[Any, bool]: + """Returns a vscode setting with a fallback in case there's an error + + Args: + key (str): The key of the setting to look up + default_value (Any): The default value to return if the setting is not defined + fallback_value (Any): The value to return if there is an error looking up the setting + fallback_message (str): The message to show to the user if we end up having to use the fallback + + Returns: + tuple[Any, bool]: The value of the setting or the default or fall back, along with boolean which is true if there was an error + """ + try: + return actions.user.vscode_get_setting(key, default_value), False + except Exception as e: + print(fallback_message) + traceback.print_exc() + return fallback_value, True + def pick_path(paths: list[Path]): existing_paths = [path for path in paths if path.exists()] @@ -79,28 +103,3 @@ def vscode_settings_path() -> Path: Path(f"{os.environ['APPDATA']}/VSCodium/User/settings.json"), ] ) - - -def vscode_get_setting_with_fallback( - key: str, - default_value: Any, - fallback_value: Any, - fallback_message: str, -): - """Returns a vscode setting with a fallback in case there's an error - - Args: - key (str): The key of the setting to look up - default_value (Any): The default value to return if the setting is not defined - fallback_value (Any): The value to return if there is an error looking up the setting - fallback_message (str): The message to show to the user if we end up having to use the fallback - - Returns: - Any: The value of the setting or the default or fall back - """ - try: - return actions.user.vscode_get_setting(key, default_value) - except Exception as e: - print(fallback_message) - traceback.print_exc() - return fallback_value