davsclaus commented on code in PR #28456:
URL: https://github.com/apache/camel/pull/28456#discussion_r4371390175


##########
dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/RouteDiagramZoom.java:
##########
@@ -0,0 +1,377 @@
+/*
+ * 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.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.WeakHashMap;
+import java.util.concurrent.ConcurrentHashMap;
+
+import dev.tamboui.text.Line;
+import dev.tamboui.text.Span;
+import org.apache.camel.diagram.RouteDiagramLayoutEngine;
+import org.apache.camel.diagram.RouteDiagramLayoutEngine.LayoutNode;
+import org.apache.camel.diagram.RouteDiagramLayoutEngine.LayoutRoute;
+import org.apache.camel.diagram.RouteDiagramLayoutEngine.NodeInfo;
+import org.apache.camel.diagram.RouteDiagramLayoutEngine.RouteInfo;
+import org.apache.camel.diagram.RouteDiagramLayoutEngine.TreeNode;
+import org.apache.camel.diagram.RouteErrorFrame;
+import org.apache.camel.diagram.TopologyErrorFrame;
+import org.apache.camel.dsl.jbang.core.commands.tui.diagram.RouteDensity;
+
+/**
+ * The zoom of the route diagram: how much room a step takes ({@link 
RouteDensity}), or the most detail that fits the
+ * screen, and the blocks folded into their first step. A folded block is left 
out of the route before the engine lays
+ * it out, so the steps after it move up and its branches give their columns 
back.
+ * <p>
+ * The keys change the zoom on the UI thread; the layout reads it on the 
background thread, so the state is volatile or
+ * concurrent. When the zoom changes, the selected step stays selected and on 
the same row of the screen.
+ */
+final class RouteDiagramZoom {
+
+    /** The zoom chosen last: a density, or fit; the folded blocks are not 
kept. */
+    static final String PROP_ROUTE_ZOOM = "camel.tui.routeZoom";
+
+    /** The selected step to select again once the route is laid out anew, and 
its row on the screen. */
+    record Restore(int index, int row, int screenRow) {
+    }
+
+    /** The density until another is chosen: boxes of one line, about twice 
the steps of the detailed on a screen. */
+    static final RouteDensity DEFAULT = RouteDensity.COMPACT;
+
+    private volatile RouteDensity density = DEFAULT;
+    private volatile boolean fit;
+    /** The folded blocks of each route: the ids of their first steps. */
+    private final Map<String, Set<String>> folded = new ConcurrentHashMap<>();
+    /** The steps of each route as last laid out, without its folds: fold all 
folds the blocks hidden in others too. */
+    private final Map<String, RouteInfo> unfolded = new ConcurrentHashMap<>();
+    /** What each layout was made with: its density, and the steps folded into 
each folded step. */
+    private final Map<LayoutRoute, RouteDensity> densities = 
Collections.synchronizedMap(new WeakHashMap<>());
+    private final Map<LayoutRoute, Map<String, Integer>> foldedSteps
+            = Collections.synchronizedMap(new WeakHashMap<>());
+    // the step to select again after the next layout, and the layout it was 
selected on
+    private LayoutRoute anchorLayout;
+    private String anchorNodeId;
+    private int anchorScreenRow;

Review Comment:
   Fixed in 996f32c26526. Three volatile fields would still let the layout 
thread read a new node id with the old layout, so the anchor is now one 
`AtomicReference<Anchor>` (a record of the layout, the node id and the screen 
row). `restore()` takes it with `compareAndSet`, so an anchor that the UI 
thread sets in the meantime is not cleared.
   
   _Claude Code on behalf of davsclaus_



##########
dsl/camel-jbang/camel-jbang-plugin-tui/src/main/java/org/apache/camel/dsl/jbang/core/commands/tui/diagram/RouteDiagramWidget.java:
##########
@@ -885,7 +961,89 @@ private List<String> rewrapText(LayoutNode node, int 
maxWidth) {
                 }
             }
         }
-        return wrapText(label, maxWidth);
+        return label;
+    }
+
+    /** The route a link marker names: by id, or a from box's caller in words 
in the business view. */
+    private String linkName(LayoutNode node, String linkedRouteId) {
+        if (showDescription && "from".equals(node.type)) {
+            // a from box names its caller in words; a to box already shows 
the route it links to in words, so
+            // its marker names the route by id, as the breadcrumb does
+            String desc = routeDescriptions.get(linkedRouteId);
+            if (desc != null && !desc.isBlank()) {
+                return desc;
+            }
+        }
+        return linkedRouteId;
+    }
+
+    private void addFoldedMarker(LayoutNode node, int row, int col) {
+        Integer steps = node.id != null ? foldedSteps.get(node.id) : null;
+        if (steps != null) {
+            markers.add(new Marker(
+                    row, col, " ▸ " + steps + (steps == 1 ? " step" : " 
steps") + " folded",
+                    Theme.muted()));
+        }
+    }
+
+    /** A text with its EIP (up to its first bracket) in the EIP's colour, and 
the rest as a label. */
+    private void writeLabel(Buffer buffer, Rect area, int row, int col, String 
text, Color eipColor, boolean selected) {
+        int open = text.indexOf('[');
+        String eip = open > 0 ? text.substring(0, open) : text;
+        writeText(buffer, area, row, col, eip, 
style(Style.EMPTY.fg(eipColor).bold(), selected));
+        if (open > 0) {
+            writeText(buffer, area, row, col + CharWidth.of(eip), 
text.substring(open), style(fromLabelStyle(), selected));
+        }
+    }
+
+    /**
+     * A step at the bare density: a mark of its kind and its text on one row, 
with no box; the arrows meet at the mark.
+     * Its text goes on up to half way to the next branch.
+     */
+    private void drawBareNode(Buffer buffer, Rect area, LayoutNode node) {
+        int col = toCol(node.x);
+        int row = toRow(node.y);
+        boolean selected = nodeBoxes.size() == selectedNodeIndex;
+        boolean external = isExternalEndpoint(node);
+        boolean highlighted = node.id != null && 
highlightNodeIds.contains(node.id);
+        Color eipColor;
+        if (highlighted) {
+            eipColor = highlightFailed ? highlightFailColor() : 
highlightOkColor();
+        } else {
+            eipColor = external ? externalColor() : getEipColor(node.type);
+        }
+        String text = DiagramText.fit(labelText(node), boxWidth + boxWidth / 2 
- 4);
+        writeText(buffer, area, row, col + 1, bareMark(node), 
style(Style.EMPTY.fg(eipColor).bold(), selected));
+        if (selected) {
+            setChar(buffer, area, row, col + 2, ' ', selectionStyle());
+        }
+        writeLabel(buffer, area, row, col + 3, text, eipColor, selected);
+        int end = col + 3 + CharWidth.of(text);
+
+        String linkedRouteId = findLinkedRouteId(node);
+        if (linkedRouteId != null) {
+            markers.add(new Marker(row, end, " ↵ " + linkName(node, 
linkedRouteId), Theme.label().bold()));
+            end += 3 + CharWidth.of(linkName(node, linkedRouteId));

Review Comment:
   Done in 996f32c26526.
   
   _Claude Code on behalf of davsclaus_



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to