mirror of
https://github.com/feigeCode/navop.git
synced 2026-11-06 00:07:34 +00:00
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:
Generated
+350
-549
File diff suppressed because it is too large
Load Diff
+53
-53
@@ -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" }
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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!(
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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, ¤t, 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(" ")
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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(¤t_shortcuts));
|
||||
keybindings.push(secondary_enter_binding(¤t_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(¤t_shortcuts));
|
||||
keybindings.push(secondary_enter_binding(¤t_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);
|
||||
|
||||
@@ -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>,
|
||||
) {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
})
|
||||
|
||||
@@ -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,
|
||||
)]);
|
||||
}
|
||||
|
||||
@@ -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,"));
|
||||
}
|
||||
|
||||
@@ -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(" ")
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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"));
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>()?)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
}))
|
||||
|
||||
Vendored
+2
-2
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+2
-2
@@ -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),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user