use gpui_kit::{App, Div, ElementId, KeyBinding, Stateful, Window, actions, div, prelude::*};
actions!(macos_focus, [Next, Previous]);
pub(crate) fn init(cx: &mut App) {
cx.bind_keys([
KeyBinding::new(
if cfg!(target_os = "macos") {
"cmd-c"
} else {
"ctrl-c"
},
gpui_kit::base::input::Copy,
Some("macOSFocusScope"),
),
KeyBinding::new("tab", Next, Some("macOSFocusScope")),
KeyBinding::new("shift-tab", Previous, Some("macOSFocusScope")),
]);
}
pub fn focus_scope(id: impl Into<ElementId>) -> Stateful<Div> {
div()
.id(id)
.tab_group()
.key_context("macOSFocusScope")
.on_action(|_: &gpui_kit::base::input::Copy, window: &mut Window, cx| {
let selected = gpui_kit::base::TextSelection::selected_text(window, cx);
if selected.is_empty() {
cx.propagate();
} else {
cx.write_to_clipboard(gpui_kit::ClipboardItem::new_string(selected));
}
})
.on_action(|_: &Next, window: &mut Window, cx| traverse(window, cx, false))
.on_action(|_: &Previous, window: &mut Window, cx| traverse(window, cx, true))
.on_action(
|_: &gpui_kit::base::input::IndentInline, window: &mut Window, cx| {
traverse(window, cx, false)
},
)
.on_action(
|_: &gpui_kit::base::input::OutdentInline, window: &mut Window, cx| {
traverse(window, cx, true)
},
)
}
fn traverse(window: &mut Window, cx: &mut App, backwards: bool) {
let trap = gpui_kit::base::active_focus_trap(window, cx);
let mut visited = Vec::new();
loop {
if backwards {
window.focus_prev(cx);
} else {
window.focus_next(cx);
}
let Some(trap) = &trap else {
return;
};
if trap.contains_focused(window, cx) {
return;
}
let focused = window.focused(cx);
if focused.is_none() || visited.contains(&focused) {
trap.focus(window, cx);
return;
}
visited.push(focused);
}
}