feat(settings): Keymap category — preset select (T-451)
The keybindings-ui extension contributes a Keymap SettingsCategory: a preset select (Default / Vim / VS Code / JetBrains) reading the active preset from kKeymapPresetSetting. Picking one routes through a new schema affordance — SettingsField.applyCommandPrefix — running `keymap.preset.<value>`, which calls KeymapService.setPreset to persist and reload the layered keymap live. The prefix path keeps the engine generic: settings a subsystem applies via a command (rather than a bare key write) declare the prefix; the scope tag and current-value read still use the key. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -42,5 +42,39 @@ class KeybindingsUiExtension extends ClideExtension {
|
||||
return IpcResponse.ok(id: '', data: {'preset': entry.key});
|
||||
},
|
||||
),
|
||||
// Keymap settings category (T-451). The select reads the active preset
|
||||
// from kKeymapPresetSetting; picking one runs `keymap.preset.<value>`
|
||||
// (applyCommandPrefix), which calls KeymapService.setPreset — persisting
|
||||
// and reloading the layered keymap live.
|
||||
const SettingsCategoryContribution(
|
||||
id: 'keymap',
|
||||
category: SettingsCategory(
|
||||
id: 'keymap',
|
||||
title: 'Keymap',
|
||||
iconName: 'keyboard',
|
||||
priority: 20,
|
||||
sections: [
|
||||
SettingsSection(
|
||||
label: 'Preset',
|
||||
fields: [
|
||||
SettingsField(
|
||||
key: kKeymapPresetSetting,
|
||||
kind: SettingsFieldKind.select,
|
||||
label: 'Active preset',
|
||||
help: 'Keyboard layout for the whole app.',
|
||||
defaultValue: 'default',
|
||||
applyCommandPrefix: 'keymap.preset.',
|
||||
options: [
|
||||
SettingsOption(value: 'default', label: 'Default'),
|
||||
SettingsOption(value: 'vim', label: 'Vim'),
|
||||
SettingsOption(value: 'vscode', label: 'VS Code'),
|
||||
SettingsOption(value: 'jetbrains', label: 'JetBrains'),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -206,7 +206,19 @@ class _Control extends StatelessWidget {
|
||||
case SettingsFieldKind.toggle:
|
||||
return _ToggleControl(checked: value == true, onChanged: _set);
|
||||
case SettingsFieldKind.select:
|
||||
return _SelectControl(field: field, value: value?.toString(), onPick: _set);
|
||||
return _SelectControl(
|
||||
field: field,
|
||||
value: value?.toString(),
|
||||
onPick: (v) {
|
||||
final prefix = field.applyCommandPrefix;
|
||||
if (prefix != null) {
|
||||
// Value selects a command (the subsystem applies + persists).
|
||||
ClideKernel.of(context).commands.execute('$prefix$v');
|
||||
} else {
|
||||
_set(v);
|
||||
}
|
||||
},
|
||||
);
|
||||
case SettingsFieldKind.text:
|
||||
return _EditControl(field: field, value: value?.toString() ?? '', numeric: false, onCommit: _set);
|
||||
case SettingsFieldKind.number:
|
||||
|
||||
@@ -52,6 +52,7 @@ class SettingsField {
|
||||
this.min,
|
||||
this.max,
|
||||
this.fileCommand,
|
||||
this.applyCommandPrefix,
|
||||
});
|
||||
|
||||
final String key;
|
||||
@@ -73,6 +74,13 @@ class SettingsField {
|
||||
|
||||
/// For [SettingsFieldKind.file]: the command id the row's button invokes.
|
||||
final String? fileCommand;
|
||||
|
||||
/// For [SettingsFieldKind.select]: when set, picking option `<value>` runs
|
||||
/// the command `<applyCommandPrefix><value>` instead of writing [key]
|
||||
/// directly — for settings a subsystem applies via a command (and only then
|
||||
/// persists). The current value is still read from [key], so the scope tag
|
||||
/// and selection still work. Example: `'keymap.preset.'` → `keymap.preset.vim`.
|
||||
final String? applyCommandPrefix;
|
||||
}
|
||||
|
||||
/// A carded group of fields (surface.md "sectioned cards"). [label] is the
|
||||
|
||||
Reference in New Issue
Block a user