Components / controls
KeybindingRecorder view
A field that records one keystroke.
A view survives a frame. Hold it in an Entity with cx.new(..) and reach it with .update(..).
use gpui_kit::controls::keybinding_recorder::KeybindingRecorder;
Reviewed in keybinding.
Construct
new(ident: impl Into<Ident>, _window: &mut Window, cx: &mut Context<Self>) -> Self
Options
Chain onto the value.
label(label: impl Into<SharedString>) -> Self
placeholder(placeholder: impl Into<SharedString>) -> Self
binding(binding: impl Into<SharedString>) -> Self
conflict(reason: Option<impl Into<SharedString>>) -> Self
allow_escape(allow: bool) -> Self
Commands
Need a Context, so they need a view.
set_binding(binding: Option<SharedString>, cx: &mut Context<Self>)
set_conflict(reason: Option<SharedString>, cx: &mut Context<Self>)
set_label(label: Option<SharedString>, cx: &mut Context<Self>)
set_placeholder(placeholder: Option<SharedString>, cx: &mut Context<Self>)
set_allow_escape(allow: bool, cx: &mut Context<Self>)
set_disabled(disabled: bool, cx: &mut Context<Self>)
set_control_size(size: ControlSize, cx: &mut Context<Self>)
start(window: &mut Window, cx: &mut Context<Self>)
cancel(cx: &mut Context<Self>)
Queries
Only answer; they change nothing.
is_disabled() -> bool
is_recording() -> bool
current_binding() -> Option<&SharedString>
Reports
The variants of the event it emits. It never applies the change itself.
- Started
- Captured
- Cancelled
Example · keybinding
fn keybinding(window: &mut Window, cx: &mut App) -> AnyElement {
if !cx.has_global::<SceneRecorders>() {
let idle = cx.new(|cx| {
KeybindingRecorder::new("scene.keybinding.idle", window, cx).label("Open workspace")
});
let recording = cx.new(|cx| {
KeybindingRecorder::new("scene.keybinding.recording", window, cx)
.label("Command palette")
});
let captured = cx.new(|cx| {
KeybindingRecorder::new("scene.keybinding.captured", window, cx)
.label("Toggle terminal")
.binding("ctrl-`")
});
let conflicting = cx.new(|cx| {
KeybindingRecorder::new("scene.keybinding.conflicting", window, cx)
.label("Split editor")
.binding("cmd-shift-p")
// The host's words, not the recorder's: it has no keymap.
.conflict(Some("Already opens the command palette"))
});
// Recording is a state, not a gesture, so the scene puts one recorder
// into it by hand rather than waiting for a keystroke that a still
// image could not photograph anyway.
recording.update(cx, |recorder, cx| recorder.start(window, cx));
cx.set_global(SceneRecorders {
idle,
recording,
captured,
conflicting,
});
}
let recorders = cx.global::<SceneRecorders>().clone();
let theme = cx.theme().clone();
// A recorder carries its name in the tree rather than drawing one, the way
// every other control here does, so the scene puts it where a keymap page
// would: in a settings row that states what the binding is for.
stack(&theme)
.w(px(680.0))
.child(
SettingsSection::new("scene.keybinding.keymap", "Keyboard shortcuts")
.description("Recording captures the next keystroke instead of acting on it.")
.row(
SettingsRow::new("scene.keybinding.row.open", "Open workspace")
.description("Nothing is bound yet")
.control(recorders.idle),
)
.row(
SettingsRow::new("scene.keybinding.row.palette", "Command palette")
.description("Listening for a keystroke")
.control(recorders.recording),
)
.row(
SettingsRow::new("scene.keybinding.row.terminal", "Toggle terminal")
.control(recorders.captured),
)
.row(
SettingsRow::new("scene.keybinding.row.split", "Split editor")
.description("The host judged this one, and said so")
.control(recorders.conflicting),
),
)
.child(caption(
&theme,
"Escape ends recording without capturing, so escape cannot be bound \
unless the caller turns allow_escape on.",
))
.into_any_element()
}