This is an automated email from the ASF dual-hosted git repository.
paulk-asert pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/master by this push:
new 620aa3171b groovysh additional tests (cont'd)
620aa3171b is described below
commit 620aa3171b174329c8c5ec6bd04893e496d7e7e3
Author: Paul King <[email protected]>
AuthorDate: Sat May 9 11:30:17 2026 +1000
groovysh additional tests (cont'd)
---
.agents/skills/groovysh/SKILL.md | 11 +++
.../groovy/groovysh/jline/GroovyBuiltins.groovy | 2 +-
.../groovy/groovysh/jline/GroovyPosixCommands.java | 6 +-
.../groovysh/jline/GroovyPosixContext.groovy | 13 +++-
.../groovy-groovysh/src/spec/doc/groovysh.adoc | 43 +++++++++++
.../groovysh/jline/GroovyPosixContextTest.groovy | 90 ++++++++++++++++++++++
6 files changed, 162 insertions(+), 3 deletions(-)
diff --git a/.agents/skills/groovysh/SKILL.md b/.agents/skills/groovysh/SKILL.md
index 831e8b19a0..534146ad34 100644
--- a/.agents/skills/groovysh/SKILL.md
+++ b/.agents/skills/groovysh/SKILL.md
@@ -123,6 +123,17 @@ demonstrates the property under test:
The no-arg `/save` form is a separate path that JSON-serialises
`engine.sharedData` and *does* include variables. Round-trip tests
for the file-form should exercise definitions, not bare variables.
+10. **`Less` and other highlight-aware JLine constructors silently
+ no-op highlighting if `ConfigurationPath` is omitted.** `Less` has
+ both 3-arg `(terminal, dir, opt)` and 4-arg
+ `(terminal, dir, opt, configPath)` constructors; the shorter form
+ compiles without warning but produces plain-text output. When
+ forking or wrapping these commands, plumb `configPath` through and
+ verify with a round-trip test (e.g. `GroovyPosixContextTest`). User-
+ visible symptom: plain text where coloured tokens are expected. We
+ hit this with `/less` after forking `PosixCommands`; `/nano` stayed
+ correct because it routes through `Commands.nano(...)`, which takes
+ `configPath` as a required argument.
(Locale/platform/format brittleness is covered by the project-wide
[`groovy-tests`](../groovy-tests/SKILL.md) skill — it's not unique to
diff --git
a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/jline/GroovyBuiltins.groovy
b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/jline/GroovyBuiltins.groovy
index 93c99d57ba..9f200f73a6 100644
---
a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/jline/GroovyBuiltins.groovy
+++
b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/jline/GroovyBuiltins.groovy
@@ -82,7 +82,7 @@ class GroovyBuiltins extends Builtins {
temp.text = engine.buffer
input = new CommandInput(input.command(), [*input.args(),
temp.absolutePath] as String[], input.terminal(), input.in(), input.out(),
input.err())
}
- GroovyPosixCommands.less(new GroovyPosixContext(input.in(), new
PrintStream(input.out()), new PrintStream(input.err()), workDir.get(),
input.terminal(), engine::get), ['/less', *input.args()] as String[])
+ GroovyPosixCommands.less(new GroovyPosixContext(input.in(), new
PrintStream(input.out()), new PrintStream(input.err()), workDir.get(),
input.terminal(), engine::get, configPath), ['/less', *input.args()] as
String[])
} catch (Exception e) {
saveException(e)
}
diff --git
a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/jline/GroovyPosixCommands.java
b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/jline/GroovyPosixCommands.java
index a8442c8528..1aa005dd6b 100644
---
a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/jline/GroovyPosixCommands.java
+++
b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/jline/GroovyPosixCommands.java
@@ -27,6 +27,7 @@
package org.apache.groovy.groovysh.jline;
import org.codehaus.groovy.runtime.ArrayGroovyMethods;
+import org.jline.builtins.ConfigurationPath;
import org.jline.builtins.Less;
import org.jline.builtins.Options;
import org.jline.builtins.PosixCommands.Context;
@@ -1136,7 +1137,10 @@ public class GroovyPosixCommands {
return;
}
- Less less = new Less(context.terminal(), context.currentDir(), opt);
+ ConfigurationPath cfg = (context instanceof GroovyPosixContext)
+ ? ((GroovyPosixContext) context).getConfigPath()
+ : null;
+ Less less = new Less(context.terminal(), context.currentDir(), opt,
cfg);
less.run(sources);
}
diff --git
a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/jline/GroovyPosixContext.groovy
b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/jline/GroovyPosixContext.groovy
index b2a2279425..a59a8717da 100644
---
a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/jline/GroovyPosixContext.groovy
+++
b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/jline/GroovyPosixContext.groovy
@@ -18,6 +18,7 @@
*/
package org.apache.groovy.groovysh.jline
+import org.jline.builtins.ConfigurationPath
import org.jline.builtins.PosixCommands
import org.jline.terminal.Terminal
@@ -30,6 +31,12 @@ import java.util.function.Function
class GroovyPosixContext extends PosixCommands.Context {
/** Current working directory exposed to groovysh POSIX commands. */
Path currentDir
+ /**
+ * Configuration path used to locate {@code jnanorc} and theme files for
+ * commands that integrate with the JLine syntax-highlighter (e.g. {@code
/less}).
+ * Optional; null disables highlighting.
+ */
+ ConfigurationPath configPath
/**
* Creates a POSIX command context backed by groovysh state.
@@ -40,10 +47,14 @@ class GroovyPosixContext extends PosixCommands.Context {
* @param currentDir current working directory
* @param terminal active terminal
* @param variables variable lookup function
+ * @param configPath configuration path used by syntax-highlighting
commands; null disables highlighting
*/
- GroovyPosixContext(InputStream inputStream, PrintStream out, PrintStream
err, Path currentDir, Terminal terminal, Function<String, Object> variables) {
+ GroovyPosixContext(InputStream inputStream, PrintStream out, PrintStream
err, Path currentDir,
+ Terminal terminal, Function<String, Object> variables,
+ ConfigurationPath configPath = null) {
super(inputStream, out, err, null, terminal, variables)
this.currentDir = currentDir
+ this.configPath = configPath
}
/**
diff --git a/subprojects/groovy-groovysh/src/spec/doc/groovysh.adoc
b/subprojects/groovy-groovysh/src/spec/doc/groovysh.adoc
index b222f49047..e53a5522c4 100644
--- a/subprojects/groovy-groovysh/src/spec/doc/groovysh.adoc
+++ b/subprojects/groovy-groovysh/src/spec/doc/groovysh.adoc
@@ -586,6 +586,49 @@ apple
banana
----
+[[GroovyShell-highlighter]]
+==== `/highlighter`
+
+The `/highlighter` command manages the nanorc theme system. Useful options
+include `--list` (show available themes), `--view=THEME` (preview a theme),
+`--switch=THEME` (change the active theme by rewriting your user-config
+`jnanorc`), and `--refresh` (reapply highlighting after a switch).
+
+Note: `--view` and `--switch` take *full filenames including the
+`.nanorctheme` extension*, not bare theme names. `/highlighter --list`
+shows the canonical form:
+
+[source,jshell]
+----
+groovy> /highlighter --list
+/Users/<you>/.groovy:
+dark.nanorctheme
+light.nanorctheme
+groovy> /highlighter --switch=light.nanorctheme
+groovy> /highlighter --refresh
+----
+
+Theme switching operates on user-config copies of `jnanorc` (used by the
+line reader and most commands) *and* `jlessrc` (used by `/less`); if a
+file is missing, that path silently no-ops on `--switch`. So a partial
+setup with only `jnanorc` will switch the prompt highlighting but leave
+`/less` permanently on whichever theme the classpath copy of `jlessrc`
+ships with.
+
+Once you create user-config copies, JLine resolves both the `theme`
+directive and the `include *.nanorc` entries *relative to the user-config
+directory* — the classpath copies are no longer consulted. So you also
+need the per-language syntax files (`groovy.nanorc`, `java.nanorc`,
+`json.nanorc`, `xml.nanorc`, `yaml.nanorc`, etc.) in the same directory,
+or you'll see the theme palette loaded but no actual highlighting (every
+file rendered as plain text). Easiest setup is to copy the entire
+`nanorc/` resource directory in one go:
+
+[source,bash]
+----
+cp <groovysh-src>/src/main/resources/nanorc/* ~/.groovy/
+----
+
[[GroovyShell-history]]
==== `/history`
diff --git
a/subprojects/groovy-groovysh/src/test/groovy/org/apache/groovy/groovysh/jline/GroovyPosixContextTest.groovy
b/subprojects/groovy-groovysh/src/test/groovy/org/apache/groovy/groovysh/jline/GroovyPosixContextTest.groovy
new file mode 100644
index 0000000000..a32d59a868
--- /dev/null
+++
b/subprojects/groovy-groovysh/src/test/groovy/org/apache/groovy/groovysh/jline/GroovyPosixContextTest.groovy
@@ -0,0 +1,90 @@
+/*
+ * 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.groovy.groovysh.jline
+
+import org.jline.builtins.ConfigurationPath
+import org.jline.terminal.Terminal
+import org.jline.terminal.TerminalBuilder
+import org.junit.jupiter.api.AfterEach
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+
+import java.nio.charset.StandardCharsets
+import java.nio.file.Files
+import java.nio.file.Path
+import java.util.function.Function
+
+/**
+ * Tests for {@link GroovyPosixContext}'s {@code configPath} plumbing — the
+ * field that {@link GroovyPosixCommands#less} reads to wire JLine's
+ * syntax-highlighter into {@code /less}. A regression here surfaces as
+ * {@code /less} losing colour rendering, which is silent (no error, just
+ * plain text).
+ */
+class GroovyPosixContextTest {
+
+ private Terminal terminal
+ private Path tmpDir
+
+ @BeforeEach
+ void setUp() {
+ terminal = TerminalBuilder.builder()
+ .dumb(true)
+ .streams(new ByteArrayInputStream(new byte[0]), new
ByteArrayOutputStream())
+ .encoding(StandardCharsets.UTF_8)
+ .name('groovysh-test')
+ .build()
+ tmpDir = Files.createTempDirectory('groovysh-context-')
+ }
+
+ @AfterEach
+ void tearDown() {
+ terminal?.close()
+ tmpDir?.toFile()?.deleteDir()
+ }
+
+ private GroovyPosixContext context(ConfigurationPath cfg = null) {
+ new GroovyPosixContext(
+ new ByteArrayInputStream(new byte[0]),
+ new PrintStream(new ByteArrayOutputStream(), true,
StandardCharsets.UTF_8),
+ new PrintStream(new ByteArrayOutputStream(), true,
StandardCharsets.UTF_8),
+ tmpDir,
+ terminal,
+ { name -> null } as Function<String, Object>,
+ cfg)
+ }
+
+ @Test
+ void configPathDefaultsToNull() {
+ // Backward-compatible 6-arg constructor: callers that don't need
+ // syntax highlighting (most posix commands) keep working.
+ def ctx = context()
+ assert ctx.configPath == null
+ }
+
+ @Test
+ void configPathRoundTrips() {
+ // The 7-arg constructor is the path /less now uses; verify the
+ // ConfigurationPath survives construction so GroovyPosixCommands.less
+ // can hand it to the JLine Less constructor for highlighting.
+ ConfigurationPath cfg = new ConfigurationPath(tmpDir, tmpDir)
+ def ctx = context(cfg)
+ assert ctx.configPath.is(cfg)
+ }
+}