From b04ea31a7dd69018de6bf389900b7213fe328114 Mon Sep 17 00:00:00 2001 From: "zed-zippy[bot]" <234243425+zed-zippy[bot]@users.noreply.github.com> Date: Wed, 25 Mar 2026 10:20:42 -0400 Subject: [PATCH] ep: Follow-ups for binding changes (#52258) (cherry-pick to preview) (#52367) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cherry-pick of #52258 to preview ---- ## Context - Updates docs for how to update edit prediction bindings - Walks back how often we use tab to accept prediction where we previously didn't; now just when in leading whitespace, tab does not accept completion when completions menu is open - migration for keymaps using the old `edit_prediction_conflict` key context ## How to Review The only code worth reviewing is the migration ## Self-Review Checklist - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [x] The content is consistent with the [UI/UX checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) - [x] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable Release Notes: - N/A or Added/Fixed/Improved ... --------- Co-authored-by: Max Co-authored-by: Ben Kunkle Co-authored-by: Max --- assets/keymaps/default-linux.json | 2 +- assets/keymaps/default-macos.json | 2 +- assets/keymaps/default-windows.json | 2 +- assets/keymaps/vim.json | 2 +- crates/migrator/src/migrations.rs | 6 + .../src/migrations/m_2026_03_23/keymap.rs | 47 +++ crates/migrator/src/migrator.rs | 340 +++++++++++++----- 7 files changed, 304 insertions(+), 97 deletions(-) create mode 100644 crates/migrator/src/migrations/m_2026_03_23/keymap.rs diff --git a/assets/keymaps/default-linux.json b/assets/keymaps/default-linux.json index ecd603a9afd64a97e2f4e54cd687c94c06e7fc41..65b587fc88c2678159636c53f2e616c17a285359 100644 --- a/assets/keymaps/default-linux.json +++ b/assets/keymaps/default-linux.json @@ -775,7 +775,7 @@ }, }, { - "context": "Editor && edit_prediction && edit_prediction_mode == eager", + "context": "Editor && edit_prediction && edit_prediction_mode == eager && !showing_completions", "bindings": { "tab": "editor::AcceptEditPrediction", }, diff --git a/assets/keymaps/default-macos.json b/assets/keymaps/default-macos.json index 3310d060baf4a063fc7f9a9cd23609b3b07c1f7f..eff14efa73437e1b3cec774ece4afc8a1bdbc1d4 100644 --- a/assets/keymaps/default-macos.json +++ b/assets/keymaps/default-macos.json @@ -839,7 +839,7 @@ }, }, { - "context": "Editor && edit_prediction && edit_prediction_mode == eager", + "context": "Editor && edit_prediction && edit_prediction_mode == eager && !showing_completions", "bindings": { "tab": "editor::AcceptEditPrediction", }, diff --git a/assets/keymaps/default-windows.json b/assets/keymaps/default-windows.json index 08a85a92d994e1d77ff9de79f2b28fd625cc457c..d7b686b038658c4f5aa1318de35b345e5ab65665 100644 --- a/assets/keymaps/default-windows.json +++ b/assets/keymaps/default-windows.json @@ -771,7 +771,7 @@ }, }, { - "context": "Editor && edit_prediction && edit_prediction_mode == eager", + "context": "Editor && edit_prediction && edit_prediction_mode == eager && !showing_completions", "use_key_equivalents": true, "bindings": { "tab": "editor::AcceptEditPrediction", diff --git a/assets/keymaps/vim.json b/assets/keymaps/vim.json index ce5a363dbebe465e732e365f3527f26880f9f770..a571efb150da7bdaa7816e463605561d78e056a1 100644 --- a/assets/keymaps/vim.json +++ b/assets/keymaps/vim.json @@ -1060,7 +1060,7 @@ }, }, { - "context": "Editor && edit_prediction && edit_prediction_mode == eager", + "context": "Editor && edit_prediction && edit_prediction_mode == eager && !showing_completions", "bindings": { // This is identical to the binding in the base keymap, but the vim bindings above to // "vim::Tab" shadow it, so it needs to be bound again. diff --git a/crates/migrator/src/migrations.rs b/crates/migrator/src/migrations.rs index 4f6af2b42cbd5fb545877829fbbcfb9a5bb13aed..d554ee1dd887d6048f55a584ed2534db944b3c08 100644 --- a/crates/migrator/src/migrations.rs +++ b/crates/migrator/src/migrations.rs @@ -310,3 +310,9 @@ pub(crate) mod m_2026_03_16 { pub(crate) use settings::SETTINGS_PATTERNS; } + +pub(crate) mod m_2026_03_23 { + mod keymap; + + pub(crate) use keymap::KEYMAP_PATTERNS; +} diff --git a/crates/migrator/src/migrations/m_2026_03_23/keymap.rs b/crates/migrator/src/migrations/m_2026_03_23/keymap.rs new file mode 100644 index 0000000000000000000000000000000000000000..8fadc8201a0d2846e66ddf0de80275732d701acd --- /dev/null +++ b/crates/migrator/src/migrations/m_2026_03_23/keymap.rs @@ -0,0 +1,47 @@ +use std::ops::Range; + +use tree_sitter::{Query, QueryMatch}; + +use crate::MigrationPatterns; + +pub const KEYMAP_PATTERNS: MigrationPatterns = + &[(crate::patterns::KEYMAP_CONTEXT_PATTERN, rename_context_key)]; + +fn rename_context_key( + contents: &str, + mat: &QueryMatch, + query: &Query, +) -> Option<(Range, String)> { + let context_predicate_ix = query.capture_index_for_name("context_predicate")?; + let context_predicate_range = mat + .nodes_for_capture_index(context_predicate_ix) + .next()? + .byte_range(); + let old_predicate = contents.get(context_predicate_range.clone())?.to_string(); + let mut new_predicate = old_predicate.clone(); + + const REPLACEMENTS: &[(&str, &str)] = &[ + ( + "edit_prediction_conflict && !showing_completions", + "(edit_prediction && in_leading_whitespace)", + ), + ( + "edit_prediction_conflict && showing_completions", + "(edit_prediction && showing_completions)", + ), + ( + "edit_prediction_conflict", + "(edit_prediction && (showing_completions || in_leading_whitespace))", + ), + ]; + + for (old, new) in REPLACEMENTS { + new_predicate = new_predicate.replace(old, new); + } + + if new_predicate != old_predicate { + Some((context_predicate_range, new_predicate)) + } else { + None + } +} diff --git a/crates/migrator/src/migrator.rs b/crates/migrator/src/migrator.rs index 8e26d486506b419431cd845a7f1bb285620d3cc2..ceb6ec2e0e35f0dd3bbd23174637bba00baab6b3 100644 --- a/crates/migrator/src/migrator.rs +++ b/crates/migrator/src/migrator.rs @@ -143,6 +143,10 @@ pub fn migrate_keymap(text: &str) -> Result> { migrations::m_2025_12_08::KEYMAP_PATTERNS, &KEYMAP_QUERY_2025_12_08, ), + MigrationType::TreeSitter( + migrations::m_2026_03_23::KEYMAP_PATTERNS, + &KEYMAP_QUERY_2026_03_23, + ), ]; run_migrations(text, migrations) } @@ -381,6 +385,10 @@ define_query!( SETTINGS_QUERY_2026_03_16, migrations::m_2026_03_16::SETTINGS_PATTERNS ); +define_query!( + KEYMAP_QUERY_2026_03_23, + migrations::m_2026_03_23::KEYMAP_PATTERNS +); // custom query static EDIT_PREDICTION_SETTINGS_MIGRATION_QUERY: LazyLock = LazyLock::new(|| { @@ -408,6 +416,7 @@ mod tests { } } + #[track_caller] fn assert_migrate_keymap(input: &str, output: Option<&str>) { let migrated = migrate_keymap(input).unwrap(); pretty_assertions::assert_eq!(migrated.as_deref(), output); @@ -426,7 +435,7 @@ mod tests { } #[track_caller] - fn assert_migrate_settings_with_migrations( + fn assert_migrate_with_migrations( migrations: &[MigrationType], input: &str, output: Option<&str>, @@ -974,7 +983,7 @@ mod tests { #[test] fn test_mcp_settings_migration() { - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::TreeSitter( migrations::m_2025_06_16::SETTINGS_PATTERNS, &SETTINGS_QUERY_2025_06_16, @@ -1163,7 +1172,7 @@ mod tests { } } }"#; - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::TreeSitter( migrations::m_2025_06_16::SETTINGS_PATTERNS, &SETTINGS_QUERY_2025_06_16, @@ -1175,7 +1184,7 @@ mod tests { #[test] fn test_custom_agent_server_settings_migration() { - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::TreeSitter( migrations::m_2025_11_20::SETTINGS_PATTERNS, &SETTINGS_QUERY_2025_11_20, @@ -1391,7 +1400,7 @@ mod tests { #[test] fn test_flatten_code_action_formatters_basic_array() { - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2025_10_01::flatten_code_actions_formatters, )], @@ -1425,7 +1434,7 @@ mod tests { #[test] fn test_flatten_code_action_formatters_basic_object() { - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2025_10_01::flatten_code_actions_formatters, )], @@ -1582,7 +1591,7 @@ mod tests { #[test] fn test_flatten_code_action_formatters_array_with_multiple_action_blocks_in_defaults_and_multiple_languages() { - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2025_10_01::flatten_code_actions_formatters, )], @@ -1708,7 +1717,7 @@ mod tests { #[test] fn test_flatten_code_action_formatters_array_with_format_on_save_and_multiple_languages() { - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2025_10_01::flatten_code_actions_formatters, )], @@ -1895,7 +1904,7 @@ mod tests { #[test] fn test_format_on_save_formatter_migration_basic() { - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2025_10_02::remove_formatters_on_save, )], @@ -1915,7 +1924,7 @@ mod tests { #[test] fn test_format_on_save_formatter_migration_array() { - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2025_10_02::remove_formatters_on_save, )], @@ -1940,7 +1949,7 @@ mod tests { #[test] fn test_format_on_save_on_off_unchanged() { - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2025_10_02::remove_formatters_on_save, )], @@ -1951,7 +1960,7 @@ mod tests { None, ); - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2025_10_02::remove_formatters_on_save, )], @@ -1965,7 +1974,7 @@ mod tests { #[test] fn test_format_on_save_formatter_migration_in_languages() { - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2025_10_02::remove_formatters_on_save, )], @@ -2003,7 +2012,7 @@ mod tests { #[test] fn test_format_on_save_formatter_migration_mixed_global_and_languages() { - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2025_10_02::remove_formatters_on_save, )], @@ -2040,7 +2049,7 @@ mod tests { #[test] fn test_format_on_save_no_migration_when_no_format_on_save() { - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2025_10_02::remove_formatters_on_save, )], @@ -2054,7 +2063,7 @@ mod tests { #[test] fn test_restore_code_actions_on_format() { - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2025_10_16::restore_code_actions_on_format, )], @@ -2075,7 +2084,7 @@ mod tests { ), ); - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2025_10_16::restore_code_actions_on_format, )], @@ -2089,7 +2098,7 @@ mod tests { None, ); - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2025_10_16::restore_code_actions_on_format, )], @@ -2116,7 +2125,7 @@ mod tests { ), ); - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2025_10_16::restore_code_actions_on_format, )], @@ -2145,7 +2154,7 @@ mod tests { ), ); - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2025_10_16::restore_code_actions_on_format, )], @@ -2163,7 +2172,7 @@ mod tests { #[test] fn test_make_file_finder_include_ignored_an_enum() { - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2025_10_17::make_file_finder_include_ignored_an_enum, )], @@ -2171,7 +2180,7 @@ mod tests { None, ); - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2025_10_17::make_file_finder_include_ignored_an_enum, )], @@ -2191,7 +2200,7 @@ mod tests { ), ); - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2025_10_17::make_file_finder_include_ignored_an_enum, )], @@ -2211,7 +2220,7 @@ mod tests { ), ); - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2025_10_17::make_file_finder_include_ignored_an_enum, )], @@ -2232,7 +2241,7 @@ mod tests { ); // Platform key: settings nested inside "linux" should be migrated - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2025_10_17::make_file_finder_include_ignored_an_enum, )], @@ -2261,7 +2270,7 @@ mod tests { ); // Profile: settings nested inside profiles should be migrated - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2025_10_17::make_file_finder_include_ignored_an_enum, )], @@ -2296,7 +2305,7 @@ mod tests { #[test] fn test_make_relative_line_numbers_an_enum() { - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2025_10_21::make_relative_line_numbers_an_enum, )], @@ -2304,7 +2313,7 @@ mod tests { None, ); - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2025_10_21::make_relative_line_numbers_an_enum, )], @@ -2320,7 +2329,7 @@ mod tests { ), ); - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2025_10_21::make_relative_line_numbers_an_enum, )], @@ -2337,7 +2346,7 @@ mod tests { ); // Platform key: settings nested inside "macos" should be migrated - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2025_10_21::make_relative_line_numbers_an_enum, )], @@ -2362,7 +2371,7 @@ mod tests { ); // Profile: settings nested inside profiles should be migrated - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2025_10_21::make_relative_line_numbers_an_enum, )], @@ -2439,7 +2448,7 @@ mod tests { ); // Platform key: settings nested inside "linux" should be migrated - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2025_11_25::remove_context_server_source, )], @@ -2477,7 +2486,7 @@ mod tests { ); // Profile: settings nested inside profiles should be migrated - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2025_11_25::remove_context_server_source, )], @@ -2618,7 +2627,7 @@ mod tests { #[test] fn test_make_auto_indent_an_enum() { // Empty settings should not change - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2025_01_27::make_auto_indent_an_enum, )], @@ -2627,7 +2636,7 @@ mod tests { ); // true should become "syntax_aware" - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2025_01_27::make_auto_indent_an_enum, )], @@ -2644,7 +2653,7 @@ mod tests { ); // false should become "none" - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2025_01_27::make_auto_indent_an_enum, )], @@ -2661,7 +2670,7 @@ mod tests { ); // Already valid enum values should not change - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2025_01_27::make_auto_indent_an_enum, )], @@ -2673,7 +2682,7 @@ mod tests { ); // Should also work inside languages - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2025_01_27::make_auto_indent_an_enum, )], @@ -2702,7 +2711,7 @@ mod tests { #[test] fn test_move_edit_prediction_provider_to_edit_predictions() { - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_02::move_edit_prediction_provider_to_edit_predictions, )], @@ -2710,7 +2719,7 @@ mod tests { None, ); - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_02::move_edit_prediction_provider_to_edit_predictions, )], @@ -2734,7 +2743,7 @@ mod tests { ), ); - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_02::move_edit_prediction_provider_to_edit_predictions, )], @@ -2762,7 +2771,7 @@ mod tests { ), ); - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_02::move_edit_prediction_provider_to_edit_predictions, )], @@ -2789,7 +2798,7 @@ mod tests { ), ); - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_02::move_edit_prediction_provider_to_edit_predictions, )], @@ -2806,7 +2815,7 @@ mod tests { // Non-object edit_predictions (e.g. true) should gracefully skip // instead of bail!-ing and aborting the entire migration chain. - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_02::move_edit_prediction_provider_to_edit_predictions, )], @@ -2830,7 +2839,7 @@ mod tests { ); // Platform key: settings nested inside "macos" should be migrated - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_02::move_edit_prediction_provider_to_edit_predictions, )], @@ -2859,7 +2868,7 @@ mod tests { ); // Profile: settings nested inside profiles should be migrated - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_02::move_edit_prediction_provider_to_edit_predictions, )], @@ -2892,7 +2901,7 @@ mod tests { ); // Combined: root + platform + profile should all be migrated simultaneously - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_02::move_edit_prediction_provider_to_edit_predictions, )], @@ -2943,7 +2952,7 @@ mod tests { #[test] fn test_migrate_experimental_sweep_mercury() { - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_03::migrate_experimental_sweep_mercury, )], @@ -2951,7 +2960,7 @@ mod tests { None, ); - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_03::migrate_experimental_sweep_mercury, )], @@ -2977,7 +2986,7 @@ mod tests { ), ); - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_03::migrate_experimental_sweep_mercury, )], @@ -3003,7 +3012,7 @@ mod tests { ), ); - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_03::migrate_experimental_sweep_mercury, )], @@ -3029,7 +3038,7 @@ mod tests { ), ); - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_03::migrate_experimental_sweep_mercury, )], @@ -3044,7 +3053,7 @@ mod tests { None, ); - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_03::migrate_experimental_sweep_mercury, )], @@ -3062,7 +3071,7 @@ mod tests { ); // Platform key: settings nested inside "linux" should be migrated - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_03::migrate_experimental_sweep_mercury, )], @@ -3093,7 +3102,7 @@ mod tests { ); // Profile: settings nested inside profiles should be migrated - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_03::migrate_experimental_sweep_mercury, )], @@ -3128,7 +3137,7 @@ mod tests { ); // Combined: root + platform + profile should all be migrated simultaneously - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_03::migrate_experimental_sweep_mercury, )], @@ -3186,7 +3195,7 @@ mod tests { #[test] fn test_migrate_always_allow_tool_actions_to_default() { // No agent settings - no change - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_04::migrate_tool_permission_defaults, )], @@ -3195,7 +3204,7 @@ mod tests { ); // always_allow_tool_actions: true -> tool_permissions.default: "allow" - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_04::migrate_tool_permission_defaults, )], @@ -3222,7 +3231,7 @@ mod tests { ); // always_allow_tool_actions: false -> just remove it - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_04::migrate_tool_permission_defaults, )], @@ -3241,7 +3250,7 @@ mod tests { ); // Preserve existing tool_permissions.tools when migrating - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_04::migrate_tool_permission_defaults, )], @@ -3280,7 +3289,7 @@ mod tests { ); // Don't override existing default (and migrate default_mode to default) - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_04::migrate_tool_permission_defaults, )], @@ -3310,7 +3319,7 @@ mod tests { ); // Migrate existing default_mode to default (no always_allow_tool_actions) - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_04::migrate_tool_permission_defaults, )], @@ -3339,7 +3348,7 @@ mod tests { ); // No migration needed if already using new format with "default" - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_04::migrate_tool_permission_defaults, )], @@ -3357,7 +3366,7 @@ mod tests { ); // Migrate default_mode to default in tool-specific rules - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_04::migrate_tool_permission_defaults, )], @@ -3396,7 +3405,7 @@ mod tests { ); // When tool_permissions is null, replace it so always_allow is preserved - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_04::migrate_tool_permission_defaults, )], @@ -3424,7 +3433,7 @@ mod tests { ); // Platform-specific agent migration - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_04::migrate_tool_permission_defaults, )], @@ -3455,7 +3464,7 @@ mod tests { ); // Channel-specific agent migration - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_04::migrate_tool_permission_defaults, )], @@ -3496,7 +3505,7 @@ mod tests { ); // Profile-level migration - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_04::migrate_tool_permission_defaults, )], @@ -3534,7 +3543,7 @@ mod tests { ); // Platform-specific agent with profiles - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_04::migrate_tool_permission_defaults, )], @@ -3579,7 +3588,7 @@ mod tests { ); // Root-level profile with always_allow_tool_actions - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_04::migrate_tool_permission_defaults, )], @@ -3614,7 +3623,7 @@ mod tests { ); // Root-level profile with default_mode - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_04::migrate_tool_permission_defaults, )], @@ -3651,7 +3660,7 @@ mod tests { ); // Root-level profile + root-level agent both migrated - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_04::migrate_tool_permission_defaults, )], @@ -3697,7 +3706,7 @@ mod tests { // Non-boolean always_allow_tool_actions (string "true") is left in place // so the schema validator can report it, rather than silently dropping user data. - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_04::migrate_tool_permission_defaults, )], @@ -3713,7 +3722,7 @@ mod tests { ); // null always_allow_tool_actions is removed (treated as false) - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_04::migrate_tool_permission_defaults, )], @@ -3730,7 +3739,7 @@ mod tests { // Project-local settings (.zed/settings.json) with always_allow_tool_actions // These files have no platform/channel overrides or root-level profiles. - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_04::migrate_tool_permission_defaults, )], @@ -3771,7 +3780,7 @@ mod tests { ); // Project-local settings with only default_mode (no always_allow_tool_actions) - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_04::migrate_tool_permission_defaults, )], @@ -3800,7 +3809,7 @@ mod tests { ); // Project-local settings with no agent section at all - no change - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_04::migrate_tool_permission_defaults, )], @@ -3815,7 +3824,7 @@ mod tests { ); // Existing agent_servers are left untouched - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_04::migrate_tool_permission_defaults, )], @@ -3858,7 +3867,7 @@ mod tests { ); // Existing agent_servers are left untouched even with partial entries - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_04::migrate_tool_permission_defaults, )], @@ -3895,7 +3904,7 @@ mod tests { ); // always_allow_tool_actions: false leaves agent_servers untouched - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_04::migrate_tool_permission_defaults, )], @@ -3918,7 +3927,7 @@ mod tests { #[test] fn test_migrate_builtin_agent_servers_to_registry_simple() { - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_25::migrate_builtin_agent_servers_to_registry, )], @@ -3958,7 +3967,7 @@ mod tests { #[test] fn test_migrate_builtin_agent_servers_empty_entries() { - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_25::migrate_builtin_agent_servers_to_registry, )], @@ -3989,7 +3998,7 @@ mod tests { #[test] fn test_migrate_builtin_agent_servers_with_command() { - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_25::migrate_builtin_agent_servers_to_registry, )], @@ -4027,7 +4036,7 @@ mod tests { #[test] fn test_migrate_builtin_agent_servers_gemini_with_command() { - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_25::migrate_builtin_agent_servers_to_registry, )], @@ -4055,7 +4064,7 @@ mod tests { #[test] fn test_migrate_builtin_agent_servers_gemini_ignore_system_version_false() { - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_25::migrate_builtin_agent_servers_to_registry, )], @@ -4083,7 +4092,7 @@ mod tests { #[test] fn test_migrate_builtin_agent_servers_gemini_ignore_system_version_true() { - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_25::migrate_builtin_agent_servers_to_registry, )], @@ -4110,7 +4119,7 @@ mod tests { #[test] fn test_migrate_builtin_agent_servers_already_typed_unchanged() { - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_25::migrate_builtin_agent_servers_to_registry, )], @@ -4132,7 +4141,7 @@ mod tests { #[test] fn test_migrate_builtin_agent_servers_preserves_custom_entries() { - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_25::migrate_builtin_agent_servers_to_registry, )], @@ -4166,7 +4175,7 @@ mod tests { #[test] fn test_migrate_builtin_agent_servers_target_already_exists() { - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_25::migrate_builtin_agent_servers_to_registry, )], @@ -4196,7 +4205,7 @@ mod tests { #[test] fn test_migrate_builtin_agent_servers_no_agent_servers_key() { - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_25::migrate_builtin_agent_servers_to_registry, )], @@ -4211,7 +4220,7 @@ mod tests { #[test] fn test_migrate_builtin_agent_servers_all_fields() { - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_25::migrate_builtin_agent_servers_to_registry, )], @@ -4259,7 +4268,7 @@ mod tests { #[test] fn test_migrate_builtin_agent_servers_codex_with_command() { - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_25::migrate_builtin_agent_servers_to_registry, )], @@ -4291,7 +4300,7 @@ mod tests { #[test] fn test_migrate_builtin_agent_servers_mixed_migrated_and_not() { - assert_migrate_settings_with_migrations( + assert_migrate_with_migrations( &[MigrationType::Json( migrations::m_2026_02_25::migrate_builtin_agent_servers_to_registry, )], @@ -4326,4 +4335,149 @@ mod tests { ), ); } + + #[test] + fn test_migrate_edit_prediction_conflict_context() { + assert_migrate_with_migrations( + &[MigrationType::TreeSitter( + migrations::m_2026_03_23::KEYMAP_PATTERNS, + &KEYMAP_QUERY_2026_03_23, + )], + &r#" + [ + { + "context": "Editor && edit_prediction_conflict", + "bindings": { + "ctrl-enter": "editor::AcceptEditPrediction" // Example of a modified keybinding + } + } + ] + "#.unindent(), + Some( + &r#" + [ + { + "context": "Editor && (edit_prediction && (showing_completions || in_leading_whitespace))", + "bindings": { + "ctrl-enter": "editor::AcceptEditPrediction" // Example of a modified keybinding + } + } + ] + "#.unindent(), + ), + ); + + assert_migrate_with_migrations( + &[MigrationType::TreeSitter( + migrations::m_2026_03_23::KEYMAP_PATTERNS, + &KEYMAP_QUERY_2026_03_23, + )], + &r#" + [ + { + "context": "Editor && edit_prediction_conflict && !showing_completions", + "bindings": { + // Here we don't require a modifier unless there's a language server completion + "tab": "editor::AcceptEditPrediction" + } + } + ] + "#.unindent(), + Some( + &r#" + [ + { + "context": "Editor && (edit_prediction && in_leading_whitespace)", + "bindings": { + // Here we don't require a modifier unless there's a language server completion + "tab": "editor::AcceptEditPrediction" + } + } + ] + "#.unindent(), + ), + ); + + assert_migrate_with_migrations( + &[MigrationType::TreeSitter( + migrations::m_2026_03_23::KEYMAP_PATTERNS, + &KEYMAP_QUERY_2026_03_23, + )], + &r#" + [ + { + "context": "Editor && edit_prediction_conflict && showing_completions", + "bindings": { + "tab": "editor::AcceptEditPrediction" + } + } + ] + "# + .unindent(), + Some( + &r#" + [ + { + "context": "Editor && (edit_prediction && showing_completions)", + "bindings": { + "tab": "editor::AcceptEditPrediction" + } + } + ] + "# + .unindent(), + ), + ); + + assert_migrate_with_migrations( + &[MigrationType::TreeSitter( + migrations::m_2026_03_23::KEYMAP_PATTERNS, + &KEYMAP_QUERY_2026_03_23, + )], + &r#" + [ + { + "context": "Editor && edit_prediction", + "bindings": { + "tab": "editor::AcceptEditPrediction", + // Optional: This makes the default `alt-l` binding do nothing. + "alt-l": null + } + }, + { + "context": "Editor && edit_prediction_conflict", + "bindings": { + "alt-tab": "editor::AcceptEditPrediction", + // Optional: This makes the default `alt-l` binding do nothing. + "alt-l": null + } + }, + ] + "# + .unindent(), + Some( + &r#" + [ + { + "context": "Editor && edit_prediction", + "bindings": { + "tab": "editor::AcceptEditPrediction", + // Optional: This makes the default `alt-l` binding do nothing. + "alt-l": null + } + }, + { + "context": "Editor && (edit_prediction && (showing_completions || in_leading_whitespace))", + "bindings": { + "alt-tab": "editor::AcceptEditPrediction", + // Optional: This makes the default `alt-l` binding do nothing. + "alt-l": null + } + }, + ] + "# + .unindent(), + ), + ); + } }