Select keyboard layouts and input methods in the Typing menu
This commit is contained in:
1 parent
73c0660fde
commit
58d7429f53
15 files changed
+407
-15
No files matched your search
@@ -13,6 +13,15 @@ local vconsole = os.getenv("OMARCHY_VCONSOLE")
|
||||
local real_open = io.open
|
||||
|
||||
io.open = function(path, mode)
|
||||
if path:match("/omarchy/keyboard%-layouts$") then
|
||||
local selected = os.getenv("TEST_KEYBOARD_SELECTION")
|
||||
if not selected then return nil end
|
||||
local file = io.tmpfile()
|
||||
file:write(selected)
|
||||
file:seek("set")
|
||||
return file
|
||||
end
|
||||
|
||||
if path == "/etc/omarchy/input-method" then
|
||||
local preference = os.getenv("TEST_INPUT_PREFERENCE")
|
||||
if not preference then return nil end
|
||||
@@ -141,3 +150,6 @@ pass "greeter non-latin layout list stays in sync with the initramfs hook"
|
||||
TEST_INPUT_PREFERENCE=$'INPUT_METHOD=hangul\n XKB_LAYOUT="kr" # desktop only\n' assert_input "Korean selection overrides its installer US layout" "[kr] [] [$base_options]" $'XKBLAYOUT=us\n'
|
||||
TEST_INPUT_PREFERENCE=$'INPUT_METHOD=hangul\nXKB_LAYOUT=kr\n' assert_input "a later US variant overrides the Korean preference" "[us] [intl] [$base_options]" $'XKBLAYOUT=us\nXKBVARIANT=intl\n'
|
||||
TEST_INPUT_PREFERENCE=$'INPUT_METHOD=hangul\nXKB_LAYOUT=kr\n' assert_input "a later layout overrides the Korean preference" "[de] [nodeadkeys] [$base_options]" $'XKBLAYOUT=de\nXKBVARIANT=nodeadkeys\n'
|
||||
|
||||
TEST_KEYBOARD_SELECTION=$'XKBLAYOUT=us,fr\nXKBVARIANT=intl,\n' assert_input "menu selections replace installer desktop defaults" "[us,fr] [intl,] [$base_options]" $'XKBLAYOUT=jp\n'
|
||||
TEST_KEYBOARD_SELECTION=$'XKBLAYOUT=us,fr\nXKBVARIANT=intl,\n' assert_greeter_input "menu selections leave the greeter keyboard unchanged" "[jp] [] []" $'XKBLAYOUT=jp\n'
|
||||
@@ -0,0 +1,90 @@
|
||||
import importlib.util
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
|
||||
ROOT = Path(os.environ["OMARCHY_PATH"])
|
||||
sys.path.insert(0, str(ROOT / "default/input-methods"))
|
||||
spec = importlib.util.spec_from_file_location("typing_setup", ROOT / "default/input-methods/typing.py")
|
||||
typing = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(typing)
|
||||
|
||||
|
||||
class TypingSetupTest(unittest.TestCase):
|
||||
def test_variants_and_installer_binding_safety(self):
|
||||
self.assertEqual(typing.keyboard_values(["us:intl", "fr"]), ("us,fr", "intl,"))
|
||||
self.assertEqual(typing.keyboard_values(["ru:phonetic"]), ("us,ru", ",phonetic"))
|
||||
with self.assertRaises(ValueError):
|
||||
typing.keyboard_values([])
|
||||
|
||||
def test_keyboard_catalog_includes_variants(self):
|
||||
with patch.object(typing, "controller", return_value=[["us", "English (US)", ["en"], [["intl", "English (US, international)", ["en"]]]]]):
|
||||
self.assertEqual(typing.keyboard_catalog(), {"us": "English (US)", "us:intl": "English (US, international)"})
|
||||
|
||||
def test_input_deselection_keeps_keyboard_and_selected_overrides(self):
|
||||
items = [["keyboard-us", ""], ["mozc", "jp"], ["hangul", ""], ["custom", "de"]]
|
||||
self.assertEqual(typing.input_items(items, ["custom", "mozc"]), [["keyboard-us", ""], ["custom", "de"], ["mozc", "jp"]])
|
||||
self.assertEqual(typing.input_items(items, []), [["keyboard-us", ""]])
|
||||
|
||||
def test_cancellation_does_not_change_input_settings(self):
|
||||
with patch.object(typing.setup, "live_group", return_value=("Default", "us", [["keyboard-us", ""]])), patch.object(typing, "input_catalog", return_value=({"mozc": "Japanese"}, {"mozc": "Japanese"})), patch.object(typing, "choose", return_value=None), patch.object(typing.setup, "live_set") as setter:
|
||||
self.assertFalse(typing.configure_inputs())
|
||||
setter.assert_not_called()
|
||||
|
||||
def test_failed_input_save_restores_the_original_group(self):
|
||||
before = [["keyboard-us", ""], ["mozc", "jp"]]
|
||||
after = [["keyboard-us", ""]]
|
||||
with patch.object(typing.setup, "run"), patch.object(typing.setup, "live_set") as setter, patch.object(typing.setup, "live_group", return_value=("Default", "us", before)):
|
||||
with self.assertRaises(RuntimeError):
|
||||
typing.set_inputs("Default", "us", before, after)
|
||||
self.assertEqual(setter.call_args_list[-1].args, ("Default", "us", before))
|
||||
|
||||
def test_picker_preselects_current_entries_and_returns_empty_selection(self):
|
||||
result = subprocess.CompletedProcess([], 0, stdout="[]")
|
||||
with patch.object(typing.subprocess, "run", return_value=result) as process:
|
||||
self.assertEqual(typing.choose("Inputs", {"mozc": "Japanese", "hangul": "Korean"}, ["hangul"]), [])
|
||||
args = process.call_args.args[0]
|
||||
self.assertEqual(args[2], "\tKorean")
|
||||
self.assertIn("--multiple", args)
|
||||
self.assertEqual(args[-2:], ["--selected", "Korean"])
|
||||
|
||||
def test_picker_rejects_unknown_returned_values(self):
|
||||
with patch.object(typing.subprocess, "run", return_value=subprocess.CompletedProcess([], 0, stdout='["unknown"]')):
|
||||
with self.assertRaises(ValueError):
|
||||
typing.choose("Inputs", {"mozc": "Japanese"}, [])
|
||||
|
||||
def test_keyboard_override_failure_preserves_symlink_and_restores_settings(self):
|
||||
with tempfile.TemporaryDirectory() as temporary:
|
||||
config = Path(temporary)
|
||||
target = config / "actual-layouts"
|
||||
target.write_text("XKBLAYOUT=de\n")
|
||||
target.chmod(0o600)
|
||||
path = config / "omarchy/keyboard-layouts"
|
||||
path.parent.mkdir()
|
||||
path.symlink_to(target)
|
||||
before = ("Default", "us", [["keyboard-us", ""], ["mozc", "jp"]])
|
||||
with patch.dict(os.environ, {"XDG_CONFIG_HOME": str(config)}), patch.object(typing.setup, "live_group", return_value=before), patch.object(typing.setup, "run", return_value=""), patch.object(typing, "keyboard_selection", return_value=["de"]), patch.object(typing.setup, "live_set") as setter:
|
||||
with self.assertRaisesRegex(RuntimeError, "override"):
|
||||
typing.save_keyboard(["us", "fr"])
|
||||
self.assertTrue(path.is_symlink())
|
||||
self.assertEqual(target.read_text(), "XKBLAYOUT=de\n")
|
||||
self.assertEqual(target.stat().st_mode & 0o777, 0o600)
|
||||
setter.assert_not_called()
|
||||
|
||||
def test_keyboard_save_aligns_fcitx_and_preserves_language_overrides(self):
|
||||
with tempfile.TemporaryDirectory() as temporary:
|
||||
before = ("Default", "us", [["keyboard-us", ""], ["mozc", "jp"]])
|
||||
after = ("Default", "fr", [["keyboard-fr", ""], ["mozc", "jp"]])
|
||||
with patch.dict(os.environ, {"XDG_CONFIG_HOME": temporary}), patch.object(typing.setup, "live_group", side_effect=[before, after]), patch.object(typing.setup, "run", return_value=""), patch.object(typing, "keyboard_selection", return_value=["fr", "us:intl"]), patch.object(typing.setup, "live_set") as setter:
|
||||
typing.save_keyboard(["fr", "us:intl"])
|
||||
self.assertEqual(setter.call_args.args, after)
|
||||
self.assertEqual((Path(temporary) / "omarchy/keyboard-layouts").read_text(), "XKBLAYOUT=fr,us\nXKBVARIANT=,intl\n")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,15 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euo pipefail
|
||||
source "$(dirname "${BASH_SOURCE[0]}")/base-test.sh"
|
||||
|
||||
OMARCHY_PATH="$ROOT" python "$ROOT/test/shell.d/typing-setup-checks.py"
|
||||
|
||||
run_node_test <<'JS'
|
||||
const menu = requireFromRoot('shell/plugins/menu/MenuModel.js')
|
||||
const options = ['French', '\tJapanese (Mozc)', 'x\tSame label\tfirst', 'x\tSame label\tsecond']
|
||||
assertEqual(menu.dmenuValue(options[2]), 'Same label\tfirst', 'multi-select keeps a stable subtext value without the icon')
|
||||
assertDeepEqual(menu.dmenuSelections(options, ['Same label\tsecond', 'French', 'stale']), ['French', 'Same label\tsecond'], 'multi-select preserves option order and excludes stale choices')
|
||||
assertDeepEqual(menu.toggleDmenuSelection(['French'], 'French'), [], 'deselecting the final option produces an empty selection')
|
||||
assertDeepEqual(menu.toggleDmenuSelection(['French'], 'Japanese (Mozc)'), ['French', 'Japanese (Mozc)'], 'selecting an input retains earlier choices')
|
||||
JS
|
||||
Reference in new issue
Block a user