diff --git a/default/input-methods/typing_setup.py b/default/input-methods/typing_setup.py index add64095..6364aa1d 100644 --- a/default/input-methods/typing_setup.py +++ b/default/input-methods/typing_setup.py @@ -106,12 +106,27 @@ def configure_inputs(): choose("Input Methods", catalog, current, "input", dict(items)) +def load_engines(names, catalog): + packages = sorted({package for name in names for package in setup.PRESETS.get(name, {}).get("packages", [])}) + absent = [package for package in packages + if subprocess.run(["omarchy-pkg-present", package], capture_output=True).returncode] + if absent or any(name not in setup.PRESETS for name in names): + labels = ", ".join(catalog.get(name, name) for name in names) + raise RuntimeError(f"Install {' '.join(absent) or 'its engine'} to use {labels}") + # Fcitx discovers engines only at startup, so one installed while it was + # running (by an update, say) needs a restart before it can be selected. + setup.run(["omarchy-restart-xcompose"]) + for name in names: + setup.wait_ready(name) + + def save_inputs(selected, overrides=None): group, layout, items = setup.live_group() catalog, available = input_catalog(items) - missing = [catalog.get(name, name) for name in selected if name not in available] + missing = [name for name in selected if name not in available] if missing: - raise RuntimeError("Restart input after updating Omarchy to use: " + ", ".join(missing)) + load_engines(missing, catalog) + group, layout, items = setup.live_group() set_inputs(group, layout, items, input_items(items, selected, overrides)) # Only a saved engine claims the CJK font fallback, and a failed font write # returns the group so the menu's restored checks stay true. diff --git a/test/shell.d/typing-setup-checks.py b/test/shell.d/typing-setup-checks.py index 1fcc56c1..21dca265 100644 --- a/test/shell.d/typing-setup-checks.py +++ b/test/shell.d/typing-setup-checks.py @@ -63,6 +63,23 @@ class TypingSetupTest(unittest.TestCase): typing.save_inputs(["mozc"]) self.assertFalse((Path(temporary) / "fontconfig/conf.d/50-omarchy-input-method.conf").exists()) + def test_an_engine_installed_after_fcitx_started_loads_on_selection(self): + group = ("Default", "us", [["keyboard-us", ""]]) + present = subprocess.CompletedProcess([], 0) + with patch.object(typing.setup, "live_group", return_value=group), patch.object(typing.setup, "available_methods", return_value=[]), patch.object(typing.subprocess, "run", return_value=present), patch.object(typing.setup, "run") as run, patch.object(typing.setup, "wait_ready") as ready, patch.object(typing, "set_inputs") as save, patch.object(typing.setup, "font_default"): + typing.save_inputs(["mozc"]) + run.assert_called_once_with(["omarchy-restart-xcompose"]) + ready.assert_called_once_with("mozc") + self.assertEqual(save.call_args.args[3], [["keyboard-us", ""], ["mozc", ""]]) + + def test_an_uninstalled_engine_names_its_package_without_restarting(self): + absent = subprocess.CompletedProcess([], 1) + with patch.object(typing.setup, "live_group", return_value=("Default", "us", [["keyboard-us", ""]])), patch.object(typing.setup, "available_methods", return_value=[]), patch.object(typing.subprocess, "run", return_value=absent), patch.object(typing.setup, "run") as run, patch.object(typing, "set_inputs") as save: + with self.assertRaisesRegex(RuntimeError, "Install fcitx5-mozc to use Japanese"): + typing.save_inputs(["mozc"]) + run.assert_not_called() + save.assert_not_called() + def test_failed_font_write_restores_the_input_group(self): before = [["keyboard-us", ""]] with patch.object(typing.setup, "live_group", return_value=("Default", "us", before)), patch.object(typing.setup, "available_methods", return_value=[["mozc", "Mozc"]]), patch.object(typing, "set_inputs"), patch.object(typing.setup, "font_default", side_effect=OSError("read-only")), patch.object(typing.setup, "live_set") as setter: