ep: Follow-ups for binding changes (#52258)

Ben Kunkle and Max created

## 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
<!-- Help reviewers focus their attention:
- For small PRs: note what to focus on (e.g., "error handling in
foo.rs")
- For large PRs (>400 LOC): provide a guided tour — numbered list of
files/commits to read in order. (The `large-pr` label is applied
automatically.)
     - See the review process guidelines for comment conventions -->

## Self-Review Checklist

<!-- Check before requesting review: -->
- [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 <max@zed.dev>

Change summary

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 
crates/migrator/src/migrations/m_2026_03_23/keymap.rs |  47 +
crates/migrator/src/migrator.rs                       | 340 +++++++++---
7 files changed, 304 insertions(+), 97 deletions(-)

Detailed changes

assets/keymaps/default-linux.json 🔗

@@ -796,7 +796,7 @@
     },
   },
   {
-    "context": "Editor && edit_prediction && edit_prediction_mode == eager",
+    "context": "Editor && edit_prediction && edit_prediction_mode == eager && !showing_completions",
     "bindings": {
       "tab": "editor::AcceptEditPrediction",
     },

assets/keymaps/default-macos.json 🔗

@@ -858,7 +858,7 @@
     },
   },
   {
-    "context": "Editor && edit_prediction && edit_prediction_mode == eager",
+    "context": "Editor && edit_prediction && edit_prediction_mode == eager && !showing_completions",
     "bindings": {
       "tab": "editor::AcceptEditPrediction",
     },

assets/keymaps/default-windows.json 🔗

@@ -790,7 +790,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",

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.

crates/migrator/src/migrations.rs 🔗

@@ -304,3 +304,9 @@ pub(crate) mod m_2026_02_25 {
 
     pub(crate) use settings::migrate_builtin_agent_servers_to_registry;
 }
+
+pub(crate) mod m_2026_03_23 {
+    mod keymap;
+
+    pub(crate) use keymap::KEYMAP_PATTERNS;
+}

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<usize>, 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
+    }
+}

crates/migrator/src/migrator.rs 🔗

@@ -143,6 +143,10 @@ pub fn migrate_keymap(text: &str) -> Result<Option<String>> {
             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)
 }
@@ -373,6 +377,10 @@ define_query!(
     SETTINGS_QUERY_2025_12_15,
     migrations::m_2025_12_15::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<Query> = LazyLock::new(|| {
@@ -400,6 +408,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);
@@ -418,7 +427,7 @@ mod tests {
     }
 
     #[track_caller]
-    fn assert_migrate_settings_with_migrations(
+    fn assert_migrate_with_migrations(
         migrations: &[MigrationType],
         input: &str,
         output: Option<&str>,
@@ -966,7 +975,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,
@@ -1155,7 +1164,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,
@@ -1167,7 +1176,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,
@@ -1383,7 +1392,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,
             )],
@@ -1417,7 +1426,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,
             )],
@@ -1574,7 +1583,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,
             )],
@@ -1700,7 +1709,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,
             )],
@@ -1887,7 +1896,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,
             )],
@@ -1907,7 +1916,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,
             )],
@@ -1932,7 +1941,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,
             )],
@@ -1943,7 +1952,7 @@ mod tests {
             None,
         );
 
-        assert_migrate_settings_with_migrations(
+        assert_migrate_with_migrations(
             &[MigrationType::Json(
                 migrations::m_2025_10_02::remove_formatters_on_save,
             )],
@@ -1957,7 +1966,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,
             )],
@@ -1995,7 +2004,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,
             )],
@@ -2032,7 +2041,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,
             )],
@@ -2046,7 +2055,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,
             )],
@@ -2067,7 +2076,7 @@ mod tests {
             ),
         );
 
-        assert_migrate_settings_with_migrations(
+        assert_migrate_with_migrations(
             &[MigrationType::Json(
                 migrations::m_2025_10_16::restore_code_actions_on_format,
             )],
@@ -2081,7 +2090,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,
             )],
@@ -2108,7 +2117,7 @@ mod tests {
             ),
         );
 
-        assert_migrate_settings_with_migrations(
+        assert_migrate_with_migrations(
             &[MigrationType::Json(
                 migrations::m_2025_10_16::restore_code_actions_on_format,
             )],
@@ -2137,7 +2146,7 @@ mod tests {
             ),
         );
 
-        assert_migrate_settings_with_migrations(
+        assert_migrate_with_migrations(
             &[MigrationType::Json(
                 migrations::m_2025_10_16::restore_code_actions_on_format,
             )],
@@ -2155,7 +2164,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,
             )],
@@ -2163,7 +2172,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,
             )],
@@ -2183,7 +2192,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,
             )],
@@ -2203,7 +2212,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,
             )],
@@ -2224,7 +2233,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,
             )],
@@ -2253,7 +2262,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,
             )],
@@ -2288,7 +2297,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,
             )],
@@ -2296,7 +2305,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,
             )],
@@ -2312,7 +2321,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,
             )],
@@ -2329,7 +2338,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,
             )],
@@ -2354,7 +2363,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,
             )],
@@ -2431,7 +2440,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,
             )],
@@ -2469,7 +2478,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,
             )],
@@ -2610,7 +2619,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,
             )],
@@ -2619,7 +2628,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,
             )],
@@ -2636,7 +2645,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,
             )],
@@ -2653,7 +2662,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,
             )],
@@ -2665,7 +2674,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,
             )],
@@ -2694,7 +2703,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,
             )],
@@ -2702,7 +2711,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,
             )],
@@ -2726,7 +2735,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,
             )],
@@ -2754,7 +2763,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,
             )],
@@ -2781,7 +2790,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,
             )],
@@ -2798,7 +2807,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,
             )],
@@ -2822,7 +2831,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,
             )],
@@ -2851,7 +2860,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,
             )],
@@ -2884,7 +2893,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,
             )],
@@ -2935,7 +2944,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,
             )],
@@ -2943,7 +2952,7 @@ mod tests {
             None,
         );
 
-        assert_migrate_settings_with_migrations(
+        assert_migrate_with_migrations(
             &[MigrationType::Json(
                 migrations::m_2026_02_03::migrate_experimental_sweep_mercury,
             )],
@@ -2969,7 +2978,7 @@ mod tests {
             ),
         );
 
-        assert_migrate_settings_with_migrations(
+        assert_migrate_with_migrations(
             &[MigrationType::Json(
                 migrations::m_2026_02_03::migrate_experimental_sweep_mercury,
             )],
@@ -2995,7 +3004,7 @@ mod tests {
             ),
         );
 
-        assert_migrate_settings_with_migrations(
+        assert_migrate_with_migrations(
             &[MigrationType::Json(
                 migrations::m_2026_02_03::migrate_experimental_sweep_mercury,
             )],
@@ -3021,7 +3030,7 @@ mod tests {
             ),
         );
 
-        assert_migrate_settings_with_migrations(
+        assert_migrate_with_migrations(
             &[MigrationType::Json(
                 migrations::m_2026_02_03::migrate_experimental_sweep_mercury,
             )],
@@ -3036,7 +3045,7 @@ mod tests {
             None,
         );
 
-        assert_migrate_settings_with_migrations(
+        assert_migrate_with_migrations(
             &[MigrationType::Json(
                 migrations::m_2026_02_03::migrate_experimental_sweep_mercury,
             )],
@@ -3054,7 +3063,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,
             )],
@@ -3085,7 +3094,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,
             )],
@@ -3120,7 +3129,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,
             )],
@@ -3178,7 +3187,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,
             )],
@@ -3187,7 +3196,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,
             )],
@@ -3214,7 +3223,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,
             )],
@@ -3233,7 +3242,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,
             )],
@@ -3272,7 +3281,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,
             )],
@@ -3302,7 +3311,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,
             )],
@@ -3331,7 +3340,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,
             )],
@@ -3349,7 +3358,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,
             )],
@@ -3388,7 +3397,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,
             )],
@@ -3416,7 +3425,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,
             )],
@@ -3447,7 +3456,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,
             )],
@@ -3488,7 +3497,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,
             )],
@@ -3526,7 +3535,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,
             )],
@@ -3571,7 +3580,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,
             )],
@@ -3606,7 +3615,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,
             )],
@@ -3643,7 +3652,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,
             )],
@@ -3689,7 +3698,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,
             )],
@@ -3705,7 +3714,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,
             )],
@@ -3722,7 +3731,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,
             )],
@@ -3763,7 +3772,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,
             )],
@@ -3792,7 +3801,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,
             )],
@@ -3807,7 +3816,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,
             )],
@@ -3850,7 +3859,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,
             )],
@@ -3887,7 +3896,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,
             )],
@@ -3910,7 +3919,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,
             )],
@@ -3950,7 +3959,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,
             )],
@@ -3981,7 +3990,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,
             )],
@@ -4019,7 +4028,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,
             )],
@@ -4047,7 +4056,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,
             )],
@@ -4075,7 +4084,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,
             )],
@@ -4102,7 +4111,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,
             )],
@@ -4124,7 +4133,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,
             )],
@@ -4158,7 +4167,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,
             )],
@@ -4188,7 +4197,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,
             )],
@@ -4203,7 +4212,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,
             )],
@@ -4251,7 +4260,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,
             )],
@@ -4283,7 +4292,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,
             )],
@@ -4318,4 +4327,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(),
+            ),
+        );
+    }
 }