You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by pa...@apache.org on 2019/07/30 23:24:50 UTC
[groovy] branch master updated: GROOVY-9208: Adapt the groovysh
with the new parser Parrot (closes #983)
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 faa80fd GROOVY-9208: Adapt the groovysh with the new parser Parrot (closes #983)
faa80fd is described below
commit faa80fdfcbade6fb0f6df4a5ad03368dd495d23b
Author: Paul King <pa...@asert.com.au>
AuthorDate: Wed Jul 24 21:51:09 2019 +1000
GROOVY-9208: Adapt the groovysh with the new parser Parrot (closes #983)
---
.../groovy/groovysh/InteractiveShellRunner.groovy | 50 ++++--
.../completion/CustomClassSyntaxCompleter.groovy | 1 +
.../completion/GroovySyntaxCompleter.groovy | 1 +
.../groovysh/completion/IdentifierCompleter.groovy | 1 +
.../completion/ImportsSyntaxCompleter.groovy | 1 +
.../completion/InfixKeywordSyntaxCompleter.groovy | 3 +-
.../completion/KeywordSyntaxCompleter.groovy | 1 +
.../groovysh/completion/ReflectionCompleter.groovy | 1 +
.../completion/VariableSyntaxCompleter.groovy | 1 +
.../{ => antlr4}/CustomClassSyntaxCompleter.groovy | 6 +-
.../{ => antlr4}/GroovySyntaxCompleter.groovy | 186 +++++++++----------
.../{ => antlr4}/IdentifierCompleter.groovy | 6 +-
.../{ => antlr4}/ImportsSyntaxCompleter.groovy | 7 +-
.../InfixKeywordSyntaxCompleter.groovy | 10 +-
.../{ => antlr4}/KeywordSyntaxCompleter.groovy | 8 +-
.../{ => antlr4}/ReflectionCompleter.groovy | 200 ++++++++++++++-------
.../{ => antlr4}/VariableSyntaxCompleter.groovy | 6 +-
.../tools/shell/InteractiveShellRunner.groovy | 1 +
18 files changed, 298 insertions(+), 192 deletions(-)
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/InteractiveShellRunner.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/InteractiveShellRunner.groovy
index 80e385c..fdb446e 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/InteractiveShellRunner.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/InteractiveShellRunner.groovy
@@ -23,17 +23,19 @@ import jline.console.completer.AggregateCompleter
import jline.console.completer.CandidateListCompletionHandler
import jline.console.completer.CompletionHandler
import jline.console.history.FileHistory
-import org.apache.groovy.groovysh.completion.CustomClassSyntaxCompleter
import org.apache.groovy.groovysh.completion.FileNameCompleter
-import org.apache.groovy.groovysh.completion.GroovySyntaxCompleter
-import org.apache.groovy.groovysh.completion.ImportsSyntaxCompleter
-import org.apache.groovy.groovysh.completion.KeywordSyntaxCompleter
-import org.apache.groovy.groovysh.completion.ReflectionCompleter
-import org.apache.groovy.groovysh.completion.VariableSyntaxCompleter
+//import org.apache.groovy.groovysh.completion.GroovySyntaxCompleter
+//import org.apache.groovy.groovysh.completion.ImportsSyntaxCompleter
+//import org.apache.groovy.groovysh.completion.KeywordSyntaxCompleter
+//import org.apache.groovy.groovysh.completion.ReflectionCompleter
+//import org.apache.groovy.groovysh.completion.VariableSyntaxCompleter
import org.apache.groovy.groovysh.util.WrappedInputStream
+import org.codehaus.groovy.tools.shell.IO
import org.codehaus.groovy.tools.shell.util.Logger
import org.codehaus.groovy.tools.shell.util.Preferences
+import static org.apache.groovy.util.SystemUtil.getSystemPropertySafe
+
/**
* Support for running a {@link Shell} interactively using the JLine library.
*/
@@ -68,16 +70,36 @@ class InteractiveShellRunner extends ShellRunner implements Runnable {
this.completer = new CommandsMultiCompleter()
reader.addCompleter(this.completer)
- CustomClassSyntaxCompleter classnameCompleter = new CustomClassSyntaxCompleter(shell)
+ def antlr4 = Boolean.parseBoolean(getSystemPropertySafe("groovy.antlr4", "true"))
+
+ def reflectionCompleter = antlr4 ?
+ new org.apache.groovy.groovysh.completion.antlr4.ReflectionCompleter(shell) :
+ new org.apache.groovy.groovysh.completion.ReflectionCompleter(shell)
- reader.addCompleter(new GroovySyntaxCompleter(shell,
- new ReflectionCompleter(shell),
+ def classnameCompleter = antlr4 ?
+ new org.apache.groovy.groovysh.completion.antlr4.CustomClassSyntaxCompleter(shell) :
+ new org.apache.groovy.groovysh.completion.CustomClassSyntaxCompleter(shell)
+
+ def identifierCompleters = antlr4 ? [
+ new org.apache.groovy.groovysh.completion.antlr4.KeywordSyntaxCompleter(),
+ new org.apache.groovy.groovysh.completion.antlr4.VariableSyntaxCompleter(shell),
+ classnameCompleter,
+ new org.apache.groovy.groovysh.completion.antlr4.ImportsSyntaxCompleter(shell),
+ ] : [
+ new org.apache.groovy.groovysh.completion.KeywordSyntaxCompleter(),
+ new org.apache.groovy.groovysh.completion.VariableSyntaxCompleter(shell),
classnameCompleter,
- [new KeywordSyntaxCompleter(),
- new VariableSyntaxCompleter(shell),
- classnameCompleter,
- new ImportsSyntaxCompleter(shell)],
- new FileNameCompleter(false)))
+ new org.apache.groovy.groovysh.completion.ImportsSyntaxCompleter(shell),
+ ]
+
+ def filenameCompleter = new FileNameCompleter(false)
+
+ def completerArgs = [shell, reflectionCompleter, classnameCompleter, identifierCompleters, filenameCompleter]
+
+ reader.addCompleter(antlr4 ?
+ new org.apache.groovy.groovysh.completion.antlr4.GroovySyntaxCompleter(*completerArgs) :
+ new org.apache.groovy.groovysh.completion.GroovySyntaxCompleter(*completerArgs)
+ )
}
@Override
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/CustomClassSyntaxCompleter.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/CustomClassSyntaxCompleter.groovy
index 07efae7..e26657c 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/CustomClassSyntaxCompleter.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/CustomClassSyntaxCompleter.groovy
@@ -24,6 +24,7 @@ import org.codehaus.groovy.antlr.GroovySourceToken
/**
* Completer completing classes defined in the shell
*/
+@Deprecated
class CustomClassSyntaxCompleter implements IdentifierCompleter {
private final Groovysh shell
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/GroovySyntaxCompleter.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/GroovySyntaxCompleter.groovy
index a8179aa..3d383a4 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/GroovySyntaxCompleter.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/GroovySyntaxCompleter.groovy
@@ -63,6 +63,7 @@ import static org.codehaus.groovy.antlr.parser.GroovyTokenTypes.SPREAD_DOT
* Implements the Completer interface to provide completions for
* GroovyShell by tokenizing the buffer and invoking other classes depending on the tokens found.
*/
+@Deprecated
class GroovySyntaxCompleter implements Completer {
protected final static Logger LOG = Logger.create(GroovySyntaxCompleter)
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/IdentifierCompleter.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/IdentifierCompleter.groovy
index c2d7042..2541618 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/IdentifierCompleter.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/IdentifierCompleter.groovy
@@ -25,6 +25,7 @@ import org.codehaus.groovy.antlr.GroovySourceToken
* (Class, variable, keyword, method, ...)
* Similar to JLine Completer, but adapted for usage in GroovySyntaxCompleter
*/
+@Deprecated
interface IdentifierCompleter {
/**
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/ImportsSyntaxCompleter.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/ImportsSyntaxCompleter.groovy
index b4a77f7..410b4c7 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/ImportsSyntaxCompleter.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/ImportsSyntaxCompleter.groovy
@@ -25,6 +25,7 @@ import org.codehaus.groovy.control.ResolveVisitor
/**
* Completer completing imported classnames
*/
+@Deprecated
class ImportsSyntaxCompleter implements IdentifierCompleter {
final Groovysh shell
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/InfixKeywordSyntaxCompleter.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/InfixKeywordSyntaxCompleter.groovy
index 8780ca4..ab72c3c 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/InfixKeywordSyntaxCompleter.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/InfixKeywordSyntaxCompleter.groovy
@@ -23,6 +23,7 @@ import org.codehaus.groovy.antlr.GroovySourceToken
/**
* Completer completing groovy keywords that appear after identifiers
*/
+@Deprecated
class InfixKeywordSyntaxCompleter implements IdentifierCompleter {
// INFIX keywords can only occur after identifiers
@@ -31,7 +32,7 @@ class InfixKeywordSyntaxCompleter implements IdentifierCompleter {
'instanceof',
'extends',
'implements',
- ]
+ ]
@Override
boolean complete(final List<GroovySourceToken> tokens, final List<CharSequence> candidates) {
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/KeywordSyntaxCompleter.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/KeywordSyntaxCompleter.groovy
index bcfaa3c..9251b78 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/KeywordSyntaxCompleter.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/KeywordSyntaxCompleter.groovy
@@ -23,6 +23,7 @@ import org.codehaus.groovy.antlr.GroovySourceToken
/**
* Completer completing Groovy keywords and special functions
*/
+@Deprecated
class KeywordSyntaxCompleter implements IdentifierCompleter {
private static final String[] KEYWORDS = [
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/ReflectionCompleter.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/ReflectionCompleter.groovy
index 023309b..af23e2a 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/ReflectionCompleter.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/ReflectionCompleter.groovy
@@ -37,6 +37,7 @@ import java.util.regex.Pattern
* Does not quite respect the contract of IdentifierCompleter, as last Token may be a dot or not,
* thus also returns as int the cursor position.
*/
+@Deprecated
class ReflectionCompleter implements GroovyTokenTypes {
private static final NavigablePropertiesCompleter PROPERTIES_COMPLETER = new NavigablePropertiesCompleter()
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/VariableSyntaxCompleter.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/VariableSyntaxCompleter.groovy
index edd339c..6d1743a 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/VariableSyntaxCompleter.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/VariableSyntaxCompleter.groovy
@@ -25,6 +25,7 @@ import org.codehaus.groovy.runtime.MethodClosure
/**
* Completer completing variable and method names from known variables in the shell
*/
+@Deprecated
class VariableSyntaxCompleter implements IdentifierCompleter {
final Groovysh shell
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/CustomClassSyntaxCompleter.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/antlr4/CustomClassSyntaxCompleter.groovy
similarity index 89%
copy from subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/CustomClassSyntaxCompleter.groovy
copy to subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/antlr4/CustomClassSyntaxCompleter.groovy
index 07efae7..4577b9c 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/CustomClassSyntaxCompleter.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/antlr4/CustomClassSyntaxCompleter.groovy
@@ -16,10 +16,10 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.groovy.groovysh.completion
+package org.apache.groovy.groovysh.completion.antlr4
+import org.antlr.v4.runtime.Token
import org.apache.groovy.groovysh.Groovysh
-import org.codehaus.groovy.antlr.GroovySourceToken
/**
* Completer completing classes defined in the shell
@@ -33,7 +33,7 @@ class CustomClassSyntaxCompleter implements IdentifierCompleter {
}
@Override
- boolean complete(final List<GroovySourceToken> tokens, final List<CharSequence> candidates) {
+ boolean complete(final List<Token> tokens, final List<CharSequence> candidates) {
String prefix = tokens.last().text
boolean foundMatch = false
Class[] classes = shell.interp.classLoader.loadedClasses
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/GroovySyntaxCompleter.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/antlr4/GroovySyntaxCompleter.groovy
similarity index 68%
copy from subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/GroovySyntaxCompleter.groovy
copy to subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/antlr4/GroovySyntaxCompleter.groovy
index a8179aa..d1b5a1e 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/GroovySyntaxCompleter.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/antlr4/GroovySyntaxCompleter.groovy
@@ -16,48 +16,48 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.groovy.groovysh.completion
+package org.apache.groovy.groovysh.completion.antlr4
-import antlr.TokenStreamException
import groovy.transform.TupleConstructor
import jline.console.completer.Completer
import jline.internal.Configuration
+import org.antlr.v4.runtime.CharStream
+import org.antlr.v4.runtime.CharStreams
+import org.antlr.v4.runtime.CommonTokenStream
+import org.antlr.v4.runtime.ConsoleErrorListener
+import org.antlr.v4.runtime.Token
import org.apache.groovy.groovysh.CommandRegistry
import org.apache.groovy.groovysh.Groovysh
-import org.codehaus.groovy.antlr.GroovySourceToken
-import org.codehaus.groovy.antlr.SourceBuffer
-import org.codehaus.groovy.antlr.UnicodeEscapingReader
-import org.codehaus.groovy.antlr.parser.GroovyLexer
+import org.apache.groovy.groovysh.completion.BackslashEscapeCompleter
+import org.apache.groovy.groovysh.completion.FileNameCompleter
+import org.apache.groovy.parser.antlr4.GroovyLangLexer
import org.codehaus.groovy.tools.shell.util.Logger
-import static org.codehaus.groovy.antlr.parser.GroovyTokenTypes.DOT
-import static org.codehaus.groovy.antlr.parser.GroovyTokenTypes.EOF
-import static org.codehaus.groovy.antlr.parser.GroovyTokenTypes.IDENT
-import static org.codehaus.groovy.antlr.parser.GroovyTokenTypes.LITERAL_as
-import static org.codehaus.groovy.antlr.parser.GroovyTokenTypes.LITERAL_boolean
-import static org.codehaus.groovy.antlr.parser.GroovyTokenTypes.LITERAL_byte
-import static org.codehaus.groovy.antlr.parser.GroovyTokenTypes.LITERAL_catch
-import static org.codehaus.groovy.antlr.parser.GroovyTokenTypes.LITERAL_char
-import static org.codehaus.groovy.antlr.parser.GroovyTokenTypes.LITERAL_class
-import static org.codehaus.groovy.antlr.parser.GroovyTokenTypes.LITERAL_def
-import static org.codehaus.groovy.antlr.parser.GroovyTokenTypes.LITERAL_double
-import static org.codehaus.groovy.antlr.parser.GroovyTokenTypes.LITERAL_enum
-import static org.codehaus.groovy.antlr.parser.GroovyTokenTypes.LITERAL_false
-import static org.codehaus.groovy.antlr.parser.GroovyTokenTypes.LITERAL_finally
-import static org.codehaus.groovy.antlr.parser.GroovyTokenTypes.LITERAL_float
-import static org.codehaus.groovy.antlr.parser.GroovyTokenTypes.LITERAL_import
-import static org.codehaus.groovy.antlr.parser.GroovyTokenTypes.LITERAL_instanceof
-import static org.codehaus.groovy.antlr.parser.GroovyTokenTypes.LITERAL_int
-import static org.codehaus.groovy.antlr.parser.GroovyTokenTypes.LITERAL_interface
-import static org.codehaus.groovy.antlr.parser.GroovyTokenTypes.LITERAL_long
-import static org.codehaus.groovy.antlr.parser.GroovyTokenTypes.LITERAL_package
-import static org.codehaus.groovy.antlr.parser.GroovyTokenTypes.LITERAL_short
-import static org.codehaus.groovy.antlr.parser.GroovyTokenTypes.LITERAL_this
-import static org.codehaus.groovy.antlr.parser.GroovyTokenTypes.LITERAL_true
-import static org.codehaus.groovy.antlr.parser.GroovyTokenTypes.LITERAL_try
-import static org.codehaus.groovy.antlr.parser.GroovyTokenTypes.LITERAL_void
-import static org.codehaus.groovy.antlr.parser.GroovyTokenTypes.OPTIONAL_DOT
-import static org.codehaus.groovy.antlr.parser.GroovyTokenTypes.SPREAD_DOT
+import static org.apache.groovy.parser.antlr4.GroovyLexer.AS
+import static org.apache.groovy.parser.antlr4.GroovyLexer.BooleanLiteral
+import static org.apache.groovy.parser.antlr4.GroovyLexer.BuiltInPrimitiveType
+import static org.apache.groovy.parser.antlr4.GroovyLexer.CATCH
+import static org.apache.groovy.parser.antlr4.GroovyLexer.CLASS
+import static org.apache.groovy.parser.antlr4.GroovyLexer.CapitalizedIdentifier
+import static org.apache.groovy.parser.antlr4.GroovyLexer.DEF
+import static org.apache.groovy.parser.antlr4.GroovyLexer.DOT
+import static org.apache.groovy.parser.antlr4.GroovyLexer.ENUM
+import static org.apache.groovy.parser.antlr4.GroovyLexer.EOF
+import static org.apache.groovy.parser.antlr4.GroovyLexer.FINALLY
+import static org.apache.groovy.parser.antlr4.GroovyLexer.IMPORT
+import static org.apache.groovy.parser.antlr4.GroovyLexer.INSTANCEOF
+import static org.apache.groovy.parser.antlr4.GroovyLexer.INTERFACE
+import static org.apache.groovy.parser.antlr4.GroovyLexer.Identifier
+import static org.apache.groovy.parser.antlr4.GroovyLexer.METHOD_POINTER
+import static org.apache.groovy.parser.antlr4.GroovyLexer.METHOD_REFERENCE
+import static org.apache.groovy.parser.antlr4.GroovyLexer.NOT
+import static org.apache.groovy.parser.antlr4.GroovyLexer.NOT_INSTANCEOF
+import static org.apache.groovy.parser.antlr4.GroovyLexer.PACKAGE
+import static org.apache.groovy.parser.antlr4.GroovyLexer.SAFE_DOT
+import static org.apache.groovy.parser.antlr4.GroovyLexer.SPREAD_DOT
+import static org.apache.groovy.parser.antlr4.GroovyLexer.THIS
+import static org.apache.groovy.parser.antlr4.GroovyLexer.TRY
+import static org.apache.groovy.parser.antlr4.GroovyLexer.VOID
/**
* Implements the Completer interface to provide completions for
@@ -116,7 +116,7 @@ class GroovySyntaxCompleter implements Completer {
}
// complete given the context of the whole buffer, not just last line
// Build a single string for the lexer
- List<GroovySourceToken> tokens = []
+ List<Token> tokens = []
try {
if (!tokenizeBuffer(bufferLine.substring(0, cursor), shell.buffers.current(), tokens)) {
return -1
@@ -157,13 +157,13 @@ class GroovySyntaxCompleter implements Completer {
}
if (completionCase == CompletionCase.SECOND_IDENT) {
if (infixCompleter.complete(tokens, candidates)) {
- return tokens.last().column - 1
+ return tokens.last().startIndex
}
return -1
}
if (completionCase == CompletionCase.INSTANCEOF) {
if (classnameCompleter.complete(tokens, candidates)) {
- return tokens.last().column - 1
+ return tokens.last().startIndex
}
return -1
}
@@ -188,24 +188,24 @@ class GroovySyntaxCompleter implements Completer {
return result
}
- static CompletionCase getCompletionCase(final List<GroovySourceToken> tokens) {
- GroovySourceToken currentToken = tokens[-1]
+ static CompletionCase getCompletionCase(final List<Token> tokens) {
+ Token currentToken = tokens[-1]
// now look at last 2 tokens to decide whether we are in a completion situation at all
- if (currentToken.type == IDENT) {
+ if (currentToken.type == Identifier || currentToken.type == CapitalizedIdentifier) {
// cursor is on identifier, use it as prefix and check whether it follows a dot
if (tokens.size() == 1) {
return CompletionCase.NO_DOT_PREFIX
}
- GroovySourceToken previousToken = tokens[-2]
- if (previousToken.type == DOT || previousToken.type == OPTIONAL_DOT) {
+ Token previousToken = tokens[-2]
+ if (previousToken.type == DOT || previousToken.type == SAFE_DOT) {
// we have a dot, so need to evaluate the statement up to the dot for completion
if (tokens.size() < 3) {
return CompletionCase.NO_COMPLETION
}
return CompletionCase.PREFIX_AFTER_DOT
- } else if (previousToken.type == SPREAD_DOT) {
+ } else if (previousToken.type == SPREAD_DOT || previousToken.type == METHOD_POINTER || previousToken.type == METHOD_REFERENCE) {
// we have a dot, so need to evaluate the statement up to the dot for completion
if (tokens.size() < 3) {
return CompletionCase.NO_COMPLETION
@@ -215,30 +215,33 @@ class GroovySyntaxCompleter implements Completer {
// no dot, so we complete a varname, classname, or similar
switch (previousToken.type) {
// if any of these is before, no useful completion possible in this completer
- case LITERAL_import:
- case LITERAL_class:
- case LITERAL_interface:
- case LITERAL_enum:
- case LITERAL_def:
- case LITERAL_void:
- case LITERAL_boolean:
- case LITERAL_byte:
- case LITERAL_char:
- case LITERAL_short:
- case LITERAL_int:
- case LITERAL_float:
- case LITERAL_long:
- case LITERAL_double:
- case LITERAL_package:
- case LITERAL_true:
- case LITERAL_false:
- case LITERAL_as:
- case LITERAL_this:
- case LITERAL_try:
- case LITERAL_finally:
- case LITERAL_catch:
+ case IMPORT:
+ case CLASS:
+ case INTERFACE:
+ case ENUM:
+ case DEF:
+ case VOID:
+ case BuiltInPrimitiveType:
+// case LITERAL_byte:
+// case LITERAL_char:
+// case LITERAL_short:
+// case LITERAL_int:
+// case LITERAL_float:
+// case LITERAL_long:
+// case LITERAL_double:
+ case PACKAGE:
+ case BooleanLiteral:
+// case LITERAL_true:
+// case LITERAL_false:
+ case AS:
+ case THIS:
+ case TRY:
+ case FINALLY:
+ case CATCH:
return CompletionCase.NO_COMPLETION
- case IDENT:
+ case NOT: // just for !in and !instanceof; maybe needs special case
+ case CapitalizedIdentifier:
+ case Identifier:
// identifiers following each other could mean Declaration (no completion) or closure invocation
// closure invocation too complex for now to complete
return CompletionCase.SECOND_IDENT
@@ -247,33 +250,33 @@ class GroovySyntaxCompleter implements Completer {
}
}
- } else if (currentToken.type == DOT || currentToken.type == OPTIONAL_DOT) {
+ } else if (currentToken.type == DOT || currentToken.type == SAFE_DOT) {
// cursor is on dot, so need to evaluate the statement up to the dot for completion
if (tokens.size() == 1) {
return CompletionCase.NO_COMPLETION
}
return CompletionCase.DOT_LAST
- } else if (currentToken.type == SPREAD_DOT) {
+ } else if (currentToken.type == SPREAD_DOT || currentToken.type == METHOD_REFERENCE || currentToken.type == METHOD_POINTER) {
// cursor is on spread-dot, so need to evaluate the statement up to the dot for completion
if (tokens.size() == 1) {
return CompletionCase.NO_COMPLETION
}
return CompletionCase.SPREAD_DOT_LAST
- } else if (currentToken.type == LITERAL_instanceof) {
+ } else if (currentToken.type == INSTANCEOF || currentToken.type == NOT_INSTANCEOF) {
return CompletionCase.INSTANCEOF
} else {
- LOG.debug('Untreated toke type: ' + currentToken.type)
+ LOG.debug('Unhandled token type: ' + currentToken.type)
}
return CompletionCase.NO_COMPLETION
}
- int completeIdentifier(final List<GroovySourceToken> tokens, final List<CharSequence> candidates) {
+ int completeIdentifier(final List<Token> tokens, final List<CharSequence> candidates) {
boolean foundMatches = false
for (IdentifierCompleter completer : identifierCompleters) {
foundMatches |= completer.complete(tokens, candidates)
}
if (foundMatches) {
- return tokens.last().column - 1
+ return tokens.last().startIndex
}
return -1
}
@@ -292,11 +295,13 @@ class GroovySyntaxCompleter implements Completer {
return false
}
- static GroovyLexer createGroovyLexer(final String src) {
- Reader unicodeReader = new UnicodeEscapingReader(new StringReader(src), new SourceBuffer())
- GroovyLexer lexer = new GroovyLexer(unicodeReader)
- unicodeReader.setLexer(lexer)
- return lexer
+ static createTokenStream(String text) {
+ CharStream charStream = CharStreams.fromReader(new StringReader(text))
+ GroovyLangLexer lexer = new GroovyLangLexer(charStream)
+ lexer.removeErrorListener(ConsoleErrorListener.INSTANCE)
+ def tokenStream = new CommonTokenStream(lexer)
+ tokenStream.fill()
+ return tokenStream
}
@TupleConstructor
@@ -321,24 +326,24 @@ class GroovySyntaxCompleter implements Completer {
*/
static boolean tokenizeBuffer(final String bufferLine,
final List<String> previousLines,
- final List<GroovySourceToken> result) {
- GroovyLexer groovyLexer
+ final List<Token> result) {
+ def tokenStream
if (previousLines.size() > 0) {
StringBuilder src = new StringBuilder()
for (String line : previousLines) {
src.append(line).append('\n')
}
src.append(bufferLine)
- groovyLexer = createGroovyLexer(src.toString())
+ tokenStream = createTokenStream(src.toString()).getTokens().iterator()
} else {
- groovyLexer = createGroovyLexer(bufferLine)
+ tokenStream = createTokenStream(bufferLine).getTokens().iterator()
}
- // Build a list of tokens using a GroovyLexer
- GroovySourceToken nextToken
- GroovySourceToken lastToken
+ // Build a list of tokens
+ Token nextToken
+ Token lastToken
while (true) {
try {
- nextToken = groovyLexer.nextToken() as GroovySourceToken
+ nextToken = tokenStream.next() as Token
if (nextToken.type == EOF) {
if (!result.isEmpty() && nextToken.line > result.last().line) {
// no completion if EOF line has no tokens
@@ -348,14 +353,14 @@ class GroovySyntaxCompleter implements Completer {
}
result << nextToken
lastToken = nextToken
- } catch (TokenStreamException e) {
+ } catch (Exception e) {
+ // TODO this whole section needs a rework for antlr4
// getting the next token failed, possibly due to unclosed quotes; investigate rest of the line to confirm
if (lastToken != null) {
String restline = bufferLine.substring(lastToken.columnLast - 1)
int leadingBlanks = restline.find('^[ ]*').length()
if (restline) {
String remainder = restline.substring(leadingBlanks)
- //System.err.println "|" + remainder + "|"
// Exception with following quote either means we're in String or at end of GString.
String openDelim = STRING_STARTERS.find { remainder.startsWith(it) }
if (openDelim && previousLines.size() + 1 == lastToken.line) {
@@ -364,9 +369,10 @@ class GroovySyntaxCompleter implements Completer {
}
}
return false
- } catch (NullPointerException e) {
- // this can happen when e.g. a string as not closed
- return false
+// } catch (NullPointerException e) {
+// // this can happen when e.g. a string as not closed
+// new File('/tmp/groovysh_log.txt') << e.message << '\n'
+// return false
}
}
return !result.empty
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/IdentifierCompleter.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/antlr4/IdentifierCompleter.groovy
similarity index 87%
copy from subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/IdentifierCompleter.groovy
copy to subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/antlr4/IdentifierCompleter.groovy
index c2d7042..96a97bc 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/IdentifierCompleter.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/antlr4/IdentifierCompleter.groovy
@@ -16,9 +16,9 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.groovy.groovysh.completion
+package org.apache.groovy.groovysh.completion.antlr4
-import org.codehaus.groovy.antlr.GroovySourceToken
+import org.antlr.v4.runtime.Token
/**
* Interface for classes that complete identifier tokens within a groovy Statement
@@ -33,6 +33,6 @@ interface IdentifierCompleter {
* @param candidates
* @return
*/
- boolean complete(List<GroovySourceToken> tokens, List<CharSequence> candidates)
+ boolean complete(List<Token> tokens, List<CharSequence> candidates)
}
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/ImportsSyntaxCompleter.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/antlr4/ImportsSyntaxCompleter.groovy
similarity index 95%
copy from subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/ImportsSyntaxCompleter.groovy
copy to subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/antlr4/ImportsSyntaxCompleter.groovy
index b4a77f7..f675788 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/ImportsSyntaxCompleter.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/antlr4/ImportsSyntaxCompleter.groovy
@@ -16,10 +16,11 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.groovy.groovysh.completion
+package org.apache.groovy.groovysh.completion.antlr4
+import org.antlr.v4.runtime.Token
import org.apache.groovy.groovysh.Groovysh
-import org.codehaus.groovy.antlr.GroovySourceToken
+import org.apache.groovy.groovysh.completion.ReflectionCompleter
import org.codehaus.groovy.control.ResolveVisitor
/**
@@ -42,7 +43,7 @@ class ImportsSyntaxCompleter implements IdentifierCompleter {
}
@Override
- boolean complete(final List<GroovySourceToken> tokens, final List<CharSequence> candidates) {
+ boolean complete(final List<Token> tokens, final List<CharSequence> candidates) {
String prefix = tokens.last().getText()
boolean foundMatch = findMatchingPreImportedClasses(prefix, candidates)
for (String importSpec in shell.imports) {
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/InfixKeywordSyntaxCompleter.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/antlr4/InfixKeywordSyntaxCompleter.groovy
similarity index 86%
copy from subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/InfixKeywordSyntaxCompleter.groovy
copy to subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/antlr4/InfixKeywordSyntaxCompleter.groovy
index 8780ca4..4b016b4 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/InfixKeywordSyntaxCompleter.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/antlr4/InfixKeywordSyntaxCompleter.groovy
@@ -16,9 +16,9 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.groovy.groovysh.completion
+package org.apache.groovy.groovysh.completion.antlr4
-import org.codehaus.groovy.antlr.GroovySourceToken
+import org.antlr.v4.runtime.Token
/**
* Completer completing groovy keywords that appear after identifiers
@@ -29,12 +29,14 @@ class InfixKeywordSyntaxCompleter implements IdentifierCompleter {
private static final String[] INFIX_KEYWORDS = [
'in',
'instanceof',
+ '!in',
+ '!instanceof',
'extends',
'implements',
- ]
+ ]
@Override
- boolean complete(final List<GroovySourceToken> tokens, final List<CharSequence> candidates) {
+ boolean complete(final List<Token> tokens, final List<CharSequence> candidates) {
String prefix = tokens.last().text
boolean foundMatch = false
for (String varName in INFIX_KEYWORDS) {
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/KeywordSyntaxCompleter.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/antlr4/KeywordSyntaxCompleter.groovy
similarity index 94%
copy from subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/KeywordSyntaxCompleter.groovy
copy to subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/antlr4/KeywordSyntaxCompleter.groovy
index bcfaa3c..294b265 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/KeywordSyntaxCompleter.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/antlr4/KeywordSyntaxCompleter.groovy
@@ -16,9 +16,9 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.groovy.groovysh.completion
+package org.apache.groovy.groovysh.completion.antlr4
-import org.codehaus.groovy.antlr.GroovySourceToken
+import org.antlr.v4.runtime.Token
/**
* Completer completing Groovy keywords and special functions
@@ -63,7 +63,7 @@ class KeywordSyntaxCompleter implements IdentifierCompleter {
'transient',
//'true', // value
//'try {', //special
- 'void', 'volatile'
+ 'var', 'void', 'volatile'
//'while (' // special
]
@@ -93,7 +93,7 @@ class KeywordSyntaxCompleter implements IdentifierCompleter {
]
@Override
- boolean complete(final List<GroovySourceToken> tokens, final List<CharSequence> candidates) {
+ boolean complete(final List<Token> tokens, final List<CharSequence> candidates) {
String prefix = tokens.last().text
boolean foundMatch = false
for (String varName in KEYWORDS) {
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/ReflectionCompleter.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/antlr4/ReflectionCompleter.groovy
similarity index 77%
copy from subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/ReflectionCompleter.groovy
copy to subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/antlr4/ReflectionCompleter.groovy
index 023309b..d49c4bf 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/ReflectionCompleter.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/antlr4/ReflectionCompleter.groovy
@@ -16,11 +16,12 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.groovy.groovysh.completion
+package org.apache.groovy.groovysh.completion.antlr4
+import org.antlr.v4.runtime.Token
import org.apache.groovy.groovysh.Groovysh
-import org.codehaus.groovy.antlr.GroovySourceToken
-import org.codehaus.groovy.antlr.parser.GroovyTokenTypes
+import org.apache.groovy.groovysh.completion.NavigablePropertiesCompleter
+import org.apache.groovy.groovysh.completion.ReflectionCompletionCandidate
import org.codehaus.groovy.control.MultipleCompilationErrorsException
import org.codehaus.groovy.runtime.InvokerHelper
import org.codehaus.groovy.tools.shell.util.Preferences
@@ -32,12 +33,62 @@ import java.lang.reflect.Method
import java.lang.reflect.Modifier
import java.util.regex.Pattern
+import static org.apache.groovy.parser.antlr4.GroovyLexer.ADD
+import static org.apache.groovy.parser.antlr4.GroovyLexer.ADD_ASSIGN
+import static org.apache.groovy.parser.antlr4.GroovyLexer.AND
+import static org.apache.groovy.parser.antlr4.GroovyLexer.AND_ASSIGN
+import static org.apache.groovy.parser.antlr4.GroovyLexer.ASSIGN
+import static org.apache.groovy.parser.antlr4.GroovyLexer.BITAND
+import static org.apache.groovy.parser.antlr4.GroovyLexer.BITNOT
+import static org.apache.groovy.parser.antlr4.GroovyLexer.BITOR
+import static org.apache.groovy.parser.antlr4.GroovyLexer.BooleanLiteral
+import static org.apache.groovy.parser.antlr4.GroovyLexer.BuiltInPrimitiveType
+import static org.apache.groovy.parser.antlr4.GroovyLexer.COLON
+import static org.apache.groovy.parser.antlr4.GroovyLexer.COMMA
+import static org.apache.groovy.parser.antlr4.GroovyLexer.CapitalizedIdentifier
+import static org.apache.groovy.parser.antlr4.GroovyLexer.DIV
+import static org.apache.groovy.parser.antlr4.GroovyLexer.DIV_ASSIGN
+import static org.apache.groovy.parser.antlr4.GroovyLexer.DOT
+import static org.apache.groovy.parser.antlr4.GroovyLexer.EQUAL
+import static org.apache.groovy.parser.antlr4.GroovyLexer.GE
+import static org.apache.groovy.parser.antlr4.GroovyLexer.GStringBegin
+import static org.apache.groovy.parser.antlr4.GroovyLexer.GT
+import static org.apache.groovy.parser.antlr4.GroovyLexer.Identifier
+import static org.apache.groovy.parser.antlr4.GroovyLexer.IN
+import static org.apache.groovy.parser.antlr4.GroovyLexer.INSTANCEOF
+import static org.apache.groovy.parser.antlr4.GroovyLexer.LBRACE
+import static org.apache.groovy.parser.antlr4.GroovyLexer.LBRACK
+import static org.apache.groovy.parser.antlr4.GroovyLexer.LPAREN
+import static org.apache.groovy.parser.antlr4.GroovyLexer.LE
+import static org.apache.groovy.parser.antlr4.GroovyLexer.LT
+import static org.apache.groovy.parser.antlr4.GroovyLexer.METHOD_POINTER
+import static org.apache.groovy.parser.antlr4.GroovyLexer.METHOD_REFERENCE
+import static org.apache.groovy.parser.antlr4.GroovyLexer.MUL
+import static org.apache.groovy.parser.antlr4.GroovyLexer.MUL_ASSIGN
+import static org.apache.groovy.parser.antlr4.GroovyLexer.NOT
+import static org.apache.groovy.parser.antlr4.GroovyLexer.NOTEQUAL
+import static org.apache.groovy.parser.antlr4.GroovyLexer.OR
+import static org.apache.groovy.parser.antlr4.GroovyLexer.OR_ASSIGN
+import static org.apache.groovy.parser.antlr4.GroovyLexer.RANGE_EXCLUSIVE
+import static org.apache.groovy.parser.antlr4.GroovyLexer.RANGE_INCLUSIVE
+import static org.apache.groovy.parser.antlr4.GroovyLexer.RBRACK
+import static org.apache.groovy.parser.antlr4.GroovyLexer.RPAREN
+import static org.apache.groovy.parser.antlr4.GroovyLexer.SAFE_DOT
+import static org.apache.groovy.parser.antlr4.GroovyLexer.SEMI
+import static org.apache.groovy.parser.antlr4.GroovyLexer.SPACESHIP
+import static org.apache.groovy.parser.antlr4.GroovyLexer.SPREAD_DOT
+import static org.apache.groovy.parser.antlr4.GroovyLexer.StringLiteral
+import static org.apache.groovy.parser.antlr4.GroovyLexer.SUB
+import static org.apache.groovy.parser.antlr4.GroovyLexer.SUB_ASSIGN
+import static org.apache.groovy.parser.antlr4.GroovyLexer.XOR
+import static org.apache.groovy.parser.antlr4.GroovyLexer.XOR_ASSIGN
+
/**
* Completes fields and methods of Classes or instances.
* Does not quite respect the contract of IdentifierCompleter, as last Token may be a dot or not,
* thus also returns as int the cursor position.
*/
-class ReflectionCompleter implements GroovyTokenTypes {
+class ReflectionCompleter {
private static final NavigablePropertiesCompleter PROPERTIES_COMPLETER = new NavigablePropertiesCompleter()
private static final Pattern BEAN_ACCESSOR_PATTERN = ~'^(get|set|is)[A-Z].*'
@@ -53,19 +104,19 @@ class ReflectionCompleter implements GroovyTokenTypes {
this.shell = shell
}
- int complete(final List<GroovySourceToken> tokens, final List<CharSequence> candidates) {
- GroovySourceToken currentElementToken = null
- GroovySourceToken dotToken
- List<GroovySourceToken> previousTokens
+ int complete(final List<Token> tokens, final List<CharSequence> candidates) {
+ Token currentElementToken = null
+ Token dotToken
+ List<Token> previousTokens
if (tokens.size() < 2) {
- throw new IllegalArgumentException('must be invoked with at least 2 tokens, one of which is dot' + tokens*.text)
+ throw new IllegalArgumentException('Must be invoked with at least 2 tokens, one of which is a dot-like operator: ' + tokens*.text)
}
- if (tokens.last().type == DOT || tokens.last().type == OPTIONAL_DOT || tokens.last().type == SPREAD_DOT) {
+ if (tokens.last().type == DOT || tokens.last().type == SAFE_DOT || tokens.last().type == SPREAD_DOT || tokens.last().type == METHOD_POINTER || tokens.last().type == METHOD_REFERENCE) {
dotToken = tokens.last()
previousTokens = tokens[0..-2]
} else {
- if (tokens[-2].type != DOT && tokens[-2].type != OPTIONAL_DOT && tokens[-2].type != SPREAD_DOT) {
- throw new IllegalArgumentException('must be invoked with token list with dot at last position or one position before' + tokens*.text)
+ if (tokens[-2].type != DOT && tokens[-2].type != SAFE_DOT && tokens[-2].type != SPREAD_DOT && tokens[-2].type != METHOD_POINTER && tokens[-2].type != METHOD_REFERENCE) {
+ throw new IllegalArgumentException('Must be invoked with token list with dot-like operator at last position or one position before: ' + tokens*.text)
}
currentElementToken = tokens.last()
dotToken = tokens[-2]
@@ -103,10 +154,11 @@ class ReflectionCompleter implements GroovyTokenTypes {
private int completeInstanceMembers(final Object instanceOrClass,
final String identifierPrefix,
final List<CharSequence> candidates,
- final GroovySourceToken currentElementToken,
- final GroovySourceToken dotToken) {
+ final Token currentElementToken,
+ final Token dotToken) {
// look for public methods/fields that match the prefix
- Collection<ReflectionCompletionCandidate> myCandidates = getPublicFieldsAndMethods(instanceOrClass, identifierPrefix)
+ def methodRef = dotToken.type == METHOD_POINTER || dotToken.type == METHOD_REFERENCE
+ Collection<ReflectionCompletionCandidate> myCandidates = getPublicFieldsAndMethods(instanceOrClass, identifierPrefix, methodRef)
boolean showAllMethods = (identifierPrefix.length() >= Integer.valueOf(Preferences.get(Groovysh.METACLASS_COMPLETION_PREFIX_LENGTH_PREFERENCE_KEY, '3')))
// Also add metaclass methods if prefix is long enough (user would usually not care about those)
@@ -127,6 +179,15 @@ class ReflectionCompleter implements GroovyTokenTypes {
if (myCandidates.size() > 0) {
myCandidates = myCandidates.sort()
+ if (methodRef) {
+ // strip braces for :: and .& operators
+ myCandidates = myCandidates.collect { cand ->
+ def val = cand.value
+ val = val.endsWith('()') ? val[0..-3] :
+ (val.endsWith('(') ? val[0..-2] : val)
+ new ReflectionCompletionCandidate(val, *cand.jAnsiCodes)
+ }
+ }
if (Boolean.valueOf(Preferences.get(Groovysh.COLORS_PREFERENCE_KEY, 'true'))) {
candidates.addAll(myCandidates.collect(
{ ReflectionCompletionCandidate it ->
@@ -140,10 +201,10 @@ class ReflectionCompleter implements GroovyTokenTypes {
int lastDot
// dot could be on previous line
if (currentElementToken && dotToken.line != currentElementToken.line) {
- lastDot = currentElementToken.column - 1
+ lastDot = currentElementToken.startIndex
} else {
- // Spread-dot has length 2!
- lastDot = dotToken.column + (dotToken.getText().length() - 1)
+ // Spread-dot/Method-ref/Method-pointer have length 2!
+ lastDot = dotToken.startIndex + dotToken.text.size()
}
return lastDot
}
@@ -157,15 +218,15 @@ class ReflectionCompleter implements GroovyTokenTypes {
* evaluates it and returns a result. "Simple" means evaluation is known to be
* side-effect free.
*/
- Object getInvokerClassOrInstance(final List<GroovySourceToken> groovySourceTokens) {
+ Object getInvokerClassOrInstance(final List<Token> groovySourceTokens) {
if (!groovySourceTokens
|| groovySourceTokens.last().type == DOT
- || groovySourceTokens.last().type == OPTIONAL_DOT) {
+ || groovySourceTokens.last().type == SAFE_DOT) {
// we expect the list of tokens before a dot.
return null
}
// first, try to detect a sequence of token before the dot that can safely be evaluated.
- List<GroovySourceToken> invokerTokens = getInvokerTokens(groovySourceTokens)
+ List<Token> invokerTokens = getInvokerTokens(groovySourceTokens)
if (invokerTokens) {
try {
String instanceRefExpression = tokenListToEvalString(invokerTokens)
@@ -190,7 +251,7 @@ class ReflectionCompleter implements GroovyTokenTypes {
* @param groovySourceTokens
* @return
*/
- static List<GroovySourceToken> getInvokerTokens(final List<GroovySourceToken> groovySourceTokens) {
+ static List<Token> getInvokerTokens(final List<Token> groovySourceTokens) {
int validIndex = groovySourceTokens.size()
if (validIndex == 0) {
return []
@@ -199,15 +260,15 @@ class ReflectionCompleter implements GroovyTokenTypes {
// to be evaluated later
// need to collect using Strings, to support evaluation of string literals
Stack<Integer> expectedOpeners = new Stack<Integer>()
- GroovySourceToken lastToken = null
+ Token lastToken = null
outerloop:
- for (GroovySourceToken loopToken in groovySourceTokens.reverse()) {
+ for (Token loopToken in groovySourceTokens.reverse()) {
switch (loopToken.type) {
// a combination of any of these can be evaluated without side effects
// this just avoids any parentheses,
// could maybe be extended further if harmless parentheses can be detected .
// This allows already a lot of powerful simple completions, like [foo: Baz.bar]['foo'].
- case STRING_LITERAL:
+ case StringLiteral:
// must escape String for evaluation, need the original string e.g. for mapping key
break
case LPAREN:
@@ -234,51 +295,53 @@ class ReflectionCompleter implements GroovyTokenTypes {
break
// tokens which indicate we have reached the beginning of a statement
// operator tokens (must not be evaluated, as they can have side effects via evil overriding
- case COMPARE_TO:
+ case SPACESHIP:
case EQUAL:
- case NOT_EQUAL:
+ case NOTEQUAL:
case ASSIGN:
case GT:
case LT:
case GE:
case LE:
- case PLUS:
- case PLUS_ASSIGN:
- case MINUS:
- case MINUS_ASSIGN:
- case STAR:
- case STAR_ASSIGN:
+ case ADD:
+ case ADD_ASSIGN:
+ case SUB:
+ case SUB_ASSIGN:
+ case MUL:
+ case MUL_ASSIGN:
case DIV:
case DIV_ASSIGN:
- case BOR:
- case BOR_ASSIGN:
- case BAND:
- case BAND_ASSIGN:
- case BXOR:
- case BXOR_ASSIGN:
- case BNOT:
- case LOR:
- case LAND:
- case LNOT:
- case LITERAL_in:
- case LITERAL_instanceof:
+ case BITOR:
+ case OR_ASSIGN:
+ case BITAND:
+ case AND_ASSIGN:
+ case XOR:
+ case XOR_ASSIGN:
+ case BITNOT:
+ case OR:
+ case AND:
+ case NOT:
+ case IN:
+ case INSTANCEOF:
if (expectedOpeners.empty()) {
break outerloop
}
break
// tokens which indicate we have reached the beginning of a statement
- case LCURLY:
+ case LBRACE:
case SEMI:
- case STRING_CTOR_START:
+// case STRING_CTOR_START:
+ case GStringBegin:
break outerloop
// tokens we accept
- case IDENT:
+ case Identifier:
+ case CapitalizedIdentifier:
if (lastToken) {
if (lastToken.type == LPAREN) {
//Method invocation,must be avoided
return []
}
- if (lastToken.type == IDENT) {
+ if (lastToken.type == Identifier || lastToken.type == CapitalizedIdentifier) {
// could be attempt to invoke closure like 'foo.each bar.baz'
return []
}
@@ -293,17 +356,19 @@ class ReflectionCompleter implements GroovyTokenTypes {
break outerloop
}
// harmless literals
- case LITERAL_true:
- case LITERAL_false:
- case NUM_INT:
- case NUM_FLOAT:
- case NUM_LONG:
- case NUM_DOUBLE:
- case NUM_BIG_INT:
- case NUM_BIG_DECIMAL:
- case MEMBER_POINTER:
+ case BooleanLiteral:
+// case LITERAL_true:
+// case LITERAL_false:
+ case BuiltInPrimitiveType:
+// case NUM_INT:
+// case NUM_FLOAT:
+// case NUM_LONG:
+// case NUM_DOUBLE:
+// case NUM_BIG_INT:
+// case NUM_BIG_DECIMAL:
+ case METHOD_POINTER:
case DOT:
- case OPTIONAL_DOT:
+ case SAFE_DOT:
break
default:
return null
@@ -314,10 +379,10 @@ class ReflectionCompleter implements GroovyTokenTypes {
return groovySourceTokens[(validIndex)..-1]
}
- static String tokenListToEvalString(final List<GroovySourceToken> groovySourceTokens) {
+ static String tokenListToEvalString(final List<Token> groovySourceTokens) {
StringBuilder builder = new StringBuilder()
- for (GroovySourceToken token : groovySourceTokens) {
- if (token.type == STRING_LITERAL) {
+ for (Token token : groovySourceTokens) {
+ if (token.type == StringLiteral) {
builder.append('\'').append(token.text).append('\'')
} else {
builder.append(token.text)
@@ -351,7 +416,7 @@ class ReflectionCompleter implements GroovyTokenTypes {
* @param prefix the prefix that must be matched
* @return the list of public methods and fields that begin with the prefix
*/
- static Collection<ReflectionCompletionCandidate> getPublicFieldsAndMethods(final Object instance, final String prefix) {
+ static Collection<ReflectionCompletionCandidate> getPublicFieldsAndMethods(final Object instance, final String prefix, final boolean all = false) {
Set<ReflectionCompletionCandidate> rv = new HashSet<ReflectionCompletionCandidate>()
Class clazz = instance.getClass()
if (clazz == null) {
@@ -367,13 +432,14 @@ class ReflectionCompleter implements GroovyTokenTypes {
// render immediate class members bold when completing an instance
boolean renderBold = !isClass
// hide static members for instances unless user typed a prefix
- boolean showStatic = isClass || (prefix.length() >= Integer.valueOf(Preferences.get(Groovysh.METACLASS_COMPLETION_PREFIX_LENGTH_PREFERENCE_KEY, '3')))
+ boolean showStatic = isClass || all || (prefix.length() >= Integer.valueOf(Preferences.get(Groovysh.METACLASS_COMPLETION_PREFIX_LENGTH_PREFERENCE_KEY, '3')))
+ boolean showInstance = !isClass || all
while (loopclazz != null && loopclazz != Object && loopclazz != GroovyObject) {
- addClassFieldsAndMethods(loopclazz, showStatic, !isClass, prefix, rv, renderBold)
+ addClassFieldsAndMethods(loopclazz, showStatic, showInstance, prefix, rv, renderBold)
renderBold = false
loopclazz = loopclazz.superclass
}
- if (clazz.isArray() && !isClass) {
+ if (clazz.isArray() && showInstance) {
// Arrays are special, these public members cannot be found via Reflection
for (String member : ['length', 'clone()']) {
if (member.startsWith(prefix)) {
@@ -383,7 +449,7 @@ class ReflectionCompleter implements GroovyTokenTypes {
}
// other completions that are commonly possible with properties
- if (!isClass) {
+ if (showInstance) {
Set<String> candidates = new HashSet<String>()
PROPERTIES_COMPLETER.addCompletions(instance, prefix, candidates)
rv.addAll(candidates.collect({ String it -> new ReflectionCompletionCandidate(it, AnsiRenderer.Code.MAGENTA.name()) }))
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/VariableSyntaxCompleter.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/antlr4/VariableSyntaxCompleter.groovy
similarity index 91%
copy from subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/VariableSyntaxCompleter.groovy
copy to subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/antlr4/VariableSyntaxCompleter.groovy
index edd339c..31e3247 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/VariableSyntaxCompleter.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/apache/groovy/groovysh/completion/antlr4/VariableSyntaxCompleter.groovy
@@ -16,10 +16,10 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.groovy.groovysh.completion
+package org.apache.groovy.groovysh.completion.antlr4
+import org.antlr.v4.runtime.Token
import org.apache.groovy.groovysh.Groovysh
-import org.codehaus.groovy.antlr.GroovySourceToken
import org.codehaus.groovy.runtime.MethodClosure
/**
@@ -34,7 +34,7 @@ class VariableSyntaxCompleter implements IdentifierCompleter {
}
@Override
- boolean complete(final List<GroovySourceToken> tokens, final List<CharSequence> candidates) {
+ boolean complete(final List<Token> tokens, final List<CharSequence> candidates) {
String prefix = tokens.last().text
Map vars = shell.interp.context.variables
boolean foundMatch = false
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/InteractiveShellRunner.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/InteractiveShellRunner.groovy
index 11a20ac..de73fde 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/InteractiveShellRunner.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/InteractiveShellRunner.groovy
@@ -30,6 +30,7 @@ import org.codehaus.groovy.tools.shell.completion.ImportsSyntaxCompletor
import org.codehaus.groovy.tools.shell.completion.KeywordSyntaxCompletor
import org.codehaus.groovy.tools.shell.completion.ReflectionCompletor
import org.codehaus.groovy.tools.shell.completion.VariableSyntaxCompletor
+import org.codehaus.groovy.tools.shell.IO
import org.codehaus.groovy.tools.shell.util.Logger
import org.codehaus.groovy.tools.shell.util.Preferences
import org.codehaus.groovy.tools.shell.util.WrappedInputStream