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 bb2d22945585 camel-tui: Align view and edit mode layout with >> cursor 
marker
bb2d22945585 is described below

commit bb2d22945585f5be49238ba4f59eab888872f82e
Author: Claus Ibsen <[email protected]>
AuthorDate: Fri Aug 14 14:32:47 2026 +0200

    camel-tui: Align view and edit mode layout with >> cursor marker
    
    Add 3-char prefix column in edit mode for the >> cursor marker,
    matching view mode layout. Use pipe separator in view mode line
    numbers (N |) to match TextArea gutter format. Align minimum line
    number width with TextArea (min 2 digits). Content no longer shifts
    when switching between view and edit mode with F4.
    
    camel-tui: Remove scroll sync hack on view-to-edit transition
    
    The scroll position sync between view and edit mode caused visible
    jumping. Removed in favor of letting TextArea position naturally.
    A proper fix requires unifying the rendering paths (CAMEL-24395).
    
    camel-tui: Fix syntax highlight colors matching between view and edit mode
    
    The pipe separator in the line number format was being fed to the
    syntax highlighter in view mode, causing different colors than edit
    mode. Now the pipe is included in the prefix and rendered in dim
    style, so only the actual code goes through the highlighter in both
    modes. Also fixed plain mode prefix stripping for the new format.
    
    camel-tui: Position cursor at 2/3 viewport when entering edit mode
    
    Set the initial scroll position before TextArea renders so the
    cursor line appears at 2/3 of the viewport height instead of the
    bottom. Fixed scrollDown parameter (was passing lineCount instead
    of viewportHeight, which made maxScroll=0).
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
    Signed-off-by: Claus Ibsen <[email protected]>
---
 .../dsl/jbang/core/commands/tui/SourceViewer.java  | 61 +++++++++++++++++-----
 1 file changed, 48 insertions(+), 13 deletions(-)

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 82665e2b917d..b25415b06382 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
@@ -181,6 +181,7 @@ class SourceViewer {
     private List<String> validationErrors;
     private int validationErrorScroll;
     private Map<Integer, String> inlineErrors = Collections.emptyMap();
+    private boolean editInitialScroll;
     private long lastBackgroundValidationTime;
     private String lastBackgroundValidationContent;
     private static final long BACKGROUND_VALIDATION_INTERVAL_MS = 2000;
@@ -829,6 +830,8 @@ class SourceViewer {
         for (int i = 0; i < targetRow && i < editState.lineCount() - 1; i++) {
             editState.moveCursorDown();
         }
+        editState.moveCursorToLineStart();
+        editInitialScroll = true;
         markdownModeBeforeEdit = markdownMode;
         markdownMode = false;
         quickDocEnabled = false;
@@ -2495,21 +2498,46 @@ class SourceViewer {
             editDocEntries = editQuickDocProvider.provideForLine(editLines(), 
editState.cursorRow());
         }
 
+        int prefixWidth = plainMode ? 0 : 3;
+        Rect textAreaRect = plainMode
+                ? editorArea
+                : new Rect(
+                        editorArea.left() + prefixWidth, editorArea.top(),
+                        editorArea.width() - prefixWidth, editorArea.height());
+
         TextArea textArea = TextArea.builder()
                 .cursorStyle(Style.EMPTY.reversed())
                 .showLineNumbers(!plainMode)
                 .lineNumberStyle(Style.EMPTY.dim())
                 .build();
-        textArea.renderWithCursor(editorArea, frame.buffer(), editState, 
frame);
+        // on first render, position cursor at 2/3 of viewport before TextArea 
renders
+        if (editInitialScroll) {
+            editInitialScroll = false;
+            int viewportH = textAreaRect.height();
+            int twoThirds = viewportH * 2 / 3;
+            int targetScroll = Math.max(0, editState.cursorRow() - twoThirds);
+            if (targetScroll > 0) {
+                editState.scrollDown(targetScroll, viewportH);
+            }
+        }
+
+        textArea.renderWithCursor(textAreaRect, frame.buffer(), editState, 
frame);
 
-        applySyntaxHighlightOverlay(frame, editorArea);
+        applySyntaxHighlightOverlay(frame, textAreaRect);
 
-        // cursor line highlight
+        // cursor line highlight with >> marker
         int cursorRelRow = editState.cursorRow() - editState.scrollRow();
         if (cursorRelRow >= 0 && cursorRelRow < editorArea.height()) {
             int screenY = editorArea.top() + cursorRelRow;
             Rect lineRect = new Rect(editorArea.left(), screenY, 
editorArea.width(), 1);
             frame.buffer().setStyle(lineRect, Style.EMPTY.bg(Theme.zebra()));
+            if (!plainMode) {
+                Style markerStyle = Theme.label().bold().bg(Theme.zebra());
+                frame.buffer().set(editorArea.left(), screenY,
+                        new dev.tamboui.buffer.Cell(">", markerStyle));
+                frame.buffer().set(editorArea.left() + 1, screenY,
+                        new dev.tamboui.buffer.Cell(">", markerStyle));
+            }
         }
 
         // scope line highlight — shows which EIP or uri: line the cursor 
belongs to
@@ -2540,7 +2568,7 @@ class SourceViewer {
                         Style bg = 
Style.EMPTY.fg(dev.tamboui.style.Color.WHITE)
                                 .bg(dev.tamboui.style.Color.rgb(0x1B, 0x4D, 
0x1B));
                         int screenY = editorArea.top() + r;
-                        for (int x = editorArea.left(); x < editorArea.left() 
+ gutterWidth; x++) {
+                        for (int x = textAreaRect.left(); x < 
textAreaRect.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));
@@ -2559,7 +2587,7 @@ class SourceViewer {
                     Style errorBg = 
Style.EMPTY.fg(dev.tamboui.style.Color.WHITE)
                             .bg(dev.tamboui.style.Color.rgb(0x8B, 0x00, 0x00));
                     int screenY = editorArea.top() + r;
-                    for (int x = editorArea.left(); x < editorArea.left() + 
gutterWidth; x++) {
+                    for (int x = textAreaRect.left(); x < textAreaRect.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(), 
errorBg));
@@ -2908,13 +2936,13 @@ class SourceViewer {
         boolean isMd = fileName.toLowerCase().endsWith(".md");
         try {
             List<String> rawLines = Files.readAllLines(filePath, 
StandardCharsets.UTF_8);
-            int lineNumWidth = String.valueOf(rawLines.size()).length();
+            int lineNumWidth = Math.max(2, 
String.valueOf(rawLines.size()).length());
             List<String> result = new ArrayList<>();
             List<JsonObject> codeLines = new ArrayList<>();
             for (int i = 0; i < rawLines.size(); i++) {
                 int lineNum = i + 1;
                 String code = rawLines.get(i);
-                result.add(String.format("%" + lineNumWidth + "d  %s", 
lineNum, code));
+                result.add(String.format("%" + lineNumWidth + "d |%s", 
lineNum, code));
                 JsonObject jo = new JsonObject();
                 jo.put("line", lineNum);
                 jo.put("code", code);
@@ -3082,15 +3110,15 @@ class SourceViewer {
                 maxLineNum = lineNum;
             }
         }
-        int lineNumWidth = String.valueOf(maxLineNum).length();
+        int lineNumWidth = Math.max(2, String.valueOf(maxLineNum).length());
         int matchIdx = -1;
         int idx = 0;
         for (JsonObject codeLine : codeLines) {
             Integer lineNum = codeLine.getInteger("line");
             String code = Jsoner.unescape(objToString(codeLine.get("code")));
             String prefix = lineNum != null
-                    ? String.format("%" + lineNumWidth + "d  ", lineNum)
-                    : String.format("%" + lineNumWidth + "s  ", "");
+                    ? String.format("%" + lineNumWidth + "d |", lineNum)
+                    : String.format("%" + lineNumWidth + "s |", "");
             result.add(prefix + code);
             if (targetLine > 0 && lineNum != null && lineNum == targetLine && 
matchIdx < 0) {
                 matchIdx = idx;
@@ -3342,6 +3370,10 @@ class SourceViewer {
         while (prefixEnd < raw.length() && (raw.charAt(prefixEnd) == ' ' || 
Character.isDigit(raw.charAt(prefixEnd)))) {
             prefixEnd++;
         }
+        // include the | separator after the line number
+        if (prefixEnd < raw.length() && raw.charAt(prefixEnd) == '|') {
+            prefixEnd++;
+        }
 
         String prefix = raw.substring(0, prefixEnd);
         String code = raw.substring(prefixEnd);
@@ -3352,7 +3384,7 @@ class SourceViewer {
         List<Span> spans = new ArrayList<>();
         Style selBg = focused ? Theme.selectionBg() : 
Theme.selectionBg().dim();
         if (plainMode) {
-            // strip line-number prefix (spaces, digits, 2 separator spaces) 
but keep code indentation
+            // strip line-number prefix (spaces, digits, space, pipe 
separator) but keep code indentation
             int pos = 0;
             while (pos < raw.length() && raw.charAt(pos) == ' ') {
                 pos++;
@@ -3360,8 +3392,11 @@ class SourceViewer {
             while (pos < raw.length() && Character.isDigit(raw.charAt(pos))) {
                 pos++;
             }
-            if (pos + 1 < raw.length() && raw.charAt(pos) == ' ' && 
raw.charAt(pos + 1) == ' ') {
-                pos += 2;
+            if (pos < raw.length() && raw.charAt(pos) == ' ') {
+                pos++;
+            }
+            if (pos < raw.length() && raw.charAt(pos) == '|') {
+                pos++;
             }
             String plainCode = raw.substring(pos);
             spans.addAll(SyntaxHighlighter.highlightLine(plainCode, 
language).spans());

Reply via email to