Skip to content

CAMEL-24372: camel-tui YAML editor undo/redo, block ops, word nav, find in edit - #25408

Merged
davsclaus merged 4 commits into
apache:mainfrom
atiaomar1978-hub:feature/CAMEL-24372-tui-yaml-editor
Aug 10, 2026
Merged

CAMEL-24372: camel-tui YAML editor undo/redo, block ops, word nav, find in edit#25408
davsclaus merged 4 commits into
apache:mainfrom
atiaomar1978-hub:feature/CAMEL-24372-tui-yaml-editor

Conversation

@atiaomar1978-hub

Copy link
Copy Markdown
Contributor

Summary

Implements CAMEL-24372: enhanced plain-text edit mode in the camel-jbang TUI source viewer for YAML (and other local files).

Editor features

Shortcut Action
Ctrl+Z / Ctrl+Y / Ctrl+Shift+Z Undo / redo
Alt+↑ / Alt+↓ Move YAML list block up/down
Ctrl+D Duplicate current block
Ctrl+Shift+K Delete current block
Ctrl+/ Toggle # comment on block
Ctrl+← / Ctrl+→ Word navigation
Ctrl+Backspace / Ctrl+Delete Delete word backward/forward
Home Smart home (content indent, then column 0)
Ctrl+F, then n/N Find in edit mode

Implementation

  • SourceEditHistory — snapshot-based undo/redo stack (max 100)
  • YamlBlockEditor — YAML list-item block detection and move/duplicate/delete/comment
  • SourceEditorNavigation — word boundaries and smart home
  • SourceViewer — key bindings, footer hints, find-while-editing via SearchHighlighter
  • SearchHighlighter — edit-mode find input/navigation, closeInputOnly(), jumpToNearestMatch on confirm

Review follow-ups addressed

  • Fixed tamboui modifier key handling (isKey(KeyCode.*) instead of isUp()/isLeft()/isDelete*() with Ctrl/Alt)
  • Find-in-edit: n/N navigation aligned with view mode; Esc clears find; paste routes to find input; jump to nearest match after confirm
  • moveBlockUp cursor lands on the moved block after swap

Tests

  • YamlBlockEditorTest — block find/move/duplicate/delete/comment
  • SourceEditHistoryTest — undo/redo stack behavior
  • SourceEditorNavigationTest — word nav and smart home
  • SourceViewerEditorOpsTest — integration via SourceViewer edit mode

AI-generated PR description on behalf of atiaomar1978-hub.

@atiaomar1978-hub

Copy link
Copy Markdown
Contributor Author

Reopened on correctly named branch feature/CAMEL-24372-tui-yaml-editor (replacing closed #25407 which used the cursor/ branch prefix).

@atiaomar1978-hub

Copy link
Copy Markdown
Contributor Author

Grok code review

Verdict: Approve with minor follow-ups

CAMEL-24372 is implemented cleanly with appropriate helper extraction and solid test coverage. The tamboui KeyEvent pitfalls (modifier + semantic key helpers) were caught and fixed before this PR.


Architecture

SourceViewer (key routing, edit lifecycle)
    ├── SourceEditHistory      (undo/redo snapshots)
    ├── YamlBlockEditor        (block find/move/dup/delete/comment)
    ├── SourceEditorNavigation (word nav, smart home, word delete)
    └── SearchHighlighter      (find input + n/N nav in edit mode)

Good separation — block logic is testable without spinning up the full TUI.


Strengths

  • YAML list-item block ops match JIRA intent (Alt+↑/↓ move, Ctrl+D duplicate, Ctrl+Shift+K delete, Ctrl+/ comment).
  • Undo/redo wired through recordEditChange() on all mutating paths including paste and completion insert.
  • Footer hints document primary shortcuts for discoverability.
  • Tests use AssertJ and package-private access — follows project conventions.
  • Key bindings now use isKey(KeyCode.*) pattern consistent with existing view-mode Ctrl+scroll code.

Minor follow-ups (optional, non-blocking)

# Area Suggestion
1 Find UX Document that n/N navigate matches while find term is active (consistent with view mode but may conflict with typing).
2 Find highlight Apply SearchHighlighter.applyHighlights in renderEditMode for visual parity with read-only view.
3 Undo Consider coalescing rapid consecutive inserts or skipping duplicate snapshots on beforeChange.
4 Footer Add Ctrl+Shift+K and Ctrl+Y hints.
5 Properties files JIRA mentions .properties line ops — yamlListBlocks=false path exists but lacks dedicated integration test.
6 Commented blocks # - to: lines no longer match list-item detection — expected, worth a one-line doc note.

Test coverage

Test class Count Focus
YamlBlockEditorTest 10 Block find/move/dup/delete/comment, non-YAML fallback
SourceEditHistoryTest 6 Undo/redo/cursor restore
SourceEditorNavigationTest 7 Word boundaries, smart home, word delete
SourceViewerEditorOpsTest 10 Integration: undo, comment, dup, delete, Alt+↓, Ctrl+←/→, find, footer
SourceViewerEditTest (existing) Edit mode baseline — still passes

Recommendation

Ready for human committer review. Suggest reviewers: davsclaus, gnodet (recent SourceViewer / TUI activity).

AI-generated Grok review on behalf of atiaomar1978-hub.

@atiaomar1978-hub

Copy link
Copy Markdown
Contributor Author

Bugbot review

Reviewed feature/CAMEL-24372-tui-yaml-editor vs main.

Scope

YAML/plain-text edit mode enhancements for SourceViewer in camel-jbang-plugin-tui: undo/redo, block ops, word navigation, smart Home, find-in-edit.

Verified (looks good)

  • YamlBlockEditor: sibling block detection for - list items; duplicate/delete/move/comment logic is coherent; non-YAML files fall back to single-line blocks.
  • SourceEditHistory: seed + beforeChange + undo/redo stack; depth capped at 100.
  • SourceEditorNavigation: word boundaries treat _, -, . as word chars; : splits component names (timer:tick).
  • Tests: Good unit coverage (YamlBlockEditorTest, SourceEditHistoryTest, SourceEditorNavigationTest) plus integration tests in SourceViewerEditorOpsTest.

Issues found & fixed in branch

Severity Issue Status
Blocker Alt+↑/↓, Ctrl+←/→, Ctrl+Backspace/Delete used isUp()/isLeft()/isDelete*() with modifiers — tamboui only matches unmodified keys on those helpers Fixed — uses isKey(KeyCode.*) && hasAlt/hasCtrl
Major Find-in-edit did not jump to nearest match on confirm FixedjumpToNearestMatch(editState.cursorRow())
Major Find prev used isChar('n') && hasShift() instead of isChar('N') Fixed — aligned with view mode
Major Esc in edit mode did not clear active find term Fixedsearch.handleEscape() before discard
Major Paste while find input open went into edit buffer Fixed — routes to search.handlePaste
Major moveBlockUp cursor landed on wrong line after swap Fixed — cursor at previous.startRow()

Remaining suggestions (non-blocking)

  1. Find typing conflict: Plain n navigates find when a term is active (same as view mode) — may surprise users typing in buffer.
  2. Find highlighting: renderEditMode does not apply SearchHighlighter.applyHighlights in the TextArea widget (footer status only).
  3. Undo granularity: Per-keystroke snapshots; 100-depth limit may be shallow for large paste ops.
  4. Blank lines in blocks: findBlockEnd extends through blank lines between siblings — may pull extra lines on duplicate/delete.

Bugbot verdict: No blockers remaining. Approve with minor follow-ups.

AI-generated Bugbot review on behalf of atiaomar1978-hub.

@davsclaus davsclaus left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this contribution, Omar — nice work on the block-aware editing! The decomposition into SourceEditHistory, YamlBlockEditor, and SourceEditorNavigation is clean and well-tested.

A few items to flag:

Confirmed Issues

  1. n/N find navigation conflicts with normal typing in edit mode — When a find term is active, pressing n or N navigates matches instead of inserting the character. This is the view-mode convention but is surprising in edit mode where users expect to type freely. Consider requiring Ctrl+N / Ctrl+Shift+N in edit mode, or only consuming n/N while the find input bar is visible.

  2. moveBlockDown cursor follows the wrong blockmoveBlockUp explicitly corrects the cursor position (cursorRow = previous.startRow()), but moveBlockDown returns the raw swapBlocks result which lands on second.startRow() — that's where the other block landed, not where the user's block went. The cursor should follow the moved block.

Questions

  • The editText() and editState() package-private accessors on SourceViewer — are these only for test access? If so that's fine, just confirming.
  • viewer.setValidateOnSave(false) in SourceViewerEditorOpsTest — does that method exist on main, or is it also added by this PR? I don't see it in the diff.

This review does not replace specialized AI review tools (CodeRabbit, Sourcery) or static analysis (SonarCloud).

This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.

Claude Code on behalf of davsclaus

@atiaomar1978-hub

Copy link
Copy Markdown
Contributor Author

Thanks @davsclaus for the review — addressed both confirmed issues in 8559ab1:

Confirmed issues

  1. n/N find navigation in edit mode — Edit mode now uses Ctrl+N / Ctrl+Shift+N to step matches while a find term is active. Plain n/N are no longer consumed, so users can type freely. Footer hint updated to show Ctrl+N for next match. Test: plainNInsertsWhileFindTermActive.

  2. moveBlockDown cursor — Cursor now follows the moved block (same intent as the moveBlockUp fix). Test: moveBlockDownCursorFollowsMovedBlock.

Questions

  • editText() / editState() — Yes, these are package-private for tests that drive the edit buffer directly. Added brief javadoc on both.
  • setValidateOnSave(false) — Already on main in SourceViewer (also used in SourceViewerEditTest); not introduced by this PR.

Ready for another look when you have time.

AI-generated comment on behalf of atiaomar1978-hub.

@davsclaus

Copy link
Copy Markdown
Contributor

Is the F1 help doc for this page updated

@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

🌟 Thank you for your contribution to the Apache Camel project! 🌟
🤖 CI automation will test this PR automatically.

🐫 Apache Camel Committers, please review the following items:

  • First-time contributors require MANUAL approval for the GitHub Actions to run
  • You can use the command /component-test (camel-)component-name1 (camel-)component-name2.. to request a test from the test bot although they are normally detected and executed by CI.
  • You can label PRs using skip-tests and test-dependents to fine-tune the checks executed by this PR.
  • Build and test logs are available in the summary page. Only Apache Camel committers have access to the summary.

⚠️ Be careful when sharing logs. Review their contents before sharing them publicly.

@github-actions github-actions Bot added the dsl label Aug 8, 2026
@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

🧪 CI tested the following changed modules:

  • dsl/camel-jbang/camel-jbang-plugin-tui

🔬 Scalpel shadow comparison — Scalpel: 2 tested, 1 compile-only — current: 2 all tested

Maveniverse Scalpel detected 3 affected modules (current approach: 2).

⚠️ Modules only in Scalpel (1)
  • camel-launcher

Skip-tests mode would test 2 modules (1 direct + 1 downstream), skip tests for 1 (generated code, meta-modules)

Modules Scalpel would test (2)
  • camel-jbang-plugin-tui
  • camel-launcher-container
Modules with tests skipped (1)
  • camel-launcher

ℹ️ Shadow mode — Scalpel observes but does not affect test execution. Learn more

All tested modules (3 modules)
  • Camel :: JBang :: Plugin :: TUI
  • Camel :: Launcher
  • Camel :: Launcher :: Container

⚙️ View full build and test results

@davsclaus davsclaus left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work, Omar — the decomposition into SourceEditHistory, YamlBlockEditor, and SourceEditorNavigation is clean and well-tested. Both prior review issues (n/N conflict and moveBlockDown cursor) are properly fixed.

Minor nits (non-blocking)

  1. Home key logic duplicated — the inline Home handler in SourceViewer reimplements SourceEditorNavigation.smartHome() using YamlBlockEditor.leadingSpaces(). Calling smartHome(editState, false) would remove the duplication.

  2. positionCursor housed in SourceEditHistory — it's used from SourceEditorNavigation, YamlBlockEditor, and SourceViewer as a general cursor utility unrelated to undo/redo. Could move to SourceEditorNavigation or a shared utility in a future tidy-up.

Positive highlights

  • Progressive Esc flow (close find input → clear find term → discard confirmation) is good UX
  • Find term persisting from view mode into edit mode (closeInputOnly() replacing search.reset()) is a nice touch
  • Ctrl+N / Ctrl+Shift+N for find navigation avoids the n/N typing conflict cleanly
  • 4 test classes with solid coverage

This review does not replace specialized AI review tools (CodeRabbit, Sourcery) or static analysis (SonarCloud).

This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.

Claude Code on behalf of davsclaus

cursoragent and others added 3 commits August 10, 2026 09:36
…edit

Add SourceEditHistory, YamlBlockEditor, and SourceEditorNavigation helpers
and wire them into SourceViewer edit mode for undo/redo (Ctrl+Z/Y),
YAML block move/duplicate/delete (Alt+arrows, Ctrl+D/K), comment toggle
(Ctrl+/), word navigation/delete, smart Home, and find while editing.

Includes comprehensive unit and integration tests for the new editor ops.

Co-authored-by: Omar Atie <atiaomar1978-hub@users.noreply.github.com>
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 <atiaomar1978-hub@users.noreply.github.com>
Use Ctrl+N / Ctrl+Shift+N for find match navigation in edit mode so plain
n/N can be typed while a find term is active. Fix moveBlockDown cursor to
follow the moved block (same intent as moveBlockUp). Document test-only
editText/editState accessors and add footer hints for redo/delete/find nav.

Co-authored-by: Omar Atie <atiaomar1978-hub@users.noreply.github.com>
@davsclaus
davsclaus force-pushed the feature/CAMEL-24372-tui-yaml-editor branch from 8559ab1 to ca667a3 Compare August 10, 2026 07:43
…y, add F1 help

- Move positionCursor from SourceEditHistory to SourceEditorNavigation
  where it belongs as a general cursor utility
- Replace inline Home key logic in SourceViewer with smartHome() call
- Add edit mode shortcuts section to F1 help text

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Claus Ibsen <claus.ibsen@gmail.com>
@davsclaus

Copy link
Copy Markdown
Contributor

F1 help text updated in 3a10cef — added an Edit Mode (Shortcuts) section documenting all new keybindings (undo/redo, block ops, word nav, find in edit, smart home).

Claude Code on behalf of davsclaus

@davsclaus

Copy link
Copy Markdown
Contributor

Addressed review nits in 3a10cef:

  1. Smart-home duplication — Home key handler in SourceViewer now calls SourceEditorNavigation.smartHome(editState, false) instead of inlining the logic.

  2. positionCursor location — Moved from SourceEditHistory to SourceEditorNavigation where it belongs as a general cursor utility. All callers updated (main + test code). SourceEditHistory.restore() delegates to SourceEditorNavigation.positionCursor().

Claude Code on behalf of davsclaus

@davsclaus davsclaus added this to the 4.22.0 milestone Aug 10, 2026
@davsclaus davsclaus added the enhancement New feature or request label Aug 10, 2026
@davsclaus
davsclaus merged commit e78bb3c into apache:main Aug 10, 2026
5 checks passed
@davsclaus davsclaus modified the milestones: 4.22.0, 4.23.0 Aug 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dsl enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants