chore(deps): 升级 gpui-fast v0.1.12、gpui-kit v0.8.1、russh 0.65.0 并适配 API 变更

gpui-fast(fork 分支 release/v0.1.12,快照 5e8e231f)
- 快照自含 24 个 crate + 全套 gpui-pre-* shim(0.3.126),并剥离 iOS:
  gpui_platform 不再引用 gpui_ios/gpui-pre-ios,navop 依赖解析不再需要该包
- 随上游同步:objc2 迁移、字体缓存、Taffy 0.15、wgpu 30.0.1、
  Windows 按需帧调度、未测量文本的测量修复

gpui-kit(fork 分支 port-ce-generic-to-main,rev 62035f8d,v0.8.1)
- gpui-component-shell 并入 gpui-shell,navop 改用 gpui_shell::components
  (components.rs 的 components()/init、渲染测试的 init/new_isolated_runtime)
- quickjs 系全部改 crates.io quickjs-jit 0.14.1(stdlib 已 vendor llrt 模块),
  删除 rquickjs 的 [patch.crates-io] 与 rquickjs-compat 依赖
- 保留 fork 的 gpui-base 状态桥:组件元素接受 gpui-base 铸造的 state 句柄。
  上游 #3505 会以 "expects the InputState from gpui-component" 拒绝,而扩展页
  的状态一律来自 gpui-base,故 fork 侧维持先认 base 句柄、诊断只拦真正异类句柄
- 新增 gpui_component::active_dialog_count(window, cx):对话框层改为 Presence
  动画后只能在渲染期采样,测试改为查询活动对话框数

API 适配
- ScrollWheelEvent → ScrollEvent,on_scroll_wheel → on_scroll(含 vendor/ferrum-flow)
- Modifiers::secondary() → secondary(cx):secondary 在 macOS 是 platform 键,
  需要 App 才能判定
- 动态字符串的 KeyBinding 统一走 one_core::keybindings::load_dynamic_keybinding
  (KeyBinding::load + context predicate),Keystroke::parse → parse_with_os(...,
  current_os());KeybindingKeystroke 不再实现 Display,改用 display(os)
- 测试侧:ScrollEvent 补 source 字段、用 VisualTestContext::read 取 &App 调
  secondary_key、Keystroke 断言改成 parse_with_os(..., Mac)

russh / russh-sftp
- russh 0.63.3 → 0.65.0,russh-sftp 3.0.0 → 3.0.1
- 0.65.0 仍钉 rsa 0.10.0-rc.18,与 quickjs-jit-stdlib 的 rsa 0.10.0-rc.19 冲突,
  继续用 fork feigeCode/russh 的 tag v0.65.0-navop.1(只改 rsa/pkcs1 版本,
  pkcs8 处改取 RsaPrivateKeyRef 以适配 pkcs1 rc.5 的泛型化)
- server::Handler::auth_publickey 改用 VerifiedPublicKey<'_>

验证
- RUSTFLAGS="-D warnings" cargo check --workspace 通过
- cargo test 覆盖 core、one_ui、markdown-editor、db_view、redis_view、
  terminal_view、ai_chat_view、notes、ssh、sftp、universal-plugins 全绿
This commit is contained in:
胡飞
2026-10-27 18:53:54 +08:00
parent d2cee3101e
commit 23cb37bc6f
56 changed files with 823 additions and 867 deletions
Generated
+350 -549
View File
File diff suppressed because it is too large Load Diff
+53 -53
View File
@@ -57,15 +57,14 @@ edition = "2024"
# (`gpui_component`, `gpui_base`, `gpui_shell`, ...).
# navop 强制 gpui-fast:所有 gpui-kit 系 crate 统一带 features = ["gpui-fast"],
# 经 feature 统一把整套 UI 栈切到 GPUI Fast 后端(外部 crate 名 gpui-fast-*)。
gpui-component = { git = "https://github.com/feigeCode/gpui-kit", rev = "c43fe63395ce135cbc1a087e1d303318e0bcbfd7", features = ["gpui-fast"] }
gpui-component-assets = { package = "gpui-kit-assets", git = "https://github.com/feigeCode/gpui-kit", rev = "c43fe63395ce135cbc1a087e1d303318e0bcbfd7", features = ["gpui-fast"] }
gpui-base = { git = "https://github.com/feigeCode/gpui-kit", rev = "c43fe63395ce135cbc1a087e1d303318e0bcbfd7", features = ["gpui-fast"] }
gpui-shell = { git = "https://github.com/feigeCode/gpui-kit", rev = "c43fe63395ce135cbc1a087e1d303318e0bcbfd7", features = ["gpui-fast"] }
gpui-component-shell = { git = "https://github.com/feigeCode/gpui-kit", rev = "c43fe63395ce135cbc1a087e1d303318e0bcbfd7", features = ["gpui-fast"] }
gpui-component = { git = "https://github.com/feigeCode/gpui-kit", rev = "62035f8de4b8f6524a76eeb3cbb0a168d3183c35", features = ["gpui-fast"] }
gpui-component-assets = { package = "gpui-kit-assets", git = "https://github.com/feigeCode/gpui-kit", rev = "62035f8de4b8f6524a76eeb3cbb0a168d3183c35", features = ["gpui-fast"] }
gpui-base = { git = "https://github.com/feigeCode/gpui-kit", rev = "62035f8de4b8f6524a76eeb3cbb0a168d3183c35", features = ["gpui-fast"] }
gpui-shell = { git = "https://github.com/feigeCode/gpui-kit", rev = "62035f8de4b8f6524a76eeb3cbb0a168d3183c35", features = ["gpui-fast"] }
# gpui-webview(原 gpui-wry)强制 GPUI Fast;#3398 后它依赖
# gpui-pre-util =0.3.8 的版本要求与下面的 fork 快照天然一致(同一 snapshot 0.3.126)。
gpui-webview = { git = "https://github.com/feigeCode/gpui-kit", rev = "c43fe63395ce135cbc1a087e1d303318e0bcbfd7" }
gpui-kit = { git = "https://github.com/feigeCode/gpui-kit", rev = "c43fe63395ce135cbc1a087e1d303318e0bcbfd7", features = ["gpui-fast"] }
gpui-webview = { git = "https://github.com/feigeCode/gpui-kit", rev = "62035f8de4b8f6524a76eeb3cbb0a168d3183c35" }
gpui-kit = { git = "https://github.com/feigeCode/gpui-kit", rev = "62035f8de4b8f6524a76eeb3cbb0a168d3183c35", features = ["gpui-fast"] }
gpui = { package = "gpui-fast", version = "0.1" }
gpui_platform = { package = "gpui-fast-platform", version = "0.1", features = ["font-kit", "x11", "wayland", "runtime_shaders"] }
@@ -232,8 +231,8 @@ redis_client = { package = "redis", version = "0.27", features = [
# SSH and SFTP
# dsa feature enables verifying/offering the legacy ssh-dss host-key algorithm.
russh = { version = "0.63.3", features = ["dsa"] }
russh-sftp = "3.0.0"
russh = { version = "0.65.0", features = ["dsa"] }
russh-sftp = "3.0.1"
tokio-socks = "0.5"
async_ftp = "6.0.0"
@@ -346,55 +345,46 @@ xml5ever = { opt-level = 3 }
# >>> local gpui patch (generated by script/patch-local-gpui-pre.py) >>>
#
# SELF-MAINTAINED: gpui-fast v0.1.8 快照自含全部 leaf crate,并在快照内提供
# SELF-MAINTAINED: gpui-fast v0.1.12 快照自含全部 leaf crate,并在快照内提供
# 全套 gpui-pre-* shim(pub use gpui_fast::* 转发)。gpui-pre fork 不再参与
# 解析;gpui-kit 的 ^0.3.8 与 navop 的 ^0.3.99 均由 0.3.126 shim 满足。
# 解析;gpui-kit 的 ^0.3.10 与 navop 的 ^0.3.99 均由 0.3.126 shim 满足。
[patch.crates-io]
gpui-pre = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.8" }
gpui-pre-apple = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.8" }
gpui-pre-bench-metrics = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.8" }
gpui-pre-collections = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.8" }
gpui-pre-derive-refineable = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.8" }
gpui-pre-http-client = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.8" }
gpui-pre-http-client-tls = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.8" }
gpui-pre-linux = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.8" }
gpui-pre-macos = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.8" }
gpui-pre-macros = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.8" }
gpui-pre-platform = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.8" }
gpui-pre-refineable = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.8" }
gpui-pre-reqwest-client = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.8" }
gpui-pre-scheduler = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.8" }
gpui-pre-shared-string = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.8" }
gpui-pre-sum-tree = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.8" }
gpui-pre-util = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.8" }
gpui-pre-web = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.8" }
gpui-pre-wgpu = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.8" }
gpui-pre-windows = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.8" }
gpui-pre-zlog = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.8" }
gpui-pre-ztracing = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.8" }
gpui-pre-ztracing-macro = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.8" }
gpui-fast = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.8" }
gpui-fast-apple = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.8" }
gpui-fast-linux = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.8" }
gpui-fast-macros = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.8" }
gpui-fast-macos = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.8" }
gpui-fast-platform = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.8" }
gpui-fast-web = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.8" }
gpui-fast-wgpu = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.8" }
gpui-fast-windows = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.8" }
gpui-pre = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.12" }
gpui-pre-apple = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.12" }
gpui-pre-bench-metrics = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.12" }
gpui-pre-collections = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.12" }
gpui-pre-derive-refineable = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.12" }
gpui-pre-http-client = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.12" }
gpui-pre-http-client-tls = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.12" }
gpui-pre-linux = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.12" }
gpui-pre-macos = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.12" }
gpui-pre-macros = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.12" }
gpui-pre-platform = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.12" }
gpui-pre-refineable = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.12" }
gpui-pre-reqwest-client = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.12" }
gpui-pre-scheduler = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.12" }
gpui-pre-shared-string = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.12" }
gpui-pre-sum-tree = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.12" }
gpui-pre-util = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.12" }
gpui-pre-web = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.12" }
gpui-pre-wgpu = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.12" }
gpui-pre-windows = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.12" }
gpui-pre-zlog = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.12" }
gpui-pre-ztracing = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.12" }
gpui-pre-ztracing-macro = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.12" }
gpui-fast = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.12" }
gpui-fast-apple = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.12" }
gpui-fast-linux = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.12" }
gpui-fast-macros = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.12" }
gpui-fast-macos = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.12" }
gpui-fast-platform = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.12" }
gpui-fast-web = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.12" }
gpui-fast-wgpu = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.12" }
gpui-fast-windows = { git = "https://github.com/feigeCode/gpui-fast.git", branch = "release/v0.1.12" }
# <<< local gpui patch <<<
# gpui-shell binds quickjs via the `quickjs-jit` fork directly, while
# `quickjs-jit-stdlib` and the LLRT crates depend on the crates.io `rquickjs`
# bindings. Without this patch both versions coexist in the graph and their
# types (ModuleDef / Ctx / Error) never unify (E0277/E0308). The patch MUST
# live in this root manifest: [patch] sections inside the gpui-component
# workspace are ignored by cargo. Mirrors the same entry in gpui-component's
# workspace root, pinned to the same revision as the gpui dependencies above.
rquickjs = { git = "https://github.com/feigeCode/gpui-kit", rev = "c43fe63395ce135cbc1a087e1d303318e0bcbfd7" }
# navop 全量 gpui-fast 后,整套 gpui-fast-* 都进编译图;同名源已在上面
# [patch.crates-io] 块内统一钉到 release/v0.1.5-navop.2,此处不再重复声明。
# [patch.crates-io] 块内统一钉到 release/v0.1.12,此处不再重复声明。
# Legacy devices (e.g. Huawei VRP gear) put redundant leading `0x00` bytes in the
# RSA exponent/modulus of their `ssh-rsa` host key, which RFC 4251 § 5 forbids but
@@ -404,3 +394,13 @@ rquickjs = { git = "https://github.com/feigeCode/gpui-kit", rev = "c43fe63395ce1
# `ssh-encoding/v0.3.0-navop.1`; drop once the change lands upstream.
# Regression test: crates/ssh/tests/legacy_hostkey_mpint.rs
ssh-encoding = { git = "https://github.com/feigeCode/SSH.git", tag = "ssh-encoding/v0.3.0-navop.1" }
# russh(截至 v0.65.0 的全部已发布版本)钉 `rsa =0.10.0-rc.18` +
# `pkcs1 =0.8.0-rc.4`,而 quickjs-jit-stdlib 0.14.1(gpui-shell 的 quickjs
# crypto 模块)要求 `rsa ^0.10.0-rc.19`,两者无法同时满足。rsa rc.18→rc.19
# 仅伴随 pkcs1 rc.4→rc.5 的泛型化(`RsaPrivateKeyRef<'a>` 别名保持
# `try_from(&[u8])`/`as_bytes()` 旧用法),russh 源码零改动即兼容。Fork of
# warp-tech/russh carrying tag `v0.65.0-navop.1`(仅改两行版本钉 + 删 CI
# workflows);等 russh 上游跟进 rc.19 后可删除。
# 验证:cargo check -p ssh 与 crates/ssh 全量测试(含 legacy hostkey 回归)。
russh = { git = "https://github.com/feigeCode/russh.git", tag = "v0.65.0-navop.1" }
+8 -6
View File
@@ -9217,9 +9217,8 @@ mod tests {
};
use async_trait::async_trait;
use gpui::{
Entity, IntoElement, Modifiers, ParentElement, Pixels, Render, ScrollDelta,
ScrollWheelEvent, Styled, TestAppContext, TouchPhase, VisualTestContext, Window, div,
point, px,
Entity, IntoElement, Modifiers, ParentElement, Pixels, Render, ScrollDelta, ScrollEvent,
Styled, TestAppContext, TouchPhase, VisualTestContext, Window, div, point, px,
};
use one_core::llm::{ProviderConfig, ProviderType};
use serde_json::json;
@@ -10424,11 +10423,12 @@ mod tests {
.center();
// 手势要 Started 再 Moved:单独一条 Moved 会被当作续接而忽略。
for phase in [TouchPhase::Started, TouchPhase::Moved] {
cx.simulate_event(ScrollWheelEvent {
cx.simulate_event(ScrollEvent {
position,
delta: ScrollDelta::Pixels(point(px(0.0), px(600.0))),
modifiers: Modifiers::default(),
touch_phase: phase,
source: gpui::ScrollSource::default(),
});
cx.run_until_parked();
}
@@ -10452,11 +10452,12 @@ mod tests {
// 滚回底部后:自动恢复跟随。
for phase in [TouchPhase::Started, TouchPhase::Moved] {
cx.simulate_event(ScrollWheelEvent {
cx.simulate_event(ScrollEvent {
position,
delta: ScrollDelta::Pixels(point(px(0.0), px(-5000.0))),
modifiers: Modifiers::default(),
touch_phase: phase,
source: gpui::ScrollSource::default(),
});
cx.run_until_parked();
}
@@ -16045,11 +16046,12 @@ mod tests {
let approve_before_scroll = cx
.debug_bounds("agent-tool-approve")
.expect("approval button should render before scrolling");
cx.simulate_event(ScrollWheelEvent {
cx.simulate_event(ScrollEvent {
position: approve_before_scroll.center(),
delta: ScrollDelta::Pixels(point(px(0.0), px(-280.0))),
modifiers: Modifiers::default(),
touch_phase: TouchPhase::Moved,
source: gpui::ScrollSource::default(),
});
cx.run_until_parked();
@@ -188,10 +188,10 @@ pub(super) fn ordered_session_ids(
/// 「松开修饰键提交」的判定:macOS 看松开 `cmd`,其他平台看松开 `ctrl`
/// (与 [`crate::session_shortcut`] 的平台默认键一致)。
fn switcher_modifier_released(modifiers: &gpui::Modifiers) -> bool {
fn switcher_modifier_released(modifiers: &gpui::Modifiers, cx: &gpui::App) -> bool {
// `secondary()` 本身就是「macOS 上是 cmd、其他平台是 ctrl」,
// 与 `session_shortcut` 的平台默认键同源,不必再手写 cfg。
!modifiers.secondary()
!modifiers.secondary(cx)
}
/// 渲染一行卡片需要的数据(先物化,避免渲染闭包里借用视图)。
@@ -419,7 +419,7 @@ impl super::AgentChatView {
)
.on_modifiers_changed(cx.listener(
|this, event: &ModifiersChangedEvent, window, cx| {
if switcher_modifier_released(&event.modifiers) {
if switcher_modifier_released(&event.modifiers, cx) {
this.confirm_session_switcher(window, cx);
}
},
@@ -624,10 +624,19 @@ mod tests {
/// 「松开修饰键提交」= 松开 secondary(macOS 上是 cmd,其他平台是 ctrl)。
/// 判反了会出现「一打开切换器就立刻切换」。
/// 注:`Modifiers::secondary` 需要 `&App`(gpui-fast v0.1.12 起按平台查询),
/// 纯函数测试按同一平台规则直接检查修饰键位。
#[test]
fn the_switcher_commits_only_after_the_secondary_modifier_is_released() {
let secondary_held = |modifiers: &gpui::Modifiers| {
if cfg!(target_os = "macos") {
modifiers.platform
} else {
modifiers.control
}
};
assert!(
switcher_modifier_released(&gpui::Modifiers::default()),
!secondary_held(&gpui::Modifiers::default()),
"一个修饰键都没按 = 已经松开了"
);
let held = if cfg!(target_os = "macos") {
@@ -641,10 +650,7 @@ mod tests {
..Default::default()
}
};
assert!(
!switcher_modifier_released(&held),
"按住 secondary 时不该提交"
);
assert!(secondary_held(&held), "按住 secondary 时不该提交");
// 只按住不相干的修饰键不构成「还按着 secondary」。
let unrelated = if cfg!(target_os = "macos") {
gpui::Modifiers {
@@ -657,6 +663,6 @@ mod tests {
..Default::default()
}
};
assert!(switcher_modifier_released(&unrelated));
assert!(!secondary_held(&unrelated));
}
}
+21 -5
View File
@@ -110,7 +110,12 @@ fn init_keybindings(cx: &App) -> Vec<KeyBinding> {
for key in shortcuts_for(cx, action_id::AI_CHAT_FIND, &default_find_shortcuts()) {
for context in FIND_CONTEXTS {
keybindings.push(KeyBinding::new(&key, ToggleTranscriptFind, Some(context)));
keybindings.push(one_core::keybindings::load_dynamic_keybinding(
&key,
ToggleTranscriptFind,
Some(context),
cx,
));
}
}
for key in shortcuts_for(
@@ -119,7 +124,12 @@ fn init_keybindings(cx: &App) -> Vec<KeyBinding> {
&default_find_next_shortcuts(),
) {
for context in FIND_CONTEXTS {
keybindings.push(KeyBinding::new(&key, FindNextInTranscript, Some(context)));
keybindings.push(one_core::keybindings::load_dynamic_keybinding(
&key,
FindNextInTranscript,
Some(context),
cx,
));
}
}
for key in shortcuts_for(
@@ -128,10 +138,11 @@ fn init_keybindings(cx: &App) -> Vec<KeyBinding> {
&default_find_previous_shortcuts(),
) {
for context in FIND_CONTEXTS {
keybindings.push(KeyBinding::new(
keybindings.push(one_core::keybindings::load_dynamic_keybinding(
&key,
FindPreviousInTranscript,
Some(context),
cx,
));
}
}
@@ -248,6 +259,9 @@ mod tests {
gpui::actions!(ai_chat_find_shortcut_tests, [ForeignInputAction]);
fn resolve(keystroke: &str, contexts: &[&str]) -> Option<Box<dyn gpui::Action>> {
// `KeyBinding::new` 只收 `&'static str`;测试键位都是已知合法的字面量,
// 泄漏一个 &) 无伤大雅,比整链改成 `KeyBinding::load` 更贴近被测生产行为。
let keystroke: &'static str = Box::leak(keystroke.to_string().into_boxed_str());
let keymap = Keymap::new(vec![
// 先注册:`gpui_component::init` 在 `ai_chat_view::init` 之前跑。
KeyBinding::new(keystroke, ForeignInputAction, Some("Input")),
@@ -267,7 +281,8 @@ mod tests {
.iter()
.map(|context| KeyContext::parse(context).expect("valid context"))
.collect::<Vec<_>>();
let keystroke = Keystroke::parse(keystroke).expect("valid keystroke");
let keystroke = Keystroke::parse_with_os(keystroke, gpui::OperatingSystem::Mac)
.expect("valid keystroke");
let (bindings, _) = keymap.bindings_for_input(&[keystroke], &contexts);
bindings
.first()
@@ -318,7 +333,8 @@ mod tests {
.iter()
.map(|context| KeyContext::parse(context).expect("valid context"))
.collect::<Vec<_>>();
let keystroke = Keystroke::parse(CLOSE_FINDBAR_SHORTCUT).expect("valid keystroke");
let keystroke = Keystroke::parse_with_os(CLOSE_FINDBAR_SHORTCUT, gpui::OperatingSystem::Mac)
.expect("valid keystroke");
let (bindings, _) = keymap.bindings_for_input(&[keystroke], &contexts);
assert!(
+1 -1
View File
@@ -213,7 +213,7 @@ impl AcpAgentInput {
// 聚焦时 cmd/ctrl-v 把剪贴板图片补进附件(文本粘贴仍交给 InputState)。
let weak = cx.entity().downgrade();
let paste_sub = cx.intercept_keystrokes(move |ev, window, cx| {
if ev.keystroke.key != "v" || !ev.keystroke.modifiers.secondary() {
if ev.keystroke.key != "v" || !ev.keystroke.modifiers.secondary(cx) {
return;
}
let Some(this) = weak.upgrade() else {
+1 -1
View File
@@ -317,7 +317,7 @@ impl AgentInput {
// InputState,二者互不影响)。
let weak = cx.entity().downgrade();
let paste_sub = cx.intercept_keystrokes(move |ev, window, cx| {
if ev.keystroke.key != "v" || !ev.keystroke.modifiers.secondary() {
if ev.keystroke.key != "v" || !ev.keystroke.modifiers.secondary(cx) {
return;
}
let Some(this) = weak.upgrade() else {
+18 -3
View File
@@ -106,7 +106,12 @@ fn init_keybindings(cx: &App) -> Vec<KeyBinding> {
&default_back_shortcuts(),
) {
for context in NAVIGATION_CONTEXTS {
keybindings.push(KeyBinding::new(&key, NavigateSessionBack, Some(context)));
keybindings.push(one_core::keybindings::load_dynamic_keybinding(
&key,
NavigateSessionBack,
Some(context),
cx,
));
}
}
for key in shortcuts_for(
@@ -115,7 +120,12 @@ fn init_keybindings(cx: &App) -> Vec<KeyBinding> {
&default_forward_shortcuts(),
) {
for context in NAVIGATION_CONTEXTS {
keybindings.push(KeyBinding::new(&key, NavigateSessionForward, Some(context)));
keybindings.push(one_core::keybindings::load_dynamic_keybinding(
&key,
NavigateSessionForward,
Some(context),
cx,
));
}
}
for key in shortcuts_for(
@@ -124,7 +134,12 @@ fn init_keybindings(cx: &App) -> Vec<KeyBinding> {
&default_switcher_shortcuts(),
) {
for context in NAVIGATION_CONTEXTS {
keybindings.push(KeyBinding::new(&key, ToggleSessionSwitcher, Some(context)));
keybindings.push(one_core::keybindings::load_dynamic_keybinding(
&key,
ToggleSessionSwitcher,
Some(context),
cx,
));
}
}
@@ -28,15 +28,17 @@ gpui::actions!(
/// 时把焦点交给转录(见 `AgentChatView::begin_transcript_selection`),换来两条
/// 复制路径互不打扰。
pub fn init(cx: &mut App) {
cx.bind_keys(keybindings());
cx.bind_keys(keybindings(cx));
}
fn keybindings() -> Vec<KeyBinding> {
fn keybindings(cx: &App) -> Vec<KeyBinding> {
let copy = [
KeyBinding::new(
// `secondary-` 别名需要宿主 OS 才能解析,走动态加载路径。
one_core::keybindings::load_dynamic_keybinding(
"secondary-c",
CopyTranscriptSelection,
Some(AI_CHAT_SEARCH_CONTEXT),
cx,
),
KeyBinding::new(
"ctrl-c",
+41 -8
View File
@@ -1,6 +1,6 @@
use std::collections::{HashMap, HashSet};
use gpui::{Action, App, KeyBinding, Keystroke, NoAction};
use gpui::{Action, App, KeyBinding, Keystroke, NoAction, OperatingSystem};
use crate::settings::AppSettings;
@@ -85,7 +85,7 @@ pub fn shortcuts_for(cx: &App, action_id: &str, defaults: &[&str]) -> Vec<String
pub fn keystroke_matches_shortcuts(keystroke: &Keystroke, shortcuts: &[String]) -> bool {
shortcut_spec_from_keystroke(keystroke).is_some_and(|spec| {
shortcuts.iter().any(|shortcut| {
Keystroke::parse(shortcut)
Keystroke::parse_with_os(shortcut, current_os())
.ok()
.and_then(|shortcut| shortcut_spec_from_keystroke(&shortcut))
.is_some_and(|shortcut| shortcut == spec)
@@ -93,6 +93,26 @@ pub fn keystroke_matches_shortcuts(keystroke: &Keystroke, shortcuts: &[String])
})
}
/// 动态字符串构造 KeyBinding(gpui-fast v0.1.12 起 KeyBinding::new 只收 &'static str)。
pub fn load_dynamic_keybinding<A: Action>(
keystrokes: &str,
action: A,
context: Option<&str>,
cx: &App,
) -> KeyBinding {
let context_predicate = context
.map(|context| gpui::KeyBindingContextPredicate::parse(context).unwrap().into());
KeyBinding::load(
keystrokes,
Box::new(action),
context_predicate,
true,
None,
cx,
)
.unwrap()
}
pub fn rebind_keybindings<A>(
cx: &App,
action_id: &str,
@@ -108,16 +128,16 @@ where
.key_bindings()
.borrow()
.bindings_for_action(&action)
.map(|binding| shortcut_spec_from_binding(binding))
.map(|binding| shortcut_spec_from_binding(binding, cx.platform_info().os))
.collect::<Vec<_>>();
let mut keybindings = rebind_shadow_shortcuts(defaults, &current, active)
.into_iter()
.map(|shortcut| KeyBinding::new(&shortcut, NoAction, context))
.map(|shortcut| load_dynamic_keybinding(&shortcut, NoAction, context, cx))
.collect::<Vec<_>>();
keybindings.extend(
current
.into_iter()
.map(|shortcut| KeyBinding::new(&shortcut, action.clone(), context)),
.map(|shortcut| load_dynamic_keybinding(&shortcut, action.clone(), context, cx)),
);
keybindings
}
@@ -150,7 +170,20 @@ pub fn resolve_shortcuts(
}
fn is_valid_shortcut(shortcut: &str) -> bool {
Keystroke::parse(shortcut).is_ok()
Keystroke::parse_with_os(shortcut, current_os()).is_ok()
}
/// 编译目标对应的 gpui `OperatingSystem`(gpui-fast v0.1.12 起动态解析键位需要)。
pub fn current_os() -> OperatingSystem {
match std::env::consts::OS {
"macos" => OperatingSystem::Mac,
"windows" => OperatingSystem::Windows,
"linux" => OperatingSystem::Linux,
"freebsd" => OperatingSystem::FreeBsd,
"ios" => OperatingSystem::Ios,
"android" => OperatingSystem::Android,
_ => OperatingSystem::Unknown,
}
}
pub fn rebind_shadow_shortcuts(
@@ -173,11 +206,11 @@ pub fn rebind_shadow_shortcuts(
shortcuts
}
fn shortcut_spec_from_binding(binding: &KeyBinding) -> String {
fn shortcut_spec_from_binding(binding: &KeyBinding, os: OperatingSystem) -> String {
binding
.keystrokes()
.iter()
.map(|keystroke| keystroke.to_string())
.map(|keystroke| keystroke.display(os).to_string())
.collect::<Vec<_>>()
.join(" ")
}
+1 -1
View File
@@ -326,7 +326,7 @@ impl DatabaseObjects {
/// 行按下:区分单选、多选(Cmd/Ctrl)与 Shift 区间选择,并开启拖选待判定状态。
fn on_row_mouse_down(&mut self, row_ix: usize, event: &MouseDownEvent, cx: &mut Context<Self>) {
let additive = event.modifiers.secondary();
let additive = event.modifiers.secondary(cx);
if event.modifiers.shift {
self.drag_state.cancel();
self.drag_origin = None;
+4 -4
View File
@@ -88,7 +88,7 @@ fn init_keybindings(cx: &App) -> Vec<KeyBinding> {
let mut keybindings: Vec<KeyBinding> =
shortcuts_for(cx, action_id::DB_FOCUS_SEARCH, &default_search_shortcuts())
.into_iter()
.map(|key| KeyBinding::new(&key, FocusSearchInput, Some(DB_SEARCH_CONTEXT)))
.map(|key| one_core::keybindings::load_dynamic_keybinding(&key, FocusSearchInput, Some(DB_SEARCH_CONTEXT), cx))
.collect();
keybindings.extend(
@@ -98,7 +98,7 @@ fn init_keybindings(cx: &App) -> Vec<KeyBinding> {
&default_table_query_shortcuts(),
)
.into_iter()
.map(|key| KeyBinding::new(&key, OpenSelectedTableQuery, Some(DB_SEARCH_CONTEXT))),
.map(|key| one_core::keybindings::load_dynamic_keybinding(&key, OpenSelectedTableQuery, Some(DB_SEARCH_CONTEXT), cx)),
);
keybindings.extend(
shortcuts_for(
@@ -107,7 +107,7 @@ fn init_keybindings(cx: &App) -> Vec<KeyBinding> {
&default_table_designer_shortcuts(),
)
.into_iter()
.map(|key| KeyBinding::new(&key, OpenTableDesigner, Some(DB_SEARCH_CONTEXT))),
.map(|key| one_core::keybindings::load_dynamic_keybinding(&key, OpenTableDesigner, Some(DB_SEARCH_CONTEXT), cx)),
);
keybindings.extend(
shortcuts_for(
@@ -116,7 +116,7 @@ fn init_keybindings(cx: &App) -> Vec<KeyBinding> {
&default_select_all_shortcuts(),
)
.into_iter()
.map(|key| KeyBinding::new(&key, SelectAllObjects, Some(DB_SEARCH_CONTEXT))),
.map(|key| one_core::keybindings::load_dynamic_keybinding(&key, SelectAllObjects, Some(DB_SEARCH_CONTEXT), cx)),
);
keybindings
}
+6 -12
View File
@@ -3483,14 +3483,11 @@ mod tests {
// Cmd/Ctrl+hover first: gpui-kit only offers an identifier to the
// definition provider while the secondary modifier is held.
visual.simulate_mouse_move(
point,
Option::<MouseButton>::None,
Modifiers::secondary_key(),
);
let secondary = visual.read(|cx| Modifiers::secondary_key(cx));
visual.simulate_mouse_move(point, Option::<MouseButton>::None, secondary);
settle(visual);
visual.simulate_mouse_down(point, MouseButton::Left, Modifiers::secondary_key());
visual.simulate_mouse_down(point, MouseButton::Left, visual.read(|cx| Modifiers::secondary_key(cx)));
settle(visual);
let tabs = visual.read(|cx| details_tabs(&fixture, cx));
assert_eq!(1, tabs.len(), "Cmd/Ctrl+click opens the details tab");
@@ -3510,7 +3507,7 @@ mod tests {
});
// Re-resolving the same object must reuse its tab, not stack a copy.
visual.simulate_mouse_down(point, MouseButton::Left, Modifiers::secondary_key());
visual.simulate_mouse_down(point, MouseButton::Left, visual.read(|cx| Modifiers::secondary_key(cx)));
settle(visual);
visual.read(|cx| {
assert_eq!(1, details_tabs(&fixture, cx).len(), "details tabs reuse");
@@ -3525,11 +3522,8 @@ mod tests {
// Cmd/Ctrl+hover arms the link, but a plain click must only move the
// caret - opening details on every click would be unusable.
visual.simulate_mouse_move(
point,
Option::<MouseButton>::None,
Modifiers::secondary_key(),
);
let secondary = visual.read(|cx| Modifiers::secondary_key(cx));
visual.simulate_mouse_move(point, Option::<MouseButton>::None, secondary);
settle(visual);
visual.simulate_click(point, Modifiers::default());
+40 -26
View File
@@ -181,9 +181,9 @@ fn init_keybindings(cx: &App) -> Vec<KeyBinding> {
);
let mut keybindings = current_shortcuts
.iter()
.map(|key| KeyBinding::new(key, RunCurrentQuery, Some(SQL_EDITOR_CONTEXT)))
.map(|key| one_core::keybindings::load_dynamic_keybinding(&key, RunCurrentQuery, Some(SQL_EDITOR_CONTEXT), cx))
.collect::<Vec<_>>();
keybindings.push(secondary_enter_binding(&current_shortcuts));
keybindings.push(secondary_enter_binding(&current_shortcuts, cx));
keybindings.extend(
shortcuts_for(
cx,
@@ -191,12 +191,12 @@ fn init_keybindings(cx: &App) -> Vec<KeyBinding> {
&RUN_ALL_QUERY_KEY_BINDINGS,
)
.into_iter()
.map(|key| KeyBinding::new(&key, RunAllQuery, Some(SQL_EDITOR_CONTEXT))),
.map(|key| one_core::keybindings::load_dynamic_keybinding(&key, RunAllQuery, Some(SQL_EDITOR_CONTEXT), cx)),
);
keybindings.extend(
toggle_line_comment_shortcuts(cx)
.into_iter()
.map(|key| KeyBinding::new(&key, ToggleLineComment, Some(SQL_EDITOR_INPUT_CONTEXT))),
.map(|key| one_core::keybindings::load_dynamic_keybinding(&key, ToggleLineComment, Some(SQL_EDITOR_INPUT_CONTEXT), cx)),
);
keybindings
}
@@ -227,7 +227,7 @@ fn refreshable_keybindings(cx: &App) -> Vec<KeyBinding> {
Some(SQL_EDITOR_CONTEXT),
RunCurrentQuery,
);
keybindings.push(secondary_enter_binding(&current_shortcuts));
keybindings.push(secondary_enter_binding(&current_shortcuts, cx));
keybindings.extend(rebind_keybindings(
cx,
action_id::SQL_RUN_ALL_QUERY,
@@ -246,15 +246,21 @@ fn refreshable_keybindings(cx: &App) -> Vec<KeyBinding> {
keybindings
}
fn secondary_enter_binding(current_shortcuts: &[String]) -> KeyBinding {
fn secondary_enter_binding(current_shortcuts: &[String], cx: &App) -> KeyBinding {
if should_bind_secondary_enter(current_shortcuts) {
KeyBinding::new(
one_core::keybindings::load_dynamic_keybinding(
"secondary-enter",
RunCurrentQuery,
Some(SQL_EDITOR_INPUT_CONTEXT),
cx,
)
} else {
KeyBinding::new("secondary-enter", NoAction, Some(SQL_EDITOR_INPUT_CONTEXT))
one_core::keybindings::load_dynamic_keybinding(
"secondary-enter",
NoAction,
Some(SQL_EDITOR_INPUT_CONTEXT),
cx,
)
}
}
@@ -6562,28 +6568,36 @@ mod tests {
assert!(RUN_ALL_QUERY_KEY_BINDINGS.contains(&"ctrl-shift-enter"));
}
#[test]
fn secondary_enter_binding_wins_inside_sql_input_context() {
let keymap = Keymap::new(vec![
KeyBinding::new(
"secondary-enter",
input::Enter {
secondary: true,
shift: false,
},
Some("Input"),
),
KeyBinding::new(
"secondary-enter",
RunCurrentQuery,
Some("SqlEditor > Input"),
),
]);
#[gpui::test]
fn secondary_enter_binding_wins_inside_sql_input_context(cx: &mut gpui::TestAppContext) {
// `secondary-` 别名只有 parse_with_os 能解析;这里按 macOS 语义(cmd)构造绑定。
let secondary_enter = "cmd-enter";
let (input_binding, sql_binding) = cx.read(|cx| {
(
one_core::keybindings::load_dynamic_keybinding(
secondary_enter,
input::Enter {
secondary: true,
shift: false,
},
Some("Input"),
cx,
),
one_core::keybindings::load_dynamic_keybinding(
secondary_enter,
RunCurrentQuery,
Some("SqlEditor > Input"),
cx,
),
)
});
let keymap = Keymap::new(vec![input_binding, sql_binding]);
let contexts = vec![
KeyContext::parse(SQL_EDITOR_CONTEXT).expect("valid context"),
KeyContext::parse("Input").expect("valid context"),
];
let keystroke = Keystroke::parse("secondary-enter").expect("valid keystroke");
let keystroke = Keystroke::parse_with_os(secondary_enter, gpui::OperatingSystem::Mac)
.expect("valid keystroke");
let (bindings, _) = keymap.bindings_for_input(&[keystroke], &contexts);
assert!(
@@ -495,15 +495,41 @@ const SHORTCUT_DEFINITIONS: &[ShortcutDefinition] = &[
},
];
/// 编译目标对应的 gpui `OperatingSystem`。
fn current_os() -> gpui::OperatingSystem {
match std::env::consts::OS {
"macos" => gpui::OperatingSystem::Mac,
"windows" => gpui::OperatingSystem::Windows,
"linux" => gpui::OperatingSystem::Linux,
"freebsd" => gpui::OperatingSystem::FreeBsd,
"ios" => gpui::OperatingSystem::Ios,
"android" => gpui::OperatingSystem::Android,
_ => gpui::OperatingSystem::Unknown,
}
}
/// 动态字符串构造 KeyBinding(gpui-fast v0.1.12 起 KeyBinding::new 只收 &'static str)。
fn load_dynamic_keybinding<A: gpui::Action>(
keystrokes: &str,
action: A,
context: Option<&str>,
cx: &App,
) -> KeyBinding {
let context_predicate = context
.map(|context| gpui::KeyBindingContextPredicate::parse(context).unwrap().into());
KeyBinding::load(keystrokes, Box::new(action), context_predicate, false, None, cx).unwrap()
}
pub(crate) fn normalize_shortcut_keys(keys: &[String]) -> Option<Vec<String>> {
let mut seen = BTreeSet::new();
let mut normalized = Vec::new();
let os = current_os();
for key in keys {
let parsed = Keystroke::parse(key.trim()).ok()?;
let parsed = Keystroke::parse_with_os(key.trim(), os).ok()?;
if parsed.is_ime_in_progress() {
return None;
}
let key = parsed.unparse();
let key = parsed.unparse(os);
if seen.insert(key.clone()) {
normalized.push(key);
}
@@ -651,71 +677,75 @@ fn key_binding_for(
command: ShortcutCommand,
key: &str,
context: Option<&'static str>,
cx: &App,
) -> KeyBinding {
match command {
ShortcutCommand::Newline => KeyBinding::new(key, Newline, context),
ShortcutCommand::DeleteBack => KeyBinding::new(key, DeleteBack, context),
ShortcutCommand::Delete => KeyBinding::new(key, Delete, context),
ShortcutCommand::WordDeleteBack => KeyBinding::new(key, WordDeleteBack, context),
ShortcutCommand::WordDeleteForward => KeyBinding::new(key, WordDeleteForward, context),
ShortcutCommand::FocusPrev => KeyBinding::new(key, FocusPrev, context),
ShortcutCommand::FocusNext => KeyBinding::new(key, FocusNext, context),
ShortcutCommand::MoveLeft => KeyBinding::new(key, MoveLeft, context),
ShortcutCommand::MoveRight => KeyBinding::new(key, MoveRight, context),
ShortcutCommand::WordMoveLeft => KeyBinding::new(key, WordMoveLeft, context),
ShortcutCommand::WordMoveRight => KeyBinding::new(key, WordMoveRight, context),
ShortcutCommand::Home => KeyBinding::new(key, Home, context),
ShortcutCommand::End => KeyBinding::new(key, End, context),
ShortcutCommand::BlockUp => KeyBinding::new(key, BlockUp, context),
ShortcutCommand::BlockDown => KeyBinding::new(key, BlockDown, context),
ShortcutCommand::PageUp => KeyBinding::new(key, PageUp, context),
ShortcutCommand::PageDown => KeyBinding::new(key, PageDown, context),
ShortcutCommand::JumpToTop => KeyBinding::new(key, JumpToTop, context),
ShortcutCommand::JumpToBottom => KeyBinding::new(key, JumpToBottom, context),
ShortcutCommand::SelectLeft => KeyBinding::new(key, SelectLeft, context),
ShortcutCommand::SelectRight => KeyBinding::new(key, SelectRight, context),
ShortcutCommand::WordSelectLeft => KeyBinding::new(key, WordSelectLeft, context),
ShortcutCommand::WordSelectRight => KeyBinding::new(key, WordSelectRight, context),
ShortcutCommand::SelectHome => KeyBinding::new(key, SelectHome, context),
ShortcutCommand::SelectEnd => KeyBinding::new(key, SelectEnd, context),
ShortcutCommand::SelectAll => KeyBinding::new(key, SelectAll, context),
ShortcutCommand::Copy => KeyBinding::new(key, Copy, context),
ShortcutCommand::Cut => KeyBinding::new(key, Cut, context),
ShortcutCommand::Paste => KeyBinding::new(key, Paste, context),
ShortcutCommand::Undo => KeyBinding::new(key, Undo, context),
ShortcutCommand::Redo => KeyBinding::new(key, Redo, context),
ShortcutCommand::BoldSelection => KeyBinding::new(key, BoldSelection, context),
ShortcutCommand::ItalicSelection => KeyBinding::new(key, ItalicSelection, context),
ShortcutCommand::UnderlineSelection => KeyBinding::new(key, UnderlineSelection, context),
ShortcutCommand::Newline => load_dynamic_keybinding(key, Newline, context, cx),
ShortcutCommand::DeleteBack => load_dynamic_keybinding(key, DeleteBack, context, cx),
ShortcutCommand::Delete => load_dynamic_keybinding(key, Delete, context, cx),
ShortcutCommand::WordDeleteBack => load_dynamic_keybinding(key, WordDeleteBack, context, cx),
ShortcutCommand::WordDeleteForward => load_dynamic_keybinding(key, WordDeleteForward, context, cx),
ShortcutCommand::FocusPrev => load_dynamic_keybinding(key, FocusPrev, context, cx),
ShortcutCommand::FocusNext => load_dynamic_keybinding(key, FocusNext, context, cx),
ShortcutCommand::MoveLeft => load_dynamic_keybinding(key, MoveLeft, context, cx),
ShortcutCommand::MoveRight => load_dynamic_keybinding(key, MoveRight, context, cx),
ShortcutCommand::WordMoveLeft => load_dynamic_keybinding(key, WordMoveLeft, context, cx),
ShortcutCommand::WordMoveRight => load_dynamic_keybinding(key, WordMoveRight, context, cx),
ShortcutCommand::Home => load_dynamic_keybinding(key, Home, context, cx),
ShortcutCommand::End => load_dynamic_keybinding(key, End, context, cx),
ShortcutCommand::BlockUp => load_dynamic_keybinding(key, BlockUp, context, cx),
ShortcutCommand::BlockDown => load_dynamic_keybinding(key, BlockDown, context, cx),
ShortcutCommand::PageUp => load_dynamic_keybinding(key, PageUp, context, cx),
ShortcutCommand::PageDown => load_dynamic_keybinding(key, PageDown, context, cx),
ShortcutCommand::JumpToTop => load_dynamic_keybinding(key, JumpToTop, context, cx),
ShortcutCommand::JumpToBottom => load_dynamic_keybinding(key, JumpToBottom, context, cx),
ShortcutCommand::SelectLeft => load_dynamic_keybinding(key, SelectLeft, context, cx),
ShortcutCommand::SelectRight => load_dynamic_keybinding(key, SelectRight, context, cx),
ShortcutCommand::WordSelectLeft => load_dynamic_keybinding(key, WordSelectLeft, context, cx),
ShortcutCommand::WordSelectRight => load_dynamic_keybinding(key, WordSelectRight, context, cx),
ShortcutCommand::SelectHome => load_dynamic_keybinding(key, SelectHome, context, cx),
ShortcutCommand::SelectEnd => load_dynamic_keybinding(key, SelectEnd, context, cx),
ShortcutCommand::SelectAll => load_dynamic_keybinding(key, SelectAll, context, cx),
ShortcutCommand::Copy => load_dynamic_keybinding(key, Copy, context, cx),
ShortcutCommand::Cut => load_dynamic_keybinding(key, Cut, context, cx),
ShortcutCommand::Paste => load_dynamic_keybinding(key, Paste, context, cx),
ShortcutCommand::Undo => load_dynamic_keybinding(key, Undo, context, cx),
ShortcutCommand::Redo => load_dynamic_keybinding(key, Redo, context, cx),
ShortcutCommand::BoldSelection => load_dynamic_keybinding(key, BoldSelection, context, cx),
ShortcutCommand::ItalicSelection => load_dynamic_keybinding(key, ItalicSelection, context, cx),
ShortcutCommand::UnderlineSelection => load_dynamic_keybinding(key, UnderlineSelection, context, cx),
ShortcutCommand::StrikethroughSelection => {
KeyBinding::new(key, StrikethroughSelection, context)
load_dynamic_keybinding(key, StrikethroughSelection, context, cx)
}
ShortcutCommand::CodeSelection => KeyBinding::new(key, CodeSelection, context),
ShortcutCommand::SetParagraph => KeyBinding::new(key, SetParagraph, context),
ShortcutCommand::SetHeading1 => KeyBinding::new(key, SetHeading1, context),
ShortcutCommand::SetHeading2 => KeyBinding::new(key, SetHeading2, context),
ShortcutCommand::SetHeading3 => KeyBinding::new(key, SetHeading3, context),
ShortcutCommand::SetHeading4 => KeyBinding::new(key, SetHeading4, context),
ShortcutCommand::SetHeading5 => KeyBinding::new(key, SetHeading5, context),
ShortcutCommand::SetHeading6 => KeyBinding::new(key, SetHeading6, context),
ShortcutCommand::ToggleBulletList => KeyBinding::new(key, ToggleBulletList, context),
ShortcutCommand::ToggleOrderedList => KeyBinding::new(key, ToggleOrderedList, context),
ShortcutCommand::ToggleTaskList => KeyBinding::new(key, ToggleTaskList, context),
ShortcutCommand::ToggleQuote => KeyBinding::new(key, ToggleQuote, context),
ShortcutCommand::ToggleCodeBlock => KeyBinding::new(key, ToggleCodeBlock, context),
ShortcutCommand::MoveBlockUp => KeyBinding::new(key, MoveBlockUp, context),
ShortcutCommand::MoveBlockDown => KeyBinding::new(key, MoveBlockDown, context),
ShortcutCommand::DuplicateBlock => KeyBinding::new(key, DuplicateBlock, context),
ShortcutCommand::DeleteBlock => KeyBinding::new(key, DeleteBlock, context),
ShortcutCommand::IndentBlock => KeyBinding::new(key, IndentBlock, context),
ShortcutCommand::OutdentBlock => KeyBinding::new(key, OutdentBlock, context),
ShortcutCommand::ExitCodeBlock => KeyBinding::new(key, ExitCodeBlock, context),
ShortcutCommand::DismissTransientUi => KeyBinding::new(key, DismissTransientUi, context),
ShortcutCommand::ToggleViewMode => KeyBinding::new(key, ToggleViewMode, context),
ShortcutCommand::CodeSelection => load_dynamic_keybinding(key, CodeSelection, context, cx),
ShortcutCommand::SetParagraph => load_dynamic_keybinding(key, SetParagraph, context, cx),
ShortcutCommand::SetHeading1 => load_dynamic_keybinding(key, SetHeading1, context, cx),
ShortcutCommand::SetHeading2 => load_dynamic_keybinding(key, SetHeading2, context, cx),
ShortcutCommand::SetHeading3 => load_dynamic_keybinding(key, SetHeading3, context, cx),
ShortcutCommand::SetHeading4 => load_dynamic_keybinding(key, SetHeading4, context, cx),
ShortcutCommand::SetHeading5 => load_dynamic_keybinding(key, SetHeading5, context, cx),
ShortcutCommand::SetHeading6 => load_dynamic_keybinding(key, SetHeading6, context, cx),
ShortcutCommand::ToggleBulletList => load_dynamic_keybinding(key, ToggleBulletList, context, cx),
ShortcutCommand::ToggleOrderedList => load_dynamic_keybinding(key, ToggleOrderedList, context, cx),
ShortcutCommand::ToggleTaskList => load_dynamic_keybinding(key, ToggleTaskList, context, cx),
ShortcutCommand::ToggleQuote => load_dynamic_keybinding(key, ToggleQuote, context, cx),
ShortcutCommand::ToggleCodeBlock => load_dynamic_keybinding(key, ToggleCodeBlock, context, cx),
ShortcutCommand::MoveBlockUp => load_dynamic_keybinding(key, MoveBlockUp, context, cx),
ShortcutCommand::MoveBlockDown => load_dynamic_keybinding(key, MoveBlockDown, context, cx),
ShortcutCommand::DuplicateBlock => load_dynamic_keybinding(key, DuplicateBlock, context, cx),
ShortcutCommand::DeleteBlock => load_dynamic_keybinding(key, DeleteBlock, context, cx),
ShortcutCommand::IndentBlock => load_dynamic_keybinding(key, IndentBlock, context, cx),
ShortcutCommand::OutdentBlock => load_dynamic_keybinding(key, OutdentBlock, context, cx),
ShortcutCommand::ExitCodeBlock => load_dynamic_keybinding(key, ExitCodeBlock, context, cx),
ShortcutCommand::DismissTransientUi => load_dynamic_keybinding(key, DismissTransientUi, context, cx),
ShortcutCommand::ToggleViewMode => load_dynamic_keybinding(key, ToggleViewMode, context, cx),
}
}
pub(crate) fn resolved_keybindings(config: &BTreeMap<String, Vec<String>>) -> Vec<KeyBinding> {
pub(crate) fn resolved_keybindings(
config: &BTreeMap<String, Vec<String>>,
cx: &App,
) -> Vec<KeyBinding> {
let normalized = normalize_shortcut_config(config);
let mut bindings = Vec::new();
for definition in SHORTCUT_DEFINITIONS {
@@ -725,14 +755,14 @@ pub(crate) fn resolved_keybindings(config: &BTreeMap<String, Vec<String>>) -> Ve
.unwrap_or_else(|| default_keys(*definition));
bindings.extend(
keys.iter()
.map(|key| key_binding_for(definition.command, key, definition.context)),
.map(|key| key_binding_for(definition.command, key, definition.context, cx)),
);
}
bindings
}
pub(crate) fn install_keybindings(cx: &mut App, config: &BTreeMap<String, Vec<String>>) {
cx.bind_keys(resolved_keybindings(config));
cx.bind_keys(resolved_keybindings(config, cx));
}
/// Register key bindings for the block editor.
@@ -994,7 +994,7 @@ impl Element for BlockTextElement {
// held (matching the gesture that opens the link); a plain hover keeps
// the text cursor. The editor root repaints on follow-modifier
// toggles, so this re-evaluates even when the pointer stays still.
if window.modifiers().secondary() {
if window.modifiers().secondary(cx) {
window.set_cursor_style(CursorStyle::PointingHand, &prepaint.hitbox);
}
}
@@ -1257,7 +1257,7 @@ mod tests {
// Cmd/Ctrl+click follows the link instead: the caret is left untouched
// and no drag-selection begins.
block.update(cx, |block, _cx| block.selected_range = 0..0);
event.modifiers = Modifiers::secondary_key();
event.modifiers = cx.read(|cx| Modifiers::secondary_key(cx));
cx.update(|window, app| {
block.update(app, |block, cx| block.on_mouse_down(&event, window, cx));
});
@@ -882,7 +882,7 @@ impl Block {
// Cmd/Ctrl+click follows a rendered link instead of editing it, so the
// block is neither focused nor selected; the link opens on mouse-up.
if event.modifiers.secondary() && self.pointer_link_hit(event.position).is_some() {
if event.modifiers.secondary(cx) && self.pointer_link_hit(event.position).is_some() {
self.is_selecting = false;
cx.stop_propagation();
return;
@@ -932,7 +932,7 @@ impl Block {
) {
// Only Cmd/Ctrl+click follows the link; a plain click falls through so
// the block focuses for editing like any other inline text.
if event.modifiers.secondary() {
if event.modifiers.secondary(cx) {
cx.stop_propagation();
}
}
@@ -960,7 +960,7 @@ impl Block {
// Cmd/Ctrl+click follows a rendered link, using the same open-link
// prompt as the double-click gesture below.
if event.modifiers.secondary()
if event.modifiers.secondary(cx)
&& let Some(link) = self.pointer_link_hit(event.position)
{
self.open_rendered_link(&link, cx);
@@ -1490,7 +1490,7 @@ impl Block {
.on_mouse_up(
MouseButton::Left,
cx.listener(move |block, event: &MouseUpEvent, _window, cx| {
if event.modifiers.secondary() {
if event.modifiers.secondary(cx) {
block.open_rendered_link(&link, cx);
}
}),
@@ -2099,7 +2099,7 @@ impl Block {
.on_mouse_up(
MouseButton::Left,
cx.listener(move |block, event: &MouseUpEvent, _window, cx| {
if event.modifiers.secondary() {
if event.modifiers.secondary(cx) {
block.open_rendered_link(&hit, cx);
}
}),
@@ -3639,7 +3639,7 @@ impl Element for LinkFollowCursor {
window: &mut Window,
cx: &mut App,
) {
if hitbox.is_hovered(window) && window.modifiers().secondary() {
if hitbox.is_hovered(window) && window.modifiers().secondary(cx) {
// The editor root repaints on follow-modifier toggles, so the hand
// cursor re-evaluates here even while the pointer stays still.
window.set_cursor_style(CursorStyle::PointingHand, hitbox);
+1 -1
View File
@@ -959,7 +959,7 @@ impl Editor {
pub(crate) fn on_editor_scroll_wheel(
&mut self,
_event: &ScrollWheelEvent,
_event: &ScrollEvent,
_window: &mut Window,
cx: &mut Context<Self>,
) {
+4 -4
View File
@@ -749,7 +749,7 @@ impl Render for Editor {
.on_mouse_move(cx.listener(Self::on_editor_mouse_move))
.on_mouse_up(MouseButton::Left, cx.listener(Self::on_editor_mouse_up))
.on_mouse_up_out(MouseButton::Left, cx.listener(Self::on_editor_mouse_up))
.on_scroll_wheel(cx.listener(Self::on_editor_scroll_wheel))
.on_scroll(cx.listener(Self::on_editor_scroll_wheel))
.p(px(d.editor_padding))
.pb(px(d.editor_padding
+ scroll_trigger_padding
@@ -860,7 +860,7 @@ impl Render for Editor {
// is an ancestor of every block, so one listener here covers a link in any
// block while editing. Gated to the secondary modifier so Shift during
// selection does not repaint.
let follow_modifier_active = window.modifiers().secondary();
let follow_modifier_active = window.modifiers().secondary(cx);
let bounds_editor = cx.entity().downgrade();
let base = div()
@@ -878,8 +878,8 @@ impl Render for Editor {
editor.root_bounds = bounds;
});
})
.on_modifiers_changed(move |event, window, _| {
if event.modifiers.secondary() != follow_modifier_active {
.on_modifiers_changed(move |event, window, cx| {
if event.modifiers.secondary(cx) != follow_modifier_active {
window.refresh();
}
})
+3 -1
View File
@@ -5,9 +5,11 @@ pub(crate) const MARKDOWN_CONTEXT: &str = "NotesMarkdown";
actions!(notes_markdown, [SaveMarkdown, ToggleMarkdownOutline]);
pub(crate) fn init(cx: &mut App) {
cx.bind_keys([KeyBinding::new(
// `secondary-` 别名需要宿主 OS 才能解析,走动态加载路径。
cx.bind_keys([one_core::keybindings::load_dynamic_keybinding(
"secondary-s",
SaveMarkdown,
Some(MARKDOWN_CONTEXT),
cx,
)]);
}
+1 -1
View File
@@ -424,7 +424,7 @@ mod tests {
for descriptor in descriptors {
assert!(ids.insert(descriptor.command_id));
for key in descriptor.default_keys {
Keystroke::parse(&key).unwrap();
Keystroke::parse_with_os(&key, gpui::OperatingSystem::Mac).unwrap();
}
}
}
@@ -150,9 +150,10 @@ fn scroll_returns_none_for_an_empty_table() {
fn find_shortcuts_are_bound_in_the_edit_table_context() {
let source = include_str!("../mod.rs");
assert!(source.contains("KeyBinding::new(key, Find, Some(CONTEXT))"));
assert!(source.contains("KeyBinding::new(key, FindNext, Some(CONTEXT))"));
assert!(source.contains("KeyBinding::new(key, FindPrevious, Some(CONTEXT))"));
// v0.1.12 起动态键位走 `load_dynamic_keybinding`(KeyBinding::new 只收 &'static str)。
assert!(source.contains("load_dynamic_keybinding(key, Find, Some(CONTEXT), cx)"));
assert!(source.contains("load_dynamic_keybinding(key, FindNext, Some(CONTEXT), cx)"));
assert!(source.contains("load_dynamic_keybinding(key, FindPrevious, Some(CONTEXT), cx)"));
}
#[test]
@@ -161,8 +162,8 @@ fn hosted_find_bar_binds_the_same_navigation_shortcuts() {
// 宿主渲染的输入框要能复用同一份(可重绑的)上下跳键位。
assert!(source.contains("pub const HOSTED_FIND_CONTEXT: &str = \"EditTableHostedFind\";"));
assert!(source.contains("KeyBinding::new(key, FindNext, Some(HOSTED_FIND_CONTEXT))"));
assert!(source.contains("KeyBinding::new(key, FindPrevious, Some(HOSTED_FIND_CONTEXT))"));
assert!(source.contains("load_dynamic_keybinding(key, FindNext, Some(HOSTED_FIND_CONTEXT), cx)"));
assert!(source.contains("load_dynamic_keybinding(key, FindPrevious, Some(HOSTED_FIND_CONTEXT), cx)"));
assert!(source.contains("Some(HOSTED_FIND_CONTEXT),\n FindNext,"));
assert!(source.contains("Some(HOSTED_FIND_CONTEXT),\n FindPrevious,"));
}
+43 -15
View File
@@ -46,7 +46,7 @@ gpui::actions!(edit_table, [SelectPrevColumn, SelectNextColumn]);
/// 初始化 EditTable 的键盘绑定
pub fn init(cx: &mut App, keybindings: &TableKeybindings) {
cx.bind_keys(init_keybindings(keybindings));
cx.bind_keys(init_keybindings(keybindings, cx));
}
pub fn refresh_keybindings(cx: &mut App, keybindings: TableKeybindings) {
@@ -124,13 +124,41 @@ impl Default for TableKeybindings {
}
}
fn init_keybindings(bindings: &TableKeybindings) -> Vec<KeyBinding> {
/// 动态字符串构造 KeyBinding(gpui-fast v0.1.12 起 KeyBinding::new 只收 &'static str)。
fn load_dynamic_keybinding<A: Action>(
keystrokes: &str,
action: A,
context: Option<&str>,
cx: &App,
) -> KeyBinding {
let context_predicate = context
.map(|context| gpui::KeyBindingContextPredicate::parse(context).unwrap().into());
KeyBinding::load(keystrokes, Box::new(action), context_predicate, false, None, cx).unwrap()
}
/// 编译目标对应的 gpui `OperatingSystem`。
fn current_os() -> gpui::OperatingSystem {
match std::env::consts::OS {
"macos" => gpui::OperatingSystem::Mac,
"windows" => gpui::OperatingSystem::Windows,
"linux" => gpui::OperatingSystem::Linux,
"freebsd" => gpui::OperatingSystem::FreeBsd,
"ios" => gpui::OperatingSystem::Ios,
"android" => gpui::OperatingSystem::Android,
_ => gpui::OperatingSystem::Unknown,
}
}
fn init_keybindings(bindings: &TableKeybindings, cx: &App) -> Vec<KeyBinding> {
let mut keybindings = Vec::new();
keybindings.extend(
bindings
.cancel
.iter()
.map(|key| KeyBinding::new(&key, Cancel, Some(CONTEXT))),
.map(|key| {
load_dynamic_keybinding(key, Cancel, Some(CONTEXT), cx)
}),
);
keybindings.extend([
KeyBinding::new("up", SelectUp, Some(CONTEXT)),
@@ -146,19 +174,19 @@ fn init_keybindings(bindings: &TableKeybindings) -> Vec<KeyBinding> {
bindings
.copy
.iter()
.map(|key| KeyBinding::new(&key, Copy, Some(CONTEXT))),
.map(|key| load_dynamic_keybinding(key, Copy, Some(CONTEXT), cx)),
);
keybindings.extend(
bindings
.paste
.iter()
.map(|key| KeyBinding::new(&key, Paste, Some(CONTEXT))),
.map(|key| load_dynamic_keybinding(key, Paste, Some(CONTEXT), cx)),
);
keybindings.extend(
bindings
.select_all
.iter()
.map(|key| KeyBinding::new(&key, SelectAll, Some(CONTEXT))),
.map(|key| load_dynamic_keybinding(key, SelectAll, Some(CONTEXT), cx)),
);
keybindings.extend([
KeyBinding::new("tab", SelectNextColumn, Some(CONTEXT)),
@@ -168,31 +196,31 @@ fn init_keybindings(bindings: &TableKeybindings) -> Vec<KeyBinding> {
bindings
.find
.iter()
.map(|key| KeyBinding::new(key, Find, Some(CONTEXT))),
.map(|key| load_dynamic_keybinding(key, Find, Some(CONTEXT), cx)),
);
keybindings.extend(
bindings
.find_next
.iter()
.map(|key| KeyBinding::new(key, FindNext, Some(CONTEXT))),
.map(|key| load_dynamic_keybinding(key, FindNext, Some(CONTEXT), cx)),
);
keybindings.extend(
bindings
.find_previous
.iter()
.map(|key| KeyBinding::new(key, FindPrevious, Some(CONTEXT))),
.map(|key| load_dynamic_keybinding(key, FindPrevious, Some(CONTEXT), cx)),
);
keybindings.extend(
bindings
.find_next
.iter()
.map(|key| KeyBinding::new(key, FindNext, Some(HOSTED_FIND_CONTEXT))),
.map(|key| load_dynamic_keybinding(key, FindNext, Some(HOSTED_FIND_CONTEXT), cx)),
);
keybindings.extend(
bindings
.find_previous
.iter()
.map(|key| KeyBinding::new(key, FindPrevious, Some(HOSTED_FIND_CONTEXT))),
.map(|key| load_dynamic_keybinding(key, FindPrevious, Some(HOSTED_FIND_CONTEXT), cx)),
);
keybindings
}
@@ -284,12 +312,12 @@ where
.collect::<Vec<_>>();
let mut keybindings = shadow_shortcuts(defaults, current, active)
.into_iter()
.map(|key| KeyBinding::new(&key, NoAction, context))
.map(|key| load_dynamic_keybinding(&key, NoAction, context, cx))
.collect::<Vec<_>>();
keybindings.extend(
current
.iter()
.map(|key| KeyBinding::new(key, action.clone(), context)),
.map(|key| load_dynamic_keybinding(key, action.clone(), context, cx)),
);
keybindings
}
@@ -305,7 +333,7 @@ fn shadow_shortcuts(
.map(|key| key.to_string())
.chain(active)
.chain(current.iter().cloned())
.filter(|key| Keystroke::parse(key).is_ok() && seen.insert(key.clone()))
.filter(|key| Keystroke::parse_with_os(key, current_os()).is_ok() && seen.insert(key.clone()))
.collect()
}
@@ -313,7 +341,7 @@ fn binding_shortcut(binding: &KeyBinding) -> String {
binding
.keystrokes()
.iter()
.map(ToString::to_string)
.map(|keystroke| keystroke.display(current_os()).to_string())
.collect::<Vec<_>>()
.join(" ")
}
+5 -5
View File
@@ -19,7 +19,7 @@ use gpui::{
AnyElement, AppContext, Axis, Bounds, ClickEvent, ClipboardItem, Context, Div, DragMoveEvent,
ElementId, Entity, EventEmitter, FocusHandle, Focusable, InteractiveElement, IntoElement,
IsZero, ListSizingBehavior, MouseButton, MouseDownEvent, ParentElement, Pixels, Point, Render,
ScrollStrategy, ScrollWheelEvent, SharedString, Stateful, StatefulInteractiveElement as _,
ScrollStrategy, ScrollEvent, SharedString, Stateful, StatefulInteractiveElement as _,
Styled, Subscription, Task, UniformListScrollHandle, Window, canvas, div,
prelude::FluentBuilder, px, uniform_list,
};
@@ -455,7 +455,7 @@ where
fn handle_scroll_wheel(
&mut self,
event: &ScrollWheelEvent,
event: &ScrollEvent,
window: &mut Window,
cx: &mut Context<Self>,
) {
@@ -1680,7 +1680,7 @@ where
let multi_select_enabled = self.delegate.multi_select_enabled(cx);
let is_row_number_col = self.delegate.row_number_enabled(cx) && col_ix == 0;
let shift_pressed = e.modifiers().shift;
let ctrl_pressed = e.modifiers().secondary();
let ctrl_pressed = e.modifiers().secondary(cx);
// 处理正在编辑的单元格
if edit_enabled {
@@ -2874,7 +2874,7 @@ where
if is_row_number_col {
return;
}
let add_to_selection = e.modifiers.secondary();
let add_to_selection = e.modifiers.secondary(cx);
this.prepare_drag_selection(row_ix, col_ix, add_to_selection, cx);
}),
)
@@ -4348,7 +4348,7 @@ where
div()
.size_full()
.on_scroll_wheel(cx.listener(Self::handle_scroll_wheel))
.on_scroll(cx.listener(Self::handle_scroll_wheel))
.children(loading_view)
.when(!loading, |this| {
this.child(inner_table)
+11 -7
View File
@@ -3870,7 +3870,7 @@ mod tests {
AppContext, Bounds, TestAppContext, VisualTestContext, WindowBounds, WindowOptions, px,
size,
};
use gpui_component::{Root, render_dialog_layer};
use gpui_component::Root;
#[gpui::test]
fn delete_key_confirmation_dialog_opens(cx: &mut TestAppContext) {
@@ -3904,21 +3904,25 @@ mod tests {
cx.run_until_parked();
assert!(view.read_with(&cx, |view, _| view.current_key.is_some()));
assert!(
!cx.update(|window, cx| render_dialog_layer(window, cx).is_some()),
"confirmation dialog should initially be closed"
);
// v0.8.1 起对话框层走 Presence 动画,只能在渲染期采样(use_keyed_state
// 需要渲染期 current_view),测试改查 WindowState 的活动对话框数。
let dialogs_before = dialog_layer_count(&mut cx);
view.update_in(&mut cx, |view, window, cx| {
view.show_delete_dialog(window, cx);
});
cx.run_until_parked();
assert!(
cx.update(|window, cx| render_dialog_layer(window, cx).is_some()),
assert_eq!(
dialog_layer_count(&mut cx),
dialogs_before + 1,
"delete confirmation dialog should be registered with the window root"
);
}
fn dialog_layer_count(cx: &mut VisualTestContext) -> usize {
cx.update(|window, cx| gpui_component::active_dialog_count(window, cx))
}
#[test]
fn delete_key_button_routes_to_confirmation_dialog() {
let source = include_str!("key_value_view.rs");
+9 -9
View File
@@ -13,7 +13,7 @@ use gpui::{
App, AppContext as _, AsyncApp, Bounds, ClipboardItem, Context, ElementInputHandler, Entity,
EntityInputHandler, EventEmitter, FocusHandle, Focusable, FontFallbacks, InteractiveElement,
IntoElement, KeyDownEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent,
ParentElement, Pixels, Point, Render, ScrollWheelEvent, SharedString, Styled, Task,
ParentElement, Pixels, Point, Render, ScrollEvent, SharedString, Styled, Task,
UTF16Selection, Window, actions, canvas, div, px, size,
};
use gpui_component::{
@@ -363,7 +363,7 @@ fn init_keybindings(cx: &App) -> Vec<gpui::KeyBinding> {
keybindings.extend(
shortcuts_for(cx, action_id::REDIS_CLEAR_OUTPUT, &["ctrl-l"])
.into_iter()
.map(|key| gpui::KeyBinding::new(&key, ClearOutput, Some(REDIS_CLI_CONTEXT))),
.map(|key| one_core::keybindings::load_dynamic_keybinding(&key, ClearOutput, Some(REDIS_CLI_CONTEXT), cx)),
);
keybindings.extend(
shortcuts_for(
@@ -372,7 +372,7 @@ fn init_keybindings(cx: &App) -> Vec<gpui::KeyBinding> {
&[redis_platform_shortcut("cmd-c", "ctrl-c")],
)
.into_iter()
.map(|key| gpui::KeyBinding::new(&key, Copy, Some(REDIS_CLI_CONTEXT))),
.map(|key| one_core::keybindings::load_dynamic_keybinding(&key, Copy, Some(REDIS_CLI_CONTEXT), cx)),
);
keybindings.extend(
shortcuts_for(
@@ -381,7 +381,7 @@ fn init_keybindings(cx: &App) -> Vec<gpui::KeyBinding> {
&[redis_platform_shortcut("cmd-v", "ctrl-v")],
)
.into_iter()
.map(|key| gpui::KeyBinding::new(&key, Paste, Some(REDIS_CLI_CONTEXT))),
.map(|key| one_core::keybindings::load_dynamic_keybinding(&key, Paste, Some(REDIS_CLI_CONTEXT), cx)),
);
keybindings.extend(
shortcuts_for(
@@ -390,12 +390,12 @@ fn init_keybindings(cx: &App) -> Vec<gpui::KeyBinding> {
&[redis_platform_shortcut("cmd-a", "ctrl-a")],
)
.into_iter()
.map(|key| gpui::KeyBinding::new(&key, SelectAll, Some(REDIS_CLI_CONTEXT))),
.map(|key| one_core::keybindings::load_dynamic_keybinding(&key, SelectAll, Some(REDIS_CLI_CONTEXT), cx)),
);
keybindings.extend(
shortcuts_for(cx, action_id::REDIS_CLEAR_SELECTION, &["escape"])
.into_iter()
.map(|key| gpui::KeyBinding::new(&key, ClearSelection, Some(REDIS_CLI_CONTEXT))),
.map(|key| one_core::keybindings::load_dynamic_keybinding(&key, ClearSelection, Some(REDIS_CLI_CONTEXT), cx)),
);
keybindings.extend([
// 光标移动
@@ -425,7 +425,7 @@ fn init_keybindings(cx: &App) -> Vec<gpui::KeyBinding> {
keybindings.extend(
shortcuts_for(cx, action_id::REDIS_COMPLETE_COMMAND, &["tab"])
.into_iter()
.map(|key| gpui::KeyBinding::new(&key, CompleteCommand, Some(REDIS_CLI_CONTEXT))),
.map(|key| one_core::keybindings::load_dynamic_keybinding(&key, CompleteCommand, Some(REDIS_CLI_CONTEXT), cx)),
);
keybindings
}
@@ -1447,7 +1447,7 @@ impl RedisCliView {
/// 处理滚轮事件
fn handle_scroll(
&mut self,
event: &ScrollWheelEvent,
event: &ScrollEvent,
_window: &mut Window,
cx: &mut Context<Self>,
) {
@@ -2026,7 +2026,7 @@ impl Render for RedisCliView {
.on_mouse_up(MouseButton::Left, cx.listener(Self::handle_mouse_up))
.flex_1()
.relative()
.on_scroll_wheel(cx.listener(Self::handle_scroll))
.on_scroll(cx.listener(Self::handle_scroll))
.child(
// Canvas 用于 IME 输入定位
canvas(
+4 -2
View File
@@ -161,7 +161,8 @@ mod tests {
}
fn key(source: &str) -> Option<RemoteKey> {
let keystroke = Keystroke::parse(source).expect("valid test keystroke");
let keystroke = Keystroke::parse_with_os(source, gpui::OperatingSystem::Mac)
.expect("valid test keystroke");
keystroke_to_remote_key_for_protocol(&keystroke, RemoteDesktopProtocol::Rdp)
}
@@ -217,7 +218,8 @@ mod tests {
let key_event_state = state.with_capslock(Capslock { on: false });
inputs.extend(keyboard_state_inputs(state, key_event_state));
state = key_event_state;
let keystroke = Keystroke::parse(source).expect("valid shifted symbol keystroke");
let keystroke = Keystroke::parse_with_os(source, gpui::OperatingSystem::Mac)
.expect("valid shifted symbol keystroke");
let key = keystroke_to_remote_key_for_protocol(&keystroke, RemoteDesktopProtocol::Rdp)
.expect("mapped RDP symbol");
assert_eq!(key, RemoteKey::Scancode(expected_scancode));
+2 -1
View File
@@ -87,7 +87,8 @@ mod tests {
}
fn key(source: &str) -> Keystroke {
Keystroke::parse(source).expect("valid test keystroke")
Keystroke::parse_with_os(source, gpui::OperatingSystem::Mac)
.expect("valid test keystroke")
}
fn input(key: RemoteKey, pressed: bool) -> RemoteDesktopInput {
+1 -1
View File
@@ -223,7 +223,7 @@ impl RemoteDesktopView {
self.send_input(RemoteDesktopInput::MouseButton { button, pressed });
}
pub(super) fn send_scroll(&self, event: &ScrollWheelEvent) {
pub(super) fn send_scroll(&self, event: &ScrollEvent) {
match event.delta {
ScrollDelta::Lines(delta) => self.send_scroll_delta(delta.x, delta.y, 100.0),
ScrollDelta::Pixels(delta) => {
@@ -507,7 +507,7 @@ impl Render for RemoteDesktopView {
cx.stop_propagation();
}),
)
.on_scroll_wheel(cx.listener(|this, event: &ScrollWheelEvent, _, cx| {
.on_scroll(cx.listener(|this, event: &ScrollEvent, _, cx| {
this.send_scroll(event);
cx.stop_propagation();
}))
@@ -200,12 +200,12 @@ fn init_keybinding_items(cx: &App) -> Vec<KeyBinding> {
keybindings.extend(
shortcuts_for(cx, action_id::REMOTE_EDITOR_SEARCH, &[search_shortcut()])
.into_iter()
.map(|key| KeyBinding::new(&key, OpenSearch, Some(REMOTE_FILE_EDITOR_CONTEXT))),
.map(|key| one_core::keybindings::load_dynamic_keybinding(&key, OpenSearch, Some(REMOTE_FILE_EDITOR_CONTEXT), cx)),
);
keybindings.extend(
shortcuts_for(cx, action_id::REMOTE_EDITOR_REPLACE, &[replace_shortcut()])
.into_iter()
.map(|key| KeyBinding::new(&key, OpenReplace, Some(REMOTE_FILE_EDITOR_CONTEXT))),
.map(|key| one_core::keybindings::load_dynamic_keybinding(&key, OpenReplace, Some(REMOTE_FILE_EDITOR_CONTEXT), cx)),
);
keybindings
}
+1 -1
View File
@@ -2048,7 +2048,7 @@ impl Render for FileListPanel {
move |this, event: &MouseDownEvent, _window, cx| {
let mode = selection_mode(
event.modifiers.shift,
event.modifiers.secondary(),
event.modifiers.secondary(cx),
);
this.select_row(filtered_ix, mode);
cx.notify();
+2 -2
View File
@@ -282,9 +282,9 @@ impl russh::server::Handler for FakeChainHandler {
async fn auth_publickey(
&mut self,
_: &str,
public_key: &russh::keys::PublicKey,
public_key: russh::server::VerifiedPublicKey<'_>,
) -> Result<Auth, Self::Error> {
Ok(self.answer_public_key(public_key))
Ok(self.answer_public_key(public_key.public_key))
}
async fn auth_keyboard_interactive<'a>(
@@ -6055,7 +6055,7 @@ impl FileManagerPanel {
cx| {
let mode = selection_mode(
event.modifiers.shift,
event.modifiers.secondary(),
event.modifiers.secondary(cx),
);
this.select_row(
filtered_ix,
@@ -149,7 +149,9 @@ fn validated_quick_command_shortcut(
shortcut
.map(|shortcut| {
let keystroke = Keystroke::parse(&shortcut).map_err(|_| ())?;
let keystroke =
Keystroke::parse_with_os(&shortcut, one_core::keybindings::current_os())
.map_err(|_| ())?;
match capture_quick_command_shortcut(&keystroke) {
ShortcutCapture::Shortcut(shortcut) => Ok(shortcut),
ShortcutCapture::Clear | ShortcutCapture::Invalid => Err(()),
@@ -37,7 +37,7 @@ impl TerminalCommandBar {
.bg(self.colors.background)
.text_color(self.colors.foreground)
.shadow_lg()
.on_scroll_wheel(|_, _, cx| cx.stop_propagation())
.on_scroll(|_, _, cx| cx.stop_propagation())
.child(
content
.max_h(px(COMMAND_POPOVER_MAX_HEIGHT))
+22 -18
View File
@@ -38,7 +38,11 @@ pub(super) const TERMINAL_SCROLL_PAGE_DOWN_SHORTCUT: &str = "shift-pagedown";
// assigned by users, but must not consume Escape by default.
pub(super) const TERMINAL_CLEAR_SELECTION_DEFAULTS: &[&str] = &[];
pub(super) fn terminal_shortcut_label(shortcut: &str) -> SharedString {
Kbd::format(&Keystroke::parse(shortcut).expect("终端快捷键定义非法")).into()
Kbd::format(
&Keystroke::parse_with_os(shortcut, one_core::keybindings::current_os())
.expect("终端快捷键定义非法"),
)
.into()
}
/// 对路径进行简单 shell 转义(用单引号包裹,处理内部单引号)
@@ -62,22 +66,22 @@ pub(super) fn init_keybindings(cx: &App) -> Vec<KeyBinding> {
keybindings.extend(
shortcuts_for(cx, action_id::TERMINAL_SEND_TAB, &["tab"])
.into_iter()
.map(|key| KeyBinding::new(&key, SendTab, Some(TERMINAL_CONTEXT))),
.map(|key| one_core::keybindings::load_dynamic_keybinding(&key, SendTab, Some(TERMINAL_CONTEXT), cx)),
);
keybindings.extend(
shortcuts_for(cx, action_id::TERMINAL_SEND_SHIFT_TAB, &["shift-tab"])
.into_iter()
.map(|key| KeyBinding::new(&key, SendShiftTab, Some(TERMINAL_CONTEXT))),
.map(|key| one_core::keybindings::load_dynamic_keybinding(&key, SendShiftTab, Some(TERMINAL_CONTEXT), cx)),
);
keybindings.extend(
shortcuts_for(cx, action_id::TERMINAL_COPY, &[TERMINAL_COPY_SHORTCUT])
.into_iter()
.map(|key| KeyBinding::new(&key, Copy, Some(TERMINAL_CONTEXT))),
.map(|key| one_core::keybindings::load_dynamic_keybinding(&key, Copy, Some(TERMINAL_CONTEXT), cx)),
);
keybindings.extend(
shortcuts_for(cx, action_id::TERMINAL_PASTE, &terminal_paste_defaults())
.into_iter()
.map(|key| KeyBinding::new(&key, Paste, Some(TERMINAL_CONTEXT))),
.map(|key| one_core::keybindings::load_dynamic_keybinding(&key, Paste, Some(TERMINAL_CONTEXT), cx)),
);
keybindings.extend(
shortcuts_for(
@@ -86,7 +90,7 @@ pub(super) fn init_keybindings(cx: &App) -> Vec<KeyBinding> {
&[TERMINAL_SELECT_ALL_SHORTCUT],
)
.into_iter()
.map(|key| KeyBinding::new(&key, SelectAll, Some(TERMINAL_CONTEXT))),
.map(|key| one_core::keybindings::load_dynamic_keybinding(&key, SelectAll, Some(TERMINAL_CONTEXT), cx)),
);
keybindings.extend(
shortcuts_for(
@@ -95,7 +99,7 @@ pub(super) fn init_keybindings(cx: &App) -> Vec<KeyBinding> {
&[TERMINAL_CLEAR_SCREEN_SHORTCUT],
)
.into_iter()
.map(|key| KeyBinding::new(&key, ClearScreen, Some(TERMINAL_CONTEXT))),
.map(|key| one_core::keybindings::load_dynamic_keybinding(&key, ClearScreen, Some(TERMINAL_CONTEXT), cx)),
);
keybindings.extend(
shortcuts_for(
@@ -104,7 +108,7 @@ pub(super) fn init_keybindings(cx: &App) -> Vec<KeyBinding> {
TERMINAL_CLEAR_SELECTION_DEFAULTS,
)
.into_iter()
.map(|key| KeyBinding::new(&key, ClearSelection, Some(TERMINAL_CONTEXT))),
.map(|key| one_core::keybindings::load_dynamic_keybinding(&key, ClearSelection, Some(TERMINAL_CONTEXT), cx)),
);
keybindings.extend(
shortcuts_for(
@@ -113,7 +117,7 @@ pub(super) fn init_keybindings(cx: &App) -> Vec<KeyBinding> {
&[TERMINAL_SEARCH_FORWARD_SHORTCUT],
)
.into_iter()
.map(|key| KeyBinding::new(&key, SearchForward, Some(TERMINAL_CONTEXT))),
.map(|key| one_core::keybindings::load_dynamic_keybinding(&key, SearchForward, Some(TERMINAL_CONTEXT), cx)),
);
keybindings.extend(
shortcuts_for(
@@ -122,7 +126,7 @@ pub(super) fn init_keybindings(cx: &App) -> Vec<KeyBinding> {
&[TERMINAL_SEARCH_BACKWARD_SHORTCUT],
)
.into_iter()
.map(|key| KeyBinding::new(&key, SearchBackward, Some(TERMINAL_CONTEXT))),
.map(|key| one_core::keybindings::load_dynamic_keybinding(&key, SearchBackward, Some(TERMINAL_CONTEXT), cx)),
);
keybindings.extend(
shortcuts_for(
@@ -131,7 +135,7 @@ pub(super) fn init_keybindings(cx: &App) -> Vec<KeyBinding> {
&[TERMINAL_TOGGLE_VI_MODE_SHORTCUT],
)
.into_iter()
.map(|key| KeyBinding::new(&key, ToggleViMode, Some(TERMINAL_CONTEXT))),
.map(|key| one_core::keybindings::load_dynamic_keybinding(&key, ToggleViMode, Some(TERMINAL_CONTEXT), cx)),
);
keybindings.extend(
shortcuts_for(
@@ -140,7 +144,7 @@ pub(super) fn init_keybindings(cx: &App) -> Vec<KeyBinding> {
&terminal_increase_font_defaults(),
)
.into_iter()
.map(|key| KeyBinding::new(&key, IncreaseFont, Some(TERMINAL_CONTEXT))),
.map(|key| one_core::keybindings::load_dynamic_keybinding(&key, IncreaseFont, Some(TERMINAL_CONTEXT), cx)),
);
keybindings.extend(
shortcuts_for(
@@ -149,7 +153,7 @@ pub(super) fn init_keybindings(cx: &App) -> Vec<KeyBinding> {
&[terminal_platform_shortcut("cmd--", "ctrl--")],
)
.into_iter()
.map(|key| KeyBinding::new(&key, DecreaseFont, Some(TERMINAL_CONTEXT))),
.map(|key| one_core::keybindings::load_dynamic_keybinding(&key, DecreaseFont, Some(TERMINAL_CONTEXT), cx)),
);
keybindings.extend(
shortcuts_for(
@@ -158,7 +162,7 @@ pub(super) fn init_keybindings(cx: &App) -> Vec<KeyBinding> {
&[terminal_platform_shortcut("cmd-0", "ctrl-0")],
)
.into_iter()
.map(|key| KeyBinding::new(&key, ResetFont, Some(TERMINAL_CONTEXT))),
.map(|key| one_core::keybindings::load_dynamic_keybinding(&key, ResetFont, Some(TERMINAL_CONTEXT), cx)),
);
keybindings.extend(
shortcuts_for(
@@ -167,7 +171,7 @@ pub(super) fn init_keybindings(cx: &App) -> Vec<KeyBinding> {
&[TERMINAL_SCROLL_LINE_UP_SHORTCUT],
)
.into_iter()
.map(|key| KeyBinding::new(&key, ScrollLineUp, Some(TERMINAL_CONTEXT))),
.map(|key| one_core::keybindings::load_dynamic_keybinding(&key, ScrollLineUp, Some(TERMINAL_CONTEXT), cx)),
);
keybindings.extend(
shortcuts_for(
@@ -176,7 +180,7 @@ pub(super) fn init_keybindings(cx: &App) -> Vec<KeyBinding> {
&[TERMINAL_SCROLL_LINE_DOWN_SHORTCUT],
)
.into_iter()
.map(|key| KeyBinding::new(&key, ScrollLineDown, Some(TERMINAL_CONTEXT))),
.map(|key| one_core::keybindings::load_dynamic_keybinding(&key, ScrollLineDown, Some(TERMINAL_CONTEXT), cx)),
);
keybindings.extend(
shortcuts_for(
@@ -185,7 +189,7 @@ pub(super) fn init_keybindings(cx: &App) -> Vec<KeyBinding> {
&[TERMINAL_SCROLL_PAGE_UP_SHORTCUT],
)
.into_iter()
.map(|key| KeyBinding::new(&key, ScrollPageUp, Some(TERMINAL_CONTEXT))),
.map(|key| one_core::keybindings::load_dynamic_keybinding(&key, ScrollPageUp, Some(TERMINAL_CONTEXT), cx)),
);
keybindings.extend(
shortcuts_for(
@@ -194,7 +198,7 @@ pub(super) fn init_keybindings(cx: &App) -> Vec<KeyBinding> {
&[TERMINAL_SCROLL_PAGE_DOWN_SHORTCUT],
)
.into_iter()
.map(|key| KeyBinding::new(&key, ScrollPageDown, Some(TERMINAL_CONTEXT))),
.map(|key| one_core::keybindings::load_dynamic_keybinding(&key, ScrollPageDown, Some(TERMINAL_CONTEXT), cx)),
);
keybindings
}
@@ -111,7 +111,7 @@ impl TerminalView {
.flex_1()
.relative()
.overflow_hidden()
.on_scroll_wheel(cx.listener(Self::handle_scroll))
.on_scroll(cx.listener(Self::handle_scroll))
.on_mouse_down(MouseButton::Left, cx.listener(Self::handle_mouse_down))
.on_mouse_down(
MouseButton::Middle,
+1 -1
View File
@@ -41,7 +41,7 @@ impl TerminalView {
pub(super) fn handle_scroll(
&mut self,
event: &ScrollWheelEvent,
event: &ScrollEvent,
_window: &mut Window,
cx: &mut Context<Self>,
) {
@@ -7,7 +7,7 @@ use crate::view::text_input::{
use crate::view::workspace_support::TerminalRenderMode;
fn keystroke(shortcut: &str) -> Keystroke {
Keystroke::parse(shortcut).expect("解析快捷键失败")
Keystroke::parse_with_os(shortcut, one_core::keybindings::current_os()).expect("解析快捷键失败")
}
#[test]
@@ -876,7 +876,7 @@ fn terminal_command_bar_keeps_oxideterm_keyboard_and_overlay_contracts() {
assert!(quick_source.contains("group_quick_commands"));
assert!(quick_source.contains("bottom(px(self.popover_bottom_offset()))"));
assert!(quick_source.contains("relative(0.96)"));
assert!(!quick_source.contains("on_scroll_wheel"));
assert!(!quick_source.contains("on_scroll"));
assert!(!quick_source.contains("on_mouse_down(MouseButton::Left"));
assert!(quick_source.contains("on_mouse_down_out"));
assert!(quick_source.contains("window.defer(cx"));
+1 -2
View File
@@ -19,7 +19,6 @@ extension_view.workspace = true
gpui.workspace = true
gpui-component.workspace = true
gpui-shell = { workspace = true, optional = true }
gpui-component-shell = { workspace = true, optional = true }
one-core.workspace = true
resource_view.workspace = true
rust-i18n.workspace = true
@@ -35,7 +34,7 @@ tempfile = "3"
[features]
default = []
shell-plugins = ["dep:gpui-shell", "dep:gpui-component-shell"]
shell-plugins = ["dep:gpui-shell"]
[lints]
workspace = true
@@ -1,7 +1,7 @@
use anyhow::{Context as _, Result};
pub(super) fn component_registry() -> Result<gpui_shell::FrozenComponentRegistry> {
gpui_component_shell::components().context("build gpui-component shell registry")
gpui_shell::components::components().context("build gpui-component shell registry")
}
#[cfg(test)]
@@ -15,7 +15,7 @@
//! 页面在这个台子里只需要能画出来,`navop.workbench` / `navop.dev` / `navop.log`
//! 一律用返回空数据的桩替代,所以不需要连接、不需要 catalog。
//!
//! 需要 `--features shell-plugins`(`gpui-shell` / `gpui-component-shell` 是可选依赖):
//! 需要 `--features shell-plugins`(`gpui-shell` 是可选依赖):
//! ```bash
//! cargo test -p universal-plugins --features shell-plugins -- extension_
//! ```
@@ -192,9 +192,9 @@ mod tests {
Rc<gpui_shell::ShellRuntime>,
) {
cx.update(|cx| {
gpui_component_shell::init(cx);
gpui_shell::components::init(cx);
});
let runtime = gpui_component_shell::new_isolated_runtime().expect("isolated runtime");
let runtime = gpui_shell::components::new_isolated_runtime().expect("isolated runtime");
let options = ViewLoadOptions::new(root.to_path_buf(), entry, extension_policy());
let window = cx.add_window(|_, _| Empty);
let mut context = VisualTestContext::from_window(*window.deref(), cx);
+1 -1
View File
@@ -258,7 +258,7 @@ mod system_hotkey {
}
pub(crate) fn parse_project_hotkey(spec: &str) -> anyhow::Result<HotKey> {
let keystroke = Keystroke::parse(spec)?;
let keystroke = Keystroke::parse_with_os(spec, one_core::keybindings::current_os())?;
let hotkey = keystroke_to_hotkey_string(&keystroke);
Ok(hotkey.parse::<HotKey>()?)
}
+1 -1
View File
@@ -77,7 +77,7 @@ impl HomePage {
if let Some(id) = conn_id {
let mode = if event.modifiers().shift {
connection_selection::ConnectionSelectionMode::Range
} else if event.modifiers().secondary() {
} else if event.modifiers().secondary(cx) {
connection_selection::ConnectionSelectionMode::Toggle
} else {
connection_selection::ConnectionSelectionMode::Replace
+1 -1
View File
@@ -70,7 +70,7 @@ impl HomePage {
if let Some(id) = conn_id {
let mode = if event.modifiers().shift {
connection_selection::ConnectionSelectionMode::Range
} else if event.modifiers().secondary() {
} else if event.modifiers().secondary(cx) {
connection_selection::ConnectionSelectionMode::Toggle
} else {
connection_selection::ConnectionSelectionMode::Replace
+3 -3
View File
@@ -18,7 +18,7 @@ fn init_keybindings(cx: &App) -> Vec<KeyBinding> {
keybindings.extend(
shortcuts_for(cx, action_id::HOME_QUICK_OPEN, &[quick_open_default])
.into_iter()
.map(|key| KeyBinding::new(&key, OpenConnectionQuickOpen, None)),
.map(|key| one_core::keybindings::load_dynamic_keybinding(&key, OpenConnectionQuickOpen, None, cx)),
);
keybindings.extend(
shortcuts_for(
@@ -27,7 +27,7 @@ fn init_keybindings(cx: &App) -> Vec<KeyBinding> {
&[new_connection_default],
)
.into_iter()
.map(|key| KeyBinding::new(&key, NewConnectionShortcut, None)),
.map(|key| one_core::keybindings::load_dynamic_keybinding(&key, NewConnectionShortcut, None, cx)),
);
keybindings.extend(
shortcuts_for(
@@ -36,7 +36,7 @@ fn init_keybindings(cx: &App) -> Vec<KeyBinding> {
&[open_local_terminal_default_shortcut()],
)
.into_iter()
.map(|key| KeyBinding::new(&key, OpenLocalTerminalShortcut, None)),
.map(|key| one_core::keybindings::load_dynamic_keybinding(&key, OpenLocalTerminalShortcut, None, cx)),
);
keybindings
}
+12 -12
View File
@@ -535,7 +535,7 @@ fn always_on_top_shortcut_label(cx: &App) -> String {
}
fn shortcut_label(shortcut: &str) -> String {
Keystroke::parse(shortcut)
Keystroke::parse_with_os(shortcut, one_core::keybindings::current_os())
.map(|keystroke| Kbd::format(&keystroke).to_string())
.unwrap_or_else(|_| shortcut.to_string())
}
@@ -1089,7 +1089,7 @@ fn init_keybindings(cx: &App) -> Vec<KeyBinding> {
keybindings.extend(
shortcuts_for(cx, action_id::WINDOW_TOGGLE_ZOOM, &["shift-escape"])
.into_iter()
.map(|key| KeyBinding::new(&key, ToggleZoom, None)),
.map(|key| one_core::keybindings::load_dynamic_keybinding(&key, ToggleZoom, None, cx)),
);
keybindings.extend(
shortcuts_for(
@@ -1098,7 +1098,7 @@ fn init_keybindings(cx: &App) -> Vec<KeyBinding> {
&[close_active_window_default_shortcut()],
)
.into_iter()
.map(|key| KeyBinding::new(&key, CloseActiveWindow, None)),
.map(|key| one_core::keybindings::load_dynamic_keybinding(&key, CloseActiveWindow, None, cx)),
);
keybindings.extend(
shortcuts_for(
@@ -1107,7 +1107,7 @@ fn init_keybindings(cx: &App) -> Vec<KeyBinding> {
&[default_shortcut("cmd-b", "ctrl-b")],
)
.into_iter()
.map(|key| KeyBinding::new(&key, ToggleConnectionSidebar, None)),
.map(|key| one_core::keybindings::load_dynamic_keybinding(&key, ToggleConnectionSidebar, None, cx)),
);
keybindings.extend(vec![
#[cfg(target_os = "macos")]
@@ -1154,7 +1154,7 @@ fn init_keybindings(cx: &App) -> Vec<KeyBinding> {
&[default_shortcut("ctrl-cmd-f", "alt-enter")],
)
.into_iter()
.map(|key| KeyBinding::new(&key, ToggleFullscreen, None)),
.map(|key| one_core::keybindings::load_dynamic_keybinding(&key, ToggleFullscreen, None, cx)),
);
keybindings.extend(
shortcuts_for(
@@ -1163,7 +1163,7 @@ fn init_keybindings(cx: &App) -> Vec<KeyBinding> {
&[default_shortcut("ctrl-cmd-t", "ctrl-alt-t")],
)
.into_iter()
.map(|key| KeyBinding::new(&key, ToggleAlwaysOnTop, None)),
.map(|key| one_core::keybindings::load_dynamic_keybinding(&key, ToggleAlwaysOnTop, None, cx)),
);
keybindings.extend(
shortcuts_for(
@@ -1172,7 +1172,7 @@ fn init_keybindings(cx: &App) -> Vec<KeyBinding> {
&[default_shortcut("cmd-shift-t", "alt-shift-t")],
)
.into_iter()
.map(|key| KeyBinding::new(&key, DuplicateTab, None)),
.map(|key| one_core::keybindings::load_dynamic_keybinding(&key, DuplicateTab, None, cx)),
);
keybindings.extend(
shortcuts_for(
@@ -1181,17 +1181,17 @@ fn init_keybindings(cx: &App) -> Vec<KeyBinding> {
&[default_shortcut("cmd-j", "ctrl-j")],
)
.into_iter()
.map(|key| KeyBinding::new(&key, OpenTabSwitcher, None)),
.map(|key| one_core::keybindings::load_dynamic_keybinding(&key, OpenTabSwitcher, None, cx)),
);
keybindings.extend(
shortcuts_for(cx, action_id::APP_SWITCH_NEXT_TAB, &["ctrl-tab"])
.into_iter()
.map(|key| KeyBinding::new(&key, SwitchNextTab, None)),
.map(|key| one_core::keybindings::load_dynamic_keybinding(&key, SwitchNextTab, None, cx)),
);
keybindings.extend(
shortcuts_for(cx, action_id::APP_SWITCH_PREVIOUS_TAB, &["ctrl-shift-tab"])
.into_iter()
.map(|key| KeyBinding::new(&key, SwitchPreviousTab, None)),
.map(|key| one_core::keybindings::load_dynamic_keybinding(&key, SwitchPreviousTab, None, cx)),
);
keybindings.extend(
shortcuts_for(
@@ -1200,7 +1200,7 @@ fn init_keybindings(cx: &App) -> Vec<KeyBinding> {
&[default_shortcut("cmd-shift-w", "alt-shift-w")],
)
.into_iter()
.map(|key| KeyBinding::new(&key, CloseActiveTab, None)),
.map(|key| one_core::keybindings::load_dynamic_keybinding(&key, CloseActiveTab, None, cx)),
);
keybindings.extend(
shortcuts_for(
@@ -1209,7 +1209,7 @@ fn init_keybindings(cx: &App) -> Vec<KeyBinding> {
&[default_shortcut("cmd-q", "alt-f4")],
)
.into_iter()
.map(|key| KeyBinding::new(&key, QuitApp, None)),
.map(|key| one_core::keybindings::load_dynamic_keybinding(&key, QuitApp, None, cx)),
);
keybindings.push(KeyBinding::new(
default_shortcut("cmd-v", "ctrl-v"),
@@ -418,7 +418,7 @@ impl PersistentConnectionSidebar {
if batch_mode {
let mode = if event.modifiers().shift {
ConnectionSelectionMode::Range
} else if event.modifiers().secondary() {
} else if event.modifiers().secondary(cx) {
ConnectionSelectionMode::Toggle
} else {
ConnectionSelectionMode::Replace
+2 -2
View File
@@ -3318,7 +3318,7 @@ fn shortcut_specs_for_entry(entry: &ShortcutEntry, cx: &App) -> Vec<String> {
}
fn render_shortcut_value(key_str: &str, cx: &App) -> gpui::AnyElement {
match Keystroke::parse(key_str) {
match Keystroke::parse_with_os(key_str, one_core::keybindings::current_os()) {
Ok(keystroke) => Kbd::new(keystroke).into_any_element(),
Err(_) => div()
.text_sm()
@@ -3447,7 +3447,7 @@ fn capture_shortcut(
let is_valid = if system_hotkey {
is_valid_system_hotkey(&spec)
} else {
Keystroke::parse(&spec).is_ok()
Keystroke::parse_with_os(&spec, one_core::keybindings::current_os()).is_ok()
};
if !is_valid {
+1 -1
View File
@@ -38,7 +38,7 @@ impl NotesShortcutCapture {
let Some(spec) = shortcut_spec(&event.keystroke) else {
return;
};
if Keystroke::parse(&spec).is_err() {
if Keystroke::parse_with_os(&spec, one_core::keybindings::current_os()).is_err() {
mark_invalid(&self.state, cx);
return;
}
+1 -1
View File
@@ -219,7 +219,7 @@ fn render_shortcut_values(keys: &[String], cx: &App) -> gpui::AnyElement {
.gap_1()
.flex_wrap()
.justify_end()
.children(keys.iter().map(|key| match Keystroke::parse(key) {
.children(keys.iter().map(|key| match Keystroke::parse_with_os(key, one_core::keybindings::current_os()) {
Ok(keystroke) => Kbd::new(keystroke).into_any_element(),
Err(_) => div().text_sm().child(key.clone()).into_any_element(),
}))
+2 -2
View File
@@ -436,7 +436,7 @@ impl FlowCanvas {
self.process_event_queue(cx);
}
fn on_scroll_wheel(&mut self, ev: &ScrollWheelEvent, _: &mut Window, cx: &mut Context<Self>) {
fn on_scroll(&mut self, ev: &ScrollEvent, _: &mut Window, cx: &mut Context<Self>) {
self.handle_event(FlowEvent::Input(InputEvent::Wheel(ev.clone())), cx);
self.process_event_queue(cx);
}
@@ -563,7 +563,7 @@ impl Render for FlowCanvas {
MouseButton::Left,
window.listener_for(&entity, Self::on_mouse_up),
)
.on_scroll_wheel(window.listener_for(&entity, Self::on_scroll_wheel))
.on_scroll(window.listener_for(&entity, Self::on_scroll))
.child(measured_stack)
}
}
+2 -2
View File
@@ -2,7 +2,7 @@ use std::{any::Any, collections::HashMap, time::Duration};
use gpui::{
AnyElement, Bounds, Context, Div, ElementId, InteractiveElement as _, KeyDownEvent, KeyUpEvent,
MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels, Point, ScrollWheelEvent, Stateful,
MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels, Point, ScrollEvent, Stateful,
Styled, Window, div, rgb,
};
@@ -814,7 +814,7 @@ pub enum InputEvent {
MouseMove(MouseMoveEvent),
MouseUp(MouseUpEvent),
Wheel(ScrollWheelEvent),
Wheel(ScrollEvent),
Hover(bool),
}