mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-24 19:10:24 +00:00
Fix assorted linux issues (#10061)
- Fix a bug where modifiers would be dispatched before they changed - Add a secondary modifier - Improve keybindings Release Notes: - N/A
This commit is contained in:
parent
e0cd96db7b
commit
1da2441e7b
20 changed files with 220 additions and 154 deletions
|
@ -219,7 +219,7 @@
|
|||
"context": "BufferSearchBar && in_replace",
|
||||
"bindings": {
|
||||
"enter": "search::ReplaceNext",
|
||||
"cmd-enter": "search::ReplaceAll"
|
||||
"ctrl-enter": "search::ReplaceAll"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -258,7 +258,7 @@
|
|||
"bindings": {
|
||||
"escape": "project_search::ToggleFocus",
|
||||
"alt-tab": "search::CycleMode",
|
||||
"cmd-shift-h": "search::ToggleReplace",
|
||||
"ctrl-shift-h": "search::ToggleReplace",
|
||||
"alt-ctrl-g": "search::ActivateRegexMode",
|
||||
"alt-ctrl-x": "search::ActivateTextMode"
|
||||
}
|
||||
|
@ -304,8 +304,10 @@
|
|||
}
|
||||
],
|
||||
"ctrl-alt-shift-down": "editor::DuplicateLine",
|
||||
"ctrl-shift-right": "editor::SelectLargerSyntaxNode",
|
||||
"ctrl-shift-left": "editor::SelectSmallerSyntaxNode",
|
||||
"ctrl-shift-left": "editor::SelectToPreviousWordStart",
|
||||
"ctrl-shift-right": "editor::SelectToNextWordEnd",
|
||||
"ctrl-shift-up": "editor::SelectLargerSyntaxNode", //todo(linux) tmp keybinding
|
||||
"ctrl-shift-down": "editor::SelectSmallerSyntaxNode", //todo(linux) tmp keybinding
|
||||
"ctrl-d": [
|
||||
"editor::SelectNext",
|
||||
{
|
||||
|
@ -354,14 +356,14 @@
|
|||
"ctrl-shift-]": "editor::UnfoldLines",
|
||||
"ctrl-space": "editor::ShowCompletions",
|
||||
"ctrl-.": "editor::ToggleCodeActions",
|
||||
"alt-cmd-r": "editor::RevealInFinder",
|
||||
"alt-ctrl-r": "editor::RevealInFinder",
|
||||
"ctrl-alt-shift-c": "editor::DisplayCursorNames"
|
||||
}
|
||||
},
|
||||
{
|
||||
"context": "Editor && mode == full",
|
||||
"bindings": {
|
||||
"cmd-shift-o": "outline::Toggle",
|
||||
"ctrl-shift-o": "outline::Toggle",
|
||||
"ctrl-g": "go_to_line::Toggle"
|
||||
}
|
||||
},
|
||||
|
@ -419,7 +421,7 @@
|
|||
"ctrl-shift-f": "pane::DeploySearch",
|
||||
"ctrl-k ctrl-s": "zed::OpenKeymap",
|
||||
"ctrl-k ctrl-t": "theme_selector::Toggle",
|
||||
"ctrl-t": "project_symbols::Toggle",
|
||||
"ctrl-shift-t": "project_symbols::Toggle",
|
||||
"ctrl-p": "file_finder::Toggle",
|
||||
"ctrl-tab": "tab_switcher::Toggle",
|
||||
"ctrl-shift-tab": ["tab_switcher::Toggle", { "select_last": true }],
|
||||
|
@ -549,7 +551,7 @@
|
|||
"delete": "project_panel::Delete",
|
||||
"ctrl-backspace": ["project_panel::Delete", { "skip_prompt": true }],
|
||||
"ctrl-delete": ["project_panel::Delete", { "skip_prompt": true }],
|
||||
"alt-cmd-r": "project_panel::RevealInFinder",
|
||||
"alt-ctrl-r": "project_panel::RevealInFinder",
|
||||
"alt-shift-f": "project_panel::NewSearchInDirectory"
|
||||
}
|
||||
},
|
||||
|
@ -610,7 +612,12 @@
|
|||
"pagedown": ["terminal::SendKeystroke", "pagedown"],
|
||||
"escape": ["terminal::SendKeystroke", "escape"],
|
||||
"enter": ["terminal::SendKeystroke", "enter"],
|
||||
"ctrl-c": ["terminal::SendKeystroke", "ctrl-c"]
|
||||
"ctrl-c": ["terminal::SendKeystroke", "ctrl-c"],
|
||||
|
||||
// Some nice conveniences
|
||||
"ctrl-backspace": ["terminal::SendText", "\u0015"],
|
||||
"ctrl-right": ["terminal::SendText", "\u0005"],
|
||||
"ctrl-left": ["terminal::SendText", "\u0001"]
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
|
@ -48,7 +48,8 @@
|
|||
// which gives the same size as all other panes.
|
||||
"active_pane_magnification": 1.0,
|
||||
// The key to use for adding multiple cursors
|
||||
// Currently "alt" or "cmd" are supported.
|
||||
// Currently "alt" or "cmd_or_ctrl" (also aliased as
|
||||
// "cmd" and "ctrl") are supported.
|
||||
"multi_cursor_modifier": "alt",
|
||||
// Whether to enable vim modes and key bindings
|
||||
"vim_mode": false,
|
||||
|
|
|
@ -92,7 +92,8 @@ pub enum ShowScrollbar {
|
|||
#[serde(rename_all = "snake_case")]
|
||||
pub enum MultiCursorModifier {
|
||||
Alt,
|
||||
Cmd,
|
||||
#[serde(alias = "cmd", alias = "ctrl")]
|
||||
CmdOrCtrl,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
|
||||
|
|
|
@ -449,7 +449,8 @@ impl EditorElement {
|
|||
},
|
||||
cx,
|
||||
);
|
||||
} else if modifiers.shift && !modifiers.control && !modifiers.alt && !modifiers.command {
|
||||
} else if modifiers.shift && !modifiers.control && !modifiers.alt && !modifiers.secondary()
|
||||
{
|
||||
editor.select(
|
||||
SelectPhase::Extend {
|
||||
position,
|
||||
|
@ -461,7 +462,7 @@ impl EditorElement {
|
|||
let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
|
||||
let multi_cursor_modifier = match multi_cursor_setting {
|
||||
MultiCursorModifier::Alt => modifiers.alt,
|
||||
MultiCursorModifier::Cmd => modifiers.command,
|
||||
MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
|
||||
};
|
||||
editor.select(
|
||||
SelectPhase::Begin {
|
||||
|
@ -513,8 +514,8 @@ impl EditorElement {
|
|||
|
||||
let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;
|
||||
let multi_cursor_modifier = match multi_cursor_setting {
|
||||
MultiCursorModifier::Alt => event.modifiers.command,
|
||||
MultiCursorModifier::Cmd => event.modifiers.alt,
|
||||
MultiCursorModifier::Alt => event.modifiers.secondary(),
|
||||
MultiCursorModifier::CmdOrCtrl => event.modifiers.alt,
|
||||
};
|
||||
|
||||
if !pending_nonempty_selections && multi_cursor_modifier && text_hitbox.is_hovered(cx) {
|
||||
|
|
|
@ -93,7 +93,7 @@ impl Editor {
|
|||
modifiers: Modifiers,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) {
|
||||
if !modifiers.command || self.has_pending_selection() {
|
||||
if !modifiers.secondary() || self.has_pending_selection() {
|
||||
self.hide_hovered_link(cx);
|
||||
return;
|
||||
}
|
||||
|
@ -113,7 +113,7 @@ impl Editor {
|
|||
&snapshot,
|
||||
point_for_position,
|
||||
self,
|
||||
modifiers.command,
|
||||
modifiers.secondary(),
|
||||
modifiers.shift,
|
||||
cx,
|
||||
);
|
||||
|
@ -256,7 +256,7 @@ pub fn update_inlay_link_and_hover_points(
|
|||
snapshot: &EditorSnapshot,
|
||||
point_for_position: PointForPosition,
|
||||
editor: &mut Editor,
|
||||
cmd_held: bool,
|
||||
secondary_held: bool,
|
||||
shift_held: bool,
|
||||
cx: &mut ViewContext<'_, Editor>,
|
||||
) {
|
||||
|
@ -394,7 +394,9 @@ pub fn update_inlay_link_and_hover_points(
|
|||
if let Some((language_server_id, location)) =
|
||||
hovered_hint_part.location
|
||||
{
|
||||
if cmd_held && !editor.has_pending_nonempty_selection() {
|
||||
if secondary_held
|
||||
&& !editor.has_pending_nonempty_selection()
|
||||
{
|
||||
go_to_definition_updated = true;
|
||||
show_link_definition(
|
||||
shift_held,
|
||||
|
@ -762,7 +764,7 @@ mod tests {
|
|||
let «variable» = A;
|
||||
"});
|
||||
|
||||
cx.simulate_modifiers_change(Modifiers::command());
|
||||
cx.simulate_modifiers_change(Modifiers::secondary_key());
|
||||
cx.run_until_parked();
|
||||
// Assert no link highlights
|
||||
cx.assert_editor_text_highlights::<HoveredLinkState>(indoc! {"
|
||||
|
@ -823,7 +825,7 @@ mod tests {
|
|||
])))
|
||||
});
|
||||
|
||||
cx.simulate_mouse_move(hover_point, Modifiers::command());
|
||||
cx.simulate_mouse_move(hover_point, Modifiers::secondary_key());
|
||||
requests.next().await;
|
||||
cx.background_executor.run_until_parked();
|
||||
cx.assert_editor_text_highlights::<HoveredLinkState>(indoc! {"
|
||||
|
@ -849,7 +851,7 @@ mod tests {
|
|||
])))
|
||||
});
|
||||
|
||||
cx.simulate_mouse_move(hover_point, Modifiers::command());
|
||||
cx.simulate_mouse_move(hover_point, Modifiers::secondary_key());
|
||||
requests.next().await;
|
||||
cx.background_executor.run_until_parked();
|
||||
cx.assert_editor_text_highlights::<HoveredLinkState>(indoc! {"
|
||||
|
@ -868,7 +870,7 @@ mod tests {
|
|||
// No definitions returned
|
||||
Ok(Some(lsp::GotoDefinitionResponse::Link(vec![])))
|
||||
});
|
||||
cx.simulate_mouse_move(hover_point, Modifiers::command());
|
||||
cx.simulate_mouse_move(hover_point, Modifiers::secondary_key());
|
||||
|
||||
requests.next().await;
|
||||
cx.background_executor.run_until_parked();
|
||||
|
@ -912,7 +914,7 @@ mod tests {
|
|||
])))
|
||||
});
|
||||
|
||||
cx.simulate_modifiers_change(Modifiers::command());
|
||||
cx.simulate_modifiers_change(Modifiers::secondary_key());
|
||||
|
||||
requests.next().await;
|
||||
cx.background_executor.run_until_parked();
|
||||
|
@ -928,7 +930,7 @@ mod tests {
|
|||
fn do_work() { test(); }
|
||||
"});
|
||||
|
||||
cx.simulate_mouse_move(hover_point, Modifiers::command());
|
||||
cx.simulate_mouse_move(hover_point, Modifiers::secondary_key());
|
||||
cx.background_executor.run_until_parked();
|
||||
cx.assert_editor_text_highlights::<HoveredLinkState>(indoc! {"
|
||||
fn test() { do_work(); }
|
||||
|
@ -940,7 +942,7 @@ mod tests {
|
|||
fn test() { do_work(); }
|
||||
fn do_work() { tesˇt(); }
|
||||
"});
|
||||
cx.simulate_mouse_move(hover_point, Modifiers::command());
|
||||
cx.simulate_mouse_move(hover_point, Modifiers::secondary_key());
|
||||
cx.background_executor.run_until_parked();
|
||||
cx.assert_editor_text_highlights::<HoveredLinkState>(indoc! {"
|
||||
fn test() { do_work(); }
|
||||
|
@ -948,7 +950,7 @@ mod tests {
|
|||
"});
|
||||
|
||||
// Cmd click with existing definition doesn't re-request and dismisses highlight
|
||||
cx.simulate_click(hover_point, Modifiers::command());
|
||||
cx.simulate_click(hover_point, Modifiers::secondary_key());
|
||||
cx.lsp
|
||||
.handle_request::<GotoDefinition, _, _>(move |_, _| async move {
|
||||
// Empty definition response to make sure we aren't hitting the lsp and using
|
||||
|
@ -987,7 +989,7 @@ mod tests {
|
|||
},
|
||||
])))
|
||||
});
|
||||
cx.simulate_click(hover_point, Modifiers::command());
|
||||
cx.simulate_click(hover_point, Modifiers::secondary_key());
|
||||
requests.next().await;
|
||||
cx.background_executor.run_until_parked();
|
||||
cx.assert_editor_state(indoc! {"
|
||||
|
@ -1030,7 +1032,7 @@ mod tests {
|
|||
s.set_pending_anchor_range(anchor_range, crate::SelectMode::Character)
|
||||
});
|
||||
});
|
||||
cx.simulate_mouse_move(hover_point, Modifiers::command());
|
||||
cx.simulate_mouse_move(hover_point, Modifiers::secondary_key());
|
||||
cx.background_executor.run_until_parked();
|
||||
assert!(requests.try_next().is_err());
|
||||
cx.assert_editor_text_highlights::<HoveredLinkState>(indoc! {"
|
||||
|
@ -1144,7 +1146,7 @@ mod tests {
|
|||
});
|
||||
// Press cmd to trigger highlight
|
||||
let hover_point = cx.pixel_position_for(midpoint);
|
||||
cx.simulate_mouse_move(hover_point, Modifiers::command());
|
||||
cx.simulate_mouse_move(hover_point, Modifiers::secondary_key());
|
||||
cx.background_executor.run_until_parked();
|
||||
cx.update_editor(|editor, cx| {
|
||||
let snapshot = editor.snapshot(cx);
|
||||
|
@ -1175,9 +1177,9 @@ mod tests {
|
|||
assert!(actual_ranges.is_empty(), "When no cmd is pressed, should have no hint label selected, but got: {actual_ranges:?}");
|
||||
});
|
||||
|
||||
cx.simulate_modifiers_change(Modifiers::command());
|
||||
cx.simulate_modifiers_change(Modifiers::secondary_key());
|
||||
cx.background_executor.run_until_parked();
|
||||
cx.simulate_click(hover_point, Modifiers::command());
|
||||
cx.simulate_click(hover_point, Modifiers::secondary_key());
|
||||
cx.background_executor.run_until_parked();
|
||||
cx.assert_editor_state(indoc! {"
|
||||
struct «TestStructˇ»;
|
||||
|
@ -1207,12 +1209,12 @@ mod tests {
|
|||
Let's test a [complex](https://zed.dev/channel/had-(ˇoops)) case.
|
||||
"});
|
||||
|
||||
cx.simulate_mouse_move(screen_coord, Modifiers::command());
|
||||
cx.simulate_mouse_move(screen_coord, Modifiers::secondary_key());
|
||||
cx.assert_editor_text_highlights::<HoveredLinkState>(indoc! {"
|
||||
Let's test a [complex](«https://zed.dev/channel/had-(oops)ˇ») case.
|
||||
"});
|
||||
|
||||
cx.simulate_click(screen_coord, Modifiers::command());
|
||||
cx.simulate_click(screen_coord, Modifiers::secondary_key());
|
||||
assert_eq!(
|
||||
cx.opened_url(),
|
||||
Some("https://zed.dev/channel/had-(oops)".into())
|
||||
|
@ -1235,12 +1237,12 @@ mod tests {
|
|||
let screen_coord =
|
||||
cx.pixel_position(indoc! {"https://zed.dev/relˇeases is a cool webpage."});
|
||||
|
||||
cx.simulate_mouse_move(screen_coord, Modifiers::command());
|
||||
cx.simulate_mouse_move(screen_coord, Modifiers::secondary_key());
|
||||
cx.assert_editor_text_highlights::<HoveredLinkState>(
|
||||
indoc! {"«https://zed.dev/releasesˇ» is a cool webpage."},
|
||||
);
|
||||
|
||||
cx.simulate_click(screen_coord, Modifiers::command());
|
||||
cx.simulate_click(screen_coord, Modifiers::secondary_key());
|
||||
assert_eq!(cx.opened_url(), Some("https://zed.dev/releases".into()));
|
||||
}
|
||||
|
||||
|
@ -1260,12 +1262,12 @@ mod tests {
|
|||
let screen_coord =
|
||||
cx.pixel_position(indoc! {"A cool webpage is https://zed.dev/releˇases"});
|
||||
|
||||
cx.simulate_mouse_move(screen_coord, Modifiers::command());
|
||||
cx.simulate_mouse_move(screen_coord, Modifiers::secondary_key());
|
||||
cx.assert_editor_text_highlights::<HoveredLinkState>(
|
||||
indoc! {"A cool webpage is «https://zed.dev/releasesˇ»"},
|
||||
);
|
||||
|
||||
cx.simulate_click(screen_coord, Modifiers::command());
|
||||
cx.simulate_click(screen_coord, Modifiers::secondary_key());
|
||||
assert_eq!(cx.opened_url(), Some("https://zed.dev/releases".into()));
|
||||
}
|
||||
|
||||
|
@ -1386,7 +1388,7 @@ mod tests {
|
|||
});
|
||||
|
||||
for _ in 0..5 {
|
||||
cx.simulate_click(definition_hover_point, Modifiers::command());
|
||||
cx.simulate_click(definition_hover_point, Modifiers::secondary_key());
|
||||
cx.background_executor.run_until_parked();
|
||||
cx.assert_editor_state(indoc! {"
|
||||
fn test() {
|
||||
|
@ -1398,7 +1400,7 @@ mod tests {
|
|||
}
|
||||
"});
|
||||
|
||||
cx.simulate_click(reference_hover_point, Modifiers::command());
|
||||
cx.simulate_click(reference_hover_point, Modifiers::secondary_key());
|
||||
cx.background_executor.run_until_parked();
|
||||
cx.assert_editor_state(indoc! {"
|
||||
fn «testˇ»() {
|
||||
|
|
|
@ -1490,7 +1490,7 @@ async fn test_keeps_file_finder_open_after_modifier_keys_release(cx: &mut gpui::
|
|||
|
||||
open_queried_buffer("1", 1, "1.txt", &workspace, cx).await;
|
||||
|
||||
cx.simulate_modifiers_change(Modifiers::command());
|
||||
cx.simulate_modifiers_change(Modifiers::secondary_key());
|
||||
open_file_picker(&workspace, cx);
|
||||
|
||||
cx.simulate_modifiers_change(Modifiers::none());
|
||||
|
@ -1519,7 +1519,7 @@ async fn test_opens_file_on_modifier_keys_release(cx: &mut gpui::TestAppContext)
|
|||
open_queried_buffer("1", 1, "1.txt", &workspace, cx).await;
|
||||
open_queried_buffer("2", 1, "2.txt", &workspace, cx).await;
|
||||
|
||||
cx.simulate_modifiers_change(Modifiers::command());
|
||||
cx.simulate_modifiers_change(Modifiers::secondary_key());
|
||||
let picker = open_file_picker(&workspace, cx);
|
||||
picker.update(cx, |finder, _| {
|
||||
assert_eq!(finder.delegate.matches.len(), 2);
|
||||
|
@ -1560,7 +1560,7 @@ async fn test_switches_between_release_norelease_modes_on_forward_nav(
|
|||
open_queried_buffer("2", 1, "2.txt", &workspace, cx).await;
|
||||
|
||||
// Open with a shortcut
|
||||
cx.simulate_modifiers_change(Modifiers::command());
|
||||
cx.simulate_modifiers_change(Modifiers::secondary_key());
|
||||
let picker = open_file_picker(&workspace, cx);
|
||||
picker.update(cx, |finder, _| {
|
||||
assert_eq!(finder.delegate.matches.len(), 2);
|
||||
|
@ -1581,7 +1581,7 @@ async fn test_switches_between_release_norelease_modes_on_forward_nav(
|
|||
|
||||
// Back to navigation with initial shortcut
|
||||
// Open file on modifiers release
|
||||
cx.simulate_modifiers_change(Modifiers::command());
|
||||
cx.simulate_modifiers_change(Modifiers::secondary_key());
|
||||
cx.dispatch_action(Toggle);
|
||||
cx.simulate_modifiers_change(Modifiers::none());
|
||||
cx.read(|cx| {
|
||||
|
@ -1617,7 +1617,7 @@ async fn test_switches_between_release_norelease_modes_on_backward_nav(
|
|||
open_queried_buffer("3", 1, "3.txt", &workspace, cx).await;
|
||||
|
||||
// Open with a shortcut
|
||||
cx.simulate_modifiers_change(Modifiers::command());
|
||||
cx.simulate_modifiers_change(Modifiers::secondary_key());
|
||||
let picker = open_file_picker(&workspace, cx);
|
||||
picker.update(cx, |finder, _| {
|
||||
assert_eq!(finder.delegate.matches.len(), 3);
|
||||
|
@ -1640,7 +1640,7 @@ async fn test_switches_between_release_norelease_modes_on_backward_nav(
|
|||
|
||||
// Back to navigation with initial shortcut
|
||||
// Open file on modifiers release
|
||||
cx.simulate_modifiers_change(Modifiers::command());
|
||||
cx.simulate_modifiers_change(Modifiers::secondary_key());
|
||||
cx.dispatch_action(SelectPrev); // <-- File Finder's SelectPrev, not menu's
|
||||
cx.simulate_modifiers_change(Modifiers::none());
|
||||
cx.read(|cx| {
|
||||
|
@ -1669,7 +1669,7 @@ async fn test_extending_modifiers_does_not_confirm_selection(cx: &mut gpui::Test
|
|||
|
||||
open_queried_buffer("1", 1, "1.txt", &workspace, cx).await;
|
||||
|
||||
cx.simulate_modifiers_change(Modifiers::command());
|
||||
cx.simulate_modifiers_change(Modifiers::secondary_key());
|
||||
open_file_picker(&workspace, cx);
|
||||
|
||||
cx.simulate_modifiers_change(Modifiers::command_shift());
|
||||
|
|
|
@ -1510,12 +1510,12 @@ impl Interactivity {
|
|||
};
|
||||
if self.location.is_some()
|
||||
&& text_bounds.contains(&cx.mouse_position())
|
||||
&& cx.modifiers().command
|
||||
&& cx.modifiers().secondary()
|
||||
{
|
||||
let command_held = cx.modifiers().command;
|
||||
let secondary_held = cx.modifiers().secondary();
|
||||
cx.on_key_event({
|
||||
move |e: &crate::ModifiersChangedEvent, _phase, cx| {
|
||||
if e.modifiers.command != command_held
|
||||
if e.modifiers.secondary() != secondary_held
|
||||
&& text_bounds.contains(&cx.mouse_position())
|
||||
{
|
||||
cx.refresh();
|
||||
|
|
|
@ -37,7 +37,7 @@ impl Keystroke {
|
|||
control: self.modifiers.control,
|
||||
alt: false,
|
||||
shift: false,
|
||||
command: false,
|
||||
platform: false,
|
||||
function: false,
|
||||
},
|
||||
key: ime_key.to_string(),
|
||||
|
@ -62,7 +62,7 @@ impl Keystroke {
|
|||
let mut control = false;
|
||||
let mut alt = false;
|
||||
let mut shift = false;
|
||||
let mut command = false;
|
||||
let mut platform = false;
|
||||
let mut function = false;
|
||||
let mut key = None;
|
||||
let mut ime_key = None;
|
||||
|
@ -73,8 +73,13 @@ impl Keystroke {
|
|||
"ctrl" => control = true,
|
||||
"alt" => alt = true,
|
||||
"shift" => shift = true,
|
||||
"cmd" => command = true,
|
||||
"fn" => function = true,
|
||||
#[cfg(target_os = "macos")]
|
||||
"cmd" => platform = true,
|
||||
#[cfg(target_os = "linux")]
|
||||
"super" => platform = true,
|
||||
#[cfg(target_os = "windows")]
|
||||
"win" => platform = true,
|
||||
_ => {
|
||||
if let Some(next) = components.peek() {
|
||||
if next.is_empty() && source.ends_with('-') {
|
||||
|
@ -101,7 +106,7 @@ impl Keystroke {
|
|||
control,
|
||||
alt,
|
||||
shift,
|
||||
command,
|
||||
platform,
|
||||
function,
|
||||
},
|
||||
key,
|
||||
|
@ -114,7 +119,7 @@ impl Keystroke {
|
|||
/// be able to simulate typing "space", etc.
|
||||
pub fn with_simulated_ime(mut self) -> Self {
|
||||
if self.ime_key.is_none()
|
||||
&& !self.modifiers.command
|
||||
&& !self.modifiers.platform
|
||||
&& !self.modifiers.control
|
||||
&& !self.modifiers.function
|
||||
&& !self.modifiers.alt
|
||||
|
@ -147,8 +152,15 @@ impl std::fmt::Display for Keystroke {
|
|||
if self.modifiers.alt {
|
||||
f.write_char('⌥')?;
|
||||
}
|
||||
if self.modifiers.command {
|
||||
if self.modifiers.platform {
|
||||
#[cfg(target_os = "macos")]
|
||||
f.write_char('⌘')?;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
f.write_char('❖')?;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
f.write_char('⊞')?;
|
||||
}
|
||||
if self.modifiers.shift {
|
||||
f.write_char('⇧')?;
|
||||
|
@ -188,7 +200,8 @@ pub struct Modifiers {
|
|||
|
||||
/// The command key, on macos
|
||||
/// the windows key, on windows
|
||||
pub command: bool,
|
||||
/// the super key, on linux
|
||||
pub platform: bool,
|
||||
|
||||
/// The function key
|
||||
pub function: bool,
|
||||
|
@ -197,7 +210,22 @@ pub struct Modifiers {
|
|||
impl Modifiers {
|
||||
/// Returns true if any modifier key is pressed
|
||||
pub fn modified(&self) -> bool {
|
||||
self.control || self.alt || self.shift || self.command || self.function
|
||||
self.control || self.alt || self.shift || self.platform || self.function
|
||||
}
|
||||
|
||||
/// Whether the semantically 'secondary' modifier key is pressed
|
||||
/// On macos, this is the command key
|
||||
/// On windows and linux, this is the control key
|
||||
pub fn secondary(&self) -> bool {
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
return self.platform;
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
{
|
||||
return self.control;
|
||||
}
|
||||
}
|
||||
|
||||
/// helper method for Modifiers with no modifiers
|
||||
|
@ -205,10 +233,45 @@ impl Modifiers {
|
|||
Default::default()
|
||||
}
|
||||
|
||||
/// helper method for Modifiers with just command
|
||||
/// helper method for Modifiers with just the command key
|
||||
pub fn command() -> Modifiers {
|
||||
Modifiers {
|
||||
command: true,
|
||||
platform: true,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
/// A helper method for Modifiers with just the secondary key pressed
|
||||
pub fn secondary_key() -> Modifiers {
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
Modifiers {
|
||||
platform: true,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
{
|
||||
Modifiers {
|
||||
control: true,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// helper method for Modifiers with just the windows key
|
||||
pub fn windows() -> Modifiers {
|
||||
Modifiers {
|
||||
platform: true,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
/// helper method for Modifiers with just the super key
|
||||
pub fn super_key() -> Modifiers {
|
||||
Modifiers {
|
||||
platform: true,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
@ -233,7 +296,7 @@ impl Modifiers {
|
|||
pub fn command_shift() -> Modifiers {
|
||||
Modifiers {
|
||||
shift: true,
|
||||
command: true,
|
||||
platform: true,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
@ -243,7 +306,7 @@ impl Modifiers {
|
|||
(other.control || !self.control)
|
||||
&& (other.alt || !self.alt)
|
||||
&& (other.shift || !self.shift)
|
||||
&& (other.command || !self.command)
|
||||
&& (other.platform || !self.platform)
|
||||
&& (other.function || !self.function)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -190,7 +190,7 @@ impl WaylandClient {
|
|||
control: false,
|
||||
alt: false,
|
||||
function: false,
|
||||
command: false,
|
||||
platform: false,
|
||||
},
|
||||
scroll_direction: -1.0,
|
||||
axis_source: AxisSource::Wheel,
|
||||
|
@ -692,6 +692,11 @@ impl Dispatch<wl_keyboard::WlKeyboard, ()> for WaylandClientState {
|
|||
group,
|
||||
..
|
||||
} => {
|
||||
let focused_window = state.keyboard_focused_window.clone();
|
||||
let Some(focused_window) = focused_window else {
|
||||
return;
|
||||
};
|
||||
|
||||
let keymap_state = state.keymap_state.as_mut().unwrap();
|
||||
keymap_state.update_mask(mods_depressed, mods_latched, mods_locked, 0, 0, group);
|
||||
|
||||
|
@ -707,14 +712,22 @@ impl Dispatch<wl_keyboard::WlKeyboard, ()> for WaylandClientState {
|
|||
state.modifiers.shift = shift;
|
||||
state.modifiers.alt = alt;
|
||||
state.modifiers.control = control;
|
||||
state.modifiers.command = command;
|
||||
state.modifiers.platform = command;
|
||||
|
||||
let input = PlatformInput::ModifiersChanged(ModifiersChangedEvent {
|
||||
modifiers: state.modifiers,
|
||||
});
|
||||
|
||||
drop(state);
|
||||
|
||||
focused_window.handle_input(input);
|
||||
}
|
||||
wl_keyboard::Event::Key {
|
||||
key,
|
||||
state: WEnum::Value(key_state),
|
||||
..
|
||||
} => {
|
||||
let focused_window = &state.keyboard_focused_window;
|
||||
let focused_window = state.keyboard_focused_window.clone();
|
||||
let Some(focused_window) = focused_window else {
|
||||
return;
|
||||
};
|
||||
|
@ -725,80 +738,56 @@ impl Dispatch<wl_keyboard::WlKeyboard, ()> for WaylandClientState {
|
|||
let keysym = keymap_state.key_get_one_sym(keycode);
|
||||
|
||||
match key_state {
|
||||
wl_keyboard::KeyState::Pressed => {
|
||||
let input = if keysym.is_modifier_key() {
|
||||
PlatformInput::ModifiersChanged(ModifiersChangedEvent {
|
||||
modifiers: state.modifiers,
|
||||
wl_keyboard::KeyState::Pressed if !keysym.is_modifier_key() => {
|
||||
let input = PlatformInput::KeyDown(KeyDownEvent {
|
||||
keystroke: Keystroke::from_xkb(keymap_state, state.modifiers, keycode),
|
||||
is_held: false, // todo(linux)
|
||||
});
|
||||
|
||||
state.repeat.current_id += 1;
|
||||
state.repeat.current_keysym = Some(keysym);
|
||||
|
||||
let rate = state.repeat.characters_per_second;
|
||||
let delay = state.repeat.delay;
|
||||
let id = state.repeat.current_id;
|
||||
let this = this.clone();
|
||||
|
||||
let timer = Timer::from_duration(delay);
|
||||
let state_ = Rc::clone(&this.client_state_inner);
|
||||
let input_ = input.clone();
|
||||
state
|
||||
.loop_handle
|
||||
.insert_source(timer, move |event, _metadata, shared_data| {
|
||||
let state_ = state_.borrow_mut();
|
||||
let is_repeating = id == state_.repeat.current_id
|
||||
&& state_.repeat.current_keysym.is_some()
|
||||
&& state_.keyboard_focused_window.is_some();
|
||||
|
||||
if !is_repeating {
|
||||
return TimeoutAction::Drop;
|
||||
}
|
||||
|
||||
let focused_window =
|
||||
state_.keyboard_focused_window.as_ref().unwrap().clone();
|
||||
|
||||
drop(state_);
|
||||
|
||||
focused_window.handle_input(input_.clone());
|
||||
|
||||
TimeoutAction::ToDuration(Duration::from_secs(1) / rate)
|
||||
})
|
||||
} else {
|
||||
PlatformInput::KeyDown(KeyDownEvent {
|
||||
keystroke: Keystroke::from_xkb(
|
||||
keymap_state,
|
||||
state.modifiers,
|
||||
keycode,
|
||||
),
|
||||
is_held: false, // todo(linux)
|
||||
})
|
||||
};
|
||||
|
||||
if !keysym.is_modifier_key() {
|
||||
state.repeat.current_id += 1;
|
||||
state.repeat.current_keysym = Some(keysym);
|
||||
|
||||
let rate = state.repeat.characters_per_second;
|
||||
let delay = state.repeat.delay;
|
||||
let id = state.repeat.current_id;
|
||||
let this = this.clone();
|
||||
|
||||
let timer = Timer::from_duration(delay);
|
||||
let state_ = Rc::clone(&this.client_state_inner);
|
||||
let input_ = input.clone();
|
||||
state
|
||||
.loop_handle
|
||||
.insert_source(timer, move |event, _metadata, shared_data| {
|
||||
let state_ = state_.borrow_mut();
|
||||
let is_repeating = id == state_.repeat.current_id
|
||||
&& state_.repeat.current_keysym.is_some()
|
||||
&& state_.keyboard_focused_window.is_some();
|
||||
|
||||
if !is_repeating {
|
||||
return TimeoutAction::Drop;
|
||||
}
|
||||
|
||||
let focused_window =
|
||||
state_.keyboard_focused_window.as_ref().unwrap().clone();
|
||||
|
||||
drop(state_);
|
||||
|
||||
focused_window.handle_input(input_.clone());
|
||||
|
||||
TimeoutAction::ToDuration(Duration::from_secs(1) / rate)
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
.unwrap();
|
||||
|
||||
drop(state);
|
||||
|
||||
focused_window.handle_input(input);
|
||||
}
|
||||
wl_keyboard::KeyState::Released => {
|
||||
let input = if keysym.is_modifier_key() {
|
||||
PlatformInput::ModifiersChanged(ModifiersChangedEvent {
|
||||
modifiers: state.modifiers,
|
||||
})
|
||||
} else {
|
||||
PlatformInput::KeyUp(KeyUpEvent {
|
||||
keystroke: Keystroke::from_xkb(
|
||||
keymap_state,
|
||||
state.modifiers,
|
||||
keycode,
|
||||
),
|
||||
})
|
||||
};
|
||||
wl_keyboard::KeyState::Released if !keysym.is_modifier_key() => {
|
||||
let input = PlatformInput::KeyUp(KeyUpEvent {
|
||||
keystroke: Keystroke::from_xkb(keymap_state, state.modifiers, keycode),
|
||||
});
|
||||
|
||||
if !keysym.is_modifier_key() {
|
||||
state.repeat.current_keysym = None;
|
||||
}
|
||||
state.repeat.current_keysym = None;
|
||||
|
||||
drop(state);
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ pub(crate) fn modifiers_from_state(state: xproto::KeyButMask) -> Modifiers {
|
|||
control: state.contains(xproto::KeyButMask::CONTROL),
|
||||
alt: state.contains(xproto::KeyButMask::MOD1),
|
||||
shift: state.contains(xproto::KeyButMask::SHIFT),
|
||||
command: state.contains(xproto::KeyButMask::MOD4),
|
||||
platform: state.contains(xproto::KeyButMask::MOD4),
|
||||
function: false,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -77,7 +77,7 @@ unsafe fn read_modifiers(native_event: id) -> Modifiers {
|
|||
control,
|
||||
alt,
|
||||
shift,
|
||||
command,
|
||||
platform: command,
|
||||
function,
|
||||
}
|
||||
}
|
||||
|
@ -323,7 +323,7 @@ unsafe fn parse_keystroke(native_event: id) -> Keystroke {
|
|||
control,
|
||||
alt,
|
||||
shift,
|
||||
command,
|
||||
platform: command,
|
||||
function,
|
||||
},
|
||||
key,
|
||||
|
|
|
@ -279,7 +279,7 @@ impl MacPlatform {
|
|||
let mut mask = NSEventModifierFlags::empty();
|
||||
for (modifier, flag) in &[
|
||||
(
|
||||
keystroke.modifiers.command,
|
||||
keystroke.modifiers.platform,
|
||||
NSEventModifierFlags::NSCommandKeyMask,
|
||||
),
|
||||
(
|
||||
|
|
|
@ -853,7 +853,7 @@ impl PlatformWindow for MacWindow {
|
|||
control,
|
||||
alt,
|
||||
shift,
|
||||
command,
|
||||
platform: command,
|
||||
function,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -239,7 +239,7 @@ impl WindowsWindowInner {
|
|||
control: self.is_virtual_key_pressed(VK_CONTROL),
|
||||
alt: self.is_virtual_key_pressed(VK_MENU),
|
||||
shift: self.is_virtual_key_pressed(VK_SHIFT),
|
||||
command: self.is_virtual_key_pressed(VK_LWIN) || self.is_virtual_key_pressed(VK_RWIN),
|
||||
platform: self.is_virtual_key_pressed(VK_LWIN) || self.is_virtual_key_pressed(VK_RWIN),
|
||||
function: false,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -418,7 +418,7 @@ impl<D: PickerDelegate> Picker<D> {
|
|||
.id(("item", ix))
|
||||
.cursor_pointer()
|
||||
.on_click(cx.listener(move |this, event: &ClickEvent, cx| {
|
||||
this.handle_click(ix, event.down.modifiers.command, cx)
|
||||
this.handle_click(ix, event.down.modifiers.secondary(), cx)
|
||||
}))
|
||||
// As of this writing, GPUI intercepts `ctrl-[mouse-event]`s on macOS
|
||||
// and produces right mouse button events. This matches platforms norms
|
||||
|
@ -427,7 +427,9 @@ impl<D: PickerDelegate> Picker<D> {
|
|||
.on_mouse_up(
|
||||
MouseButton::Right,
|
||||
cx.listener(move |this, event: &MouseUpEvent, cx| {
|
||||
this.handle_click(ix, event.modifiers.command, cx)
|
||||
// We specficially want to use the platform key here, as
|
||||
// ctrl will already be held down for the tab switcher.
|
||||
this.handle_click(ix, event.modifiers.platform, cx)
|
||||
}),
|
||||
)
|
||||
.children(
|
||||
|
|
|
@ -1456,7 +1456,7 @@ impl ProjectPanel {
|
|||
if kind.is_dir() {
|
||||
this.toggle_expanded(entry_id, cx);
|
||||
} else {
|
||||
if event.down.modifiers.command {
|
||||
if event.down.modifiers.secondary() {
|
||||
this.split_entry(entry_id, cx);
|
||||
} else {
|
||||
this.open_entry(entry_id, event.up.click_count > 1, cx);
|
||||
|
|
|
@ -18,7 +18,7 @@ impl AlacModifiers {
|
|||
ks.modifiers.alt,
|
||||
ks.modifiers.control,
|
||||
ks.modifiers.shift,
|
||||
ks.modifiers.command,
|
||||
ks.modifiers.platform,
|
||||
) {
|
||||
(false, false, false, false) => AlacModifiers::None,
|
||||
(true, false, false, false) => AlacModifiers::Alt,
|
||||
|
@ -336,7 +336,7 @@ mod test {
|
|||
control: false,
|
||||
alt: false,
|
||||
shift: false,
|
||||
command: false,
|
||||
platform: false,
|
||||
function: false,
|
||||
},
|
||||
key: "🖖🏻".to_string(), //2 char string
|
||||
|
|
|
@ -432,7 +432,7 @@ impl TerminalBuilder {
|
|||
last_mouse_position: None,
|
||||
next_link_id: 0,
|
||||
selection_phase: SelectionPhase::Ended,
|
||||
cmd_pressed: false,
|
||||
secondary_pressed: false,
|
||||
hovered_word: false,
|
||||
url_regex,
|
||||
word_regex,
|
||||
|
@ -585,7 +585,7 @@ pub struct Terminal {
|
|||
scroll_px: Pixels,
|
||||
next_link_id: usize,
|
||||
selection_phase: SelectionPhase,
|
||||
cmd_pressed: bool,
|
||||
secondary_pressed: bool,
|
||||
hovered_word: bool,
|
||||
url_regex: RegexSearch,
|
||||
word_regex: RegexSearch,
|
||||
|
@ -1029,11 +1029,11 @@ impl Terminal {
|
|||
}
|
||||
|
||||
pub fn try_modifiers_change(&mut self, modifiers: &Modifiers) -> bool {
|
||||
let changed = self.cmd_pressed != modifiers.command;
|
||||
if !self.cmd_pressed && modifiers.command {
|
||||
let changed = self.secondary_pressed != modifiers.secondary();
|
||||
if !self.secondary_pressed && modifiers.secondary() {
|
||||
self.refresh_hovered_word();
|
||||
}
|
||||
self.cmd_pressed = modifiers.command;
|
||||
self.secondary_pressed = modifiers.secondary();
|
||||
changed
|
||||
}
|
||||
|
||||
|
@ -1136,7 +1136,7 @@ impl Terminal {
|
|||
self.pty_tx.notify(bytes);
|
||||
}
|
||||
}
|
||||
} else if self.cmd_pressed {
|
||||
} else if self.secondary_pressed {
|
||||
self.word_from_position(Some(position));
|
||||
}
|
||||
}
|
||||
|
@ -1266,7 +1266,7 @@ impl Terminal {
|
|||
let mouse_cell_index = content_index_for_mouse(position, &self.last_content.size);
|
||||
if let Some(link) = self.last_content.cells[mouse_cell_index].hyperlink() {
|
||||
cx.open_url(link.uri());
|
||||
} else if self.cmd_pressed {
|
||||
} else if self.secondary_pressed {
|
||||
self.events
|
||||
.push_back(InternalEvent::FindHyperlink(position, true));
|
||||
}
|
||||
|
@ -1402,7 +1402,7 @@ impl Terminal {
|
|||
}
|
||||
|
||||
pub fn can_navigate_to_selected_word(&self) -> bool {
|
||||
self.cmd_pressed && self.hovered_word
|
||||
self.secondary_pressed && self.hovered_word
|
||||
}
|
||||
|
||||
pub fn task(&self) -> Option<&TaskState> {
|
||||
|
|
|
@ -113,7 +113,7 @@ impl RenderOnce for KeyBinding {
|
|||
el.child(Key::new("Alt")).child(Key::new("+"))
|
||||
}
|
||||
})
|
||||
.when(keystroke.modifiers.command, |el| {
|
||||
.when(keystroke.modifiers.platform, |el| {
|
||||
match self.platform_style {
|
||||
PlatformStyle::Mac => el.child(KeyIcon::new(IconName::Command)),
|
||||
PlatformStyle::Linux => {
|
||||
|
|
|
@ -120,7 +120,7 @@ impl NeovimConnection {
|
|||
let special = keystroke.modifiers.shift
|
||||
|| keystroke.modifiers.control
|
||||
|| keystroke.modifiers.alt
|
||||
|| keystroke.modifiers.command
|
||||
|| keystroke.modifiers.platform
|
||||
|| keystroke.key.len() > 1;
|
||||
let start = if special { "<" } else { "" };
|
||||
let shift = if keystroke.modifiers.shift { "S-" } else { "" };
|
||||
|
@ -130,7 +130,7 @@ impl NeovimConnection {
|
|||
""
|
||||
};
|
||||
let alt = if keystroke.modifiers.alt { "M-" } else { "" };
|
||||
let cmd = if keystroke.modifiers.command {
|
||||
let cmd = if keystroke.modifiers.platform {
|
||||
"D-"
|
||||
} else {
|
||||
""
|
||||
|
|
Loading…
Reference in a new issue