This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new b7c5eb6e75be CAMEL-24372: Fix TUI editor key bindings for terminal 
compatibility
b7c5eb6e75be is described below

commit b7c5eb6e75be75e362db7d6bc446fcddce8f7ec8
Author: Claus Ibsen <[email protected]>
AuthorDate: Mon Aug 10 14:07:22 2026 +0200

    CAMEL-24372: Fix TUI editor key bindings for terminal compatibility
    
    Remap broken edit-mode shortcuts that relied on terminal features
    unavailable on macOS/iTerm2: Ctrl+Shift+K to Ctrl+K (delete line
    instead of block), remove Ctrl+/ (pending tamboui fix for 0x1F),
    remove Ctrl+Backspace/Delete (terminals send same byte as unmodified),
    remove Ctrl+F find from edit mode, remove global Ctrl+F files popup.
    Fix block move/duplicate including trailing blank lines and viewport
    jumping to bottom after operations.
    
    CAMEL-24372: Remove global Ctrl+K/R/T/F shortcuts that conflict with editing
    
    Free up Ctrl+letter keys for the source editor by removing global
    shortcuts: Ctrl+K (tape recording), Ctrl+R (AI panel passthrough),
    Ctrl+T (caption overlay), and Ctrl+F (files popup, already in F2 menu).
    
    CAMEL-24372: TUI editor gutter change markers and F7 diff view
    
    Add visual change indicators in the editor gutter: green markers for
    added lines, yellow for modified lines. Changes are tracked via an
    LCS-based diff against the original text captured on edit entry.
    
    Add F7 diff overlay that renders a unified diff inline in the edit
    panel with full-width colored backgrounds (dark red for removed, dark
    green for added) with line numbers and gutter. Colors use new Theme
    methods (diffAdded, diffModified, diffRemoved) for theme support.
    
    CAMEL-24372: Fix F7 diff view line numbers, footer, and Esc handling
    
    Use real source file line numbers in diff view instead of sequential
    numbering. Show dedicated footer with only Esc/F7 and scroll hints
    when diff is active. Fix Esc not closing diff by checking diffOverlay
    first in cancelEdit() before the discard prompt.
    
    CAMEL-24372: Use green background for gutter change markers
    
    Use the same dark green background as the diff view for gutter change
    markers in edit mode, making them clearly visible instead of subtle
    style patches that were hard to see.
    
    CAMEL-24372: Move F7 diff hint next to F5 in edit mode footer
    
    Group F-key hints together in the footer for consistency.
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    Signed-off-by: Claus Ibsen <[email protected]>
---
 .../dsl/jbang/core/commands/tui/ActionsPopup.java  |   6 +-
 .../dsl/jbang/core/commands/tui/CamelMonitor.java  |  18 --
 .../dsl/jbang/core/commands/tui/EditDiff.java      | 164 ++++++++++++++++++
 .../jbang/core/commands/tui/SearchHighlighter.java |   4 -
 .../dsl/jbang/core/commands/tui/SourceTab.java     |   7 +-
 .../dsl/jbang/core/commands/tui/SourceViewer.java  | 191 +++++++++++++++++----
 .../camel/dsl/jbang/core/commands/tui/Theme.java   |  15 ++
 .../jbang/core/commands/tui/TuiToolRegistry.java   |   2 +-
 .../jbang/core/commands/tui/YamlBlockEditor.java   |  20 ++-
 .../dsl/jbang/core/commands/tui/EditDiffTest.java  | 136 +++++++++++++++
 .../commands/tui/SourceViewerEditorOpsTest.java    |  43 +----
 .../core/commands/tui/YamlBlockEditorTest.java     |  14 ++
 12 files changed, 513 insertions(+), 107 deletions(-)

diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ActionsPopup.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ActionsPopup.java
index a19d3b71ef24..403865fae1dd 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ActionsPopup.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/ActionsPopup.java
@@ -426,7 +426,7 @@ class ActionsPopup {
         labels.add("Run an Example...");
         labels.add("Open Project...");
         labels.add("Run Dev/Infra Service...");
-        labels.add("Browse Files... (Ctrl+F)");
+        labels.add("Browse Files...");
         labels.add("───");
         labels.add("Run Doctor");
         labels.add("Reset Stats");
@@ -985,8 +985,8 @@ class ActionsPopup {
         items.add(ListItem.from(TuiIcons.menuItem(TuiIcons.FOLDER_OPEN, "Open 
Project...")));
         items.add(ListItem.from(TuiIcons.menuItem(TuiIcons.INFRA, "Run 
Dev/Infra Service...")));
         items.add(hasSelection
-                ? ListItem.from(TuiIcons.menuItem(TuiIcons.FOLDER, "Browse 
Files... (Ctrl+F)"))
-                : ListItem.from(TuiIcons.menuItem(TuiIcons.FOLDER, "Browse 
Files... (Ctrl+F)")).style(Style.EMPTY.dim()));
+                ? ListItem.from(TuiIcons.menuItem(TuiIcons.FOLDER, "Browse 
Files..."))
+                : ListItem.from(TuiIcons.menuItem(TuiIcons.FOLDER, "Browse 
Files...")).style(Style.EMPTY.dim()));
         items.add(ListItem.from(divider).style(Style.EMPTY.dim()));
         // Group 2: Diagnostics & Screen
         items.add(ListItem.from(TuiIcons.menuItem(TuiIcons.DOCTOR, "Run 
Doctor")));
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelMonitor.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelMonitor.java
index dd78dbc2c718..fe75b998ffd4 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelMonitor.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/CamelMonitor.java
@@ -715,25 +715,11 @@ public class CamelMonitor extends CamelCommand {
     private boolean handleEvent(Event event, TuiRunner runner) {
         if (event instanceof KeyEvent ke) {
             recordingManager.recordKey(ke, mcpInjectedKey);
-            if (ke.hasCtrl() && ke.isChar('r')) {
-                if (aiPanel.isOpen()) {
-                    return aiPanel.handleKeyEvent(ke);
-                }
-                return true;
-            }
             if (captionOverlay.isVisible()) {
                 if (captionOverlay.handleKeyEvent(ke)) {
                     return true;
                 }
             }
-            if (ke.hasCtrl() && ke.isChar('k')) {
-                recordingManager.toggleRecording();
-                return true;
-            }
-            if (ke.hasCtrl() && ke.isChar('t')) {
-                captionOverlay.openInline();
-                return true;
-            }
             if (helpOverlay.isVisible()) {
                 return helpOverlay.handleKeyEvent(ke);
             }
@@ -972,10 +958,6 @@ public class CamelMonitor extends CamelCommand {
             processControlPopup.open();
             return true;
         }
-        if (ke.hasCtrl() && ke.isChar('f')) {
-            openFilesPopup();
-            return true;
-        }
         return false;
     }
 
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/EditDiff.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/EditDiff.java
new file mode 100644
index 000000000000..e245c1646e88
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/EditDiff.java
@@ -0,0 +1,164 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.dsl.jbang.core.commands.tui;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * LCS-based diff utility for the TUI source editor. Classifies lines as 
unchanged, modified, or added for gutter
+ * markers, and produces unified diff output for the F7 overlay.
+ */
+final class EditDiff {
+
+    enum LineStatus {
+        UNCHANGED,
+        MODIFIED,
+        ADDED
+    }
+
+    private EditDiff() {
+    }
+
+    static LineStatus[] diff(List<String> original, List<String> current) {
+        int m = original.size();
+        int n = current.size();
+        LineStatus[] statuses = new LineStatus[n];
+        Arrays.fill(statuses, LineStatus.UNCHANGED);
+
+        if (m == 0) {
+            Arrays.fill(statuses, LineStatus.ADDED);
+            return statuses;
+        }
+
+        int[][] dp = new int[m + 1][n + 1];
+        for (int i = m - 1; i >= 0; i--) {
+            for (int j = n - 1; j >= 0; j--) {
+                if (original.get(i).equals(current.get(j))) {
+                    dp[i][j] = dp[i + 1][j + 1] + 1;
+                } else {
+                    dp[i][j] = Math.max(dp[i + 1][j], dp[i][j + 1]);
+                }
+            }
+        }
+
+        // Build edit script: 0=equal, 1=delete, 2=insert
+        List<int[]> ops = new ArrayList<>();
+        int i = 0;
+        int j = 0;
+        while (i < m && j < n) {
+            if (original.get(i).equals(current.get(j))) {
+                ops.add(new int[] { 0, i++, j++ });
+            } else if (dp[i + 1][j] >= dp[i][j + 1]) {
+                ops.add(new int[] { 1, i++, -1 });
+            } else {
+                ops.add(new int[] { 2, -1, j++ });
+            }
+        }
+        while (i < m) {
+            ops.add(new int[] { 1, i++, -1 });
+        }
+        while (j < n) {
+            ops.add(new int[] { 2, -1, j++ });
+        }
+
+        for (int k = 0; k < ops.size(); k++) {
+            int[] op = ops.get(k);
+            if (op[0] == 2) {
+                boolean afterDelete = k > 0 && ops.get(k - 1)[0] == 1;
+                statuses[op[2]] = afterDelete ? LineStatus.MODIFIED : 
LineStatus.ADDED;
+            }
+        }
+        return statuses;
+    }
+
+    record DiffEntry(char type, String text, int lineNum) {
+    }
+
+    static final DiffEntry SEPARATOR = new DiffEntry('~', "───", -1);
+
+    static List<DiffEntry> unifiedDiff(List<String> original, List<String> 
current, int contextLines) {
+        int m = original.size();
+        int n = current.size();
+
+        if (m == 0 && n == 0) {
+            return List.of();
+        }
+
+        int[][] dp = new int[m + 1][n + 1];
+        for (int i = m - 1; i >= 0; i--) {
+            for (int j = n - 1; j >= 0; j--) {
+                if (original.get(i).equals(current.get(j))) {
+                    dp[i][j] = dp[i + 1][j + 1] + 1;
+                } else {
+                    dp[i][j] = Math.max(dp[i + 1][j], dp[i][j + 1]);
+                }
+            }
+        }
+
+        List<DiffEntry> rawDiff = new ArrayList<>();
+        int i = 0;
+        int j = 0;
+        while (i < m && j < n) {
+            if (original.get(i).equals(current.get(j))) {
+                rawDiff.add(new DiffEntry(' ', original.get(i), j + 1));
+                i++;
+                j++;
+            } else if (dp[i + 1][j] >= dp[i][j + 1]) {
+                rawDiff.add(new DiffEntry('-', original.get(i), i + 1));
+                i++;
+            } else {
+                rawDiff.add(new DiffEntry('+', current.get(j), j + 1));
+                j++;
+            }
+        }
+        while (i < m) {
+            rawDiff.add(new DiffEntry('-', original.get(i), i + 1));
+            i++;
+        }
+        while (j < n) {
+            rawDiff.add(new DiffEntry('+', current.get(j), j + 1));
+            j++;
+        }
+
+        // Filter to changed hunks with context
+        boolean[] visible = new boolean[rawDiff.size()];
+        for (int k = 0; k < rawDiff.size(); k++) {
+            if (rawDiff.get(k).type != ' ') {
+                for (int c = Math.max(0, k - contextLines); c <= 
Math.min(rawDiff.size() - 1, k + contextLines); c++) {
+                    visible[c] = true;
+                }
+            }
+        }
+
+        List<DiffEntry> result = new ArrayList<>();
+        boolean inHunk = false;
+        for (int k = 0; k < rawDiff.size(); k++) {
+            if (visible[k]) {
+                if (!inHunk && k > 0) {
+                    result.add(SEPARATOR);
+                }
+                inHunk = true;
+                result.add(rawDiff.get(k));
+            } else {
+                inHunk = false;
+            }
+        }
+        return result;
+    }
+}
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SearchHighlighter.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SearchHighlighter.java
index 059c2a3350ff..8eace475c730 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SearchHighlighter.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SearchHighlighter.java
@@ -336,10 +336,6 @@ class SearchHighlighter {
         if (findInputActive || highlightInputActive) {
             return handleSearchInput(ke);
         }
-        if (ke.hasCtrl() && ke.isCharIgnoreCase('f')) {
-            openFindInput();
-            return true;
-        }
         if (findTerm != null && ke.hasCtrl() && ke.isCharIgnoreCase('n') && 
!ke.hasAlt()) {
             if (ke.hasShift()) {
                 navigateToPrevMatch();
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SourceTab.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SourceTab.java
index ebf50ccf961e..439e190e7f1b 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SourceTab.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SourceTab.java
@@ -421,13 +421,10 @@ class SourceTab extends AbstractTab {
                 - **Ctrl+Y / Ctrl+Shift+Z** — redo
                 - **Alt+Up / Alt+Down** — move YAML list block up/down
                 - **Ctrl+D** — duplicate current block
-                - **Ctrl+Shift+K** — delete current block
-                - **Ctrl+/** — toggle comment on current block
+                - **Ctrl+K** — delete current line
                 - **Ctrl+Left / Ctrl+Right** — word navigation
-                - **Ctrl+Backspace / Ctrl+Delete** — delete word 
backward/forward
-                - **Ctrl+F** — find in edit mode
-                - **Ctrl+N / Ctrl+Shift+N** — next/previous find match
                 - **Home** — smart home (content indent, then column 0)
+                - **F7** — show diff of unsaved changes
 
                 ## Edit Mode (Tab Completion)
                 Press **F4** to enter edit mode, then **Tab** for 
context-aware completion:
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SourceViewer.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SourceViewer.java
index e4eee1a0b03d..8fb5db00a03d 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SourceViewer.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SourceViewer.java
@@ -149,6 +149,10 @@ class SourceViewer {
     private boolean markdownModeBeforeEdit;
     private boolean dirty;
     private boolean pendingDiscard;
+    private String originalEditText;
+    private EditDiff.LineStatus[] lineStatuses;
+    private boolean diffOverlay;
+    private int diffScrollY;
     private BiConsumer<String, Boolean> notificationCallback;
     private AutocompletePopup.AutocompleteProvider autocompleteProvider;
     private AutocompletePopup.ValueProvider autocompleteValueProvider;
@@ -301,6 +305,10 @@ class SourceViewer {
         if (!editMode) {
             return false;
         }
+        if (diffOverlay) {
+            diffOverlay = false;
+            return true;
+        }
         if (validationErrors != null) {
             validationErrors = null;
             return true;
@@ -524,6 +532,7 @@ class SourceViewer {
     private void recordEditChange() {
         editHistory.beforeChange(editState);
         dirty = true;
+        lineStatuses = null;
     }
 
     private List<String> editLines() {
@@ -539,8 +548,13 @@ class SourceViewer {
             return;
         }
         recordEditChange();
+        int prevScroll = editState.scrollRow();
         editState.setText(YamlBlockEditor.fromLines(result.lines()));
         SourceEditorNavigation.positionCursor(editState, result.cursorRow(), 
result.cursorCol());
+        // Restore scroll so the viewport doesn't jump; ensureCursorVisible 
during
+        // rendering will adjust if the cursor ended up off-screen.
+        int maxScroll = Math.max(0, editState.lineCount() - Math.max(1, 
lastVisibleLines));
+        editState.scrollDown(Math.min(prevScroll, maxScroll), 
lastVisibleLines);
     }
 
     private void refreshEditFindMatches() {
@@ -570,6 +584,20 @@ class SourceViewer {
             }
             return true;
         }
+        if (diffOverlay) {
+            if (ke.isCancel() || ke.isKey(KeyCode.F7)) {
+                diffOverlay = false;
+            } else if (ke.isUp()) {
+                diffScrollY = Math.max(0, diffScrollY - 1);
+            } else if (ke.isDown()) {
+                diffScrollY++;
+            } else if (ke.isPageUp() || ke.isKey(KeyCode.PAGE_UP)) {
+                diffScrollY = Math.max(0, diffScrollY - Math.max(1, 
lastVisibleLines));
+            } else if (ke.isPageDown() || ke.isKey(KeyCode.PAGE_DOWN)) {
+                diffScrollY += Math.max(1, lastVisibleLines);
+            }
+            return true;
+        }
         if (autocompletePopup != null) {
             boolean wasValueMode = autocompletePopup.isValueMode();
             boolean wasListItem = autocompletePopup.isListItemInsertion();
@@ -597,6 +625,7 @@ class SourceViewer {
         if (ke.hasCtrl() && ke.isCharIgnoreCase('z') && !ke.hasShift()) {
             if (editHistory.undo(editState)) {
                 dirty = true;
+                lineStatuses = null;
                 refreshEditFindMatches();
             }
             return true;
@@ -604,6 +633,7 @@ class SourceViewer {
         if (ke.hasCtrl() && (ke.isCharIgnoreCase('y') || 
(ke.isCharIgnoreCase('z') && ke.hasShift()))) {
             if (editHistory.redo(editState)) {
                 dirty = true;
+                lineStatuses = null;
                 refreshEditFindMatches();
             }
             return true;
@@ -621,18 +651,8 @@ class SourceViewer {
             applyBlockEdit(YamlBlockEditor.duplicateBlock(editLines(), 
editState.cursorRow(), yamlListBlocks));
             return true;
         }
-        if (ke.hasCtrl() && ke.hasShift() && (ke.isChar('k') || 
ke.isChar('K'))) {
-            applyBlockEdit(YamlBlockEditor.deleteBlock(editLines(), 
editState.cursorRow(), yamlListBlocks));
-            return true;
-        }
-        if (ke.hasCtrl() && ke.isChar('/')) {
-            YamlBlockEditor.BlockRange block
-                    = YamlBlockEditor.findBlock(editLines(), 
editState.cursorRow(), yamlListBlocks);
-            recordEditChange();
-            List<String> toggled = YamlBlockEditor.toggleComment(editLines(), 
block);
-            editState.setText(YamlBlockEditor.fromLines(toggled));
-            SourceEditorNavigation.positionCursor(editState, block.startRow(),
-                    
YamlBlockEditor.leadingSpaces(toggled.get(block.startRow())));
+        if (ke.hasCtrl() && ke.isCharIgnoreCase('k') && !ke.hasShift()) {
+            applyBlockEdit(YamlBlockEditor.deleteLine(editLines(), 
editState.cursorRow()));
             return true;
         }
         if (ke.isKey(KeyCode.LEFT) && ke.hasCtrl()) {
@@ -643,16 +663,6 @@ class SourceViewer {
             SourceEditorNavigation.moveWordRight(editState);
             return true;
         }
-        if (ke.isKey(KeyCode.BACKSPACE) && ke.hasCtrl()) {
-            recordEditChange();
-            SourceEditorNavigation.deleteWordBackward(editState);
-            return true;
-        }
-        if (ke.isKey(KeyCode.DELETE) && ke.hasCtrl()) {
-            recordEditChange();
-            SourceEditorNavigation.deleteWordForward(editState);
-            return true;
-        }
         if (pendingDiscard) {
             if (ke.isConfirm()) {
                 pendingDiscard = false;
@@ -673,6 +683,11 @@ class SourceViewer {
             exitEditMode();
             return true;
         }
+        if (ke.isKey(KeyCode.F7) && dirty && originalEditText != null) {
+            diffOverlay = true;
+            diffScrollY = 0;
+            return true;
+        }
         if (ke.isKey(KeyCode.F5) && ke.hasShift()) {
             saveContinueEdit();
             return true;
@@ -782,6 +797,9 @@ class SourceViewer {
         search.closeInputOnly();
         dirty = false;
         validationErrors = null;
+        originalEditText = editState.text();
+        lineStatuses = null;
+        diffOverlay = false;
         editMode = true;
         editHistory.seedInitial(editState);
         refreshEditFindMatches();
@@ -795,6 +813,9 @@ class SourceViewer {
         autocompletePopup = null;
         validationErrors = null;
         pendingDiscard = false;
+        originalEditText = null;
+        lineStatuses = null;
+        diffOverlay = false;
         if (wasEditing && isMarkdownFile) {
             markdownMode = markdownModeBeforeEdit;
         }
@@ -1768,6 +1789,8 @@ class SourceViewer {
             String content = editState.text();
             Files.writeString(editableFile, content, StandardCharsets.UTF_8);
             dirty = false;
+            originalEditText = content;
+            lineStatuses = null;
             validateAndNotify(content);
         } catch (IOException e) {
             notifySave("Save failed: " + e.getMessage(), true);
@@ -2165,11 +2188,21 @@ class SourceViewer {
         Style ts = titleStyle != null ? titleStyle : Style.EMPTY;
         List<Span> titleSpans = new ArrayList<>();
         String info = title != null ? title : "";
-        titleSpans.add(Span.styled(" Edit [" + info + (dirty ? " *" : "") + "] 
", ts));
-        int row = editState.cursorRow() + 1;
-        int col = editState.cursorCol() + 1;
-        Title posTitle = Title.from(
-                Line.from(Span.styled(" row:" + row + " col:" + col + " ", 
Style.EMPTY.dim()))).right();
+        if (diffOverlay) {
+            titleSpans.add(Span.styled(" Diff [" + info + "] ", ts));
+        } else {
+            titleSpans.add(Span.styled(" Edit [" + info + (dirty ? " *" : "") 
+ "] ", ts));
+        }
+        Title posTitle;
+        if (diffOverlay) {
+            posTitle = Title.from(
+                    Line.from(Span.styled(" F7/Esc close  ↑↓ scroll ", 
Style.EMPTY.dim()))).right();
+        } else {
+            int row = editState.cursorRow() + 1;
+            int col = editState.cursorCol() + 1;
+            posTitle = Title.from(
+                    Line.from(Span.styled(" row:" + row + " col:" + col + " ", 
Style.EMPTY.dim()))).right();
+        }
         Block.Builder blockBuilder = Block.builder()
                 .borderType(BorderType.ROUNDED);
         if (plainMode) {
@@ -2189,6 +2222,11 @@ class SourceViewer {
         lastVisibleLines = Math.max(1, inner.height());
         frame.renderWidget(block, area);
 
+        if (diffOverlay) {
+            renderDiffContent(frame, inner);
+            return;
+        }
+
         TextArea textArea = TextArea.builder()
                 .cursorStyle(Style.EMPTY.reversed())
                 .showLineNumbers(!plainMode)
@@ -2217,6 +2255,31 @@ class SourceViewer {
             }
         }
 
+        // gutter change markers — background color on the gutter area
+        if (dirty && !plainMode && originalEditText != null) {
+            if (lineStatuses == null) {
+                List<String> orig = YamlBlockEditor.toLines(originalEditText);
+                lineStatuses = EditDiff.diff(orig, editLines());
+            }
+            int gutterWidth = Math.max(2, 
String.valueOf(editState.lineCount()).length()) + 2;
+            for (int r = 0; r < inner.height(); r++) {
+                int lineIdx = editState.scrollRow() + r;
+                if (lineIdx >= 0 && lineIdx < lineStatuses.length) {
+                    EditDiff.LineStatus status = lineStatuses[lineIdx];
+                    if (status != EditDiff.LineStatus.UNCHANGED) {
+                        Style bg = 
Style.EMPTY.fg(dev.tamboui.style.Color.WHITE)
+                                .bg(dev.tamboui.style.Color.rgb(0x1B, 0x4D, 
0x1B));
+                        int screenY = inner.top() + r;
+                        for (int x = inner.left(); x < inner.left() + 
gutterWidth; x++) {
+                            dev.tamboui.buffer.Cell cell = 
frame.buffer().get(x, screenY);
+                            frame.buffer().set(x, screenY,
+                                    new dev.tamboui.buffer.Cell(cell.symbol(), 
bg));
+                        }
+                    }
+                }
+            }
+        }
+
         if (autocompletePopup != null) {
             int cursorRow = editState.cursorRow() - editState.scrollRow();
             int cursorCol = editState.cursorCol() - editState.scrollCol();
@@ -2231,6 +2294,66 @@ class SourceViewer {
         }
     }
 
+    private void renderDiffContent(Frame frame, Rect inner) {
+        List<String> orig = YamlBlockEditor.toLines(originalEditText);
+        List<EditDiff.DiffEntry> entries = EditDiff.unifiedDiff(orig, 
editLines(), 3);
+        if (entries.isEmpty()) {
+            entries = List.of(new EditDiff.DiffEntry(' ', "(no changes)", 0));
+        }
+
+        int maxLineNum = 
entries.stream().mapToInt(EditDiff.DiffEntry::lineNum).max().orElse(1);
+        int lineDigits = Math.max(2, String.valueOf(maxLineNum).length());
+        int gutterWidth = lineDigits + 2;
+
+        diffScrollY = Math.max(0, Math.min(diffScrollY, Math.max(0, 
entries.size() - inner.height())));
+        for (int r = 0; r < inner.height(); r++) {
+            int idx = diffScrollY + r;
+            if (idx >= entries.size()) {
+                break;
+            }
+            int screenY = inner.top() + r;
+            EditDiff.DiffEntry entry = entries.get(idx);
+            Style lineStyle;
+            Style gutterStyle;
+            if (entry.type() == '-') {
+                lineStyle = 
Style.EMPTY.fg(dev.tamboui.style.Color.WHITE).bg(dev.tamboui.style.Color.rgb(0x6E,
 0x1B, 0x1B));
+                gutterStyle = lineStyle;
+            } else if (entry.type() == '+') {
+                lineStyle = 
Style.EMPTY.fg(dev.tamboui.style.Color.WHITE).bg(dev.tamboui.style.Color.rgb(0x1B,
 0x4D, 0x1B));
+                gutterStyle = lineStyle;
+            } else if (entry.type() == '~') {
+                lineStyle = Style.EMPTY.dim();
+                gutterStyle = Style.EMPTY.dim();
+            } else {
+                lineStyle = Style.EMPTY;
+                gutterStyle = Style.EMPTY.dim();
+            }
+
+            // fill entire row with background for changed lines
+            if (entry.type() == '-' || entry.type() == '+') {
+                Rect rowRect = new Rect(inner.left(), screenY, inner.width(), 
1);
+                frame.buffer().setStyle(rowRect, lineStyle);
+            }
+
+            // line number from original file (for -) or current file (for + 
and context)
+            String lineNum = entry.lineNum() > 0
+                    ? String.format("%" + lineDigits + "d ", entry.lineNum())
+                    : " ".repeat(lineDigits + 1);
+            frame.buffer().setString(inner.left(), screenY, lineNum, 
gutterStyle);
+            frame.buffer().set(inner.left() + gutterWidth - 1, screenY,
+                    new dev.tamboui.buffer.Cell("│", gutterStyle));
+
+            int textX = inner.left() + gutterWidth;
+            int maxWidth = Math.max(0, inner.width() - gutterWidth);
+            String prefix = entry.type() == ' ' ? "  " : entry.type() + " ";
+            String text = prefix + entry.text();
+            if (text.length() > maxWidth) {
+                text = text.substring(0, maxWidth);
+            }
+            frame.buffer().setString(textX, screenY, text, lineStyle);
+        }
+    }
+
     private void renderValidationPopup(Frame frame, Rect area) {
         int popupW = Math.min(80, area.width() - 4);
         int innerW = popupW - 2;
@@ -2326,23 +2449,27 @@ class SourceViewer {
             TuiHelper.hintLast(spans, "Esc", "close");
             return;
         }
+        if (editMode && diffOverlay) {
+            TuiHelper.hint(spans, "Esc/F7", "close diff");
+            TuiHelper.hint(spans, TuiIcons.HINT_SCROLL, "scroll");
+            return;
+        }
         if (editMode) {
             TuiHelper.hint(spans, "Esc", "cancel");
             TuiHelper.hint(spans, "F5", "save & close");
             TuiHelper.hint(spans, "Shift+F5", "save");
+            if (dirty) {
+                TuiHelper.hint(spans, "F7", "diff");
+            }
             TuiHelper.hint(spans, "Ctrl+Z", "undo");
             TuiHelper.hint(spans, "Ctrl+Y", "redo");
             TuiHelper.hint(spans, "Alt+↑/↓", "move block");
             TuiHelper.hint(spans, "Ctrl+D", "duplicate");
-            TuiHelper.hint(spans, "Ctrl+Shift+K", "delete block");
-            TuiHelper.hint(spans, "Ctrl+/", "comment");
-            TuiHelper.hint(spans, "Ctrl+F", "find");
-            TuiHelper.hint(spans, "Ctrl+N", "next match");
+            TuiHelper.hint(spans, "Ctrl+K", "delete line");
             if (autocompleteProvider != null) {
                 TuiHelper.hint(spans, "Tab", "complete");
             }
             TuiHelper.hint(spans, TuiIcons.HINT_SCROLL, "move");
-            search.renderFindStatus(spans);
             return;
         }
         if (markdownMode) {
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/Theme.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/Theme.java
index 8b397a5b6c73..6f5a2beea43f 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/Theme.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/Theme.java
@@ -75,6 +75,9 @@ public final class Theme {
     private static final Style FALLBACK_CHANGE = 
Style.EMPTY.fg(Color.rgb(0xDC, 0xDC, 0xAA));
     private static final Style FALLBACK_SEARCH_MATCH = 
Style.EMPTY.fg(Color.BLACK).bg(Color.rgb(0xDC, 0xDC, 0xAA));
     private static final Style FALLBACK_MNEMONIC = 
Style.EMPTY.fg(Color.rgb(0xDC, 0xDC, 0xAA)).bold().underlined();
+    private static final Style FALLBACK_DIFF_ADDED = 
Style.EMPTY.fg(Color.BLACK).bg(Color.rgb(0x4E, 0xC9, 0xB0)).bold();
+    private static final Style FALLBACK_DIFF_MODIFIED = 
Style.EMPTY.fg(Color.BLACK).bg(Color.rgb(0x56, 0x9C, 0xD6)).bold();
+    private static final Style FALLBACK_DIFF_REMOVED = 
Style.EMPTY.fg(Color.LIGHT_RED);
 
     // Diagram token fallbacks (dark-theme defaults).
     private static final Color FALLBACK_DIAGRAM_BORDER = Color.rgb(0x80, 0x80, 
0x80);
@@ -249,6 +252,18 @@ public final class Theme {
         return style("mnemonic", FALLBACK_MNEMONIC);
     }
 
+    public static Style diffAdded() {
+        return style("diff-added", FALLBACK_DIFF_ADDED);
+    }
+
+    public static Style diffModified() {
+        return style("diff-modified", FALLBACK_DIFF_MODIFIED);
+    }
+
+    public static Style diffRemoved() {
+        return style("diff-removed", FALLBACK_DIFF_REMOVED);
+    }
+
     /** Theme-aware markdown styles for MarkdownView headings and other 
elements. */
     public static dev.tamboui.markdown.MarkdownStyles markdownStyles() {
         return dev.tamboui.markdown.MarkdownStyles.builder()
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiToolRegistry.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiToolRegistry.java
index 2391bdd28391..c1263c518536 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiToolRegistry.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/TuiToolRegistry.java
@@ -170,7 +170,7 @@ class TuiToolRegistry {
                                  + "and integration count. "
                                  + "Includes a 'selection' field with 
structured metadata about the active list/table. "
                                  + "captionVisible indicates if a caption 
overlay is on screen. "
-                                 + "keystrokesVisible indicates if the 
keystroke overlay is on; toggle with Ctrl+K. "
+                                 + "keystrokesVisible indicates if the 
keystroke overlay is on. "
                                  + "detailFocused (boolean, present on tabs 
with master/detail panels) indicates "
                                  + "which panel has focus: true=detail panel, 
false=table panel. "
                                  + "Press Tab to toggle focus. Up/Down and 
PgUp/PgDn operate on the focused panel.",
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/YamlBlockEditor.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/YamlBlockEditor.java
index 8c31ad3cef94..12ef619cb94e 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/YamlBlockEditor.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/YamlBlockEditor.java
@@ -60,6 +60,19 @@ final class YamlBlockEditor {
         return new BlockRange(startRow, endRow);
     }
 
+    static EditResult deleteLine(List<String> lines, int row) {
+        if (lines.isEmpty() || row < 0 || row >= lines.size()) {
+            return new EditResult(lines, row, 0);
+        }
+        List<String> answer = new ArrayList<>(lines);
+        answer.remove(row);
+        if (answer.isEmpty()) {
+            answer.add("");
+        }
+        int cursorRow = Math.min(row, answer.size() - 1);
+        return new EditResult(answer, cursorRow, 
leadingSpaces(answer.get(cursorRow)));
+    }
+
     static EditResult deleteBlock(List<String> lines, int row, boolean 
yamlListBlocks) {
         BlockRange block = findBlock(lines, row, yamlListBlocks);
         if (block.isEmpty()) {
@@ -216,20 +229,19 @@ final class YamlBlockEditor {
     }
 
     private static int findBlockEnd(List<String> lines, int startRow, int 
blockIndent) {
-        int endRow = startRow;
+        int lastContentRow = startRow;
         for (int i = startRow + 1; i < lines.size(); i++) {
             String line = lines.get(i);
             if (line.isBlank()) {
-                endRow = i;
                 continue;
             }
             int indent = leadingSpaces(line);
             if (indent <= blockIndent && (line.trim().startsWith("- ") || 
indent < blockIndent)) {
                 break;
             }
-            endRow = i;
+            lastContentRow = i;
         }
-        return endRow;
+        return lastContentRow;
     }
 
     static int leadingSpaces(String line) {
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/EditDiffTest.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/EditDiffTest.java
new file mode 100644
index 000000000000..2a94695ed58c
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/EditDiffTest.java
@@ -0,0 +1,136 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.dsl.jbang.core.commands.tui;
+
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class EditDiffTest {
+
+    @Test
+    void unchangedLinesAreUnchanged() {
+        List<String> lines = List.of("a", "b", "c");
+        EditDiff.LineStatus[] statuses = EditDiff.diff(lines, lines);
+
+        assertThat(statuses).containsExactly(
+                EditDiff.LineStatus.UNCHANGED,
+                EditDiff.LineStatus.UNCHANGED,
+                EditDiff.LineStatus.UNCHANGED);
+    }
+
+    @Test
+    void addedLineIsGreen() {
+        List<String> original = List.of("a", "c");
+        List<String> current = List.of("a", "b", "c");
+
+        EditDiff.LineStatus[] statuses = EditDiff.diff(original, current);
+
+        assertThat(statuses[0]).isEqualTo(EditDiff.LineStatus.UNCHANGED);
+        assertThat(statuses[1]).isEqualTo(EditDiff.LineStatus.ADDED);
+        assertThat(statuses[2]).isEqualTo(EditDiff.LineStatus.UNCHANGED);
+    }
+
+    @Test
+    void modifiedLineIsYellow() {
+        List<String> original = List.of("a", "b", "c");
+        List<String> current = List.of("a", "B", "c");
+
+        EditDiff.LineStatus[] statuses = EditDiff.diff(original, current);
+
+        assertThat(statuses[0]).isEqualTo(EditDiff.LineStatus.UNCHANGED);
+        assertThat(statuses[1]).isEqualTo(EditDiff.LineStatus.MODIFIED);
+        assertThat(statuses[2]).isEqualTo(EditDiff.LineStatus.UNCHANGED);
+    }
+
+    @Test
+    void addedAtEnd() {
+        List<String> original = List.of("a", "b");
+        List<String> current = List.of("a", "b", "c", "d");
+
+        EditDiff.LineStatus[] statuses = EditDiff.diff(original, current);
+
+        assertThat(statuses[0]).isEqualTo(EditDiff.LineStatus.UNCHANGED);
+        assertThat(statuses[1]).isEqualTo(EditDiff.LineStatus.UNCHANGED);
+        assertThat(statuses[2]).isEqualTo(EditDiff.LineStatus.ADDED);
+        assertThat(statuses[3]).isEqualTo(EditDiff.LineStatus.ADDED);
+    }
+
+    @Test
+    void emptyOriginalAllAdded() {
+        List<String> original = List.of();
+        List<String> current = List.of("a", "b");
+
+        EditDiff.LineStatus[] statuses = EditDiff.diff(original, current);
+
+        assertThat(statuses).containsExactly(
+                EditDiff.LineStatus.ADDED,
+                EditDiff.LineStatus.ADDED);
+    }
+
+    @Test
+    void unifiedDiffShowsChanges() {
+        List<String> original = List.of("a", "b", "c", "d", "e");
+        List<String> current = List.of("a", "B", "c", "d", "e");
+
+        List<EditDiff.DiffEntry> diff = EditDiff.unifiedDiff(original, 
current, 1);
+
+        assertThat(diff).anyMatch(e -> e.type() == '-' && e.text().equals("b") 
&& e.lineNum() == 2);
+        assertThat(diff).anyMatch(e -> e.type() == '+' && e.text().equals("B") 
&& e.lineNum() == 2);
+        assertThat(diff).anyMatch(e -> e.type() == ' ' && 
e.text().equals("a"));
+        assertThat(diff).anyMatch(e -> e.type() == ' ' && 
e.text().equals("c"));
+        assertThat(diff).noneMatch(e -> e.text().equals("e"));
+    }
+
+    @Test
+    void unifiedDiffAddedLines() {
+        List<String> original = List.of("a", "c");
+        List<String> current = List.of("a", "b", "c");
+
+        List<EditDiff.DiffEntry> diff = EditDiff.unifiedDiff(original, 
current, 1);
+
+        assertThat(diff).anyMatch(e -> e.type() == '+' && e.text().equals("b") 
&& e.lineNum() == 2);
+        assertThat(diff).anyMatch(e -> e.type() == ' ' && 
e.text().equals("a"));
+        assertThat(diff).anyMatch(e -> e.type() == ' ' && 
e.text().equals("c"));
+    }
+
+    @Test
+    void unifiedDiffLineNumbersMatchSourceFiles() {
+        List<String> original = List.of("line1", "line2", "line3", "line4");
+        List<String> current = List.of("line1", "CHANGED", "line3", "line4");
+
+        List<EditDiff.DiffEntry> diff = EditDiff.unifiedDiff(original, 
current, 1);
+
+        EditDiff.DiffEntry removed = diff.stream().filter(e -> e.type() == 
'-').findFirst().orElseThrow();
+        assertThat(removed.lineNum()).isEqualTo(2);
+        assertThat(removed.text()).isEqualTo("line2");
+
+        EditDiff.DiffEntry added = diff.stream().filter(e -> e.type() == 
'+').findFirst().orElseThrow();
+        assertThat(added.lineNum()).isEqualTo(2);
+        assertThat(added.text()).isEqualTo("CHANGED");
+    }
+
+    @Test
+    void identicalFilesEmptyDiff() {
+        List<String> lines = List.of("a", "b", "c");
+        List<EditDiff.DiffEntry> diff = EditDiff.unifiedDiff(lines, lines, 3);
+
+        assertThat(diff).isEmpty();
+    }
+}
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/SourceViewerEditorOpsTest.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/SourceViewerEditorOpsTest.java
index 1eebd6fafa46..cdbaec126b85 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/SourceViewerEditorOpsTest.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/SourceViewerEditorOpsTest.java
@@ -83,20 +83,6 @@ class SourceViewerEditorOpsTest {
         assertThat(viewer.editText()).contains("X");
     }
 
-    @Test
-    void ctrlSlashTogglesCommentOnCurrentBlock() {
-        moveCursorToLineContaining("log:info");
-
-        viewer.handleKeyEvent(KeyEvent.ofChar('/', CTRL));
-
-        assertThat(viewer.editText()).contains("# ");
-        assertThat(viewer.editText()).contains("log:info");
-
-        viewer.handleKeyEvent(KeyEvent.ofChar('/', CTRL));
-
-        assertThat(viewer.editText()).doesNotContain("# log:info");
-    }
-
     @Test
     void ctrlDDuplicatesYamlBlock() {
         moveCursorToLineContaining("log:info");
@@ -108,10 +94,10 @@ class SourceViewerEditorOpsTest {
     }
 
     @Test
-    void ctrlShiftKDeletesYamlBlock() {
+    void ctrlKDeletesCurrentLine() {
         moveCursorToLineContaining("log:warn");
 
-        viewer.handleKeyEvent(KeyEvent.ofChar('k', CTRL_SHIFT));
+        viewer.handleKeyEvent(KeyEvent.ofChar('k', CTRL));
 
         assertThat(viewer.editText()).doesNotContain("log:warn");
         assertThat(viewer.editText()).contains("log:info");
@@ -152,26 +138,6 @@ class SourceViewerEditorOpsTest {
         assertThat(viewer.editState().cursorCol()).isEqualTo(6);
     }
 
-    @Test
-    void ctrlFOpensFindInEditMode() {
-        viewer.handleKeyEvent(KeyEvent.ofChar('f', CTRL));
-
-        assertThat(viewer.isSearchInputActive()).isTrue();
-    }
-
-    @Test
-    void plainNInsertsWhileFindTermActive() {
-        viewer.handleKeyEvent(KeyEvent.ofChar('f', CTRL));
-        viewer.handleKeyEvent(KeyEvent.ofChar('l', KeyModifiers.NONE));
-        viewer.handleKeyEvent(KeyEvent.ofChar('o', KeyModifiers.NONE));
-        viewer.handleKeyEvent(KeyEvent.ofChar('g', KeyModifiers.NONE));
-        viewer.handleKeyEvent(KeyEvent.ofKey(KeyCode.ENTER, 
KeyModifiers.NONE));
-
-        viewer.handleKeyEvent(KeyEvent.ofChar('n', KeyModifiers.NONE));
-
-        assertThat(viewer.editText()).contains("n");
-    }
-
     @Test
     void footerShowsNewEditorHints() {
         List<dev.tamboui.text.Span> spans = new ArrayList<>();
@@ -182,10 +148,7 @@ class SourceViewerEditorOpsTest {
         assertThat(footer).contains("Ctrl+Y");
         assertThat(footer).contains("Alt+↑/↓");
         assertThat(footer).contains("Ctrl+D");
-        assertThat(footer).contains("Ctrl+Shift+K");
-        assertThat(footer).contains("Ctrl+/");
-        assertThat(footer).contains("Ctrl+F");
-        assertThat(footer).contains("Ctrl+N");
+        assertThat(footer).contains("Ctrl+K");
     }
 
     private void moveCursorToLineContaining(String needle) {
diff --git 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/YamlBlockEditorTest.java
 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/YamlBlockEditorTest.java
index f2fa1e947eeb..22ac6b777ead 100644
--- 
a/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/YamlBlockEditorTest.java
+++ 
b/dsl/camel-jbang/camel-jbang-plugin-tui/src/test/java/org/apache/camel/dsl/jbang/core/commands/tui/YamlBlockEditorTest.java
@@ -61,6 +61,20 @@ class YamlBlockEditorTest {
         assertThat(text.split("- to: log:info", -1)).hasSize(3);
     }
 
+    @Test
+    void deleteLineRemovesSingleLine() {
+        List<String> lines = YamlBlockEditor.toLines(SAMPLE);
+        int row = findLineContaining(lines, "- to: log:warn");
+        int before = lines.size();
+
+        YamlBlockEditor.EditResult result = YamlBlockEditor.deleteLine(lines, 
row);
+
+        assertThat(result.lines()).hasSize(before - 1);
+        
assertThat(YamlBlockEditor.fromLines(result.lines())).doesNotContain("log:warn");
+        
assertThat(YamlBlockEditor.fromLines(result.lines())).contains("log:info");
+        
assertThat(YamlBlockEditor.fromLines(result.lines())).contains("timer:tick");
+    }
+
     @Test
     void deleteBlockRemovesSelectedYamlBlock() {
         List<String> lines = YamlBlockEditor.toLines(SAMPLE);

Reply via email to