This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch feature/CAMEL-24372-tui-yaml-editor in repository https://gitbox.apache.org/repos/asf/camel.git
commit 54f6329b53544e06e6aaf3d6ef15c957013e33bd Author: Cursor Agent <[email protected]> AuthorDate: Sat Aug 8 03:28:13 2026 +0000 CAMEL-24372: Fix edit-mode key bindings and find-in-edit behavior Use isKey(KeyCode.*) with modifiers for Alt/Ctrl chords (tamboui only matches unmodified keys on isUp/isLeft/isDelete*). Align find n/N with view mode, jump to nearest match on confirm, clear find on Esc, route paste to find input, and fix moveBlockUp cursor placement. Co-authored-by: Omar Atie <[email protected]> --- .../jbang/core/commands/tui/SearchHighlighter.java | 12 +++++----- .../dsl/jbang/core/commands/tui/SourceViewer.java | 27 ++++++++++++++-------- .../jbang/core/commands/tui/YamlBlockEditor.java | 6 ++++- .../commands/tui/SourceViewerEditorOpsTest.java | 17 +++++++++++--- 4 files changed, 42 insertions(+), 20 deletions(-) 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 b23e95e273d1..c40adefada92 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 @@ -333,16 +333,16 @@ class SearchHighlighter { if (findInputActive || highlightInputActive) { return handleSearchInput(ke); } - if (ke.hasCtrl() && ke.isChar('f')) { + if (ke.hasCtrl() && ke.isCharIgnoreCase('f')) { openFindInput(); return true; } if (findTerm != null && ke.isChar('n') && !ke.hasCtrl() && !ke.hasAlt()) { - if (ke.hasShift()) { - navigateToPrevMatch(); - } else { - navigateToNextMatch(); - } + navigateToNextMatch(); + return true; + } + if (findTerm != null && ke.isChar('N') && !ke.hasCtrl() && !ke.hasAlt()) { + navigateToPrevMatch(); 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/SourceViewer.java b/dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/SourceViewer.java index efbc6066c622..c73b30fdc531 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 @@ -547,7 +547,7 @@ class SourceViewer { } private void jumpEditToCurrentFindMatch() { - int line = search.currentMatchLine(); + int line = search.jumpToNearestMatch(editState.cursorRow()); if (line >= 0) { SourceEditHistory.positionCursor(editState, line, 0); } @@ -592,14 +592,14 @@ class SourceViewer { } return true; } - if (ke.hasCtrl() && ke.isChar('z') && !ke.hasShift()) { + if (ke.hasCtrl() && ke.isCharIgnoreCase('z') && !ke.hasShift()) { if (editHistory.undo(editState)) { dirty = true; refreshEditFindMatches(); } return true; } - if (ke.hasCtrl() && (ke.isChar('y') || (ke.isChar('z') && ke.hasShift()))) { + if (ke.hasCtrl() && (ke.isCharIgnoreCase('y') || (ke.isCharIgnoreCase('z') && ke.hasShift()))) { if (editHistory.redo(editState)) { dirty = true; refreshEditFindMatches(); @@ -607,15 +607,15 @@ class SourceViewer { return true; } boolean yamlListBlocks = isCamelYamlFile(); - if (ke.hasAlt() && ke.isUp() && !ke.hasShift()) { + if (ke.isKey(KeyCode.UP) && ke.hasAlt() && !ke.hasShift()) { applyBlockEdit(YamlBlockEditor.moveBlockUp(editLines(), editState.cursorRow(), yamlListBlocks)); return true; } - if (ke.hasAlt() && ke.isDown() && !ke.hasShift()) { + if (ke.isKey(KeyCode.DOWN) && ke.hasAlt() && !ke.hasShift()) { applyBlockEdit(YamlBlockEditor.moveBlockDown(editLines(), editState.cursorRow(), yamlListBlocks)); return true; } - if (ke.hasCtrl() && ke.isChar('d') && !ke.hasShift()) { + if (ke.hasCtrl() && ke.isCharIgnoreCase('d') && !ke.hasShift()) { applyBlockEdit(YamlBlockEditor.duplicateBlock(editLines(), editState.cursorRow(), yamlListBlocks)); return true; } @@ -633,20 +633,20 @@ class SourceViewer { YamlBlockEditor.leadingSpaces(toggled.get(block.startRow()))); return true; } - if (ke.hasCtrl() && ke.isLeft()) { + if (ke.isKey(KeyCode.LEFT) && ke.hasCtrl()) { SourceEditorNavigation.moveWordLeft(editState); return true; } - if (ke.hasCtrl() && ke.isRight()) { + if (ke.isKey(KeyCode.RIGHT) && ke.hasCtrl()) { SourceEditorNavigation.moveWordRight(editState); return true; } - if (ke.hasCtrl() && ke.isDeleteBackward()) { + if (ke.isKey(KeyCode.BACKSPACE) && ke.hasCtrl()) { recordEditChange(); SourceEditorNavigation.deleteWordBackward(editState); return true; } - if (ke.hasCtrl() && ke.isDeleteForward()) { + if (ke.isKey(KeyCode.DELETE) && ke.hasCtrl()) { recordEditChange(); SourceEditorNavigation.deleteWordForward(editState); return true; @@ -661,6 +661,9 @@ class SourceViewer { return true; } if (ke.isCancel()) { + if (search.handleEscape()) { + return true; + } if (dirty) { pendingDiscard = true; return true; @@ -1971,6 +1974,10 @@ class SourceViewer { void handlePaste(String text) { if (editMode) { + if (search.isSearchInputActive()) { + search.handlePaste(text); + return; + } if (text != null && !text.isEmpty()) { recordEditChange(); editState.insert(text); 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 425179c66d48..6c31c0f69502 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 @@ -94,7 +94,11 @@ final class YamlBlockEditor { if (previous == null || previous.isEmpty()) { return null; } - return swapBlocks(lines, previous, block); + EditResult swapped = swapBlocks(lines, previous, block); + List<String> answer = swapped.lines(); + int cursorRow = previous.startRow(); + int cursorCol = answer.isEmpty() ? 0 : YamlBlockEditor.leadingSpaces(answer.get(cursorRow)); + return new EditResult(answer, cursorRow, cursorCol); } static EditResult moveBlockDown(List<String> lines, int row, boolean yamlListBlocks) { 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 dbfb5a9b5a14..2181378d9174 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 @@ -22,6 +22,7 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.List; +import dev.tamboui.tui.event.KeyCode; import dev.tamboui.tui.event.KeyEvent; import dev.tamboui.tui.event.KeyModifiers; import org.junit.jupiter.api.BeforeEach; @@ -36,6 +37,7 @@ import static org.assertj.core.api.Assertions.assertThat; class SourceViewerEditorOpsTest { private static final KeyModifiers CTRL = KeyModifiers.of(true, false, false); + private static final KeyModifiers ALT = KeyModifiers.of(false, true, false); private static final KeyModifiers CTRL_SHIFT = KeyModifiers.of(true, false, true); @TempDir @@ -130,14 +132,23 @@ class SourceViewerEditorOpsTest { } @Test - void ctrlLeftAndRightMoveByWord() { + void altDownMovesBlockDown() { + moveCursorToLineContaining("log:info"); + + viewer.handleKeyEvent(KeyEvent.ofKey(KeyCode.DOWN, KeyModifiers.ALT)); + + assertThat(viewer.editText().indexOf("log:warn")).isLessThan(viewer.editText().indexOf("log:info")); + } + + @Test + void ctrlLeftAndRightMoveByWordViaKeyBindings() { moveCursorToLineContaining("uri:"); SourceEditHistory.positionCursor(viewer.editState(), viewer.editState().cursorRow(), 0); - SourceEditorNavigation.moveWordRight(viewer.editState()); + viewer.handleKeyEvent(KeyEvent.ofKey(KeyCode.RIGHT, CTRL)); assertThat(viewer.editState().cursorCol()).isEqualTo(9); - SourceEditorNavigation.moveWordLeft(viewer.editState()); + viewer.handleKeyEvent(KeyEvent.ofKey(KeyCode.LEFT, CTRL)); assertThat(viewer.editState().cursorCol()).isEqualTo(6); }
