Add searchable input controls and display profile editing

This commit is contained in:
aria committed 2026-10-28 08:19:05 +09:00
1 parent 78ce1ed590
commit a2be421974
24 files changed
+3426 -249

No files matched your search

+173 -6
View File
@@ -291,7 +291,7 @@
"Static": "静态",
"Scrolling": "滚动",
"Tiling": "平铺",
"Floating": "浮动",
"Floating": "悬浮",
"Always": "始终",
"Never": "从不",
"Automatic": "自动",
@@ -776,7 +776,7 @@
"Allow this device to pair?": "允许此设备配对吗?",
"Another device is already pairing.": "另一个设备正在配对。",
"Argument": "参数",
"Attached to the screen edge": "贴合屏幕边缘",
"Attached to the screen edge": "连接屏幕边缘",
"Auto (battery)": "自动(电池)",
"Auto appearance: off": "自动外观:关",
"Auto appearance: on": "自动外观:开",
@@ -799,7 +799,7 @@
"Command, direction, or action argument": "命令、方向或动作参数。",
"Configuration schema query timed out": "配置结构查询超时",
"Confirm": "确认",
"Connected groups with rounded ends": "圆角端点相连的分组",
"Connected groups with rounded ends": "以圆角端点连接的分组",
"Connected · ": "已连接 · ",
"Connecting · ": "正在连接 · ",
"Connection services are unavailable. Use Refresh to try again.": "连接服务不可用,请点击刷新重试。",
@@ -837,7 +837,7 @@
"Forget this connection?": "忘记此连接吗?",
"Full": "完整",
"Group arrangement & spacing": "分组排列与间距",
"Groups blend where they meet": "分组在相接处融合",
"Groups blend where they meet": "在交汇处融合分组",
"Headphones": "耳机",
"Hidden network": "隐藏网络",
"Holiday name": "节假日名称",
@@ -913,7 +913,7 @@
"Schema query failed": "配置结构查询失败",
"Searching for devices…": "正在搜索设备…",
"Select display": "选择显示器",
"Separate floating groups": "独立悬浮分组",
"Separate floating groups": "彼此分离的悬浮分组",
"Shared": "共享",
"Shortcut": "快捷键",
"Show +n for additional activities.": "以 +n 表示更多活动。",
@@ -1042,5 +1042,172 @@
"Loading configuration options…": "正在载入配置选项…",
"Retry": "重试",
"Dark only": "仅深色",
"Light only": "仅浅色"
"Light only": "仅浅色",
"Panel": "面板",
"Shell": "Shell",
"Keyboard layouts, variants and repeat behavior.": "键盘布局、变体与按键重复行为。",
"Mouse buttons, pointer movement and scrolling.": "鼠标按键、指针移动与滚轮。",
"Touchpad taps, scrolling and gestures.": "触控板轻点、滚动与手势。",
"Shared surfaces, launcher and system menus.": "共享表面、启动器与系统菜单。",
"Shell surfaces": "Shell 表面",
"Default variant": "默认变体",
"Loading keyboard layouts…": "正在载入键盘布局…",
"Search layouts…": "搜索键盘布局…",
"Search variants…": "搜索布局变体…",
"Select a layout to add…": "选择要添加的布局…",
"Add layout": "添加布局",
"Remove layout": "移除布局",
"Move up": "上移",
"Switch keyboard layout": "切换键盘布局",
"No layout switching shortcut": "不使用快捷键切换布局",
"Search layout switching shortcuts…": "搜索布局切换快捷键…",
"Add shortcut": "添加快捷键",
"Search shortcuts…": "搜索快捷键…",
"Edit shortcut": "编辑快捷键",
"New shortcut": "新建快捷键",
"No shortcut selected": "尚未选择组合键",
"Record shortcut": "录入组合键",
"Press a shortcut · Esc cancels": "请按组合键 · Esc 取消",
"Preparing recording…": "正在准备录入…",
"Choose keys from menu": "从菜单选择按键",
"Search keys or gestures…": "搜索按键或手势…",
"Search actions…": "搜索动作…",
"Save shortcut": "保存快捷键",
"Remove shortcut": "移除快捷键",
"Show active shortcuts": "查看现有效快捷键",
"Built-in shortcuts remain active. Add a shortcut here to customize or override one.": "内置快捷键继续生效。在这里添加快捷键即可自定义或覆盖现有组合键。",
"Record or select a shortcut first": "请先录入或选择组合键",
"Choose an action": "请选择动作",
"Choose a direction": "请选择方向",
"Workspace number must be between 1 and 255": "工作区编号须在 1 到 255 之间",
"Choose a binding mode": "请选择快捷键模式",
"This shortcut belongs to another binding. Edit that binding instead.": "此组合键已属于另一项快捷键,请编辑对应项目。",
"Recording timed out. You can also select keys from the menu.": "录入超时,也可以从菜单选择按键。",
"Custom program": "自定义程序",
"Workspace number": "工作区编号",
"Launch a program": "运行程序",
"Maximize or restore window": "最大化或还原窗口",
"Focus window": "切换窗口焦点",
"Move window": "移动窗口",
"Resize window": "调整窗口大小",
"Go to workspace": "转到工作区",
"Move window to workspace": "将窗口移到工作区",
"Return to previous workspace": "返回上一工作区",
"Switch between tiled and floating windows": "在平铺窗口与浮动窗口间切换",
"Toggle stacked or tabbed column": "切换堆叠或标签列",
"Join tab group": "加入标签组",
"Join window into column": "将窗口并入列",
"Leave column": "从列移出窗口",
"Switch binding mode": "切换快捷键模式",
"Log out with confirmation": "注销(先确认)",
"Disable shortcut": "停用快捷键",
"Customize gestures": "自定义手势",
"{count}-finger swipe {direction}": "{count} 指向{direction}滑动",
"Left mouse button": "鼠标左键",
"Right mouse button": "鼠标右键",
"Middle mouse button": "鼠标中键",
"Back mouse button": "鼠标后退键",
"Forward mouse button": "鼠标前进键",
"Wheel up": "滚轮向上",
"Wheel down": "滚轮向下",
"Wheel left": "滚轮向左",
"Wheel right": "滚轮向右",
"Page up": "上一页",
"Page down": "下一页",
"Left arrow": "左方向键",
"Right arrow": "右方向键",
"Up arrow": "上方向键",
"Down arrow": "下方向键",
"Backspace": "退格",
"Escape": "Esc",
"Enter": "回车",
"Space": "空格",
"Tab": "Tab",
"Delete": "删除",
"Insert": "插入",
"Home": "Home",
"Print": "截屏",
"Display arrangement": "显示器排列",
"Save current layout as a profile": "将当前布局保存为配置",
"Profile name": "配置名称",
"Rename profile": "重命名配置",
"Remove profile": "移除配置",
"Use this profile": "使用此配置",
"Display layout": "显示模式",
"Extend": "扩展",
"Mirror": "镜像",
"Internal display only": "仅内置显示器",
"External displays only": "仅外接显示器",
"Output settings": "输出设置",
"Enable display": "启用显示器",
"At least one connected display must remain enabled.": "至少保留一个已连接的显示器启用。",
"Rotation and reflection": "旋转与翻转",
"Landscape": "横向",
"Portrait right": "纵向(向右旋转)",
"Landscape inverted": "横向倒置",
"Portrait left": "纵向(向左旋转)",
"Reflected landscape": "横向翻转",
"Reflected portrait right": "纵向翻转(向右)",
"Reflected landscape inverted": "横向倒置并翻转",
"Reflected portrait left": "纵向翻转(向左)",
"Apply position": "应用位置",
"Automatic position": "自动排列",
"Positions use logical pixels after scaling and rotation. Negative values are supported.": "位置使用缩放和旋转后的逻辑像素,支持负值。",
"Keep these display settings? Unconfirmed changes revert automatically.": "保留这些显示设置?未经确认的更改将自动回退。",
"Keep changes": "保留更改",
"Revert changes": "回退更改",
"Restore previous display configuration": "恢复修改前的显示配置",
"This display is managed by the host session. Saved profiles apply in a standalone session.": "此显示器由宿主会话管理;保存的配置将在独立会话中应用。",
"Connect a display before creating a profile": "请先连接显示器,再创建配置",
"Choose a unique profile name": "请使用非空且不重复的配置名称",
"Position must use whole logical pixels": "位置须使用整数逻辑像素",
"Desktop {number}": "桌面 {number}",
"Offline": "离线",
"Window dragging and resizing require a mouse button": "窗口拖拽和指针缩放需要使用鼠标按键",
"Default shortcuts": "默认快捷键",
"Record by key label": "按字符重新录入",
"This binding matches physical key positions. Recording chooses key labels instead.": "此绑定按物理位置匹配;重新录入将改为按键字符匹配。",
"This shortcut will replace the existing binding.": "此组合键将替换已有的自定义绑定。",
"Shortcuts apply throughout the Ferese session. Matching keys override built-in shortcuts.": "快捷键在整个 Ferese 会话内生效;相同组合键将覆盖内置快捷键。",
"Replace binding": "替换绑定",
"Current display arrangement": "当前显示器排列",
"This session does not support recording. Choose a combination from the key menu.": "此会话不支持录入组合键,请从按键菜单选择。",
"Open or close launcher": "打开或关闭启动器",
"Open or close overview": "打开或关闭概览",
"Close window": "关闭窗口",
"Toggle fullscreen": "切换全屏",
"Toggle floating window": "切换浮动窗口",
"Next workspace": "下一个工作区",
"Previous workspace": "上一个工作区",
"Return to last focused window": "返回上次聚焦的窗口",
"Next window in focus history": "焦点历史中的下一个窗口",
"Previous window in focus history": "焦点历史中的上一个窗口",
"Switch workspace layout": "切换工作区布局",
"Cycle column width": "循环切换列宽",
"Center focused column": "居中当前列",
"Leave tab group": "移出标签组",
"Next tab": "下一个标签",
"Previous tab": "上一个标签",
"Drag window": "拖动窗口",
"Resize window with pointer": "用鼠标调整窗口大小",
"Play or pause media": "播放或暂停媒体",
"Next track": "下一曲",
"Previous track": "上一曲",
"Open display mode chooser": "打开显示模式选择器",
"Open or close shortcut hint": "打开或关闭快捷键提示",
"Panel appearance": "面板外观",
"Edge to edge": "贯穿屏幕",
"A continuous edge-to-edge panel": "沿屏幕边缘连续铺开的面板",
"Capsules": "胶囊",
"Notch": "刘海",
"Frame": "框架",
"Corner wrap": "包裹边角",
"Fused islands": "融合岛",
"Morph": "动态岛",
"Adaptive": "自适应",
"Window hug": "贴合窗口",
"A detached panel with rounded corners": "带圆角的悬浮面板",
"Separate rounded groups": "独立圆角分组",
"Expands around active content": "随活动内容展开",
"A clock hub with expandable controls": "可展开控制项的时钟中心"
}
+60
View File
@@ -350,6 +350,36 @@ impl Document {
Ok(())
}
/// Restore one top-level setting from an earlier document, including its
/// authored nodes and comments, while retaining all other current settings.
pub fn restore_top_level(&mut self, key: &str, baseline: &Self) -> Result<(), Error> {
if key.is_empty() || key.contains('.') {
return Err(Error("Expected a top-level setting".into()));
}
let mut candidate = self.clone();
let index = candidate
.doc
.nodes()
.iter()
.position(|node| field(node.name().value(), "") == key)
.unwrap_or(candidate.doc.nodes().len());
candidate
.doc
.nodes_mut()
.retain(|node| field(node.name().value(), "") != key);
let restored = baseline
.doc
.nodes()
.iter()
.filter(|node| field(node.name().value(), "") == key)
.cloned();
let index = index.min(candidate.doc.nodes().len());
candidate.doc.nodes_mut().splice(index..index, restored);
candidate.refresh()?;
*self = candidate;
Ok(())
}
fn refresh(&mut self) -> Result<(), Error> {
self.value = Value::Object(object(&self.doc, "")?);
Ok(())
@@ -1124,6 +1154,36 @@ pub fn from_str<T: DeserializeOwned>(source: &str) -> Result<T, Error> {
mod tests {
use super::*;
#[test]
fn restoring_display_records_keeps_authored_comments_and_other_current_settings() {
let baseline=Document::parse("// desk note\noutput-profile \"Desk\" { output match=\"DP-1\" scale=2; }\ninput { repeat-rate 25; }\n").unwrap();
let mut current = baseline.clone();
current
.set("output_profiles.0.outputs.0.scale", 1.5.into())
.unwrap();
current.set("input.repeat_rate", 31.into()).unwrap();
current
.restore_top_level("output_profiles", &baseline)
.unwrap();
assert_eq!(
current.get("output_profiles"),
baseline.get("output_profiles")
);
assert_eq!(
current.get("input.repeat_rate"),
Some(&serde_json::json!(31))
);
assert!(current.to_string().contains("// desk note"));
current
.restore_top_level("output_profiles", &Document::parse("").unwrap())
.unwrap();
assert!(current.get("output_profiles").is_none());
assert_eq!(
current.get("input.repeat_rate"),
Some(&serde_json::json!(31))
);
}
#[test]
fn structured_activity_rules_use_native_kdl_syntax() {
let mut doc = Document::parse("activities { max-visible 2; }\n").unwrap();