rsense-core 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +1 -0
- data/README.md +35 -0
- data/Rakefile +84 -0
- data/TypeAnnotation.tokens +41 -0
- data/build.xml +84 -0
- data/build_lib/antlr-3.2.jar +0 -0
- data/lib/jars/ant-1.7.0.jar +0 -0
- data/lib/jars/ant-launcher-1.7.0.jar +0 -0
- data/lib/jars/antlr-runtime-3.2.jar +0 -0
- data/lib/jars/bsf-2.3.0.jar +0 -0
- data/lib/rsense-core.rb +28 -0
- data/lib/rsense.jar +0 -0
- data/lib/rsense/core.rb +5 -0
- data/lib/rsense/core/version.rb +5 -0
- data/lib/rsense/parser.rb +6 -0
- data/lib/rsense/ruby.rb +19 -0
- data/lib/rsense/typing.rb +13 -0
- data/lib/rsense/typing/annotation.rb +20 -0
- data/lib/rsense/typing/runtime.rb +23 -0
- data/lib/rsense/typing/vertex.rb +15 -0
- data/lib/rsense/util.rb +9 -0
- data/rsense-core.gemspec +30 -0
- data/src/org/cx4a/rsense/CodeAssist.java +744 -0
- data/src/org/cx4a/rsense/CodeAssistError.java +31 -0
- data/src/org/cx4a/rsense/CodeAssistResult.java +42 -0
- data/src/org/cx4a/rsense/CodeCompletionResult.java +65 -0
- data/src/org/cx4a/rsense/FindDefinitionResult.java +24 -0
- data/src/org/cx4a/rsense/LoadResult.java +19 -0
- data/src/org/cx4a/rsense/Main.java +916 -0
- data/src/org/cx4a/rsense/Options.java +353 -0
- data/src/org/cx4a/rsense/Project.java +103 -0
- data/src/org/cx4a/rsense/TypeInferenceResult.java +25 -0
- data/src/org/cx4a/rsense/WhereResult.java +19 -0
- data/src/org/cx4a/rsense/parser/TypeAnnotation.g +221 -0
- data/src/org/cx4a/rsense/parser/TypeAnnotationLexer.java +1759 -0
- data/src/org/cx4a/rsense/parser/TypeAnnotationParser.java +2025 -0
- data/src/org/cx4a/rsense/ruby/Block.java +10 -0
- data/src/org/cx4a/rsense/ruby/Context.java +75 -0
- data/src/org/cx4a/rsense/ruby/DynamicMethod.java +10 -0
- data/src/org/cx4a/rsense/ruby/DynamicScope.java +51 -0
- data/src/org/cx4a/rsense/ruby/Frame.java +95 -0
- data/src/org/cx4a/rsense/ruby/IRubyObject.java +17 -0
- data/src/org/cx4a/rsense/ruby/LocalScope.java +43 -0
- data/src/org/cx4a/rsense/ruby/MetaClass.java +50 -0
- data/src/org/cx4a/rsense/ruby/Ruby.java +242 -0
- data/src/org/cx4a/rsense/ruby/RubyClass.java +146 -0
- data/src/org/cx4a/rsense/ruby/RubyModule.java +255 -0
- data/src/org/cx4a/rsense/ruby/RubyObject.java +94 -0
- data/src/org/cx4a/rsense/ruby/Scope.java +7 -0
- data/src/org/cx4a/rsense/ruby/SpecialObject.java +15 -0
- data/src/org/cx4a/rsense/ruby/Visibility.java +17 -0
- data/src/org/cx4a/rsense/typing/Graph.java +1690 -0
- data/src/org/cx4a/rsense/typing/Propagation.java +73 -0
- data/src/org/cx4a/rsense/typing/Template.java +84 -0
- data/src/org/cx4a/rsense/typing/TemplateAttribute.java +158 -0
- data/src/org/cx4a/rsense/typing/TypeSet.java +48 -0
- data/src/org/cx4a/rsense/typing/annotation/ClassType.java +57 -0
- data/src/org/cx4a/rsense/typing/annotation/MethodType.java +79 -0
- data/src/org/cx4a/rsense/typing/annotation/TypeAnnotation.java +4 -0
- data/src/org/cx4a/rsense/typing/annotation/TypeAny.java +7 -0
- data/src/org/cx4a/rsense/typing/annotation/TypeApplication.java +37 -0
- data/src/org/cx4a/rsense/typing/annotation/TypeConstraint.java +29 -0
- data/src/org/cx4a/rsense/typing/annotation/TypeExpression.java +11 -0
- data/src/org/cx4a/rsense/typing/annotation/TypeIdentity.java +59 -0
- data/src/org/cx4a/rsense/typing/annotation/TypeOptional.java +22 -0
- data/src/org/cx4a/rsense/typing/annotation/TypePragma.java +22 -0
- data/src/org/cx4a/rsense/typing/annotation/TypeSplat.java +22 -0
- data/src/org/cx4a/rsense/typing/annotation/TypeTuple.java +35 -0
- data/src/org/cx4a/rsense/typing/annotation/TypeUnion.java +23 -0
- data/src/org/cx4a/rsense/typing/annotation/TypeVariable.java +44 -0
- data/src/org/cx4a/rsense/typing/runtime/AliasMethod.java +94 -0
- data/src/org/cx4a/rsense/typing/runtime/AnnotationHelper.java +69 -0
- data/src/org/cx4a/rsense/typing/runtime/AnnotationResolver.java +523 -0
- data/src/org/cx4a/rsense/typing/runtime/Array.java +84 -0
- data/src/org/cx4a/rsense/typing/runtime/ClassTag.java +27 -0
- data/src/org/cx4a/rsense/typing/runtime/DefaultMethod.java +115 -0
- data/src/org/cx4a/rsense/typing/runtime/Hash.java +131 -0
- data/src/org/cx4a/rsense/typing/runtime/LoopTag.java +21 -0
- data/src/org/cx4a/rsense/typing/runtime/Method.java +32 -0
- data/src/org/cx4a/rsense/typing/runtime/MonomorphicObject.java +77 -0
- data/src/org/cx4a/rsense/typing/runtime/ObjectAllocator.java +40 -0
- data/src/org/cx4a/rsense/typing/runtime/PolymorphicObject.java +90 -0
- data/src/org/cx4a/rsense/typing/runtime/Proc.java +100 -0
- data/src/org/cx4a/rsense/typing/runtime/RuntimeHelper.java +1339 -0
- data/src/org/cx4a/rsense/typing/runtime/SpecialMethod.java +119 -0
- data/src/org/cx4a/rsense/typing/runtime/TypeVarMap.java +112 -0
- data/src/org/cx4a/rsense/typing/runtime/VertexHolder.java +48 -0
- data/src/org/cx4a/rsense/typing/vertex/CallVertex.java +122 -0
- data/src/org/cx4a/rsense/typing/vertex/MultipleAsgnVertex.java +23 -0
- data/src/org/cx4a/rsense/typing/vertex/PassThroughVertex.java +20 -0
- data/src/org/cx4a/rsense/typing/vertex/SValueVertex.java +24 -0
- data/src/org/cx4a/rsense/typing/vertex/SplatVertex.java +24 -0
- data/src/org/cx4a/rsense/typing/vertex/ToAryVertex.java +24 -0
- data/src/org/cx4a/rsense/typing/vertex/TypeVarVertex.java +22 -0
- data/src/org/cx4a/rsense/typing/vertex/Vertex.java +221 -0
- data/src/org/cx4a/rsense/typing/vertex/YieldVertex.java +70 -0
- data/src/org/cx4a/rsense/util/HereDocReader.java +48 -0
- data/src/org/cx4a/rsense/util/Logger.java +111 -0
- data/src/org/cx4a/rsense/util/NodeUtil.java +198 -0
- data/src/org/cx4a/rsense/util/SourceLocation.java +70 -0
- data/src/org/cx4a/rsense/util/StringUtil.java +63 -0
- data/src/resources/org/cx4a/rsense/rsense.properties +1 -0
- data/stubs/1.8/_builtin.rb +3006 -0
- data/stubs/1.8/bigdecimal.rb +131 -0
- data/stubs/1.8/cgi.rb +257 -0
- data/stubs/1.8/date.rb +147 -0
- data/stubs/1.8/optparse.rb +113 -0
- data/stubs/1.8/rational.rb +47 -0
- data/stubs/1.8/set.rb +94 -0
- data/stubs/1.8/socket.rb +461 -0
- data/stubs/1.8/stringio.rb +129 -0
- data/test/data/a file.rb +1 -0
- data/test/data/benchmark.rb +12 -0
- data/test/data/crlf.rb +5 -0
- data/test/data/test.rb +19 -0
- data/test/script/all.rsense +2 -0
- data/test/script/array_dynamic.rsense +25 -0
- data/test/script/block_nested.rsense +7 -0
- data/test/script/builtin.rsense +785 -0
- data/test/script/class_method_partial_update.rsense +52 -0
- data/test/script/class_partial_update.rsense +17 -0
- data/test/script/find-definition.rsense +72 -0
- data/test/script/method_arg_onearg.rsense +6 -0
- data/test/script/method_arg_optional.rsense +7 -0
- data/test/script/method_partial_update.rsense +14 -0
- data/test/script/method_yield_arrayarg.rsense +8 -0
- data/test/script/method_yield_arrayarg_expand.rsense +8 -0
- data/test/script/method_yield_arrayarg_splat.rsense +17 -0
- data/test/script/misc.rsense +2 -0
- data/test/script/proc_higher_order.rsense +22 -0
- data/test/script/regression.rsense +95 -0
- data/test/script/stdlib.rsense +66 -0
- data/test/script/where.rsense +41 -0
- metadata +315 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
package org.cx4a.rsense;
|
|
2
|
+
|
|
3
|
+
public class CodeAssistError {
|
|
4
|
+
private String message;
|
|
5
|
+
private Throwable cause;
|
|
6
|
+
|
|
7
|
+
public CodeAssistError(String message) {
|
|
8
|
+
this.message = message;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
public CodeAssistError(String message, Throwable cause) {
|
|
12
|
+
this.message = message;
|
|
13
|
+
this.cause = cause;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
public CodeAssistError(Throwable cause) {
|
|
17
|
+
this.cause = cause;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
public String getShortError() {
|
|
21
|
+
return message != null ? message : (cause != null ? cause.getMessage() : "unknown error");
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
public String getMessage() {
|
|
25
|
+
return message;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
public Throwable getCause() {
|
|
29
|
+
return cause;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
package org.cx4a.rsense;
|
|
2
|
+
|
|
3
|
+
import java.util.List;
|
|
4
|
+
import java.util.ArrayList;
|
|
5
|
+
import java.util.Collections;
|
|
6
|
+
|
|
7
|
+
import org.jrubyparser.ast.Node;
|
|
8
|
+
|
|
9
|
+
public class CodeAssistResult {
|
|
10
|
+
private Node ast;
|
|
11
|
+
private List<CodeAssistError> errors;
|
|
12
|
+
|
|
13
|
+
public CodeAssistResult() {
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
public void setAST(Node ast) {
|
|
17
|
+
this.ast = ast;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
public Node getAST() {
|
|
21
|
+
return ast;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
public void addError(CodeAssistError error) {
|
|
25
|
+
if (errors == null) {
|
|
26
|
+
errors = new ArrayList<CodeAssistError>();
|
|
27
|
+
}
|
|
28
|
+
errors.add(error);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
public List<CodeAssistError> getErrors() {
|
|
32
|
+
return errors == null ? Collections.<CodeAssistError>emptyList() : errors;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
public void setErrors(List<CodeAssistError> errors) {
|
|
36
|
+
this.errors = errors;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
public boolean hasError() {
|
|
40
|
+
return errors != null;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
package org.cx4a.rsense;
|
|
2
|
+
|
|
3
|
+
import java.util.List;
|
|
4
|
+
import java.util.Collections;
|
|
5
|
+
|
|
6
|
+
public class CodeCompletionResult extends CodeAssistResult {
|
|
7
|
+
public static class CompletionCandidate {
|
|
8
|
+
public enum Kind {
|
|
9
|
+
CLASS, MODULE, CONSTANT, METHOD,
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
private String completion;
|
|
13
|
+
private String qualifiedName;
|
|
14
|
+
private String baseName;
|
|
15
|
+
private Kind kind;
|
|
16
|
+
|
|
17
|
+
public CompletionCandidate(String completion, String qualifiedName, String baseName, Kind kind) {
|
|
18
|
+
this.completion = completion;
|
|
19
|
+
this.qualifiedName = qualifiedName;
|
|
20
|
+
this.baseName = baseName;
|
|
21
|
+
this.kind = kind;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
public String getCompletion() {
|
|
25
|
+
return completion;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
public String getQualifiedName() {
|
|
29
|
+
return qualifiedName;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
public String getBaseName() {
|
|
33
|
+
return baseName;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
public Kind getKind() {
|
|
37
|
+
return kind;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
@Override
|
|
41
|
+
public String toString() {
|
|
42
|
+
return completion;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
private List<CompletionCandidate> candidates = Collections.<CompletionCandidate>emptyList();
|
|
47
|
+
|
|
48
|
+
public CodeCompletionResult() {
|
|
49
|
+
super();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
public void setCandidates(List<CompletionCandidate> candidates) {
|
|
53
|
+
this.candidates = candidates;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
public List<CompletionCandidate> getCandidates() {
|
|
57
|
+
return candidates;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
public static CodeCompletionResult failWithException(String message, Throwable cause) {
|
|
61
|
+
CodeCompletionResult result = new CodeCompletionResult();
|
|
62
|
+
result.addError(new CodeAssistError(message, cause));
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
package org.cx4a.rsense;
|
|
2
|
+
|
|
3
|
+
import java.util.Collection;
|
|
4
|
+
import java.util.Collections;
|
|
5
|
+
|
|
6
|
+
import org.cx4a.rsense.util.SourceLocation;
|
|
7
|
+
|
|
8
|
+
public class FindDefinitionResult extends CodeAssistResult {
|
|
9
|
+
private Collection<SourceLocation> locations = Collections.<SourceLocation>emptyList();
|
|
10
|
+
|
|
11
|
+
public void setLocations(Collection<SourceLocation> locations) {
|
|
12
|
+
this.locations = locations;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
public Collection<SourceLocation> getLocations() {
|
|
16
|
+
return locations;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
public static FindDefinitionResult failWithException(String message, Throwable cause) {
|
|
20
|
+
FindDefinitionResult result = new FindDefinitionResult();
|
|
21
|
+
result.addError(new CodeAssistError(message, cause));
|
|
22
|
+
return result;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
package org.cx4a.rsense;
|
|
2
|
+
|
|
3
|
+
public class LoadResult extends CodeAssistResult {
|
|
4
|
+
public static LoadResult failWithNotFound() {
|
|
5
|
+
LoadResult result = new LoadResult();
|
|
6
|
+
result.addError(new CodeAssistError("File not found"));
|
|
7
|
+
return result;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
public static LoadResult failWithException(String message, Throwable cause) {
|
|
11
|
+
LoadResult result = new LoadResult();
|
|
12
|
+
result.addError(new CodeAssistError(message, cause));
|
|
13
|
+
return result;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
public static LoadResult alreadyLoaded() {
|
|
17
|
+
return new LoadResult();
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,916 @@
|
|
|
1
|
+
package org.cx4a.rsense;
|
|
2
|
+
|
|
3
|
+
import java.util.Set;
|
|
4
|
+
import java.util.HashSet;
|
|
5
|
+
import java.util.Collection;
|
|
6
|
+
import java.util.Properties;
|
|
7
|
+
|
|
8
|
+
import java.io.File;
|
|
9
|
+
import java.io.InputStream;
|
|
10
|
+
import java.io.FileInputStream;
|
|
11
|
+
import java.io.FileOutputStream;
|
|
12
|
+
import java.io.PrintStream;
|
|
13
|
+
import java.io.Reader;
|
|
14
|
+
import java.io.BufferedReader;
|
|
15
|
+
import java.io.FileNotFoundException;
|
|
16
|
+
import java.io.InputStreamReader;
|
|
17
|
+
import java.io.IOException;
|
|
18
|
+
import java.nio.file.FileSystem;
|
|
19
|
+
import java.nio.file.FileSystems;
|
|
20
|
+
import java.nio.file.Path;
|
|
21
|
+
import java.nio.file.PathMatcher;
|
|
22
|
+
import java.util.HashMap;
|
|
23
|
+
import java.util.Map;
|
|
24
|
+
|
|
25
|
+
import org.cx4a.rsense.ruby.IRubyObject;
|
|
26
|
+
import org.cx4a.rsense.util.Logger;
|
|
27
|
+
import org.cx4a.rsense.util.StringUtil;
|
|
28
|
+
import org.cx4a.rsense.util.SourceLocation;
|
|
29
|
+
|
|
30
|
+
public class Main {
|
|
31
|
+
private static class TestStats {
|
|
32
|
+
public int count = 0;
|
|
33
|
+
public int success = 0;
|
|
34
|
+
public int failure = 0;
|
|
35
|
+
public int error = 0;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
private static class ProgressMonitor extends Thread implements Project.EventListener {
|
|
39
|
+
private boolean stop;
|
|
40
|
+
private PrintStream out;
|
|
41
|
+
private int interval;
|
|
42
|
+
private Project.EventListener.Event event;
|
|
43
|
+
|
|
44
|
+
public ProgressMonitor(PrintStream out, int interval) {
|
|
45
|
+
this.out = out;
|
|
46
|
+
this.interval = interval;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
public void run() {
|
|
50
|
+
if (interval > 0) {
|
|
51
|
+
while (isAlive()) {
|
|
52
|
+
print();
|
|
53
|
+
try {
|
|
54
|
+
Thread.sleep(interval);
|
|
55
|
+
} catch (InterruptedException e) {}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
public void attach(Project project) {
|
|
61
|
+
event = null;
|
|
62
|
+
if (interval >= 0) {
|
|
63
|
+
project.addEventListener(this);
|
|
64
|
+
if (!isAlive())
|
|
65
|
+
start();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
public void detach(Project project) {
|
|
70
|
+
event = null;
|
|
71
|
+
if (interval >= 0)
|
|
72
|
+
project.removeEventListener(this);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
public void update(Project.EventListener.Event event) {
|
|
76
|
+
this.event = event;
|
|
77
|
+
if (interval == 0)
|
|
78
|
+
print();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
private void print() {
|
|
82
|
+
if (event != null) {
|
|
83
|
+
switch (event.type) {
|
|
84
|
+
case DEFINE:
|
|
85
|
+
out.printf("progress: defining method %s...\n", event.name);
|
|
86
|
+
break;
|
|
87
|
+
case CLASS:
|
|
88
|
+
out.printf("progress: defining class %s...\n", event.name);
|
|
89
|
+
break;
|
|
90
|
+
case MODULE:
|
|
91
|
+
out.printf("progress: defining module %s...\n", event.name);
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
private Properties properties;
|
|
99
|
+
private File currentDir;
|
|
100
|
+
private InputStream in;
|
|
101
|
+
private PrintStream out;
|
|
102
|
+
private Reader inReader;
|
|
103
|
+
private CodeAssist codeAssist;
|
|
104
|
+
private TestStats testStats;
|
|
105
|
+
private ProgressMonitor progressMonitor;
|
|
106
|
+
|
|
107
|
+
public static void main(String[] args) throws Exception {
|
|
108
|
+
new Main().run(args);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
public void run(String[] args) throws Exception {
|
|
112
|
+
in = System.in;
|
|
113
|
+
out = System.out;
|
|
114
|
+
inReader = new InputStreamReader(in);
|
|
115
|
+
|
|
116
|
+
properties = new Properties();
|
|
117
|
+
InputStream stream = this.getClass().getResourceAsStream("rsense.properties");
|
|
118
|
+
if (stream != null) properties.load(stream);
|
|
119
|
+
|
|
120
|
+
if (args.length == 0 || args[0].equals("help")) {
|
|
121
|
+
usage();
|
|
122
|
+
return;
|
|
123
|
+
} else if (args[0].equals("version")) {
|
|
124
|
+
version();
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
String command = args[0];
|
|
129
|
+
Options options = parseOptions(args, 1);
|
|
130
|
+
System.out.println("Command: " + command);
|
|
131
|
+
System.out.println("\nOptions: " + options);
|
|
132
|
+
|
|
133
|
+
Logger.getInstance().setLevel(options.getLogLevel());
|
|
134
|
+
init(options);
|
|
135
|
+
if (options.getLog() != null) {
|
|
136
|
+
PrintStream log = new PrintStream(new FileOutputStream(options.getLog(), true));
|
|
137
|
+
try {
|
|
138
|
+
Logger.getInstance().setOut(log);
|
|
139
|
+
start(command, options);
|
|
140
|
+
} finally {
|
|
141
|
+
log.close();
|
|
142
|
+
}
|
|
143
|
+
} else {
|
|
144
|
+
start(command, options);
|
|
145
|
+
}
|
|
146
|
+
testResult(options);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
private void init(Options options) {
|
|
150
|
+
codeAssist = new CodeAssist(options);
|
|
151
|
+
|
|
152
|
+
Integer interval = options.getProgress();
|
|
153
|
+
progressMonitor = new ProgressMonitor(out, interval != null ? interval * 1000 : -1);
|
|
154
|
+
progressMonitor.setDaemon(true);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
private void start(String command, Options options) {
|
|
158
|
+
command(command, options);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
private void usage() {
|
|
162
|
+
out.print("RSense: Ruby development tools\n"
|
|
163
|
+
+ "\n"
|
|
164
|
+
+ "Usage: java -jar rsense.jar org.cx4a.rsense.Main command option...\n"
|
|
165
|
+
+ "\n"
|
|
166
|
+
+ "command:\n"
|
|
167
|
+
+ " code-completion - Code completion at specified position.\n"
|
|
168
|
+
+ " --file= - File to analyze\n"
|
|
169
|
+
+ " --location= - Location where you want to complete (pos, line:col, str)\n"
|
|
170
|
+
+ " --prefix= - Specify prefix string to complete\n"
|
|
171
|
+
+ "\n"
|
|
172
|
+
+ " type-inference - Infer type at specified position.\n"
|
|
173
|
+
+ " --file= - File to analyze\n"
|
|
174
|
+
+ " --location= - Location where you want to infer (pos, line:col, str)\n"
|
|
175
|
+
+ "\n"
|
|
176
|
+
+ " find-definition - Infer type at specified position.\n"
|
|
177
|
+
+ " --file= - File to analyze\n"
|
|
178
|
+
+ " --location= - Location where you want to find (pos, line:col, str)\n"
|
|
179
|
+
+ "\n"
|
|
180
|
+
+ " where - Print which class/module/method cursor at.\n"
|
|
181
|
+
+ " --file= - File to analyze\n"
|
|
182
|
+
+ " --line= - Line number to find\n"
|
|
183
|
+
+ "\n"
|
|
184
|
+
+ " load - Load file without any outputs.\n"
|
|
185
|
+
+ " --file= - File to analyze\n"
|
|
186
|
+
+ "\n"
|
|
187
|
+
+ " script - Run rsense script from file or stdin.\n"
|
|
188
|
+
+ " --prompt= - Prompt string in interactive shell mode\n"
|
|
189
|
+
+ " --no-prompt - Do not show prompt\n"
|
|
190
|
+
+ "\n"
|
|
191
|
+
+ " clear - Clear current environment.\n"
|
|
192
|
+
+ "\n"
|
|
193
|
+
+ " gc - Execute garbage collection.\n"
|
|
194
|
+
+ "\n"
|
|
195
|
+
+ " list-project - List loaded projects.\n"
|
|
196
|
+
+ "\n"
|
|
197
|
+
+ " open-project <dir> - Open project in <dir>.\n"
|
|
198
|
+
+ "\n"
|
|
199
|
+
+ " close-project <name> - Close project named <name>.\n"
|
|
200
|
+
+ "\n"
|
|
201
|
+
+ " environment - Print environment.\n"
|
|
202
|
+
+ "\n"
|
|
203
|
+
+ " help - Print this help.\n"
|
|
204
|
+
+ "\n"
|
|
205
|
+
+ " version - Print version information.\n"
|
|
206
|
+
+ "\n"
|
|
207
|
+
+ "script-command:\n"
|
|
208
|
+
+ " exit\n"
|
|
209
|
+
+ " quit - Exit script.\n"
|
|
210
|
+
+ "\n"
|
|
211
|
+
+ "common-options:\n"
|
|
212
|
+
+ " --home= - Specify RSense home directory\n"
|
|
213
|
+
+ " --debug - Print debug messages (shorthand of --log-evel=debug)\n"
|
|
214
|
+
+ " --log= - Log file to output (default stderr)\n"
|
|
215
|
+
+ " --log-level= - Log level (fixme, error, warn, message, info, debug)\n"
|
|
216
|
+
+ " --progress - Report progress immediately\n"
|
|
217
|
+
+ " --progress= - Report progress per seconds\n\n"
|
|
218
|
+
+ " --format= - Output format (plain, emacs)\n"
|
|
219
|
+
+ " --verbose - Verbose output\n"
|
|
220
|
+
+ " --time - Print timing of each command\n"
|
|
221
|
+
+ " --encoding= - Input encoding\n"
|
|
222
|
+
+ " --load-path= - Load path string (: or ; separated)\n"
|
|
223
|
+
+ " --gem-path= - Gem path string (: or ; separated)\n"
|
|
224
|
+
+ " --config= - Config file\n"
|
|
225
|
+
+ " --project= - Specify project name\n"
|
|
226
|
+
+ " --detect-project - Detect project from --file option\n"
|
|
227
|
+
+ " --detect-project= - Detect project from specified location\n"
|
|
228
|
+
+ "\n"
|
|
229
|
+
+ "test-options:\n"
|
|
230
|
+
+ " --test= - Specify fixture name\n"
|
|
231
|
+
+ " --test-color - Print test result with colors\n"
|
|
232
|
+
+ " --should-contain= - Success if data contains expected data\n"
|
|
233
|
+
+ " --should-not-contain= - Success if data doesn't contains expected data\n"
|
|
234
|
+
+ " --should-be= - Success if data equals to expected data\n"
|
|
235
|
+
+ " --should-be-empty - Success if data is empty\n"
|
|
236
|
+
+ "\n"
|
|
237
|
+
+ "debug-options:\n"
|
|
238
|
+
+ " --print-ast - Print parsed AST\n"
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
private void version() {
|
|
243
|
+
out.println(versionString());
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
private String versionString() {
|
|
247
|
+
return "RSense " + properties.getProperty("rsense.version");
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
private Options parseOptions(String[] args, int offset) {
|
|
251
|
+
Options options = new Options();
|
|
252
|
+
for (int i = offset; i < args.length; i++) {
|
|
253
|
+
String arg = args[i];
|
|
254
|
+
if (arg.startsWith("--")) {
|
|
255
|
+
String[] lr = arg.substring(2).split("=");
|
|
256
|
+
if (lr.length >= 1) {
|
|
257
|
+
options.addOption(lr[0], lr.length >= 2 ? lr[1] : null);
|
|
258
|
+
}
|
|
259
|
+
} else {
|
|
260
|
+
options.addRestArg(arg);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
String config = options.getConfig();
|
|
265
|
+
if (config != null) {
|
|
266
|
+
File configFile = new File(config);
|
|
267
|
+
if (configFile.isFile()) {
|
|
268
|
+
options.loadConfig(configFile);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return options;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
static HashMap map = new HashMap();
|
|
276
|
+
|
|
277
|
+
private void script(Options options) {
|
|
278
|
+
if (options.getRestArgs().isEmpty()) {
|
|
279
|
+
runScript(in, options, false);
|
|
280
|
+
} else {
|
|
281
|
+
try {
|
|
282
|
+
for (String filename : options.getRestArgs()) {
|
|
283
|
+
if (filename.contains("*")) {
|
|
284
|
+
PathMatcher matcher = FileSystems.getDefault().getPathMatcher("glob:" + filename);
|
|
285
|
+
for (String file: currentDir.list()) {
|
|
286
|
+
if (matcher.matches(new File(file).toPath()) && map.get(file) == null) {
|
|
287
|
+
map.put(file, true);
|
|
288
|
+
runFileScript(file, options);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
} else {
|
|
292
|
+
runFileScript(filename, options);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
} catch (IOException e) {
|
|
296
|
+
throw new RuntimeException(e);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
private void runFileScript(String filename, Options options) throws FileNotFoundException, IOException {
|
|
303
|
+
File file;
|
|
304
|
+
if (currentDir == null || !(file = new File(currentDir, filename)).exists()) {
|
|
305
|
+
// Load from current directory if possible
|
|
306
|
+
file = new File(filename);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
File oldCurrentDir = currentDir;
|
|
310
|
+
currentDir = file.getParentFile();
|
|
311
|
+
InputStream in = new FileInputStream(file);
|
|
312
|
+
try {
|
|
313
|
+
runScript(in, options, true);
|
|
314
|
+
} finally {
|
|
315
|
+
in.close();
|
|
316
|
+
currentDir = oldCurrentDir;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
private void runScript(InputStream in, Options options, boolean noprompt) {
|
|
321
|
+
String prompt = options.getPrompt();
|
|
322
|
+
if (prompt == null) {
|
|
323
|
+
prompt = options.defaultPrompt();
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
Reader oldInReader = inReader;
|
|
327
|
+
try {
|
|
328
|
+
BufferedReader reader = new BufferedReader(new InputStreamReader(in, options.getEncoding()));
|
|
329
|
+
inReader = reader;
|
|
330
|
+
String line;
|
|
331
|
+
String endMark = options.getEndMark();
|
|
332
|
+
if (endMark != null && endMark.length() == 0) {
|
|
333
|
+
endMark = Options.defaultEndMark();
|
|
334
|
+
}
|
|
335
|
+
while (true) {
|
|
336
|
+
if (!noprompt) {
|
|
337
|
+
out.print(prompt);
|
|
338
|
+
}
|
|
339
|
+
line = reader.readLine();
|
|
340
|
+
if (line == null) {
|
|
341
|
+
break;
|
|
342
|
+
} else if (line.matches("^\\s*#.*")) {
|
|
343
|
+
// comment
|
|
344
|
+
continue;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
String[] argv = StringUtil.shellwords(line);
|
|
348
|
+
if (argv.length > 0) {
|
|
349
|
+
String command = argv[0];
|
|
350
|
+
if (command.equals("exit") || command.equals("quit")) {
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
Options opts = parseOptions(argv, 1);
|
|
355
|
+
opts.inherit(options);
|
|
356
|
+
command(command, opts);
|
|
357
|
+
if (endMark != null) {
|
|
358
|
+
out.println(endMark);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
} catch (IOException e) {
|
|
363
|
+
throw new RuntimeException(e);
|
|
364
|
+
} finally {
|
|
365
|
+
this.inReader = oldInReader;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
private void command(String command, Options options) {
|
|
370
|
+
long start = System.currentTimeMillis();
|
|
371
|
+
Logger.info("command: %s", command);
|
|
372
|
+
if (options.isTest() && !options.isKeepEnv()) {
|
|
373
|
+
codeAssist.clear();
|
|
374
|
+
}
|
|
375
|
+
if (command.equals("code-completion")) {
|
|
376
|
+
commandCodeCompletion(options);
|
|
377
|
+
} else if (command.equals("type-inference")) {
|
|
378
|
+
commandTypeInference(options);
|
|
379
|
+
} else if (command.equals("find-definition")) {
|
|
380
|
+
commandFindDefinition(options);
|
|
381
|
+
} else if (command.equals("where")) {
|
|
382
|
+
commandWhere(options);
|
|
383
|
+
} else if (command.equals("load")) {
|
|
384
|
+
commandLoad(options);
|
|
385
|
+
} else if (command.equals("script")) {
|
|
386
|
+
script(options);
|
|
387
|
+
} else if (command.equals("clear")) {
|
|
388
|
+
commandClear(options);
|
|
389
|
+
} else if (command.equals("gc")) {
|
|
390
|
+
commandGC(options);
|
|
391
|
+
} else if (command.equals("list-project")) {
|
|
392
|
+
commandListProject(options);
|
|
393
|
+
} else if (command.equals("open-project")) {
|
|
394
|
+
commandOpenProject(options);
|
|
395
|
+
} else if (command.equals("close-project")) {
|
|
396
|
+
commandCloseProject(options);
|
|
397
|
+
} else if (command.equals("environment")) {
|
|
398
|
+
commandEnvironment(options);
|
|
399
|
+
} else if (command.equals("help")) {
|
|
400
|
+
commandHelp(options);
|
|
401
|
+
} else if (command.equals("version")) {
|
|
402
|
+
commandVersion(options);
|
|
403
|
+
} else if (command.length() == 0) {
|
|
404
|
+
} else {
|
|
405
|
+
commandUnknown(command, options);
|
|
406
|
+
}
|
|
407
|
+
if (options.isTime()) {
|
|
408
|
+
Logger.message("%s: %dms", command, (System.currentTimeMillis() - start));
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
private void commandCodeCompletion(Options options) {
|
|
413
|
+
CodeCompletionResult result;
|
|
414
|
+
Project project = codeAssist.getProject(options);
|
|
415
|
+
try {
|
|
416
|
+
progressMonitor.attach(project);
|
|
417
|
+
if (options.isFileStdin()) {
|
|
418
|
+
result = codeAssist.codeCompletion(project,
|
|
419
|
+
new File("(stdin)"),
|
|
420
|
+
options.getHereDocReader(inReader),
|
|
421
|
+
options.getLocation());
|
|
422
|
+
} else {
|
|
423
|
+
result = codeAssist.codeCompletion(project,
|
|
424
|
+
options.getFile(),
|
|
425
|
+
options.getEncoding(),
|
|
426
|
+
options.getLocation());
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
if (options.isPrintAST()) {
|
|
430
|
+
Logger.debug("AST:\n%s", result.getAST());
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
String prefix = options.getPrefix();
|
|
434
|
+
if (options.isTest()) {
|
|
435
|
+
Set<String> data = new HashSet<String>();
|
|
436
|
+
for (CodeCompletionResult.CompletionCandidate completion : result.getCandidates()) {
|
|
437
|
+
data.add(completion.getCompletion());
|
|
438
|
+
}
|
|
439
|
+
test(options, data);
|
|
440
|
+
} else {
|
|
441
|
+
if (options.isEmacsFormat()) {
|
|
442
|
+
out.print("(");
|
|
443
|
+
out.print("(completion");
|
|
444
|
+
for (CodeCompletionResult.CompletionCandidate completion : result.getCandidates()) {
|
|
445
|
+
if (prefix == null || completion.getCompletion().startsWith(prefix)) {
|
|
446
|
+
out.printf(" (\"%s\" \"%s\" \"%s\" \"%s\")",
|
|
447
|
+
completion.getCompletion(),
|
|
448
|
+
completion.getQualifiedName(),
|
|
449
|
+
completion.getBaseName(),
|
|
450
|
+
completion.getKind());
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
out.println(")");
|
|
454
|
+
codeAssistError(result, options);
|
|
455
|
+
out.println(")");
|
|
456
|
+
} else {
|
|
457
|
+
for (CodeCompletionResult.CompletionCandidate completion : result.getCandidates()) {
|
|
458
|
+
if (prefix == null || completion.getCompletion().startsWith(prefix)) {
|
|
459
|
+
out.printf("completion: %s %s %s %s\n",
|
|
460
|
+
completion.getCompletion(),
|
|
461
|
+
completion.getQualifiedName(),
|
|
462
|
+
completion.getBaseName(),
|
|
463
|
+
completion.getKind());
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
codeAssistError(result, options);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
} catch (Exception e) {
|
|
470
|
+
if (options.isTest()) {
|
|
471
|
+
testError(options);
|
|
472
|
+
}
|
|
473
|
+
commandException(e, options);
|
|
474
|
+
} finally {
|
|
475
|
+
progressMonitor.detach(project);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
private void commandTypeInference(Options options) {
|
|
480
|
+
TypeInferenceResult result;
|
|
481
|
+
Project project = codeAssist.getProject(options);
|
|
482
|
+
try {
|
|
483
|
+
progressMonitor.attach(project);
|
|
484
|
+
if (options.isFileStdin()) {
|
|
485
|
+
result = codeAssist.typeInference(project,
|
|
486
|
+
new File("(stdin)"),
|
|
487
|
+
options.getHereDocReader(inReader),
|
|
488
|
+
options.getLocation());
|
|
489
|
+
} else {
|
|
490
|
+
result = codeAssist.typeInference(project,
|
|
491
|
+
options.getFile(),
|
|
492
|
+
options.getEncoding(),
|
|
493
|
+
options.getLocation());
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
if (options.isPrintAST()) {
|
|
497
|
+
Logger.debug("AST:\n%s", result.getAST());
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
if (options.isTest()) {
|
|
501
|
+
Set<String> data = new HashSet<String>();
|
|
502
|
+
for (IRubyObject klass : result.getTypeSet()) {
|
|
503
|
+
data.add(klass.toString());
|
|
504
|
+
}
|
|
505
|
+
test(options, data);
|
|
506
|
+
} else {
|
|
507
|
+
if (options.isEmacsFormat()) {
|
|
508
|
+
out.print("(");
|
|
509
|
+
out.print("(type");
|
|
510
|
+
for (IRubyObject klass : result.getTypeSet()) {
|
|
511
|
+
out.print(" \"");
|
|
512
|
+
out.print(klass);
|
|
513
|
+
out.print("\"");
|
|
514
|
+
}
|
|
515
|
+
out.println(")");
|
|
516
|
+
codeAssistError(result, options);
|
|
517
|
+
out.println(")");
|
|
518
|
+
} else {
|
|
519
|
+
for (IRubyObject klass : result.getTypeSet()) {
|
|
520
|
+
out.print("type: ");
|
|
521
|
+
out.println(klass);
|
|
522
|
+
}
|
|
523
|
+
codeAssistError(result, options);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
} catch (Exception e) {
|
|
527
|
+
if (options.isTest()) {
|
|
528
|
+
testError(options);
|
|
529
|
+
}
|
|
530
|
+
commandException(e, options);
|
|
531
|
+
} finally {
|
|
532
|
+
progressMonitor.detach(project);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
private void commandFindDefinition(Options options) {
|
|
537
|
+
FindDefinitionResult result;
|
|
538
|
+
Project project = codeAssist.getProject(options);
|
|
539
|
+
try {
|
|
540
|
+
progressMonitor.attach(project);
|
|
541
|
+
if (options.isFileStdin()) {
|
|
542
|
+
result = codeAssist.findDefinition(project,
|
|
543
|
+
new File("(stdin)"),
|
|
544
|
+
options.getHereDocReader(inReader),
|
|
545
|
+
options.getLocation());
|
|
546
|
+
} else {
|
|
547
|
+
result = codeAssist.findDefinition(project,
|
|
548
|
+
options.getFile(),
|
|
549
|
+
options.getEncoding(),
|
|
550
|
+
options.getLocation());
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
if (options.isPrintAST()) {
|
|
554
|
+
Logger.debug("AST:\n%s", result.getAST());
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
if (options.isTest()) {
|
|
558
|
+
Set<String> data = new HashSet<String>();
|
|
559
|
+
for (SourceLocation location : result.getLocations()) {
|
|
560
|
+
data.add(location.toString());
|
|
561
|
+
}
|
|
562
|
+
test(options, data);
|
|
563
|
+
} else {
|
|
564
|
+
if (options.isEmacsFormat()) {
|
|
565
|
+
out.print("(");
|
|
566
|
+
out.print("(location");
|
|
567
|
+
for (SourceLocation location : result.getLocations()) {
|
|
568
|
+
if (location.getFile() != null)
|
|
569
|
+
out.printf(" (%s . %d)", emacsStringLiteral(location.getFile()), location.getLine());
|
|
570
|
+
}
|
|
571
|
+
out.println(")");
|
|
572
|
+
codeAssistError(result, options);
|
|
573
|
+
out.println(")");
|
|
574
|
+
} else {
|
|
575
|
+
for (SourceLocation location : result.getLocations()) {
|
|
576
|
+
out.printf("location: %d %s\n", location.getLine(), location.getFile());
|
|
577
|
+
}
|
|
578
|
+
codeAssistError(result, options);
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
} catch (Exception e) {
|
|
582
|
+
if (options.isTest())
|
|
583
|
+
testError(options);
|
|
584
|
+
commandException(e, options);
|
|
585
|
+
} finally {
|
|
586
|
+
progressMonitor.detach(project);
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
private void commandWhere(Options options) {
|
|
591
|
+
WhereResult result;
|
|
592
|
+
Project project = codeAssist.getProject(options);
|
|
593
|
+
try {
|
|
594
|
+
progressMonitor.attach(project);
|
|
595
|
+
if (options.isFileStdin()) {
|
|
596
|
+
result = codeAssist.where(project,
|
|
597
|
+
new File("(stdin)"),
|
|
598
|
+
options.getHereDocReader(inReader),
|
|
599
|
+
options.getLine());
|
|
600
|
+
} else {
|
|
601
|
+
result = codeAssist.where(project,
|
|
602
|
+
options.getFile(),
|
|
603
|
+
options.getEncoding(),
|
|
604
|
+
options.getLine());
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
if (options.isPrintAST()) {
|
|
608
|
+
Logger.debug("AST:\n%s", result.getAST());
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
if (options.isTest()) {
|
|
612
|
+
Set<String> data = new HashSet<String>();
|
|
613
|
+
if (result.getName() != null)
|
|
614
|
+
data.add(result.getName());
|
|
615
|
+
test(options, data);
|
|
616
|
+
} else {
|
|
617
|
+
if (options.isEmacsFormat()) {
|
|
618
|
+
out.print("(");
|
|
619
|
+
if (result.getName() != null)
|
|
620
|
+
out.printf("(name . \"%s\")", result.getName());
|
|
621
|
+
codeAssistError(result, options);
|
|
622
|
+
out.println(")");
|
|
623
|
+
} else {
|
|
624
|
+
if (result.getName() != null) {
|
|
625
|
+
out.print("name: ");
|
|
626
|
+
out.println(result.getName());
|
|
627
|
+
}
|
|
628
|
+
codeAssistError(result, options);
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
} catch (Exception e) {
|
|
632
|
+
if (options.isTest())
|
|
633
|
+
testError(options);
|
|
634
|
+
commandException(e, options);
|
|
635
|
+
} finally {
|
|
636
|
+
progressMonitor.detach(project);
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
private void commandLoad(Options options) {
|
|
641
|
+
LoadResult result;
|
|
642
|
+
Project project = codeAssist.getProject(options);
|
|
643
|
+
try {
|
|
644
|
+
progressMonitor.attach(project);
|
|
645
|
+
if (options.isFileStdin()) {
|
|
646
|
+
result = codeAssist.load(project,
|
|
647
|
+
new File("(stdin)"),
|
|
648
|
+
options.getHereDocReader(inReader));
|
|
649
|
+
} else {
|
|
650
|
+
result = codeAssist.load(project,
|
|
651
|
+
options.getFile(),
|
|
652
|
+
options.getEncoding());
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
if (options.isPrintAST()) {
|
|
656
|
+
Logger.debug("AST:\n%s", result.getAST());
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
if (options.isEmacsFormat()) {
|
|
660
|
+
out.print("(");
|
|
661
|
+
codeAssistError(result, options);
|
|
662
|
+
out.println(")");
|
|
663
|
+
} else {
|
|
664
|
+
codeAssistError(result, options);
|
|
665
|
+
}
|
|
666
|
+
} catch (Exception e) {
|
|
667
|
+
commandException(e, options);
|
|
668
|
+
} finally {
|
|
669
|
+
progressMonitor.detach(project);
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
private void commandClear(Options options) {
|
|
674
|
+
codeAssist.clear();
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
private void commandGC(Options options) {
|
|
678
|
+
System.gc();
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
private void commandListProject(Options options) {
|
|
682
|
+
boolean first = true;
|
|
683
|
+
boolean verbose = options.isVerbose();
|
|
684
|
+
if (options.isEmacsFormat()) {
|
|
685
|
+
out.print("(");
|
|
686
|
+
}
|
|
687
|
+
for (Map.Entry<String, Project> entry : codeAssist.getProjects().entrySet()) {
|
|
688
|
+
String name = entry.getKey();
|
|
689
|
+
Project project = entry.getValue();
|
|
690
|
+
|
|
691
|
+
if (verbose) {
|
|
692
|
+
if (!first) {
|
|
693
|
+
out.println();
|
|
694
|
+
}
|
|
695
|
+
first = false;
|
|
696
|
+
|
|
697
|
+
out.printf("%s:\n", name);
|
|
698
|
+
out.printf(" path: %s\n", project.getPath());
|
|
699
|
+
out.println(" load-path:");
|
|
700
|
+
for (File dir : project.getLoadPath()) {
|
|
701
|
+
out.println(" - " + dir.toString());
|
|
702
|
+
}
|
|
703
|
+
out.println(" gem-path:");
|
|
704
|
+
for (File dir : project.getGemPath()) {
|
|
705
|
+
out.println(" - " + dir.toString());
|
|
706
|
+
}
|
|
707
|
+
} else {
|
|
708
|
+
if (options.isEmacsFormat()) {
|
|
709
|
+
out.print("\"" + name + "\" ");
|
|
710
|
+
} else {
|
|
711
|
+
out.println(name);
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
if (options.isEmacsFormat()) {
|
|
716
|
+
out.println(")");
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
private void commandOpenProject(Options options) {
|
|
721
|
+
for (String name : options.getRestArgs()) {
|
|
722
|
+
codeAssist.openProject(name, options);
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
private void commandCloseProject(Options options) {
|
|
727
|
+
for (String name : options.getRestArgs()) {
|
|
728
|
+
codeAssist.closeProject(name);
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
private void commandEnvironment(Options options) {
|
|
733
|
+
out.println("version: " + versionString());
|
|
734
|
+
out.println("home: " + options.getRsenseHome());
|
|
735
|
+
out.println("debug: " + (options.isDebug() ? "yes" : "no"));
|
|
736
|
+
out.println("log: " + (options.getLog() != null ? options.getLog() : ""));
|
|
737
|
+
out.println("load-path:");
|
|
738
|
+
for (String path : options.getLoadPath()) {
|
|
739
|
+
out.println(" - " + path);
|
|
740
|
+
}
|
|
741
|
+
out.println("gem-path:");
|
|
742
|
+
for (String path : options.getLoadPath()) {
|
|
743
|
+
out.println(" - " + path);
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
private void commandHelp(Options options) {
|
|
748
|
+
if (options.isEmacsFormat()) {
|
|
749
|
+
out.print("\"");
|
|
750
|
+
}
|
|
751
|
+
usage();
|
|
752
|
+
if (options.isEmacsFormat()) {
|
|
753
|
+
out.println("\"");
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
private void commandVersion(Options options) {
|
|
758
|
+
if (options.isEmacsFormat()) {
|
|
759
|
+
out.println("\"" + versionString() + "\"");
|
|
760
|
+
} else {
|
|
761
|
+
version();
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
private void commandUnknown(String command, Options options) {
|
|
766
|
+
if (options.isEmacsFormat()) {
|
|
767
|
+
out.printf("((error . \"unknown command: %s\"))\n", command);
|
|
768
|
+
} else {
|
|
769
|
+
out.printf("unknown command: %s\n", command);
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
private void commandException(Exception e, Options options) {
|
|
774
|
+
if (options.isEmacsFormat()) {
|
|
775
|
+
out.println("((error . \"unexpected error\"))");
|
|
776
|
+
} else if (e instanceof Options.InvalidOptionException) {
|
|
777
|
+
out.println(e.getMessage());
|
|
778
|
+
} else {
|
|
779
|
+
out.println("unexpected error:");
|
|
780
|
+
e.printStackTrace(out);
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
private void test(Options options, Collection<String> data) {
|
|
785
|
+
if (options.isShouldBeGiven()) {
|
|
786
|
+
Set<String> shouldBe = options.getShouldBe();
|
|
787
|
+
if (shouldBe.equals(data)) {
|
|
788
|
+
testSuccess(options);
|
|
789
|
+
} else {
|
|
790
|
+
String expected = shouldBe.isEmpty() ? "empty" : shouldBe.toString();
|
|
791
|
+
testFailure(options, "%s should be %s", data, expected);
|
|
792
|
+
}
|
|
793
|
+
} else {
|
|
794
|
+
Set<String> shouldContain = options.getShouldContain();
|
|
795
|
+
Set<String> shouldNotContain = options.getShouldNotContain();
|
|
796
|
+
for (String str : shouldContain) {
|
|
797
|
+
if (!data.contains(str)) {
|
|
798
|
+
testFailure(options, "%s should be in %s", str, shouldContain);
|
|
799
|
+
return;
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
for (String str : shouldNotContain) {
|
|
803
|
+
if (data.contains(str)) {
|
|
804
|
+
testFailure(options, "%s should not be in %s", str, shouldNotContain);
|
|
805
|
+
return;
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
testSuccess(options);
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
private void testSuccess(Options options) {
|
|
813
|
+
testSuccess(options, null);
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
private void testSuccess(Options options, String format, Object... args) {
|
|
817
|
+
if (testStats == null) {
|
|
818
|
+
testStats = new TestStats();
|
|
819
|
+
}
|
|
820
|
+
testStats.count++;
|
|
821
|
+
testStats.success++;
|
|
822
|
+
if (options.isTestColor()) {
|
|
823
|
+
out.printf("\33[34m%s\33[0m... [\33[1;32mOK\33[0m]", options.getTest());
|
|
824
|
+
} else {
|
|
825
|
+
out.printf("%s... [OK]", options.getTest());
|
|
826
|
+
}
|
|
827
|
+
if (format != null) {
|
|
828
|
+
out.print("\n ");
|
|
829
|
+
out.printf(format, args);
|
|
830
|
+
}
|
|
831
|
+
out.println();
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
private void testFailure(Options options) {
|
|
835
|
+
testFailure(options, null);
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
private void testFailure(Options options, String format, Object... args) {
|
|
839
|
+
if (testStats == null) {
|
|
840
|
+
testStats = new TestStats();
|
|
841
|
+
}
|
|
842
|
+
testStats.count++;
|
|
843
|
+
testStats.failure++;
|
|
844
|
+
if (options.isTestColor()) {
|
|
845
|
+
out.printf("\33[34m%s\33[0m... [\33[1;31mBAD\33[0m]", options.getTest());
|
|
846
|
+
} else {
|
|
847
|
+
out.printf("%s... [BAD]", options.getTest());
|
|
848
|
+
}
|
|
849
|
+
if (format != null) {
|
|
850
|
+
out.print("\n ");
|
|
851
|
+
out.printf(format, args);
|
|
852
|
+
}
|
|
853
|
+
out.println();
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
private void testError(Options options) {
|
|
857
|
+
if (testStats == null) {
|
|
858
|
+
testStats = new TestStats();
|
|
859
|
+
}
|
|
860
|
+
testStats.count++;
|
|
861
|
+
testStats.error++;
|
|
862
|
+
if (options.isTestColor()) {
|
|
863
|
+
out.printf("\33[34m%s\33[0m... [\33[1;31mERROR\33[0m]", options.getTest());
|
|
864
|
+
} else {
|
|
865
|
+
out.printf("%s... [BAD]", options.getTest());
|
|
866
|
+
}
|
|
867
|
+
out.println();
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
private void testResult(Options options) {
|
|
871
|
+
if (testStats != null) {
|
|
872
|
+
String ok, bad, error;
|
|
873
|
+
if (options.isTestColor()) {
|
|
874
|
+
ok = String.format("\33[32;1m%s\33[0m", testStats.success);
|
|
875
|
+
if (testStats.failure > 0) {
|
|
876
|
+
bad = String.format("\33[31;1m%s\33[0m", testStats.failure);
|
|
877
|
+
} else {
|
|
878
|
+
bad = String.valueOf(testStats.failure);
|
|
879
|
+
}
|
|
880
|
+
if (testStats.error > 0) {
|
|
881
|
+
error = String.format("\33[31;1m%s\33[0m", testStats.error);
|
|
882
|
+
} else {
|
|
883
|
+
error = String.valueOf(testStats.error);
|
|
884
|
+
}
|
|
885
|
+
} else {
|
|
886
|
+
ok = String.valueOf(testStats.success);
|
|
887
|
+
bad = String.valueOf(testStats.failure);
|
|
888
|
+
error = String.valueOf(testStats.error);
|
|
889
|
+
}
|
|
890
|
+
out.printf("test: count=%d, success=%s, failure=%s, error=%s\n", testStats.count, ok, bad, error);
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
private void codeAssistError(CodeAssistResult result, Options options) {
|
|
895
|
+
boolean emacsFormat = options.isEmacsFormat();
|
|
896
|
+
if (emacsFormat) {
|
|
897
|
+
out.print(" (error");
|
|
898
|
+
}
|
|
899
|
+
for (CodeAssistError error : result.getErrors()) {
|
|
900
|
+
if (emacsFormat) {
|
|
901
|
+
out.print(" ");
|
|
902
|
+
out.print(error.getShortError());
|
|
903
|
+
} else {
|
|
904
|
+
out.printf("error: ", error.getShortError());
|
|
905
|
+
out.println(error.getCause());
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
if (emacsFormat) {
|
|
909
|
+
out.println(")");
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
private String emacsStringLiteral(String s) {
|
|
914
|
+
return "\"" + s.replace("\\", "\\\\").replaceAll("\"", "\\\"") + "\"";
|
|
915
|
+
}
|
|
916
|
+
}
|