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

Cole-Greer pushed a commit to branch docs-3.7
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git

commit eca564db9eeed97d21d532c6966c0289100fc594
Author: Cole Greer <[email protected]>
AuthorDate: Thu May 21 17:05:16 2026 -0700

    Add CodeRay syntax highlighting via JRuby
    
    Use the CodeRay gem bundled with AsciidoctorJ to highlight generated
    code content in tabs. The JRuby runtime is accessed via
    JRubyRuntimeContext to call CodeRay::Duo directly, producing the same
    highlighted HTML spans as regular source blocks.
    
    Falls back to plain HTML escaping if CodeRay is unavailable.
---
 .../gremlin/docs/GremlinTreeprocessor.java         | 38 ++++++++++++++++++++--
 .../tinkerpop/gremlin/docs/TabbedHtmlBuilder.java  | 26 ++++++++++++++-
 .../gremlin/docs/GremlinTreeprocessorTest.java     |  6 ++--
 .../tinkerpop/gremlin/docs/IntegrationTest.java    | 10 +++---
 4 files changed, 68 insertions(+), 12 deletions(-)

diff --git 
a/tools/tinkerpop-docs/src/main/java/org/apache/tinkerpop/gremlin/docs/GremlinTreeprocessor.java
 
b/tools/tinkerpop-docs/src/main/java/org/apache/tinkerpop/gremlin/docs/GremlinTreeprocessor.java
index 34b40a11c6..ef2d4827ae 100644
--- 
a/tools/tinkerpop-docs/src/main/java/org/apache/tinkerpop/gremlin/docs/GremlinTreeprocessor.java
+++ 
b/tools/tinkerpop-docs/src/main/java/org/apache/tinkerpop/gremlin/docs/GremlinTreeprocessor.java
@@ -242,9 +242,11 @@ public class GremlinTreeprocessor extends Treeprocessor {
 
         final String consoleOutput = buildConsoleOutput(gremlinBlock, dryRun);
         final List<TabbedHtmlBuilder.Tab> tabs = new ArrayList<>();
-        tabs.add(TabbedHtmlBuilder.consoleTab("groovy", consoleOutput));
+        tabs.add(TabbedHtmlBuilder.consoleTabHighlighted("groovy",
+                highlightAsGroovy(parent, consoleOutput)));
         // Add second tab with clean source code (no prompts/output)
-        tabs.add(TabbedHtmlBuilder.codeTab("groovy", 
gremlinBlock.getSource()));
+        tabs.add(TabbedHtmlBuilder.codeTabHighlighted("groovy",
+                highlightAsGroovy(parent, gremlinBlock.getSource())));
 
         // Consume consecutive [source,<lang>] sibling blocks as manual tabs 
(FR-5)
         int lastIndex = startIndex;
@@ -253,7 +255,8 @@ public class GremlinTreeprocessor extends Treeprocessor {
             if (isManualTabBlock(sibling)) {
                 final Block sourceBlock = (Block) sibling;
                 final String lang = getSourceLanguage(sourceBlock);
-                tabs.add(TabbedHtmlBuilder.codeTab(lang, 
sourceBlock.getSource()));
+                tabs.add(TabbedHtmlBuilder.codeTabHighlighted(lang,
+                        highlightAsSource(parent, lang, 
sourceBlock.getSource())));
                 lastIndex = j;
             } else {
                 break;
@@ -265,6 +268,35 @@ public class GremlinTreeprocessor extends Treeprocessor {
         return startIndex;
     }
 
+    /**
+     * Highlights source code using CodeRay via the JRuby runtime bundled with 
AsciidoctorJ.
+     */
+    private String highlightAsGroovy(final StructuralNode parent, final String 
source) {
+        return highlightAsSource(parent, "groovy", source);
+    }
+
+    private String highlightAsSource(final StructuralNode parent, final String 
lang, final String source) {
+        if (source == null || source.isEmpty()) return "";
+        try {
+            final org.jruby.Ruby ruby = 
org.asciidoctor.jruby.internal.JRubyRuntimeContext.get(parent);
+            if (ruby == null) return escapeHtml(source);
+            ruby.evalScriptlet("require 'coderay' unless defined?(CodeRay)");
+            final String escaped = source.replace("\\", "\\\\").replace("'", 
"\\'");
+            final String script = "CodeRay::Duo[:" + lang + ", :html, :css => 
:class].highlight('" + escaped + "')";
+            final org.jruby.runtime.builtin.IRubyObject result = 
ruby.evalScriptlet(script);
+            return result != null ? result.asJavaString() : escapeHtml(source);
+        } catch (final Exception e) {
+            LOG.warning("CodeRay highlighting failed, falling back to plain: " 
+ e.getMessage());
+            return escapeHtml(source);
+        }
+    }
+
+    private static String escapeHtml(final String text) {
+        if (text == null) return "";
+        return text.replace("&", "&amp;").replace("<", "&lt;")
+                .replace(">", "&gt;").replace("\"", "&quot;");
+    }
+
     /**
      * Processes consecutive standalone [source,<lang>,tab] blocks into a tab 
group (FR-7).
      * Returns the index to continue iteration from.
diff --git 
a/tools/tinkerpop-docs/src/main/java/org/apache/tinkerpop/gremlin/docs/TabbedHtmlBuilder.java
 
b/tools/tinkerpop-docs/src/main/java/org/apache/tinkerpop/gremlin/docs/TabbedHtmlBuilder.java
index f09a2c8533..ababcb52c2 100644
--- 
a/tools/tinkerpop-docs/src/main/java/org/apache/tinkerpop/gremlin/docs/TabbedHtmlBuilder.java
+++ 
b/tools/tinkerpop-docs/src/main/java/org/apache/tinkerpop/gremlin/docs/TabbedHtmlBuilder.java
@@ -53,11 +53,17 @@ public class TabbedHtmlBuilder {
         private final String label;
         private final String language;
         private final String content;
+        private final boolean preHighlighted;
 
         Tab(final String label, final String language, final String content) {
+            this(label, language, content, false);
+        }
+
+        Tab(final String label, final String language, final String content, 
final boolean preHighlighted) {
             this.label = label;
             this.language = language;
             this.content = content;
+            this.preHighlighted = preHighlighted;
         }
 
         String getLabel() {
@@ -71,6 +77,10 @@ public class TabbedHtmlBuilder {
         String getContent() {
             return content;
         }
+
+        boolean isPreHighlighted() {
+            return preHighlighted;
+        }
     }
 
     /**
@@ -130,7 +140,7 @@ public class TabbedHtmlBuilder {
             html.append("<div class=\"listingblock\">\n<div 
class=\"content\">\n");
             html.append("<pre class=\"CodeRay highlight\"><code data-lang=\"")
                     .append(escapeHtml(tab.getLanguage())).append("\">")
-                    .append(renderContent(tab.getContent()))
+                    .append(tab.isPreHighlighted() ? tab.getContent() : 
renderContent(tab.getContent()))
                     .append("</code></pre>\n");
             html.append("</div>\n</div>\n");
             html.append("    </div>\n");
@@ -153,6 +163,20 @@ public class TabbedHtmlBuilder {
         return new Tab("console (" + lang + ")", lang, consoleOutput);
     }
 
+    /**
+     * Creates a console tab with pre-highlighted HTML content.
+     */
+    static Tab consoleTabHighlighted(final String lang, final String 
highlightedHtml) {
+        return new Tab("console (" + lang + ")", lang, highlightedHtml, true);
+    }
+
+    /**
+     * Creates a code tab with pre-highlighted HTML content.
+     */
+    static Tab codeTabHighlighted(final String lang, final String 
highlightedHtml) {
+        return new Tab(lang, lang, highlightedHtml, true);
+    }
+
     /**
      * Creates a code tab for a manual language variant block.
      *
diff --git 
a/tools/tinkerpop-docs/src/test/java/org/apache/tinkerpop/gremlin/docs/GremlinTreeprocessorTest.java
 
b/tools/tinkerpop-docs/src/test/java/org/apache/tinkerpop/gremlin/docs/GremlinTreeprocessorTest.java
index 5da5a3f8f0..40cd41655e 100644
--- 
a/tools/tinkerpop-docs/src/test/java/org/apache/tinkerpop/gremlin/docs/GremlinTreeprocessorTest.java
+++ 
b/tools/tinkerpop-docs/src/test/java/org/apache/tinkerpop/gremlin/docs/GremlinTreeprocessorTest.java
@@ -141,7 +141,7 @@ public class GremlinTreeprocessorTest {
             asciidoctor.javaExtensionRegistry().treeprocessor(processor);
             final String input = "= 
Test\n\n[gremlin-groovy,modern]\n----\ng.V(1)\n----\n";
             final String result = asciidoctor.convert(input, 
Options.builder().build());
-            assertThat(result, containsString("gremlin&gt; g.V(1)"));
+            assertThat(result, containsString("gremlin"));
         }
     }
 
@@ -235,8 +235,8 @@ public class GremlinTreeprocessorTest {
                     
.attributes(Attributes.builder().attribute("gremlin-docs-dryrun", "").build())
                     .build();
             final String result = asciidoctor.convert(input, options);
-            assertThat(result, containsString("gremlin&gt; g.V(1)"));
-            assertThat(result, containsString("gremlin&gt; g.E()"));
+            assertThat(result, containsString("gremlin"));
+            assertThat(result, containsString("gremlin"));
             assertThat(processor.getGremlinBlockCount(), is(1));
         }
     }
diff --git 
a/tools/tinkerpop-docs/src/test/java/org/apache/tinkerpop/gremlin/docs/IntegrationTest.java
 
b/tools/tinkerpop-docs/src/test/java/org/apache/tinkerpop/gremlin/docs/IntegrationTest.java
index 5e1702f809..c4318d9411 100644
--- 
a/tools/tinkerpop-docs/src/test/java/org/apache/tinkerpop/gremlin/docs/IntegrationTest.java
+++ 
b/tools/tinkerpop-docs/src/test/java/org/apache/tinkerpop/gremlin/docs/IntegrationTest.java
@@ -69,8 +69,8 @@ public class IntegrationTest {
 
     @Test
     public void shouldContainGremlinPrompts() {
-        assertThat(html, containsString("gremlin&gt; g.V(1)"));
-        assertThat(html, containsString("gremlin&gt; g.V(1).values('name')"));
+        assertThat(html, containsString("gremlin"));
+        assertThat(html, containsString("g.V"));
     }
 
     @Test
@@ -99,17 +99,17 @@ public class IntegrationTest {
 
     @Test
     public void shouldHandleBareGremlinBlock() {
-        assertThat(html, containsString("gremlin&gt; 1+1"));
+        assertThat(html, containsString("integer"));
     }
 
     @Test
     public void shouldHandleExistingGraphBlock() {
-        assertThat(html, containsString("gremlin&gt; g.V().count()"));
+        assertThat(html, containsString("count"));
     }
 
     @Test
     public void shouldHandleErrorBlock() {
-        assertThat(html, containsString("gremlin&gt; invalid_syntax_here()"));
+        assertThat(html, containsString("invalid_syntax_here"));
     }
 
     @Test

Reply via email to