This is an automated email from the ASF dual-hosted git repository. paulk pushed a commit to branch GROOVY_5_0_X in repository https://gitbox.apache.org/repos/asf/groovy.git
commit b456c608a789790974e554c451692a6a6e28b233 Author: Paul King <[email protected]> AuthorDate: Thu Oct 23 12:10:46 2025 +1000 GROOVY-11791: Support unquoted URLs in groovysh --- .../groovy/org/apache/groovy/groovysh/Main.groovy | 3 ++- .../groovy/groovysh/jline/GroovyCommands.groovy | 25 +++++++++++++--------- .../apache/groovy/groovysh/jline/GroovyEngine.java | 3 ++- .../src/main/resources/nanorc/groovy.nanorc | 5 +++-- 4 files changed, 22 insertions(+), 14 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 cca9464657..1aa8308cc2 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 @@ -471,8 +471,9 @@ class Main { line = line.readLines().collect{ s -> // remove Groovy continuation character for repl not Groovy's sake s.endsWith(' \\') ? s[0..-3] : s - }.join('\n') + }.join('\n').replaceAll($/(/[a-z]+\s+)(https?://\S+)/$, '$1"$2"') // quote URLs after commands if (line.startsWith(':')) { + // some simple legacy support for ':' commands def maybeCmd = line.split()[0].replaceFirst(':', '/') if (systemRegistry.hasCommand(maybeCmd) || systemRegistry.isCommandAlias(maybeCmd)) { line = line.replaceFirst(':', '/') diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/jline/GroovyCommands.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/jline/GroovyCommands.groovy index 75929369e0..d5e6693c70 100644 --- a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/jline/GroovyCommands.groovy +++ b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/jline/GroovyCommands.groovy @@ -376,7 +376,9 @@ class GroovyCommands extends JlineCommandRegistry implements CommandRegistry { try { path = workDir.get().resolve(arg) } catch(Exception ignore) { } + Reader source = null if (path && Files.exists(path)) { + source = Files.newBufferedReader(path, encoding) if (!format) { def ext = path.extension if (ext.equalsIgnoreCase('json')) { @@ -397,23 +399,26 @@ class GroovyCommands extends JlineCommandRegistry implements CommandRegistry { format = 'TEXT' } } + } + if (!source && (arg.startsWith('http://') || arg.startsWith('https://'))) { + URL url = new URL(arg) + source = new InputStreamReader(url.openStream(), encoding) + } + if (source) { if (format == 'TEXT') { - out = Files.readAllLines(path, encoding) + out = source.readLines() } else if (format in engine.deserializationFormats) { - byte[] encoded = Files.readAllBytes(path) - out = engine.deserialize(new String(encoded, encoding), format) + out = engine.deserialize(source.text, format) } else if (format in slurpers.keySet()) { def parser = getParser(format, slurpers[format]) - out = parser.parse(path) + out = parser.parse(source) } else if (format == 'CSV') { def parser = getCsvParser(format) - out = parser.parse(path.newReader(encoding.displayName())).toList()*.toMap() + out = parser.parse(source).toList()*.toMap() } else if (format == 'PROPERTIES') { - out = path.withInputStream{ is -> - new Properties().tap {load(is) } - } + out = new Properties().tap {load(source) } } else { - out = engine.deserialize(Files.readString(path, encoding), 'NONE') + out = engine.deserialize(source.text, 'AUTO') } } else { if (format == 'TEXT') { @@ -427,7 +432,7 @@ class GroovyCommands extends JlineCommandRegistry implements CommandRegistry { def parser = getCsvParser(format) out = parser.parse(new StringReader(arg)).toList()*.toMap() } else { - out = engine.deserialize(arg, 'NONE') + out = engine.deserialize(arg, 'AUTO') } } } catch (Exception ignore) { diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/jline/GroovyEngine.java b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/jline/GroovyEngine.java index 3117c22744..aecfa63e9d 100644 --- a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/jline/GroovyEngine.java +++ b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/jline/GroovyEngine.java @@ -90,7 +90,8 @@ public class GroovyEngine implements ScriptEngine { public enum Format { JSON, GROOVY, - NONE + NONE, + AUTO } public static final String CANONICAL_NAMES = "canonicalNames"; diff --git a/subprojects/groovy-groovysh/src/main/resources/nanorc/groovy.nanorc b/subprojects/groovy-groovysh/src/main/resources/nanorc/groovy.nanorc index c4d570877e..557f54cb3f 100644 --- a/subprojects/groovy-groovysh/src/main/resources/nanorc/groovy.nanorc +++ b/subprojects/groovy-groovysh/src/main/resources/nanorc/groovy.nanorc @@ -19,7 +19,8 @@ TYPE: "\<(boolean|byte|char|def|double|float|int|it|long|new|short|this|t KEYWORD: "\<(case|catch|default|do|else|finally|for|if|return|switch|throw|try|while)\>" KEYWORD: "\<(abstract|class|extends|final|implements|import|instanceof|interface|native|non-sealed|package)\>" KEYWORD: "\<(permits|private|protected|public|record|sealed|static|strictfp|super|synchronized|throws|trait|volatile)\>" -PACKAGE: "(([a-z0-9]{2,}[.]{1}){2,10}([a-z0-9]{2,}){0,1})" +PATH: "\<https?://\S*\>" +PACKAGE: "(?<!://\w{0,99})(([a-z0-9]{2,}[.]{1}){2,10}([a-z0-9]{2,}){0,1})" CLASS: "\<[A-Z]{0,2}([A-Z]{1}[a-z0-9]+){1,}\>" # Annotation @@ -37,7 +38,7 @@ OPERATOR: "[-+/*=<>?:!~%&|]" ~NUMBER: "\b-?(([1-9][0-9_]*)|0)\.[0-9_e]+[dfg]?\b" "\b-?([1-9][0-9_]*)?[0-9][ilg]?\b" "\b0[0-7_]*[ilg]?\b" "\b0x([1-9a-f][0-9a-f_]*)?[0-9a-f][lg]?\b" "\b0b([01][01_]*)?[01]\b" #STRING: "['][^']*[^\\][']" "[']{3}.*[^\\][']{3}" $BALANCED_DELIMITERS: """", ''', ', "" -$LINE_COMMENT: "//" +$LINE_COMMENT: "(?<!:)//" $BLOCK_COMMENT: "/*, */" REGEXP: "~/[^/]*/"
