This is an automated email from the ASF dual-hosted git repository. paulk 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 d2ffe2a3bd GROOVY-8162: Update Groovysh to JLine3 (adjust cli params) d2ffe2a3bd is described below commit d2ffe2a3bd7e726a111716a608333c76d2446411 Author: Paul King <pa...@asert.com.au> AuthorDate: Wed Aug 13 08:44:29 2025 +1000 GROOVY-8162: Update Groovysh to JLine3 (adjust cli params) --- .../groovy/org/apache/groovy/groovysh/Main.groovy | 25 ++- .../org/apache/groovy/groovysh/Main.properties | 4 +- .../src/spec/doc/assets/img/repl_evaluate.png | Bin 0 -> 232597 bytes .../groovy-groovysh/src/spec/doc/groovysh.adoc | 210 +++++++-------------- 4 files changed, 98 insertions(+), 141 deletions(-) diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/Main.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/Main.groovy index 25cf7824f0..6e0e3d4cfb 100644 --- a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/Main.groovy +++ b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/Main.groovy @@ -274,6 +274,7 @@ class Main { V(longOpt: 'version', messages['cli.option.version.description']) v(longOpt: 'verbose', messages['cli.option.verbose.description']) q(longOpt: 'quiet', messages['cli.option.quiet.description']) + c(longOpt: 'encoding', args: 1, argName: 'CHARSET', optionalArg: false, messages['cli.option.encoding.description']) d(longOpt: 'debug', messages['cli.option.debug.description']) e(longOpt: 'evaluate', args: 1, argName: 'CODE', optionalArg: false, messages['cli.option.evaluate.description']) C(longOpt: 'color', args: 1, argName: 'FLAG', optionalArg: true, messages['cli.option.color.description']) @@ -298,6 +299,7 @@ class Main { println render(messages.format('cli.info.version', GroovySystem.version)) System.exit(0) } + String evaluate = options.e ?: null try { DefaultParser parser = new DefaultParser( @@ -308,7 +310,18 @@ class Main { parser.blockCommentDelims(new DefaultParser.BlockCommentDelims('/*', '*/')) .lineCommentDelims(new String[]{'//'}) .setEofOnUnclosedBracket(Bracket.CURLY, Bracket.ROUND, Bracket.SQUARE) - Terminal terminal = TerminalBuilder.builder().build() + Terminal terminal = TerminalBuilder.builder().tap{ + if (options.T) { + type(options.T) + } + if (options.c) { + encoding(options.c) + } + if (options.C) { + color(options.C as boolean) + } + name('groovysh') + }.build() if (terminal.width == 0 || terminal.height == 0) { terminal.size = new Size(120, 40) // hard-coded terminal size when redirecting } @@ -418,9 +431,15 @@ class Main { while (true) { try { systemRegistry.cleanUp() // delete temporary variables and reset output streams + String line // for debugging -// String line = lines[index++] - String line = reader.readLine("groovy> ") +// line = lines[index++] + if (evaluate) { + line = evaluate + evaluate = null + } else { + line = reader.readLine("groovy> ") + } line = line.readLines().collect{ s -> // remove Groovy continuation character for repl not Groovy's sake s.endsWith(' \\') ? s[0..-3] : s diff --git a/subprojects/groovy-groovysh/src/main/resources/org/apache/groovy/groovysh/Main.properties b/subprojects/groovy-groovysh/src/main/resources/org/apache/groovy/groovysh/Main.properties index 1087a4f627..f2af46b76f 100644 --- a/subprojects/groovy-groovysh/src/main/resources/org/apache/groovy/groovysh/Main.properties +++ b/subprojects/groovy-groovysh/src/main/resources/org/apache/groovy/groovysh/Main.properties @@ -49,12 +49,14 @@ cli.option.classpath.description=Specify where to find the class files - must be cli.option.color.description=Enable or disable use of ANSI colors +cli.option.encoding.description=The encoding to use + cli.option.define.description=Define a system property cli.option.terminal.description=Specify the terminal TYPE to use cli.option.enable.preview.description=Enable preview Java features (jdk12+ only) - must be after classpath but before other arguments -cli.option.parameters.description=Generate metadata for reflection on method parameter names (jdk8+ only) +cli.option.parameters.description=Generate metadata for reflection on method parameter names cli.info.version=@|red g|@@|yellow r|@@|green oo|@@|cyan v|@@|blue y|@@|magenta sh|@ {0} diff --git a/subprojects/groovy-groovysh/src/spec/doc/assets/img/repl_evaluate.png b/subprojects/groovy-groovysh/src/spec/doc/assets/img/repl_evaluate.png new file mode 100644 index 0000000000..17dc4d739d Binary files /dev/null and b/subprojects/groovy-groovysh/src/spec/doc/assets/img/repl_evaluate.png differ diff --git a/subprojects/groovy-groovysh/src/spec/doc/groovysh.adoc b/subprojects/groovy-groovysh/src/spec/doc/groovysh.adoc index 970a30264f..a22b8139e7 100644 --- a/subprojects/groovy-groovysh/src/spec/doc/groovysh.adoc +++ b/subprojects/groovy-groovysh/src/spec/doc/groovysh.adoc @@ -41,35 +41,39 @@ support and more. [[GroovyShell-Command-lineOptionsandArguments]] === Command-line Options and Arguments -The shell supports several options to control verbosity, ANSI coloring -and other features. +The shell supports several options to control various features. [source,shell] ----------------------------------------------------------------- -./bin/groovysh --help +> groovysh --help Usage: groovysh [options] [...] The Groovy Shell, aka groovysh, is a command-line application which allows easy -access to evaluate Groovy expressions, define classes and run simple -experiments. - -C, --color[=<FLAG>] Enable or disable use of ANSI colors +access to evaluate Groovy expressions, define classes and run simple experiments. + -c, --encoding=<CHARSET> The encoding to use + -C, --color[=<FLAG>] Enable or disable use of ANSI colors -cp, -classpath, --classpath - Specify where to find the class files - must be first - argument - -d, --debug Enable debug output - -D, --define=<name=value> - Define a system property - -e, --evaluate=<CODE> Evaluate the code first when starting interactive session - -h, --help Display this help message - -pa, --parameters Generate metadata for reflection on method parameter names - (jdk8+ only) - -pr, --enable-preview Enable preview Java features (jdk12+ only) - -q, --quiet Suppress superfluous output - -T, --terminal=<TYPE> Specify the terminal TYPE to use - -v, --verbose Enable verbose output - -V, --version Display the version + Specify where to find the class files - must be + first argument + -d, --debug Enable debug output + -D, --define=<name=value> Define a system property + -e, --evaluate=<CODE> Evaluate the code first when starting interactive + session + -h, --help Display this help message + -pa, --parameters Generate metadata for reflection on method + parameter names + -pr, --enable-preview Enable preview Java features (jdk12+ only) - must + be after classpath but before other arguments + -q, --quiet Suppress superfluous output + -T, --terminal=<TYPE> Specify the terminal TYPE to use + -v, --verbose Enable verbose output + -V, --version Display the version ----------------------------------------------------------------- +Here is an example showing the `-q`|`--quiet` and `-e`|`--evaluate` options: + +image:assets/img/repl_evaluate.png[Exception, width=80%] + [[GroovyShell-Model]] === Repl model @@ -112,54 +116,6 @@ The following table summarizes the differences between the two modes: Conceptually, for things that are _remembered_ in the above table, it is as if you included the related code at the start of each of your inputs. -[NOTE] --- -You should treat local variables as if you were using immutable data structures. -An input which mutates a local variable will likely be undone by subsequent statements. -So, you should pick one of the first two styles below. - -In either mode you can use shared variables: -[source,jshell] ----- -groovy> fruit = [] -groovy> fruit << 'peach' -[peach] -groovy> fruit << 'pear' -[peach, pear] -groovy> assert fruit == ['peach', 'pear'] ----- - -Use the `/show` command to see the shared variables. - -Only in interpreter mode: -[source,jshell] ----- -groovy> def noFruit = [] -[] -groovy> def oneFruit = noFruit << 'peach' -[peach] -groovy> def twoFruit = oneFruit << 'pear' -[peach, pear] -groovy> assert twoFruit == ['peach', 'pear'] ----- - -By the time you get to the last statement, the previous three local variable -definitions are remembered, so the assertion will pass. - -Avoid this (relevant to interpreter mode): -[source,jshell] ----- -groovy> def fruit = [] -[] -groovy> fruit << 'peach' -[peach] -groovy> fruit << 'pear' -[pear] -groovy> assert fruit == [] ----- -The `def fruit = []` will be _remembered_ before executing each of the next three statements. --- - The shell also has the concept of the "current buffer". This is the collection of all type, method, imports, and variable definitions. The ordering of these snippets is retained, which is important for the shell, since it is only executing one snippet at a time, @@ -1189,87 +1145,67 @@ image:assets/img/widget2.png[Tailtip,width=80%] You can accept the entire suggestion or a word at a time. Both widgets can be enabled. -[[GroovyShell-register]] -=== Custom commands +[[GroovyShell-Advanced]] +=== Advanced Topics -The `register` command allows you to register custom commands in the shell. For example, writing the following -will register the `Stats` command: +[[GroovyShell-ReplModelDetails]] +==== REPL Model Details ----- -groovy:000> :register Stats ----- +The style of coding you use in a REPL is slightly different from +what you might use in a script. The style you use may also depend on +whether you are using the Groovy Shell in _interpreter mode_ or not. -where the `Stats` class is a class extending the `org.apache.groovy.groovysh.CommandSupport` class. For example: +===== Using binding (shared) variables -[source,groovy] +Regardless of interpreter mode you can use shared variables: +[source,jshell] +---- +groovy> fruit = [] +groovy> fruit << 'peach' +[peach] +groovy> fruit << 'pear' +[peach, pear] +groovy> assert fruit == ['peach', 'pear'] ---- -class Stats extends CommandSupport { - protected Stats(final Groovysh shell) { - super(shell, 'stats', 'T') - } +Use the `/show` command to see the shared variables. - public Object execute(List args) { - println "Free memory: ${Runtime.runtime.freeMemory()}" - } +===== Using local variables -} +You should treat local variables as if you were using immutable data structures. +An input which mutates a local variable will likely be undone by subsequent statements. + +Only in interpreter mode: +[source,jshell] +---- +groovy> def noFruit = [] +[] +groovy> def oneFruit = noFruit << 'peach' +[peach] +groovy> def twoFruit = oneFruit << 'pear' +[peach, pear] +groovy> assert twoFruit == ['peach', 'pear'] ---- -Then the command can be called using: +By the time you get to the last statement, the previous three local variable +definitions are remembered, so the assertion will pass. +Avoid this (relevant to interpreter mode): +[source,jshell] ---- -groovy:000> :stats -stats -Free memory: 139474880 -groovy:000> +groovy> def fruit = [] +[] +groovy> fruit << 'peach' +[peach] +groovy> fruit << 'pear' +[pear] +groovy> assert fruit == [] ---- - -Note that the command class must be found on classpath: you cannot define a new command from within the shell. +The `def fruit = []` will be _remembered_ before executing each of the next three statements. [[GroovyShell-PlatformProblems]] -==== Platform Problems - -[[GroovyShell-ProblemsloadingtheJLineDLL]] -===== Problems loading the JLine DLL - -On Windows, https://github.com/jline/jline2[JLine2] (which is used for the fancy -shell input/history/completion fluff), uses a *tiny* DLL file to trick -the *evil* Windows faux-shell (`CMD.EXE` or `COMMAND.COM`) into -providing Java with unbuffered input. In some rare cases, this might -fail to load or initialize. - -One solution is to disable the frills and use the unsupported terminal -instance. You can do that on the command-line using the `--terminal` -flag and set it to one of: - -* `none` -* `false` -* `off` -* `jline.UnsupportedTerminal` - ------------------------- -groovysh --terminal=none ------------------------- - -[[GroovyShell-ProblemswithCygwinonWindows]] -===== Problems with Cygwin on Windows - -Some people have issues when running groovysh with cygwin. If you have -troubles, the following may help: - ------------------------- -stty -icanon min 1 -echo -groovysh --terminal=unix -stty icanon echo ------------------------- - -[[GroovyShell-GMavenPlus]] -== GMavenPlus Maven Plugin -https://github.com/groovy/GMavenPlus[GMavenPlus] is a Maven plugin with goals -that support launching a Groovy Shell or Groovy Console bound to a Maven -project. - -[[GroovyShell-GradleGroovyshPlugin]] -== Gradle Groovysh Plugin -https://github.com/tkruse/gradle-groovysh-plugin[Gradle Groovysh Plugin] is a Gradle plugin that provides gradle tasks to start a Groovy Shell bound to a Gradle project. +=== Platform Problems + +The Groovy Shell relies heavily on the JLine3 library for its platform +support. If you have specific platform problems, please refer to the +JLine documentation.