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
commit e7b32f81c2e75a0219ab9f08b8f5213fcf761d70 Author: Paul King <[email protected]> AuthorDate: Tue Jul 15 11:35:30 2025 +1000 fix some edge cases around repl parsing --- .../groovy/org/apache/groovy/groovysh/Main.groovy | 15 ++- .../groovy/groovysh/jline/GroovyCommands.groovy | 139 --------------------- 2 files changed, 12 insertions(+), 142 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 81a590277a..928b9c1f42 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 @@ -180,7 +180,8 @@ class Main { Supplier<Path> workDir = () -> Paths.get(System.getProperty('user.dir')) DefaultParser parser = new DefaultParser( regexCommand: /\/?[a-zA-Z!]+\S*/, - eofOnUnclosedQuote: true + eofOnUnclosedQuote: true, + eofOnEscapedNewLine: true ) parser.blockCommentDelims(new DefaultParser.BlockCommentDelims('/*', '*/')) .lineCommentDelims(new String[]{'//'}) @@ -288,14 +289,22 @@ class Main { println '-' * (terminal.width - 1) // for debugging // def index = 0 -// def lines = ['def x = [5, 6]', 'y = [7, 8]', +// def lines = ['println \\', 'new Date()', // '/q'] // REPL-loop while (true) { try { systemRegistry.cleanUp() // delete temporary variables and reset output streams - String line = reader.readLine("groovy> ") +// for debugging // String line = lines[index++] + String 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 + }.collect {s -> + // repl command parsing assumes whitespace around '=' + s.matches(/[a-zA-Z0-9.]*=\S.*/) ? s.replaceFirst('=', ' = ') : s + }.join('\n') line = parser.getCommand(line).startsWith("/!") ? line.replaceFirst("/!", "/! ") : line if (line.startsWith(':')) { def maybeCmd = line.split()[0].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 b3f8b7b384..804e011827 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 @@ -613,143 +613,4 @@ class GroovyCommands extends JlineCommandRegistry implements CommandRegistry { new OptionCompleter(NullCompleter.INSTANCE, this::compileOptDescs, 1)).tap{strict = false }] } -/* - static class ImportCompleter implements Completer { - - protected final Logger log = Logger.create(ImportCompleter) - - org.apache.groovy.groovysh.util.PackageHelper packageHelper - //Groovysh shell - - / * - * The following rules do not need to work for all thinkable situations, just for all reasonable situations. - * In particular the underscore and dollar signs in Class or method names usually indicate something internal, - * which we intentionally want to hide in tab completion - * / - // matches fully qualified class names with dot at the end - private static final Pattern QUALIFIED_CLASS_DOT_PATTERN = ~/^[a-z_]{1}[a-z0-9_]*(\.[a-z0-9_]*)*\.[A-Z][^.]*\.$/ - // matches empty, package names or fully qualified class names - private static final Pattern PACK_OR_CLASSNAME_PATTERN = ~/^([a-z_]{1}[a-z0-9_]*(\.[a-z0-9_]*)*(\.[A-Z][^.]*)?)?$/ - // matches empty, package names or fully qualified class names without special symbols - private static final Pattern PACK_OR_SIMPLE_CLASSNAME_PATTERN = ~'^([a-z_]{1}[a-z0-9_]*(\\.[a-z0-9_]*)*(\\.[A-Z][^.\$_]*)?)?\$' - // matches empty, package names or fully qualified class names or fully qualified method names - private static final Pattern PACK_OR_CLASS_OR_METHODNAME_PATTERN = ~'^([a-z_]{1}[a-z0-9.]*(\\.[a-z0-9_]*)*(\\.[A-Z][^.\$_]*(\\.[a-zA-Z0-9_]*)?)?)?\$' - private static final Pattern LOWERCASE_IMPORT_ITEM_PATTERN = ~/^[a-z0-9.]+$/ - - final boolean staticImport - final Evaluator interpreter - - - ImportCompleter(final org.apache.groovy.groovysh.util.PackageHelper packageHelper, final Evaluator interp, final boolean staticImport) { - this.packageHelper = packageHelper - this.staticImport = staticImport - this.interpreter = interp - this.shell = shell - } - - @Override - @CompileStatic - void complete(LineReader reader, ParsedLine line, List<Candidate> result) { - def buffer = reader.buffer - def cursor = line.cursor() - String currentImportExpression = buffer ? buffer.substring(0, cursor) : '' - if (staticImport) { - if (!(currentImportExpression.matches(PACK_OR_CLASS_OR_METHODNAME_PATTERN))) { - return - } - } else { - if (!(currentImportExpression.matches(PACK_OR_SIMPLE_CLASSNAME_PATTERN))) { - return - } - } - if (currentImportExpression.contains('..')) { - return - } - - if (currentImportExpression.endsWith('.')) { - // no upper case? - if (currentImportExpression.matches(LOWERCASE_IMPORT_ITEM_PATTERN)) { - Set<String> classnames = packageHelper.getContents(currentImportExpression[0..-2]) - if (classnames) { - if (staticImport) { - addAll(result, classnames.collect{ String it -> it + '.' }) - } else { - addAll(result, classnames.collect({ String it -> addDotOrBlank(it) })) - } - } - if (!staticImport) { - add(result, '* ') - } - return //currentImportExpression.length() - } else if (staticImport && currentImportExpression.matches(QUALIFIED_CLASS_DOT_PATTERN)) { - Class clazz = interpreter.evaluate([currentImportExpression[0..-2]]) as Class - if (clazz != null) { - Collection<ReflectionCompletionCandidate> members = ReflectionCompleter.getPublicFieldsAndMethods(clazz, '') - addAll(result, members.collect({ ReflectionCompletionCandidate it -> it.value.replace('(', '').replace(')', '') + ' ' })) - } - add(result, '* ') - return //currentImportExpression.length() - } - return - } // endif startswith '.', we have a prefix - - String prefix - int lastDot = currentImportExpression.lastIndexOf('.') - if (lastDot == -1) { - prefix = currentImportExpression - } else { - prefix = currentImportExpression.substring(lastDot + 1) - } - String baseString = currentImportExpression.substring(0, Math.max(lastDot, 0)) - - // expression could be for Classname, or for static methodname - if (currentImportExpression.matches(PACK_OR_CLASSNAME_PATTERN)) { - Set<String> candidates = packageHelper.getContents(baseString) - if (candidates == null || candidates.size() == 0) { - // At least give standard package completion, else static keyword is highly annoying - Collection<String> standards = ResolveVisitor.DEFAULT_IMPORTS.findAll({ String it -> it.startsWith(currentImportExpression) }) - if (standards) { - addAll(result, standards) - return //0 - } - return - } - - log.debug(prefix) - Collection<String> matches = candidates.findAll({ String it -> it.startsWith(prefix) }) - if (matches) { - addAll(result, matches.collect({ String it -> addDotOrBlank(it) })) - return //lastDot <= 0 ? 0 : lastDot + 1 - } - } else if (staticImport) { - Class clazz = interpreter.evaluate([baseString]) as Class - if (clazz != null) { - Collection<ReflectionCompletionCandidate> members = ReflectionCompleter.getPublicFieldsAndMethods(clazz, prefix) - if (members) { - addAll(result, members.collect({ ReflectionCompletionCandidate it -> it.value.replace('(', '').replace(')', '') + ' ' })) - return //lastDot <= 0 ? 0 : lastDot + 1 - } - } - } - return - } - - private static void addAll(List<Candidate> result, List<String> strings) { - for (String s : strings) { - result.add(new Candidate(s)) - } - } - - private static void add(List<Candidate> result, String s) { - result.add(new Candidate(s)) - } - - private static String addDotOrBlank(final String it) { - if (it[0] in 'A'..'Z') { - return it + ' ' - } - return it + '.' - } - }*/ - }
