mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Java REPL support for JDK9 (project Kulla, JShell) (IDEA-161611)
This commit is contained in:
Generated
+1
@@ -10,6 +10,7 @@
|
||||
<file url="file://$PROJECT_DIR$/jps/jps-builders-6/src/org/jetbrains/jps/javac/OptimizedFileManager.java" />
|
||||
<file url="file://$PROJECT_DIR$/jps/jps-builders-6/src/org/jetbrains/jps/javac/OptimizedFileManager17.java" />
|
||||
<file url="file://$PROJECT_DIR$/java/java-tests/testSrc/com/intellij/index/IndexTestGenerator.scala" />
|
||||
<file url="file://$PROJECT_DIR$/java/execution/jshell-frontend/src/com/intellij/execution/jshell/frontend/Main.java" />
|
||||
</excludeFromCompile>
|
||||
<resourceExtensions>
|
||||
<entry name=".+\.(properties|gif|png|jpeg|jpg|xml|dtd|tld|xsd|ft|html|template)" />
|
||||
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
<component name="libraryTable">
|
||||
<library name="precompiled_jshell-frontend">
|
||||
<CLASSES>
|
||||
<root url="jar://$PROJECT_DIR$/lib/jshell-frontend.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
Generated
+2
@@ -157,6 +157,8 @@
|
||||
<module fileurl="file://$PROJECT_DIR$/jps/model-impl/jps-model-tests.iml" filepath="$PROJECT_DIR$/jps/model-impl/jps-model-tests.iml" group="jps" />
|
||||
<module fileurl="file://$PROJECT_DIR$/jps/model-serialization/jps-serialization-tests.iml" filepath="$PROJECT_DIR$/jps/model-serialization/jps-serialization-tests.iml" group="jps" />
|
||||
<module fileurl="file://$PROJECT_DIR$/jps/standalone-builder/jps-standalone-builder.iml" filepath="$PROJECT_DIR$/jps/standalone-builder/jps-standalone-builder.iml" group="jps" />
|
||||
<module fileurl="file://$PROJECT_DIR$/java/execution/jshell-frontend/jshell-frontend.iml" filepath="$PROJECT_DIR$/java/execution/jshell-frontend/jshell-frontend.iml" group="java" />
|
||||
<module fileurl="file://$PROJECT_DIR$/java/execution/jshell-protocol/jshell-protocol.iml" filepath="$PROJECT_DIR$/java/execution/jshell-protocol/jshell-protocol.iml" group="java" />
|
||||
<module fileurl="file://$PROJECT_DIR$/json/json.iml" filepath="$PROJECT_DIR$/json/json.iml" group="json" />
|
||||
<module fileurl="file://$PROJECT_DIR$/json/tests/json-tests.iml" filepath="$PROJECT_DIR$/json/tests/json-tests.iml" group="json" />
|
||||
<module fileurl="file://$PROJECT_DIR$/java/jsp-base-openapi/jsp-base-openapi.iml" filepath="$PROJECT_DIR$/java/jsp-base-openapi/jsp-base-openapi.iml" group="java" />
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
<orderEntry type="module" module-name="java-impl" />
|
||||
<orderEntry type="module" module-name="java-indexing-api" />
|
||||
<orderEntry type="module" module-name="smRunner" />
|
||||
<orderEntry type="module" module-name="jshell-protocol" />
|
||||
<orderEntry type="library" name="Coverage" level="project" />
|
||||
<orderEntry type="library" scope="RUNTIME" name="precompiled_jshell-frontend" level="project" />
|
||||
</component>
|
||||
<component name="copyright">
|
||||
<Base>
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.execution.jshell;
|
||||
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 06-Jun-17
|
||||
*/
|
||||
class DropJShellStateAction extends AnAction{
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.execution.jshell.ExecuteJShellAction");
|
||||
private static final AnAction ourInstance = new DropJShellStateAction();
|
||||
|
||||
private DropJShellStateAction() {
|
||||
super(AllIcons.Actions.Delete);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
final Project project = e.getProject();
|
||||
if (project == null) {
|
||||
return;
|
||||
}
|
||||
final VirtualFile vFile = CommonDataKeys.VIRTUAL_FILE.getData(e.getDataContext());
|
||||
if (vFile == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
final JShellHandler handler = JShellHandler.getAssociatedHandler(vFile);
|
||||
if (handler != null) {
|
||||
handler.toFront();
|
||||
handler.dropState();
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
LOG.info(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static AnAction getSharedInstance() {
|
||||
return ourInstance;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.execution.jshell;
|
||||
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys;
|
||||
import com.intellij.openapi.actionSystem.LangDataKeys;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.ex.util.EditorUtil;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.util.DocumentUtil;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 06-Jun-17
|
||||
*/
|
||||
class ExecuteJShellAction extends AnAction{
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.execution.jshell.ExecuteJShellAction");
|
||||
private static final AnAction ourInstance = new ExecuteJShellAction();
|
||||
|
||||
private ExecuteJShellAction() {
|
||||
super(AllIcons.Toolwindows.ToolWindowRun);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
final Project project = e.getProject();
|
||||
if (project == null) {
|
||||
return;
|
||||
}
|
||||
final Editor editor = CommonDataKeys.EDITOR.getData(e.getDataContext());
|
||||
if (editor == null) {
|
||||
return;
|
||||
}
|
||||
final VirtualFile vFile = CommonDataKeys.VIRTUAL_FILE.getData(e.getDataContext());
|
||||
if (vFile == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
FileDocumentManager.getInstance().saveAllDocuments();
|
||||
|
||||
final Document document = editor.getDocument();
|
||||
final TextRange selectedRange = EditorUtil.getSelectionInAnyMode(editor);
|
||||
String code = null;
|
||||
if (selectedRange.isEmpty()) {
|
||||
final PsiElement snippet = getSnippetFromContext(project, e);
|
||||
if (snippet != null) {
|
||||
code = snippet.getText();
|
||||
}
|
||||
}
|
||||
else {
|
||||
code = document.getText(selectedRange);
|
||||
}
|
||||
|
||||
if (StringUtil.isEmptyOrSpaces(code)) {
|
||||
JShellDiagnostic.notifyInfo("Nothing to execute", project);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
JShellHandler handler = JShellHandler.getAssociatedHandler(vFile);
|
||||
if (handler == null) {
|
||||
handler = JShellHandler.create(project, vFile, e.getData(LangDataKeys.MODULE));
|
||||
}
|
||||
if (handler != null) {
|
||||
handler.toFront();
|
||||
handler.evaluate(code);
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
JShellDiagnostic.notifyError(ex, project);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiElement getSnippetFromContext(Project project, AnActionEvent e) {
|
||||
final Editor editor = e.getData(CommonDataKeys.EDITOR);
|
||||
if (editor != null) {
|
||||
final PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
|
||||
if (file instanceof PsiJShellFile) {
|
||||
|
||||
final PsiElement context = getContextElement(file, editor.getDocument(), editor.getCaretModel().getOffset());
|
||||
for (PsiElement element = context; element != null; element = element.getParent()) {
|
||||
if (element instanceof PsiJShellImportHolder || element instanceof PsiJShellHolderMethod) {
|
||||
return element;
|
||||
}
|
||||
if (element instanceof PsiMember && ((PsiMember)element).getContainingClass() instanceof PsiJShellRootClass) {
|
||||
return element;
|
||||
}
|
||||
if (element instanceof PsiClass) {
|
||||
final PsiClass containingClass = ((PsiClass)element).getContainingClass();
|
||||
if (containingClass == null || containingClass instanceof PsiJShellRootClass) {
|
||||
return element;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static PsiElement getContextElement(PsiFile file, final Document doc, final int offset) {
|
||||
final int begin = DocumentUtil.getLineStartOffset(offset, doc);
|
||||
final int end = DocumentUtil.getLineEndOffset(offset, doc);
|
||||
PsiElement result = null;
|
||||
for (int off = begin; off <= end; off++) {
|
||||
result = file.findElementAt(off);
|
||||
if (result != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (result instanceof PsiWhiteSpace) {
|
||||
final PsiElement next = result.getNextSibling();
|
||||
if (next == null || next.getTextOffset() > end) {
|
||||
break;
|
||||
}
|
||||
result = next;
|
||||
}
|
||||
|
||||
while (result != null) {
|
||||
final PsiElement parent = result.getParent();
|
||||
if (parent instanceof PsiJShellSyntheticElement) {
|
||||
break;
|
||||
}
|
||||
result = parent;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static AnAction getSharedInstance() {
|
||||
return ourInstance;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.execution.jshell;
|
||||
|
||||
import com.intellij.notification.Notification;
|
||||
import com.intellij.notification.NotificationType;
|
||||
import com.intellij.openapi.project.Project;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 04-Jul-17
|
||||
*/
|
||||
public class JShellDiagnostic {
|
||||
private static final String NOTIFICATION_GROUP = "JSHELL_NOTIFICATIONS";
|
||||
private static final String TITLE = "JShell";
|
||||
|
||||
public static void notifyInfo(final String text, final Project project) {
|
||||
new Notification(NOTIFICATION_GROUP, TITLE, text, NotificationType.INFORMATION).notify(project);
|
||||
}
|
||||
|
||||
public static void notifyError(Exception ex, final Project project) {
|
||||
new Notification(NOTIFICATION_GROUP, TITLE, ex.getMessage(), NotificationType.ERROR).notify(project);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,447 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.execution.jshell;
|
||||
|
||||
import com.intellij.execution.ExecutionManager;
|
||||
import com.intellij.execution.Executor;
|
||||
import com.intellij.execution.configurations.GeneralCommandLine;
|
||||
import com.intellij.execution.executors.DefaultRunExecutor;
|
||||
import com.intellij.execution.impl.ConsoleState;
|
||||
import com.intellij.execution.impl.ConsoleViewImpl;
|
||||
import com.intellij.execution.impl.ConsoleViewRunningState;
|
||||
import com.intellij.execution.jshell.protocol.*;
|
||||
import com.intellij.execution.jshell.protocol.Event;
|
||||
import com.intellij.execution.process.*;
|
||||
import com.intellij.execution.ui.ConsoleViewContentType;
|
||||
import com.intellij.execution.ui.RunContentDescriptor;
|
||||
import com.intellij.execution.ui.actions.CloseAction;
|
||||
import com.intellij.openapi.actionSystem.*;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.PathManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager;
|
||||
import com.intellij.openapi.fileEditor.FileEditorManagerListener;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.projectRoots.JavaSdkType;
|
||||
import com.intellij.openapi.projectRoots.JavaSdkVersion;
|
||||
import com.intellij.openapi.projectRoots.Sdk;
|
||||
import com.intellij.openapi.roots.ModuleRootManager;
|
||||
import com.intellij.openapi.roots.OrderEnumerator;
|
||||
import com.intellij.openapi.roots.ProjectRootManager;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.util.concurrency.SequentialTaskExecutor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.ide.PooledThreadExecutor;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.io.*;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 01-Jun-17
|
||||
*/
|
||||
public class JShellHandler {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.execution.jshell.JShellHandler");
|
||||
public static final Key<JShellHandler> MARKER_KEY = Key.create("JShell console key");
|
||||
private static final Charset ourCharset = StandardCharsets.UTF_8;
|
||||
|
||||
private static final Executor EXECUTOR = DefaultRunExecutor.getRunExecutorInstance();
|
||||
private static final String JSHELL_FRONTEND_JAR = "jshell-frontend.jar";
|
||||
|
||||
private final Project myProject;
|
||||
private final RunContentDescriptor myRunContent;
|
||||
private final ConsoleViewImpl myConsoleView;
|
||||
private final OSProcessHandler myProcess;
|
||||
private final MessageReader<Response> myMessageReader;
|
||||
private final MessageWriter<Request> myMessageWriter;
|
||||
private final ExecutorService myTaskQueue = new SequentialTaskExecutor("JShell Command Queue", PooledThreadExecutor.INSTANCE);
|
||||
|
||||
private JShellHandler(@NotNull Project project,
|
||||
RunContentDescriptor descriptor,
|
||||
ConsoleViewImpl view,
|
||||
VirtualFile contentFile,
|
||||
OSProcessHandler handler) throws Exception {
|
||||
myProject = project;
|
||||
myRunContent = descriptor;
|
||||
myConsoleView = view;
|
||||
myProcess = handler;
|
||||
|
||||
final PipedInputStream is = new PipedInputStream();
|
||||
final OutputStreamWriter readerSink = new OutputStreamWriter(new PipedOutputStream(is));
|
||||
myMessageReader = new MessageReader<>(is, Response.class);
|
||||
myMessageWriter = new MessageWriter<>(handler.getProcessInput(), Request.class);
|
||||
|
||||
handler.addProcessListener(new ProcessAdapter() {
|
||||
@Override
|
||||
public void onTextAvailable(ProcessEvent event, Key outputType) {
|
||||
if (outputType == ProcessOutputTypes.STDOUT) {
|
||||
try {
|
||||
readerSink.write(event.getText());
|
||||
readerSink.flush();
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.info(e);
|
||||
}
|
||||
}
|
||||
else {
|
||||
myConsoleView.print(event.getText(), outputType == ProcessOutputTypes.STDERR? ConsoleViewContentType.ERROR_OUTPUT : ConsoleViewContentType.SYSTEM_OUTPUT);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processTerminated(ProcessEvent event) {
|
||||
if (getAssociatedHandler(contentFile) == JShellHandler.this) {
|
||||
// process terminated either by closing file or by close action
|
||||
contentFile.putUserData(MARKER_KEY, null);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
project.getMessageBus().connect().subscribe(FileEditorManagerListener.FILE_EDITOR_MANAGER, new FileEditorManagerListener() {
|
||||
@Override
|
||||
public void fileClosed(@NotNull FileEditorManager source, @NotNull VirtualFile file) {
|
||||
if (file.equals(contentFile)) {
|
||||
// if file was closed then kill process and hide console content
|
||||
JShellHandler.this.stop();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
contentFile.putUserData(MARKER_KEY, this);
|
||||
view.attachToProcess(handler);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static JShellHandler getAssociatedHandler(VirtualFile contentFile) {
|
||||
return contentFile != null? contentFile.getUserData(MARKER_KEY) : null;
|
||||
}
|
||||
|
||||
public static JShellHandler create(@NotNull final Project project, @NotNull final VirtualFile contentFile, @Nullable Module module) throws Exception{
|
||||
final OSProcessHandler processHandler = launchProcess(project, module);
|
||||
final String title = "JShell " + contentFile.getNameWithoutExtension();
|
||||
|
||||
final ConsoleViewImpl consoleView = new MyConsoleView(project);
|
||||
final RunContentDescriptor descriptor = new RunContentDescriptor(consoleView, processHandler, new JPanel(new BorderLayout()), title);
|
||||
final JShellHandler jshellHandler = new JShellHandler(project, descriptor, consoleView, contentFile, processHandler);
|
||||
|
||||
// must call getComponent before createConsoleActions()
|
||||
final JComponent consoleViewComponent = consoleView.getComponent();
|
||||
|
||||
final DefaultActionGroup actionGroup = new DefaultActionGroup();
|
||||
//actionGroup.add(new BuildAndRestartConsoleAction(module, project, defaultExecutor, descriptor, restarter(project, contentFile)));
|
||||
//actionGroup.addSeparator();
|
||||
actionGroup.addAll(consoleView.createConsoleActions());
|
||||
actionGroup.add(new CloseAction(EXECUTOR, descriptor, project) {
|
||||
@Override
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
jshellHandler.stop();
|
||||
if (!processHandler.waitFor(10000)) {
|
||||
processHandler.destroyProcess();
|
||||
}
|
||||
super.actionPerformed(e);
|
||||
}
|
||||
});
|
||||
|
||||
final ActionToolbar toolbar = ActionManager.getInstance().createActionToolbar(ActionPlaces.UNKNOWN, actionGroup, false);
|
||||
toolbar.setTargetComponent(consoleViewComponent);
|
||||
|
||||
final JComponent ui = descriptor.getComponent();
|
||||
ui.add(consoleViewComponent, BorderLayout.CENTER);
|
||||
ui.add(toolbar.getComponent(), BorderLayout.WEST);
|
||||
|
||||
processHandler.startNotify();
|
||||
|
||||
ExecutionManager.getInstance(project).getContentManager().showRunContent(EXECUTOR, descriptor);
|
||||
return jshellHandler;
|
||||
}
|
||||
|
||||
// todo: do we need to include project's compiled classes into the classpath or libraries only?
|
||||
// todo: if we include project classes, make sure they are compiled
|
||||
private static OSProcessHandler launchProcess(@NotNull Project project, @Nullable Module module) throws Exception{
|
||||
final Sdk sdk = module != null? ModuleRootManager.getInstance(module).getSdk() : ProjectRootManager.getInstance(project).getProjectSdk();
|
||||
if (sdk == null || !(sdk.getSdkType() instanceof JavaSdkType)) {
|
||||
throw new ExecException(
|
||||
(sdk != null ? "Expected Java SDK" : " SDK is not configured") +
|
||||
(module != null? " for module " + module.getName() : " for project " + project.getName())
|
||||
);
|
||||
}
|
||||
final JavaSdkType javaSdkType = (JavaSdkType)sdk.getSdkType();
|
||||
final String ver = sdk.getVersionString();
|
||||
final JavaSdkVersion sdkVersion = ver == null? null : JavaSdkVersion.fromVersionString(ver);
|
||||
if (sdkVersion == null) {
|
||||
throw new ExecException("Cannot determine version for JDK " + sdk.getName() + ". Please re-configure the JDK.");
|
||||
}
|
||||
if (!sdkVersion.isAtLeast(JavaSdkVersion.JDK_1_9)) {
|
||||
throw new ExecException("JDK version is " + sdkVersion.getDescription() + ". JDK 9 or higher is needed to run JShell.");
|
||||
}
|
||||
final String vmExePath = javaSdkType.getVMExecutablePath(sdk);
|
||||
if (vmExePath == null) {
|
||||
throw new ExecException("Cannot determine path to VM executable for JDK " + sdk.getName() + ". Please re-configure the JDK.");
|
||||
}
|
||||
final File executableFile = new File(vmExePath);
|
||||
final String frontEndPath = findFrontEndLibrary();
|
||||
if (frontEndPath == null) {
|
||||
throw new ExecException("Library " + JSHELL_FRONTEND_JAR + " not found in IDE classpath");
|
||||
}
|
||||
final GeneralCommandLine cmdLine = new GeneralCommandLine();
|
||||
cmdLine.setExePath(executableFile.getAbsolutePath());
|
||||
cmdLine.setWorkDirectory(executableFile.getParent());
|
||||
cmdLine.setCharset(ourCharset);
|
||||
cmdLine.addParameter("--add-modules");
|
||||
cmdLine.addParameter("java.xml.bind");
|
||||
|
||||
final StringBuilder launchCp = new StringBuilder().append(frontEndPath);
|
||||
final String protocolJar = getLibPath(Endpoint.class);
|
||||
if (protocolJar != null) {
|
||||
launchCp.append(File.pathSeparator).append(protocolJar);
|
||||
}
|
||||
if (launchCp.length() > 0) {
|
||||
cmdLine.addParameter("-classpath");
|
||||
cmdLine.addParameter(launchCp.toString());
|
||||
}
|
||||
cmdLine.addParameter("com.intellij.execution.jshell.frontend.Main");
|
||||
final Set<File> cp = new LinkedHashSet<>();
|
||||
final Computable<OrderEnumerator> orderEnumerator = module != null ? () -> ModuleRootManager.getInstance(module).orderEntries()
|
||||
: () -> ProjectRootManager.getInstance(project).orderEntries();
|
||||
ApplicationManager.getApplication().runReadAction(() -> {
|
||||
for (String s : orderEnumerator.compute().librariesOnly().recursively().withoutSdk().getPathsList().getPathList()) {
|
||||
cp.add(new File(s));
|
||||
}
|
||||
});
|
||||
cmdLine.addParameter("--class-path");
|
||||
cmdLine.addParameter(StringUtil.join(cp, File.pathSeparator));
|
||||
return new OSProcessHandler(cmdLine);
|
||||
}
|
||||
|
||||
private static String findFrontEndLibrary() {
|
||||
final String path = PathManager.getResourceRoot(JShellHandler.class.getClassLoader(), "/com/intellij/execution/jshell/frontend/Marker.class");
|
||||
return path != null? path : JSHELL_FRONTEND_JAR;
|
||||
}
|
||||
|
||||
private static String getLibPath(final Class<?> aClass) {
|
||||
return PathManager.getResourceRoot(aClass, "/" + aClass.getName().replace('.', '/') + ".class");
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
myProcess.destroyProcess(); // use force
|
||||
ExecutionManager.getInstance(myProject).getContentManager().removeRunContent(EXECUTOR, myRunContent);
|
||||
}
|
||||
|
||||
public void toFront() {
|
||||
ExecutionManager.getInstance(myProject).getContentManager().toFrontRunContent(EXECUTOR, myRunContent);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Future<Response> evaluate(@NotNull String code) {
|
||||
return StringUtil.isEmptyOrSpaces(code) ? null : myTaskQueue.submit(() -> sendInput(new Request(nextUid(), Request.Command.EVAL, code)));
|
||||
}
|
||||
|
||||
public void dropState() {
|
||||
myTaskQueue.submit(() -> sendInput(new Request(nextUid(), Request.Command.DROP_STATE, null)));
|
||||
}
|
||||
|
||||
private static String nextUid() {
|
||||
return UUID.randomUUID().toString();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Response sendInput(final Request request) {
|
||||
final boolean alive = !myProcess.isProcessTerminating() && !myProcess.isProcessTerminated();
|
||||
if (alive) {
|
||||
myConsoleView.performWhenNoDeferredOutput(() -> {
|
||||
try {
|
||||
myMessageWriter.send(request);
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.info(e);
|
||||
}
|
||||
});
|
||||
try {
|
||||
final StringBuffer stdOut = new StringBuffer();
|
||||
final Response response = myMessageReader.receive(unparsedText -> stdOut.append(unparsedText));
|
||||
renderResponse(response, stdOut.toString());
|
||||
return response;
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.info(e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void renderResponse(Response response, String stdOut) {
|
||||
//myConsoleView.print("\n-------------------evaluation " + response.getUid() + "------------------------", ConsoleViewContentType.NORMAL_OUTPUT);
|
||||
final List<Event> events = response.getEvents();
|
||||
if (events != null) {
|
||||
for (Event event : events) {
|
||||
if (event.getCauseSnippet() == null) {
|
||||
final String exception = event.getExceptionText();
|
||||
if (!StringUtil.isEmptyOrSpaces(exception)) {
|
||||
myConsoleView.print("\n" + exception, ConsoleViewContentType.SYSTEM_OUTPUT);
|
||||
}
|
||||
final String diagnostic = event.getDiagnostic();
|
||||
if (!StringUtil.isEmptyOrSpaces(diagnostic)) {
|
||||
myConsoleView.print("\n" + diagnostic, ConsoleViewContentType.SYSTEM_OUTPUT);
|
||||
}
|
||||
|
||||
final String descr = getEventDescription(event);
|
||||
if (!StringUtil.isEmptyOrSpaces(descr)) {
|
||||
myConsoleView.print("\n" + descr, ConsoleViewContentType.SYSTEM_OUTPUT);
|
||||
}
|
||||
final CodeSnippet snippet = event.getSnippet();
|
||||
final String value = snippet != null && !snippet.getSubKind().hasValue()? null : event.getValue();
|
||||
if (value != null) {
|
||||
myConsoleView.print(" = " + (value.isEmpty()? "\"\"" : value), ConsoleViewContentType.NORMAL_OUTPUT);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
myConsoleView.print("\nCompleted.", ConsoleViewContentType.SYSTEM_OUTPUT);
|
||||
}
|
||||
if (!StringUtil.isEmpty(stdOut)) {
|
||||
//myConsoleView.print("\n-----evaluation output-----\n", ConsoleViewContentType.NORMAL_OUTPUT);
|
||||
myConsoleView.print("\n", ConsoleViewContentType.NORMAL_OUTPUT);
|
||||
// delegate unparsed text directly to console
|
||||
if (!"\n".equals(stdOut) /*hack to ignore possible empty line before 'message-begin' merker*/) {
|
||||
myConsoleView.print(stdOut, ConsoleViewContentType.NORMAL_OUTPUT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String getEventDescription(Event event) {
|
||||
final CodeSnippet snippet = event.getSnippet();
|
||||
if (event.getCauseSnippet() != null || snippet == null) {
|
||||
return "";
|
||||
}
|
||||
final CodeSnippet.Status status = event.getStatus();
|
||||
final CodeSnippet.Kind kind = snippet.getKind();
|
||||
final CodeSnippet.SubKind subKind = snippet.getSubKind();
|
||||
|
||||
String presentation = snippet.getPresentation();
|
||||
if (presentation == null || subKind == CodeSnippet.SubKind.TEMP_VAR_EXPRESSION_SUBKIND) {
|
||||
presentation = StringUtil.trim(snippet.getCodeText());
|
||||
}
|
||||
|
||||
String actionLabel;
|
||||
if (event.getPreviousStatus() == CodeSnippet.Status.NONEXISTENT && status.isDefined()) {
|
||||
if (subKind == CodeSnippet.SubKind.VAR_DECLARATION_WITH_INITIALIZER_SUBKIND ||
|
||||
/*subKind == CodeSnippet.SubKind.TEMP_VAR_EXPRESSION_SUBKIND ||*/
|
||||
!subKind.isExecutable()) {
|
||||
actionLabel = "Defined";
|
||||
}
|
||||
else {
|
||||
actionLabel = "";
|
||||
}
|
||||
}
|
||||
else if (status == CodeSnippet.Status.REJECTED){
|
||||
actionLabel = "Rejected";
|
||||
}
|
||||
else if (status == CodeSnippet.Status.DROPPED) {
|
||||
actionLabel = "Dropped";
|
||||
}
|
||||
else if (status == CodeSnippet.Status.OVERWRITTEN) {
|
||||
actionLabel = "Overwritten";
|
||||
}
|
||||
else {
|
||||
actionLabel = "";
|
||||
}
|
||||
|
||||
String kindLabel;
|
||||
if (kind == CodeSnippet.Kind.TYPE_DECL) {
|
||||
if (subKind == CodeSnippet.SubKind.INTERFACE_SUBKIND) {
|
||||
kindLabel = "interface";
|
||||
}
|
||||
else if (subKind == CodeSnippet.SubKind.ENUM_SUBKIND) {
|
||||
kindLabel = "enum";
|
||||
}
|
||||
else if (subKind == CodeSnippet.SubKind.ANNOTATION_TYPE_SUBKIND) {
|
||||
kindLabel = "annotation";
|
||||
}
|
||||
else {
|
||||
kindLabel = "class";
|
||||
}
|
||||
}
|
||||
else if (kind == CodeSnippet.Kind.VAR){
|
||||
kindLabel = subKind == CodeSnippet.SubKind.TEMP_VAR_EXPRESSION_SUBKIND ? ""/*"temp var"*/ : "field";
|
||||
}
|
||||
else if (kind == CodeSnippet.Kind.METHOD) {
|
||||
kindLabel = "method";
|
||||
}
|
||||
else if (kind == CodeSnippet.Kind.IMPORT) {
|
||||
kindLabel = subKind == CodeSnippet.SubKind.STATIC_IMPORT_ON_DEMAND_SUBKIND || subKind == CodeSnippet.SubKind.SINGLE_STATIC_IMPORT_SUBKIND ? "static import" : "import";
|
||||
}
|
||||
else {
|
||||
kindLabel = "";
|
||||
}
|
||||
|
||||
final StringBuilder descr = new StringBuilder();
|
||||
descr.append(actionLabel);
|
||||
if (!actionLabel.isEmpty()) {
|
||||
descr.append(" ");
|
||||
}
|
||||
if (!kindLabel.isEmpty()) {
|
||||
descr.append(kindLabel).append(" ");
|
||||
}
|
||||
descr.append(presentation);
|
||||
|
||||
return descr.toString();
|
||||
}
|
||||
|
||||
private static class MyConsoleView extends ConsoleViewImpl {
|
||||
public MyConsoleView(Project project) {
|
||||
super(project, GlobalSearchScope.allScope(project), true, new ConsoleState.NotStartedStated() {
|
||||
@NotNull
|
||||
@Override
|
||||
public ConsoleState attachTo(@NotNull ConsoleViewImpl console, ProcessHandler processHandler) {
|
||||
// do not automatically display all the text that is sent/recieved between processes
|
||||
// the ootput from console will be formatted and sent to console view
|
||||
return new ConsoleViewRunningState(console, processHandler, this, false, false);
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class ExecException extends Exception {
|
||||
public ExecException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public ExecException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Throwable fillInStackTrace() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.execution.jshell;
|
||||
|
||||
import com.intellij.execution.console.ConsoleRootType;
|
||||
import com.intellij.ide.highlighter.JShellFileType;
|
||||
import com.intellij.openapi.actionSystem.CommonShortcuts;
|
||||
import com.intellij.openapi.fileEditor.FileEditor;
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager;
|
||||
import com.intellij.openapi.fileEditor.TextEditor;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 09-May-17
|
||||
*/
|
||||
public final class JShellRootType extends ConsoleRootType {
|
||||
public static final String CONTENT_ID = "jshell_console";
|
||||
|
||||
public JShellRootType() {
|
||||
super("jshell", "JShell Console");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static JShellRootType getInstance() {
|
||||
return findByClass(JShellRootType.class);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getDefaultFileExtension() {
|
||||
return JShellFileType.DEFAULT_EXTENSION;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getContentPathName(@NotNull String id) {
|
||||
assert id == CONTENT_ID;
|
||||
return CONTENT_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fileOpened(@NotNull final VirtualFile file, @NotNull FileEditorManager source) {
|
||||
for (FileEditor fileEditor : source.getAllEditors(file)) {
|
||||
if (fileEditor instanceof TextEditor) {
|
||||
ExecuteJShellAction.getSharedInstance().registerCustomShortcutSet(CommonShortcuts.CTRL_ENTER, fileEditor.getComponent());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.execution.jshell;
|
||||
|
||||
import com.intellij.execution.console.ConsoleHistoryController;
|
||||
import com.intellij.ide.scratch.ScratchFileService;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.LangDataKeys;
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 09-May-17
|
||||
*/
|
||||
public class LaunchJShellConsoleAction extends AnAction{
|
||||
public LaunchJShellConsoleAction() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
final Project project = e.getProject();
|
||||
if (project == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final VirtualFile contentFile = ConsoleHistoryController.getContentFile(
|
||||
JShellRootType.getInstance(),
|
||||
JShellRootType.CONTENT_ID,
|
||||
ScratchFileService.Option.create_new_always
|
||||
);
|
||||
assert contentFile != null;
|
||||
try {
|
||||
FileEditorManager.getInstance(project).openFile(contentFile, true);
|
||||
JShellHandler.create(project, contentFile, e.getData(LangDataKeys.MODULE));
|
||||
}
|
||||
catch (Exception ex) {
|
||||
JShellDiagnostic.notifyError(ex, project);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(AnActionEvent e) {
|
||||
super.update(e);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.execution.jshell;
|
||||
|
||||
import com.intellij.ide.scratch.RootType;
|
||||
import com.intellij.ide.scratch.ScratchFileService;
|
||||
import com.intellij.openapi.actionSystem.ActionManager;
|
||||
import com.intellij.openapi.actionSystem.ActionToolbar;
|
||||
import com.intellij.openapi.actionSystem.DefaultActionGroup;
|
||||
import com.intellij.openapi.editor.impl.EditorHeaderComponent;
|
||||
import com.intellij.openapi.fileEditor.FileEditor;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.ui.EditorNotifications;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 06-Jun-17
|
||||
*/
|
||||
public class SnippetEditorDecorator extends EditorNotifications.Provider<JComponent>{
|
||||
public static final Key<JComponent> CONTEXT_KEY = Key.create("jshell.editor.toolbar");
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Key<JComponent> getKey() {
|
||||
return CONTEXT_KEY;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public JComponent createNotificationPanel(@NotNull VirtualFile file, @NotNull FileEditor fileEditor) {
|
||||
final RootType root = ScratchFileService.getInstance().getRootType(file);
|
||||
|
||||
if ((root instanceof JShellRootType)) {
|
||||
final DefaultActionGroup actions = new DefaultActionGroup(ExecuteJShellAction.getSharedInstance(), DropJShellStateAction.getSharedInstance());
|
||||
final ActionToolbar toolbar = ActionManager.getInstance().createActionToolbar("JShellSnippetEditor", actions, true);
|
||||
|
||||
final EditorHeaderComponent header = new EditorHeaderComponent();
|
||||
header.add(toolbar.getComponent());
|
||||
return header;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="module" module-name="jshell-protocol" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -0,0 +1,200 @@
|
||||
package com.intellij.execution.jshell.frontend;
|
||||
|
||||
import com.intellij.execution.jshell.protocol.*;
|
||||
import jdk.jshell.*;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 12-Jun-17
|
||||
*
|
||||
* @noinspection UseOfSystemOutOrSystemErr
|
||||
*/
|
||||
public class Main {
|
||||
private static final String ARG_CLASSPATH = "--class-path";
|
||||
private static final Consumer<String> NULL_CONSUMER = s -> {};
|
||||
|
||||
//private static Request createTestRequest() {
|
||||
// return new Request(UUID.randomUUID().toString(), Request.Command.EVAL, "int a = 77;\n" +
|
||||
// "int b = a + 3");
|
||||
//}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
final MessageReader<Request> reader = new MessageReader<>(new BufferedInputStream(System.in), Request.class);
|
||||
final MessageWriter<Response> writer = new MessageWriter<>(new BufferedOutputStream(System.out), Response.class);
|
||||
|
||||
try (JShell shell = JShell.create()) {
|
||||
configureJShell(args, shell);
|
||||
while (true) {
|
||||
final Request request = reader.receive(NULL_CONSUMER);
|
||||
if (request == null) {
|
||||
break;
|
||||
}
|
||||
final Request.Command command = request.getCommand();
|
||||
if (command == Request.Command.EXIT) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Response response = new Response();
|
||||
response.setUid(request.getUid());
|
||||
|
||||
try {
|
||||
if (command == Request.Command.DROP_STATE) {
|
||||
shell.snippets().forEach(snippet -> exportEvents(shell, shell.drop(snippet), response));
|
||||
}
|
||||
else if (command == Request.Command.EVAL) {
|
||||
final List<String> toEval = new ArrayList<>();
|
||||
|
||||
String input = request.getCodeText();
|
||||
do {
|
||||
final SourceCodeAnalysis.CompletionInfo info = shell.sourceCodeAnalysis().analyzeCompletion(input);
|
||||
final SourceCodeAnalysis.Completeness completeness = info.completeness();
|
||||
if (completeness.isComplete()) {
|
||||
toEval.add(completeness == SourceCodeAnalysis.Completeness.COMPLETE_WITH_SEMI ? info.source() + ";" : info.source());
|
||||
}
|
||||
else if (completeness != SourceCodeAnalysis.Completeness.EMPTY){
|
||||
// we try to evaluate even the snippets containing errors so that those errors will be displayed
|
||||
toEval.add(info.source());
|
||||
}
|
||||
input = info.remaining();
|
||||
}
|
||||
while (input != null && !input.isEmpty());
|
||||
|
||||
for (String inputElement : toEval) {
|
||||
exportEvents(shell, shell.eval(inputElement), response);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
writer.send(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
finally {
|
||||
System.out.println("\nJShell terminated.");
|
||||
}
|
||||
}
|
||||
|
||||
private static void exportEvents(JShell shell, List<SnippetEvent> events, Response response) {
|
||||
for (SnippetEvent event : events) {
|
||||
final Snippet.Status status = event.status();
|
||||
final Snippet snippet = event.snippet();
|
||||
final Event e = new Event(
|
||||
createCodeSnippet(snippet),
|
||||
createCodeSnippet(event.causeSnippet()),
|
||||
convertEnum(status, CodeSnippet.Status.class),
|
||||
convertEnum(event.previousStatus(), CodeSnippet.Status.class),
|
||||
event.value()
|
||||
);
|
||||
//noinspection ThrowableNotThrown
|
||||
final JShellException exception = event.exception();
|
||||
if (exception != null) {
|
||||
e.setExceptionText(exception.getMessage());
|
||||
}
|
||||
if (status == Snippet.Status.RECOVERABLE_DEFINED || status == Snippet.Status.RECOVERABLE_NOT_DEFINED || status == Snippet.Status.REJECTED) {
|
||||
final StringBuilder buf = new StringBuilder();
|
||||
shell.diagnostics(snippet).forEach(diagnostic -> {
|
||||
final String message = diagnostic.getMessage(Locale.US);
|
||||
if (message != null && !message.isEmpty()) {
|
||||
if (buf.length() > 0){
|
||||
buf.append("\n");
|
||||
}
|
||||
if (diagnostic.isError()) {
|
||||
buf.append("ERROR: ");
|
||||
}
|
||||
buf.append(message);
|
||||
}
|
||||
});
|
||||
if (buf.length() > 0) {
|
||||
e.setDiagnostic(buf.toString());
|
||||
}
|
||||
}
|
||||
response.addEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void configureJShell(String[] args, JShell shell) {
|
||||
// todo: add more parameters if needed
|
||||
boolean cpFound = false;
|
||||
for (String arg : args) {
|
||||
if (ARG_CLASSPATH.equals(arg)) {
|
||||
cpFound = true;
|
||||
}
|
||||
else {
|
||||
if (cpFound) {
|
||||
cpFound = false;
|
||||
for (String path : arg.split(File.pathSeparator)) {
|
||||
shell.addToClasspath(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static CodeSnippet createCodeSnippet(Snippet snippet) {
|
||||
return snippet == null ? null : new CodeSnippet(
|
||||
snippet.id(),
|
||||
convertEnum(snippet.kind(), CodeSnippet.Kind.class),
|
||||
convertEnum(snippet.subKind(), CodeSnippet.SubKind.class),
|
||||
snippet.source(),
|
||||
createPresentation(snippet)
|
||||
);
|
||||
}
|
||||
|
||||
private static String createPresentation(Snippet snippet) {
|
||||
if (snippet instanceof ExpressionSnippet) {
|
||||
final ExpressionSnippet expr = (ExpressionSnippet)snippet;
|
||||
return expr.typeName() + " " + expr.name();
|
||||
}
|
||||
if (snippet instanceof ImportSnippet) {
|
||||
return ((ImportSnippet)snippet).fullname();
|
||||
}
|
||||
if (snippet instanceof MethodSnippet) {
|
||||
final MethodSnippet methodSnippet = (MethodSnippet)snippet;
|
||||
final StringBuilder buf = new StringBuilder(getReturnType(methodSnippet));
|
||||
if (buf.length() > 0) {
|
||||
buf.append(" ");
|
||||
}
|
||||
return buf.append(methodSnippet.name()).append("(").append(methodSnippet.parameterTypes()).append(")").toString();
|
||||
}
|
||||
if (snippet instanceof TypeDeclSnippet) {
|
||||
return ((TypeDeclSnippet)snippet).name();
|
||||
}
|
||||
if (snippet instanceof VarSnippet) {
|
||||
final VarSnippet varSnippet = (VarSnippet)snippet;
|
||||
return varSnippet.typeName() + " " + varSnippet.name();
|
||||
}
|
||||
if (snippet instanceof PersistentSnippet) {
|
||||
return ((PersistentSnippet)snippet).name();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String getReturnType(MethodSnippet methodSnippet) {
|
||||
final String sig = methodSnippet.signature();
|
||||
final int idx = sig == null? -1 : sig.lastIndexOf(")");
|
||||
return idx > 0? sig.substring(idx + 1) : "";
|
||||
}
|
||||
|
||||
private static <TI extends Enum<TI>, TO extends Enum<TO>> TO convertEnum(Enum<TI> from, Class<TO> toEnumOfClass) {
|
||||
if (from != null) {
|
||||
try {
|
||||
return Enum.valueOf(toEnumOfClass, from.name());
|
||||
}
|
||||
catch (IllegalArgumentException ignored) {
|
||||
}
|
||||
}
|
||||
return Enum.valueOf(toEnumOfClass, "UNKNOWN");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.intellij.execution.jshell.frontend;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 13-Jun-17
|
||||
*/
|
||||
public interface Marker {
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/testStrc" isTestSource="true" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" scope="TEST" name="JUnit4" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
+200
@@ -0,0 +1,200 @@
|
||||
package com.intellij.execution.jshell.protocol;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlEnum;
|
||||
import javax.xml.bind.annotation.XmlType;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 14-Jun-17
|
||||
*/
|
||||
@XmlType
|
||||
public class CodeSnippet {
|
||||
|
||||
@XmlEnum
|
||||
public enum Status {
|
||||
VALID(true, true),
|
||||
RECOVERABLE_DEFINED(true, true),
|
||||
RECOVERABLE_NOT_DEFINED(true, false),
|
||||
DROPPED(false, false),
|
||||
OVERWRITTEN(false, false),
|
||||
REJECTED(false, false),
|
||||
NONEXISTENT(false, false),
|
||||
UNKNOWN (false, false);
|
||||
|
||||
private final boolean myIsActive;
|
||||
private final boolean myIsDefined;
|
||||
|
||||
Status(boolean isActive, boolean isDefined) {
|
||||
this.myIsActive = isActive;
|
||||
this.myIsDefined = isDefined;
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
return myIsActive;
|
||||
}
|
||||
|
||||
public boolean isDefined() {
|
||||
return myIsDefined;
|
||||
}
|
||||
}
|
||||
|
||||
@XmlEnum
|
||||
public enum Kind {
|
||||
IMPORT(true),
|
||||
TYPE_DECL(true),
|
||||
METHOD(true),
|
||||
VAR(true),
|
||||
EXPRESSION(false),
|
||||
STATEMENT(false),
|
||||
ERRONEOUS(false),
|
||||
UNKNOWN(false);
|
||||
|
||||
private final boolean isPersistent;
|
||||
Kind(boolean isPersistent) {
|
||||
this.isPersistent = isPersistent;
|
||||
}
|
||||
public boolean isPersistent() {
|
||||
return isPersistent;
|
||||
}
|
||||
}
|
||||
|
||||
@XmlEnum
|
||||
public enum SubKind {
|
||||
SINGLE_TYPE_IMPORT_SUBKIND(Kind.IMPORT),
|
||||
TYPE_IMPORT_ON_DEMAND_SUBKIND(Kind.IMPORT),
|
||||
SINGLE_STATIC_IMPORT_SUBKIND(Kind.IMPORT),
|
||||
STATIC_IMPORT_ON_DEMAND_SUBKIND(Kind.IMPORT),
|
||||
CLASS_SUBKIND(Kind.TYPE_DECL),
|
||||
INTERFACE_SUBKIND(Kind.TYPE_DECL),
|
||||
ENUM_SUBKIND(Kind.TYPE_DECL),
|
||||
ANNOTATION_TYPE_SUBKIND(Kind.TYPE_DECL),
|
||||
METHOD_SUBKIND(Kind.METHOD),
|
||||
VAR_DECLARATION_SUBKIND(Kind.VAR),
|
||||
VAR_DECLARATION_WITH_INITIALIZER_SUBKIND(Kind.VAR, true, true),
|
||||
TEMP_VAR_EXPRESSION_SUBKIND(Kind.VAR, true, true),
|
||||
VAR_VALUE_SUBKIND(Kind.EXPRESSION, true, true),
|
||||
ASSIGNMENT_SUBKIND(Kind.EXPRESSION, true, true),
|
||||
OTHER_EXPRESSION_SUBKIND(Kind.EXPRESSION, true, true),
|
||||
STATEMENT_SUBKIND(Kind.STATEMENT, true, false),
|
||||
UNKNOWN_SUBKIND(Kind.ERRONEOUS, false, false);
|
||||
|
||||
private final boolean isExecutable;
|
||||
private final boolean hasValue;
|
||||
private final Kind kind;
|
||||
|
||||
SubKind(Kind kind) {
|
||||
this.kind = kind;
|
||||
this.isExecutable = false;
|
||||
this.hasValue = false;
|
||||
}
|
||||
|
||||
SubKind(Kind kind, boolean isExecutable, boolean hasValue) {
|
||||
this.kind = kind;
|
||||
this.isExecutable = isExecutable;
|
||||
this.hasValue = hasValue;
|
||||
}
|
||||
|
||||
public boolean isExecutable() {
|
||||
return isExecutable;
|
||||
}
|
||||
|
||||
public boolean hasValue() {
|
||||
return hasValue;
|
||||
}
|
||||
|
||||
public Kind kind() {
|
||||
return kind;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private String myId;
|
||||
private Kind myKind;
|
||||
private SubKind mySubKind;
|
||||
private String myCodeText;
|
||||
private String myPresentation;
|
||||
|
||||
public CodeSnippet() {
|
||||
}
|
||||
|
||||
public CodeSnippet(String id, Kind kind, SubKind subKind, String codeText, String presentation) {
|
||||
myId = id;
|
||||
myKind = kind;
|
||||
mySubKind = subKind;
|
||||
myCodeText = codeText;
|
||||
myPresentation = presentation;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return myId;
|
||||
}
|
||||
|
||||
@XmlAttribute
|
||||
public void setId(String id) {
|
||||
myId = id;
|
||||
}
|
||||
|
||||
public Kind getKind() {
|
||||
return myKind;
|
||||
}
|
||||
|
||||
@XmlAttribute
|
||||
public void setKind(Kind kind) {
|
||||
myKind = kind;
|
||||
}
|
||||
|
||||
public SubKind getSubKind() {
|
||||
return mySubKind;
|
||||
}
|
||||
|
||||
@XmlAttribute
|
||||
public void setSubKind(SubKind subKind) {
|
||||
mySubKind = subKind;
|
||||
}
|
||||
|
||||
public String getCodeText() {
|
||||
return myCodeText;
|
||||
}
|
||||
|
||||
@XmlElement
|
||||
public void setCodeText(String codeText) {
|
||||
myCodeText = codeText;
|
||||
}
|
||||
|
||||
public String getPresentation() {
|
||||
return myPresentation;
|
||||
}
|
||||
|
||||
@XmlElement
|
||||
public void setPresentation(String presentation) {
|
||||
myPresentation = presentation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
CodeSnippet snippet = (CodeSnippet)o;
|
||||
|
||||
if (myId != null ? !myId.equals(snippet.myId) : snippet.myId != null) return false;
|
||||
if (myKind != snippet.myKind) return false;
|
||||
if (mySubKind != snippet.mySubKind) return false;
|
||||
if (myCodeText != null ? !myCodeText.equals(snippet.myCodeText) : snippet.myCodeText != null) return false;
|
||||
if (myPresentation != null ? !myPresentation.equals(snippet.myPresentation) : snippet.myPresentation != null) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = myId != null ? myId.hashCode() : 0;
|
||||
result = 31 * result + (myKind != null ? myKind.hashCode() : 0);
|
||||
result = 31 * result + (mySubKind != null ? mySubKind.hashCode() : 0);
|
||||
result = 31 * result + (myCodeText != null ? myCodeText.hashCode() : 0);
|
||||
result = 31 * result + (myPresentation != null ? myPresentation.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package com.intellij.execution.jshell.protocol;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 12-Jun-17
|
||||
*/
|
||||
public class Endpoint {
|
||||
public static final String MSG_BEGIN = "__#begin#__";
|
||||
public static final String MSG_END = "__#end#__";
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package com.intellij.execution.jshell.protocol;
|
||||
|
||||
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 12-Jun-17
|
||||
*/
|
||||
@XmlRootElement
|
||||
public class Event {
|
||||
|
||||
private CodeSnippet myCauseSnippet;
|
||||
private CodeSnippet mySnippet;
|
||||
private CodeSnippet.Status myPreviousStatus;
|
||||
private CodeSnippet.Status myStatus;
|
||||
private String myValue;
|
||||
private String myExceptionText;
|
||||
private String myDiagnostic;
|
||||
|
||||
public Event() {
|
||||
}
|
||||
|
||||
public Event(CodeSnippet snippet, CodeSnippet causeSnippet,
|
||||
CodeSnippet.Status status, CodeSnippet.Status previousStatus,
|
||||
String value) {
|
||||
myCauseSnippet = causeSnippet;
|
||||
mySnippet = snippet;
|
||||
myPreviousStatus = previousStatus;
|
||||
myStatus = status;
|
||||
myValue = value;
|
||||
}
|
||||
|
||||
public CodeSnippet.Status getPreviousStatus() {
|
||||
return myPreviousStatus;
|
||||
}
|
||||
|
||||
@XmlElement
|
||||
public void setPreviousStatus(CodeSnippet.Status previousStatus) {
|
||||
myPreviousStatus = previousStatus;
|
||||
}
|
||||
|
||||
public CodeSnippet.Status getStatus() {
|
||||
return myStatus;
|
||||
}
|
||||
|
||||
@XmlElement
|
||||
public void setStatus(CodeSnippet.Status status) {
|
||||
myStatus = status;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return myValue;
|
||||
}
|
||||
|
||||
@XmlElement
|
||||
public void setValue(String value) {
|
||||
myValue = value;
|
||||
}
|
||||
|
||||
public CodeSnippet getCauseSnippet() {
|
||||
return myCauseSnippet;
|
||||
}
|
||||
|
||||
@XmlElement
|
||||
public void setCauseSnippet(CodeSnippet causeSnippet) {
|
||||
myCauseSnippet = causeSnippet;
|
||||
}
|
||||
|
||||
public CodeSnippet getSnippet() {
|
||||
return mySnippet;
|
||||
}
|
||||
|
||||
@XmlElement
|
||||
public void setSnippet(CodeSnippet snippet) {
|
||||
mySnippet = snippet;
|
||||
}
|
||||
|
||||
public String getExceptionText() {
|
||||
return myExceptionText;
|
||||
}
|
||||
|
||||
@XmlElement
|
||||
public void setExceptionText(String exceptionText) {
|
||||
myExceptionText = exceptionText;
|
||||
}
|
||||
|
||||
public String getDiagnostic() {
|
||||
return myDiagnostic;
|
||||
}
|
||||
|
||||
@XmlElement
|
||||
public void setDiagnostic(String diagnostic) {
|
||||
myDiagnostic = diagnostic;
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package com.intellij.execution.jshell.protocol;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 12-Jun-17
|
||||
*/
|
||||
public abstract class Message {
|
||||
private String myUid;
|
||||
|
||||
public Message() {
|
||||
}
|
||||
|
||||
public Message(String uid) {
|
||||
myUid = uid;
|
||||
}
|
||||
|
||||
public String getUid() {
|
||||
return myUid;
|
||||
}
|
||||
|
||||
@XmlAttribute
|
||||
public void setUid(String uid) {
|
||||
myUid = uid;
|
||||
}
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
package com.intellij.execution.jshell.protocol;
|
||||
|
||||
import javax.xml.bind.JAXBContext;
|
||||
import javax.xml.bind.JAXBException;
|
||||
import java.io.*;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 12-Jun-17
|
||||
*/
|
||||
public class MessageReader<T> extends Endpoint {
|
||||
private final BufferedReader myIn;
|
||||
private final JAXBContext myContext;
|
||||
|
||||
public MessageReader(InputStream input, Class<T> msgType) throws Exception {
|
||||
myIn = new BufferedReader(new InputStreamReader(input));
|
||||
myContext = JAXBContext.newInstance(msgType);
|
||||
}
|
||||
|
||||
public T receive(final Consumer<String> unparsedOutputSink) throws IOException {
|
||||
while (true) {
|
||||
String line = myIn.readLine();
|
||||
if (line == null) {
|
||||
return null;
|
||||
}
|
||||
if (MSG_BEGIN.equals(line)) {
|
||||
final StringBuilder buf = new StringBuilder();
|
||||
for (String body = myIn.readLine(); !MSG_END.equals(body.trim()); body = myIn.readLine()) {
|
||||
buf.append(body).append("\n");
|
||||
}
|
||||
try {
|
||||
//noinspection unchecked
|
||||
return (T)myContext.createUnmarshaller().unmarshal(new StringReader(buf.toString()));
|
||||
}
|
||||
catch (JAXBException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
else {
|
||||
unparsedOutputSink.accept(line + "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
package com.intellij.execution.jshell.protocol;
|
||||
|
||||
import javax.xml.bind.JAXBContext;
|
||||
import javax.xml.bind.JAXBException;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 12-Jun-17
|
||||
*/
|
||||
public class MessageWriter<T extends Message> extends Endpoint {
|
||||
private final BufferedWriter myOut;
|
||||
private final JAXBContext myContext;
|
||||
|
||||
public MessageWriter(OutputStream output, Class<T> msgType) throws Exception {
|
||||
myOut = new BufferedWriter(new OutputStreamWriter(output));
|
||||
myContext = JAXBContext.newInstance(msgType);
|
||||
}
|
||||
|
||||
public void send(T message) throws IOException {
|
||||
try {
|
||||
myOut.newLine();
|
||||
myOut.write(MSG_BEGIN);
|
||||
myOut.newLine();
|
||||
myContext.createMarshaller().marshal(message, myOut);
|
||||
}
|
||||
catch (JAXBException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
finally {
|
||||
myOut.newLine();
|
||||
myOut.write(MSG_END);
|
||||
myOut.newLine();
|
||||
myOut.flush();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
package com.intellij.execution.jshell.protocol;
|
||||
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlEnum;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 12-Jun-17
|
||||
*/
|
||||
@XmlRootElement
|
||||
public class Request extends Message{
|
||||
private Command myCommand;
|
||||
private String myCodeText;
|
||||
|
||||
@XmlEnum
|
||||
public enum Command{
|
||||
EVAL, DROP_STATE, EXIT
|
||||
}
|
||||
|
||||
public Request() {
|
||||
}
|
||||
|
||||
public Request(String uid, Command cmd, String codeText) {
|
||||
super(uid);
|
||||
myCommand = cmd;
|
||||
myCodeText = codeText;
|
||||
}
|
||||
|
||||
public Command getCommand() {
|
||||
return myCommand;
|
||||
}
|
||||
|
||||
@XmlElement
|
||||
public void setCommand(Command command) {
|
||||
myCommand = command;
|
||||
}
|
||||
|
||||
public String getCodeText() {
|
||||
return myCodeText;
|
||||
}
|
||||
|
||||
@XmlElement
|
||||
public void setCodeText(String codeText) {
|
||||
myCodeText = codeText;
|
||||
}
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package com.intellij.execution.jshell.protocol;
|
||||
|
||||
import com.sun.xml.internal.txw2.annotation.XmlElement;
|
||||
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 12-Jun-17
|
||||
*/
|
||||
@XmlRootElement
|
||||
public class Response extends Message{
|
||||
private List<Event> myEvents;
|
||||
|
||||
public Response() {
|
||||
}
|
||||
|
||||
public Response(String uid, Event... events) {
|
||||
super(uid);
|
||||
Collections.addAll(myEvents = new ArrayList<>(), events);
|
||||
}
|
||||
|
||||
@XmlElement
|
||||
public List<Event> getEvents() {
|
||||
return myEvents;
|
||||
}
|
||||
|
||||
@XmlElement
|
||||
public void setEvents(List<Event> events) {
|
||||
myEvents = events;
|
||||
}
|
||||
|
||||
public void addEvent(Event event) {
|
||||
List<Event> events = myEvents;
|
||||
if (events == null) {
|
||||
events = new ArrayList<>();
|
||||
myEvents = events;
|
||||
}
|
||||
events.add(event);
|
||||
}
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
package com.intellij.execution.jshell.protocol;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.io.PipedInputStream;
|
||||
import java.io.PipedOutputStream;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 12-Jun-17
|
||||
*/
|
||||
public class JShellMessageMarshallingTest extends TestCase {
|
||||
|
||||
private static final Event[] EMPTY_EVENT_ARRAY = new Event[0];
|
||||
|
||||
public void testSendReceive() throws Exception {
|
||||
final PipedInputStream clientIn = new PipedInputStream();
|
||||
final PipedOutputStream serverOut = new PipedOutputStream(clientIn);
|
||||
|
||||
final PipedInputStream serverIn = new PipedInputStream();
|
||||
final PipedOutputStream clientOut = new PipedOutputStream(serverIn);
|
||||
|
||||
final MessageWriter<Request> clientWriter = new MessageWriter<>(clientOut, Request.class);
|
||||
final MessageReader<Request> serverReader = new MessageReader<>(serverIn, Request.class);
|
||||
final MessageWriter<Response> serverWriter = new MessageWriter<>(serverOut, Response.class);
|
||||
final MessageReader<Response> clientReader = new MessageReader<>(clientIn, Response.class);
|
||||
|
||||
final Request request = new Request(UUID.randomUUID().toString(), Request.Command.EVAL,
|
||||
"System.out.println(\"Hello, World!\");\n int var = 7 + 7;");
|
||||
clientWriter.send(request);
|
||||
final Request receivedRequest = serverReader.receive(s -> {});
|
||||
assertEquals(request.getUid(), receivedRequest.getUid());
|
||||
assertEquals(request.getCodeText(), receivedRequest.getCodeText());
|
||||
|
||||
final CodeSnippet snippet = new CodeSnippet("code-snippet-id", CodeSnippet.Kind.EXPRESSION, CodeSnippet.SubKind.OTHER_EXPRESSION_SUBKIND, "a+b", "expression:a+b");
|
||||
final Event event1 = new Event(null, null, CodeSnippet.Status.UNKNOWN, CodeSnippet.Status.NONEXISTENT, null);
|
||||
event1.setExceptionText("some exception");
|
||||
event1.setDiagnostic("error diagnostic");
|
||||
final Event event2 = new Event(snippet, null, CodeSnippet.Status.VALID, CodeSnippet.Status.NONEXISTENT, "14");
|
||||
final Response response = new Response(request.getUid(), event1, event2);
|
||||
serverWriter.send(response);
|
||||
|
||||
final Response receivedResponse = clientReader.receive(s -> {});
|
||||
assertEquals(response.getUid(), receivedResponse.getUid());
|
||||
final Event[] events = response.getEvents().toArray(EMPTY_EVENT_ARRAY);
|
||||
final Event[] receivedEvents = receivedResponse.getEvents().toArray(EMPTY_EVENT_ARRAY);
|
||||
|
||||
assertEquals(events.length, receivedEvents.length);
|
||||
for (int i = 0; i < events.length; i++) {
|
||||
final Event expectedEvent = events[i];
|
||||
final Event receivedEvent = receivedEvents[i];
|
||||
assertEquals(expectedEvent.getSnippet(), receivedEvent.getSnippet());
|
||||
assertEquals(expectedEvent.getCauseSnippet(), receivedEvent.getCauseSnippet());
|
||||
assertEquals(expectedEvent.getStatus(), receivedEvent.getStatus());
|
||||
assertEquals(expectedEvent.getPreviousStatus(), receivedEvent.getPreviousStatus());
|
||||
assertEquals(expectedEvent.getValue(), receivedEvent.getValue());
|
||||
assertEquals(expectedEvent.getExceptionText(), receivedEvent.getExceptionText());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,15 +15,21 @@
|
||||
*/
|
||||
package com.intellij.openapi.fileTypes.impl;
|
||||
|
||||
import com.intellij.ide.highlighter.*;
|
||||
import com.intellij.ide.highlighter.JShellFileType;
|
||||
import com.intellij.ide.highlighter.JavaClassFileType;
|
||||
import com.intellij.ide.highlighter.JavaFileType;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.fileTypes.FileTypeConsumer;
|
||||
import com.intellij.openapi.fileTypes.FileTypeFactory;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class JavaFileTypeFactory extends FileTypeFactory {
|
||||
@Override
|
||||
public void createFileTypes(@NotNull final FileTypeConsumer consumer) {
|
||||
consumer.consume(JavaClassFileType.INSTANCE, "class");
|
||||
consumer.consume(JavaFileType.INSTANCE, "java");
|
||||
for (FileType ft : Arrays.asList(JavaClassFileType.INSTANCE, JavaFileType.INSTANCE, JShellFileType.INSTANCE)) {
|
||||
consumer.consume(ft, ft.getDefaultExtension());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.lang.java;
|
||||
|
||||
import com.intellij.lang.Language;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class JShellLanguage extends Language {
|
||||
public static final JShellLanguage INSTANCE = new JShellLanguage();
|
||||
|
||||
private JShellLanguage() {
|
||||
super(JavaLanguage.INSTANCE, "JShellLanguage");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return "JShell Snippet";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.psi;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public interface PsiJShellFile extends PsiFile {
|
||||
Collection<PsiJShellImportHolder> getSnippets();
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.psi;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 21-Jun-17
|
||||
*/
|
||||
public interface PsiJShellHolderMethod extends PsiMethod, PsiJShellSyntheticElement{
|
||||
PsiJShellHolderMethod[] EMPTY_ARRAY = new PsiJShellHolderMethod[0];
|
||||
|
||||
@NotNull
|
||||
PsiElement[] getStatements();
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.psi;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 21-Jun-17
|
||||
*/
|
||||
public interface PsiJShellImportHolder extends PsiElement, PsiJShellSyntheticElement{
|
||||
PsiJShellImportHolder[] EMPTY_ARRAY = new PsiJShellImportHolder[0];
|
||||
|
||||
PsiImportStatement getImportStatement();
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.psi;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 24-Jun-17
|
||||
*/
|
||||
public interface PsiJShellRootClass extends PsiSyntheticClass, PsiJShellSyntheticElement{
|
||||
PsiJShellImportHolder[] getSnippets();
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.psi;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 21-Jun-17
|
||||
*/
|
||||
public interface PsiJShellSyntheticElement extends PsiElement, SyntheticElement{
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.ide.highlighter;
|
||||
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.ide.IdeBundle;
|
||||
import com.intellij.lang.java.JShellLanguage;
|
||||
import com.intellij.openapi.fileTypes.LanguageFileType;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
public class JShellFileType extends LanguageFileType {
|
||||
@NonNls public static final String DEFAULT_EXTENSION = "snippet";
|
||||
@NonNls public static final String DOT_DEFAULT_EXTENSION = "." + DEFAULT_EXTENSION;
|
||||
public static final JShellFileType INSTANCE = new JShellFileType();
|
||||
|
||||
private JShellFileType() {
|
||||
super(JShellLanguage.INSTANCE);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getName() {
|
||||
return "JSHELL";
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDescription() {
|
||||
return IdeBundle.message("filetype.description.jshell");
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getDefaultExtension() {
|
||||
return DEFAULT_EXTENSION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Icon getIcon() {
|
||||
return AllIcons.FileTypes.Java; // todo: a dedicated icon?
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isJVMDebuggingSupported() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.lang.java;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.lang.PsiBuilder;
|
||||
import com.intellij.lang.PsiParser;
|
||||
import com.intellij.lang.java.parser.JShellParser;
|
||||
import com.intellij.lang.java.parser.JavaParserUtil;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.psi.FileViewProvider;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.impl.source.JShellFileImpl;
|
||||
import com.intellij.psi.impl.source.tree.IJShellElementType;
|
||||
import com.intellij.psi.impl.source.tree.JShellElementType;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.tree.IFileElementType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 21-Jun-17
|
||||
*/
|
||||
public class JShellParserDefinition extends JavaParserDefinition{
|
||||
private static final PsiParser PARSER = new PsiParser() {
|
||||
@NotNull
|
||||
@Override
|
||||
public ASTNode parse(@NotNull IElementType rootElement, @NotNull PsiBuilder builder) {
|
||||
JavaParserUtil.setLanguageLevel(builder, LanguageLevel.HIGHEST);
|
||||
final PsiBuilder.Marker r = builder.mark();
|
||||
JShellParser.INSTANCE.getFileParser().parse(builder);
|
||||
r.done(rootElement);
|
||||
return builder.getTreeBuilt();
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public PsiFile createFile(FileViewProvider viewProvider) {
|
||||
return new JShellFileImpl(viewProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IFileElementType getFileNodeType() {
|
||||
return JShellElementType.FILE;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiElement createElement(ASTNode node) {
|
||||
final IElementType type = node.getElementType();
|
||||
if (type instanceof IJShellElementType) {
|
||||
return ((IJShellElementType)type).createPsi(node);
|
||||
}
|
||||
return super.createElement(node);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiParser createParser(Project project) {
|
||||
return PARSER;
|
||||
}
|
||||
}
|
||||
@@ -144,7 +144,7 @@ public class FileParser {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private Pair<PsiBuilder.Marker, Boolean> parseImportList(PsiBuilder builder, Predicate<PsiBuilder> stopper) {
|
||||
protected Pair<PsiBuilder.Marker, Boolean> parseImportList(PsiBuilder builder, Predicate<PsiBuilder> stopper) {
|
||||
PsiBuilder.Marker list = builder.mark();
|
||||
|
||||
boolean isEmpty = true;
|
||||
@@ -189,7 +189,7 @@ public class FileParser {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private PsiBuilder.Marker parseImportStatement(PsiBuilder builder) {
|
||||
protected PsiBuilder.Marker parseImportStatement(PsiBuilder builder) {
|
||||
if (builder.getTokenType() != JavaTokenType.IMPORT_KEYWORD) return null;
|
||||
|
||||
final PsiBuilder.Marker statement = builder.mark();
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.lang.java.parser;
|
||||
|
||||
import com.intellij.codeInsight.daemon.JavaErrorMessages;
|
||||
import com.intellij.lang.LighterASTNode;
|
||||
import com.intellij.lang.PsiBuilder;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.psi.impl.source.tree.JShellElementType;
|
||||
import com.intellij.psi.impl.source.tree.JavaElementType;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 21-Jun-17
|
||||
*/
|
||||
public class JShellParser extends JavaParser {
|
||||
public static final JShellParser INSTANCE = new JShellParser();
|
||||
|
||||
private static final Set<IElementType> IMPORT = Collections.singleton(JavaElementType.IMPORT_STATEMENT);
|
||||
private static final HashSet<IElementType> TOP_LEVEL_DECLARATIONS = new HashSet<>(Arrays.asList(
|
||||
JavaElementType.FIELD, JavaElementType.METHOD, JavaElementType.CLASS
|
||||
));
|
||||
|
||||
private final FileParser myJShellFileParser = new FileParser(JShellParser.this) {
|
||||
@Override
|
||||
public void parse(@NotNull PsiBuilder builder) {
|
||||
while (!builder.eof()) {
|
||||
PsiBuilder.Marker wrapper = builder.mark();
|
||||
IElementType wrapperType = null;
|
||||
|
||||
PsiBuilder.Marker marker = parseImportStatement(builder);
|
||||
if (isParsed(marker, builder, tokenType -> IMPORT.contains(tokenType))) {
|
||||
wrapperType = JShellElementType.IMPORT_HOLDER;
|
||||
}
|
||||
else {
|
||||
revert(marker);
|
||||
marker = getExpressionParser().parse(builder);
|
||||
if (marker != null) {
|
||||
wrapperType = JShellElementType.STATEMENTS_HOLDER;
|
||||
}
|
||||
else {
|
||||
marker = getStatementParser().parseStatement(builder);
|
||||
if (isParsed(marker, builder, tokenType-> !JavaElementType.DECLARATION_STATEMENT.equals(tokenType))) {
|
||||
wrapperType = JShellElementType.STATEMENTS_HOLDER;
|
||||
}
|
||||
else {
|
||||
revert(marker);
|
||||
marker = getDeclarationParser().parse(builder, DeclarationParser.Context.CLASS);
|
||||
if (isParsed(marker, builder, tokenType -> TOP_LEVEL_DECLARATIONS.contains(tokenType))) {
|
||||
wrapper.drop(); // don't need wrapper for top-level declaration
|
||||
wrapper = null;
|
||||
}
|
||||
else {
|
||||
revert(marker);
|
||||
marker = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (marker == null) {
|
||||
if (wrapper != null) {
|
||||
wrapper.drop();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (wrapper != null) {
|
||||
wrapper.done(wrapperType);
|
||||
}
|
||||
}
|
||||
|
||||
if (!builder.eof()) {
|
||||
builder.mark().error(JavaErrorMessages.message("unexpected.token"));
|
||||
while (!builder.eof()) {
|
||||
builder.advanceLexer();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private static boolean isParsed(@Nullable PsiBuilder.Marker parsedMarker, PsiBuilder builder, final Condition<IElementType> cond) {
|
||||
if (parsedMarker == null) {
|
||||
return false;
|
||||
}
|
||||
final LighterASTNode lastDone = builder.getLatestDoneMarker();
|
||||
if (lastDone == null) {
|
||||
return false;
|
||||
}
|
||||
return cond.value(lastDone.getTokenType());
|
||||
}
|
||||
|
||||
private static void revert(PsiBuilder.Marker parsedMarker) {
|
||||
if (parsedMarker != null) {
|
||||
parsedMarker.rollbackTo();
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public FileParser getFileParser() {
|
||||
return myJShellFileParser;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.psi.impl.source;
|
||||
|
||||
import com.intellij.ide.highlighter.JShellFileType;
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.lang.java.JShellLanguage;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.source.tree.JShellElementType;
|
||||
import com.intellij.psi.scope.PsiScopeProcessor;
|
||||
import com.intellij.util.SmartList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 28-Jul-15
|
||||
*/
|
||||
public class JShellFileImpl extends PsiJavaFileBaseImpl implements PsiJShellFile {
|
||||
public JShellFileImpl(FileViewProvider viewProvider) {
|
||||
super(JShellElementType.FILE, JShellElementType.ROOT_CLASS, viewProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean processDeclarations(@NotNull PsiScopeProcessor processor, @NotNull ResolveState state, PsiElement lastParent, @NotNull PsiElement place) {
|
||||
return super.processDeclarations(processor, state, lastParent, place);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Language getLanguage() {
|
||||
return JShellLanguage.INSTANCE;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public FileType getFileType() {
|
||||
return JShellFileType.INSTANCE;
|
||||
}
|
||||
|
||||
public boolean isPhysical() {
|
||||
return getViewProvider().isPhysical();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<PsiJShellImportHolder> getSnippets() {
|
||||
final List<PsiJShellImportHolder> result = new SmartList<>();
|
||||
PsiElement child = getFirstChild();
|
||||
while (child != null) {
|
||||
if (child instanceof PsiJShellImportHolder) {
|
||||
result.add((PsiJShellImportHolder)child);
|
||||
}
|
||||
child = child.getNextSibling();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.psi.impl.source;
|
||||
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.augment.PsiAugmentProvider;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 28-Jun-17
|
||||
*/
|
||||
public class JShellPsiAugmentProvider extends PsiAugmentProvider{
|
||||
private static final Set<String> JSHELL_FIELD_MODIFIERS = Collections.unmodifiableSet(ContainerUtil.newHashSet(PsiModifier.PUBLIC, PsiModifier.STATIC));
|
||||
@NotNull
|
||||
@Override
|
||||
protected Set<String> transformModifiers(@NotNull PsiModifierList modifierList, @NotNull Set<String> modifiers) {
|
||||
// enforce permanent field modifiers for all variables declared at top-level
|
||||
return isInsideJShellField(modifierList)? JSHELL_FIELD_MODIFIERS : modifiers;
|
||||
}
|
||||
|
||||
private static boolean isInsideJShellField(PsiElement element) {
|
||||
final PsiElement parent = element.getParent();
|
||||
return parent instanceof PsiField && parent.getParent() instanceof PsiJShellRootClass;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,240 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.psi.impl.source;
|
||||
|
||||
import com.intellij.extapi.psi.ASTWrapperPsiElement;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.PsiSuperMethodImplUtil;
|
||||
import com.intellij.psi.impl.light.LightModifierList;
|
||||
import com.intellij.psi.javadoc.PsiDocComment;
|
||||
import com.intellij.psi.util.MethodSignature;
|
||||
import com.intellij.psi.util.MethodSignatureBackedByPsiMethod;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.SmartList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 21-Jun-17
|
||||
*/
|
||||
public class PsiJShellHolderMethodImpl extends ASTWrapperPsiElement implements PsiJShellHolderMethod {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.PsiJShellHolderMethodImpl");
|
||||
|
||||
private final String myName;
|
||||
private PsiParameterList myParameterList;
|
||||
private PsiReferenceList myThrowsList;
|
||||
|
||||
public PsiJShellHolderMethodImpl(@NotNull ASTNode node, int index) {
|
||||
super(node);
|
||||
myName = "_$$jshell_holder_method$$" + index;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiElement[] getStatements() {
|
||||
List<PsiElement> result = null;
|
||||
for (PsiElement child = getFirstChild(); child != null; child = child.getNextSibling()) {
|
||||
if (child instanceof PsiStatement || child instanceof PsiExpression) {
|
||||
if (result == null) {
|
||||
result = new SmartList<>();
|
||||
}
|
||||
result.add(child);
|
||||
}
|
||||
}
|
||||
return result == null? PsiElement.EMPTY_ARRAY : result.toArray(PsiElement.EMPTY_ARRAY);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return myName;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PsiType getReturnType() {
|
||||
return PsiType.VOID;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PsiTypeElement getReturnTypeElement() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiParameterList getParameterList() {
|
||||
if (myParameterList != null) {
|
||||
return myParameterList;
|
||||
}
|
||||
try {
|
||||
PsiElementFactory elementFactory = JavaPsiFacade.getInstance(getProject()).getElementFactory();
|
||||
myParameterList = elementFactory.createParameterList(ArrayUtil.EMPTY_STRING_ARRAY, PsiType.EMPTY_ARRAY);
|
||||
return myParameterList;
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
LOG.error(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiReferenceList getThrowsList() {
|
||||
if (myThrowsList != null) {
|
||||
return myThrowsList;
|
||||
}
|
||||
final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(getProject()).getElementFactory();
|
||||
try {
|
||||
myThrowsList = elementFactory.createReferenceList(new PsiJavaCodeReferenceElement[]{
|
||||
elementFactory.createFQClassNameReferenceElement("java.lang.Throwable", getResolveScope())
|
||||
});
|
||||
return myThrowsList;
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
LOG.error(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PsiCodeBlock getBody() {
|
||||
return (PsiCodeBlock)getFirstChild();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConstructor() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVarArgs() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public MethodSignature getSignature(@NotNull PsiSubstitutor substitutor) {
|
||||
return MethodSignatureBackedByPsiMethod.create(this, PsiSubstitutor.EMPTY);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PsiIdentifier getNameIdentifier() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiMethod[] findSuperMethods() {
|
||||
return PsiMethod.EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiMethod[] findSuperMethods(boolean checkAccess) {
|
||||
return PsiMethod.EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiMethod[] findSuperMethods(PsiClass parentClass) {
|
||||
return PsiMethod.EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<MethodSignatureBackedByPsiMethod> findSuperMethodSignaturesIncludingStatic(boolean checkAccess) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PsiMethod findDeepestSuperMethod() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiMethod[] findDeepestSuperMethods() {
|
||||
return PsiMethod.EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiModifierList getModifierList() {
|
||||
return new LightModifierList(getManager());
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiElement setName(@NotNull String name) throws IncorrectOperationException {
|
||||
throw new IncorrectOperationException("Can't change name of JShell holder method");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public HierarchicalMethodSignature getHierarchicalMethodSignature() {
|
||||
return PsiSuperMethodImplUtil.getHierarchicalMethodSignature(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDeprecated() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PsiDocComment getDocComment() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasTypeParameters() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PsiTypeParameterList getTypeParameterList() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiTypeParameter[] getTypeParameters() {
|
||||
return PsiTypeParameter.EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PsiClass getContainingClass() {
|
||||
return (PsiClass)getParent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasModifierProperty(@NotNull String name) {
|
||||
return PsiModifier.PUBLIC.equals(name) || PsiModifier.STATIC.equals(name) || PsiModifier.FINAL.equals(name);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.psi.impl.source;
|
||||
|
||||
import com.intellij.extapi.psi.ASTWrapperPsiElement;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiImportStatement;
|
||||
import com.intellij.psi.PsiJShellImportHolder;
|
||||
import com.intellij.psi.ResolveState;
|
||||
import com.intellij.psi.scope.PsiScopeProcessor;
|
||||
import com.intellij.psi.scope.util.PsiScopesUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 21-Jun-17
|
||||
* according to JShell spec, a snippet must correspond to one of the following JLS syntax productions:
|
||||
Expression
|
||||
Statement
|
||||
ClassDeclaration
|
||||
InterfaceDeclaration
|
||||
MethodDeclaration
|
||||
FieldDeclaration
|
||||
ImportDeclaration
|
||||
*/
|
||||
public class PsiJShellImportHolderImpl extends ASTWrapperPsiElement implements PsiJShellImportHolder {
|
||||
public PsiJShellImportHolderImpl(@NotNull ASTNode node) {
|
||||
super(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean processDeclarations(@NotNull PsiScopeProcessor processor, @NotNull ResolveState state, PsiElement lastParent, @NotNull PsiElement place) {
|
||||
final PsiImportStatement importStatement = getImportStatement();
|
||||
if (importStatement != null) {
|
||||
processor.handleEvent(PsiScopeProcessor.Event.SET_DECLARATION_HOLDER, this);
|
||||
return processor.execute(importStatement, state);
|
||||
}
|
||||
return PsiScopesUtil.walkChildrenScopes(this, processor, state, lastParent, place);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiImportStatement getImportStatement() {
|
||||
return PsiTreeUtil.getChildOfType(this, PsiImportStatement.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,330 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.psi.impl.source;
|
||||
|
||||
import com.intellij.extapi.psi.ASTWrapperPsiElement;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.InheritanceImplUtil;
|
||||
import com.intellij.psi.impl.PsiClassImplUtil;
|
||||
import com.intellij.psi.impl.PsiSuperMethodImplUtil;
|
||||
import com.intellij.psi.javadoc.PsiDocComment;
|
||||
import com.intellij.psi.scope.PsiScopeProcessor;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 21-Jun-17
|
||||
* according to JShell spec, a snippet must correspond to one of the following JLS syntax productions:
|
||||
Expression
|
||||
Statement
|
||||
ClassDeclaration
|
||||
InterfaceDeclaration
|
||||
MethodDeclaration
|
||||
FieldDeclaration
|
||||
ImportDeclaration
|
||||
*/
|
||||
public class PsiJShellRootClassImpl extends ASTWrapperPsiElement implements PsiJShellRootClass {
|
||||
|
||||
private String myName;
|
||||
private String myQName;
|
||||
|
||||
public PsiJShellRootClassImpl(ASTNode node, int index) {
|
||||
super(node);
|
||||
myName = "$$jshell_root_class$$" + index;
|
||||
myQName = "REPL." + myName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiJShellImportHolder[] getSnippets() {
|
||||
return findChildren(PsiJShellImportHolder.class, PsiJShellImportHolder.EMPTY_ARRAY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean processDeclarations(@NotNull PsiScopeProcessor processor, @NotNull ResolveState state, PsiElement lastParent, @NotNull PsiElement place) {
|
||||
final LanguageLevel level = PsiUtil.getLanguageLevel(place);
|
||||
return PsiClassImplUtil.processDeclarationsInClass(this, processor, state, null, lastParent, place, level, false);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return myName;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getQualifiedName() {
|
||||
return myQName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInterface() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAnnotationType() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnum() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PsiReferenceList getExtendsList() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PsiReferenceList getImplementsList() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiClassType[] getExtendsListTypes() {
|
||||
return PsiClassType.EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiClassType[] getImplementsListTypes() {
|
||||
return PsiClassType.EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PsiClass getSuperClass() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiClass[] getInterfaces() {
|
||||
return PsiClass.EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiClass[] getSupers() {
|
||||
return PsiClass.EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiClassType[] getSuperTypes() {
|
||||
return PsiClassType.EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiField[] getFields() {
|
||||
return findChildren(PsiField.class, PsiField.EMPTY_ARRAY);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiMethod[] getMethods() {
|
||||
return findChildren(PsiMethod.class, PsiMethod.EMPTY_ARRAY);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiMethod[] getConstructors() {
|
||||
return PsiMethod.EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiClass[] getInnerClasses() {
|
||||
return findChildren(PsiClass.class, PsiClass.EMPTY_ARRAY);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiClassInitializer[] getInitializers() {
|
||||
return findChildren(PsiClassInitializer.class, PsiClassInitializer.EMPTY_ARRAY);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiField[] getAllFields() {
|
||||
return PsiClassImplUtil.getAllFields(this);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiMethod[] getAllMethods() {
|
||||
return PsiClassImplUtil.getAllMethods(this);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiClass[] getAllInnerClasses() {
|
||||
return PsiClassImplUtil.getAllInnerClasses(this);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PsiField findFieldByName(String name, boolean checkBases) {
|
||||
return PsiClassImplUtil.findFieldByName(this, name, checkBases);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PsiMethod findMethodBySignature(PsiMethod patternMethod, boolean checkBases) {
|
||||
return PsiClassImplUtil.findMethodBySignature(this, patternMethod, checkBases);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiMethod[] findMethodsBySignature(PsiMethod patternMethod, boolean checkBases) {
|
||||
return PsiClassImplUtil.findMethodsBySignature(this, patternMethod, checkBases);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiMethod[] findMethodsByName(String name, boolean checkBases) {
|
||||
return PsiClassImplUtil.findMethodsByName(this, name, checkBases);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<Pair<PsiMethod, PsiSubstitutor>> findMethodsAndTheirSubstitutorsByName(String name, boolean checkBases) {
|
||||
return PsiClassImplUtil.findMethodsAndTheirSubstitutorsByName(this, name, checkBases);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<Pair<PsiMethod, PsiSubstitutor>> getAllMethodsAndTheirSubstitutors() {
|
||||
return PsiClassImplUtil.getAllWithSubstitutorsByMap(this, PsiClassImplUtil.MemberType.METHOD);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PsiClass findInnerClassByName(String name, boolean checkBases) {
|
||||
return PsiClassImplUtil.findInnerByName(this, name, checkBases);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PsiIdentifier getNameIdentifier() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiElement getScope() {
|
||||
return getContainingFile();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInheritor(@NotNull PsiClass baseClass, boolean checkDeep) {
|
||||
return InheritanceImplUtil.isInheritor(this, baseClass, checkDeep);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInheritorDeep(PsiClass baseClass, @Nullable PsiClass classToByPass) {
|
||||
return InheritanceImplUtil.isInheritorDeep(this, baseClass, classToByPass);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PsiClass getContainingClass() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<HierarchicalMethodSignature> getVisibleSignatures() {
|
||||
return PsiSuperMethodImplUtil.getVisibleSignatures(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiElement setName(@NotNull String name) throws IncorrectOperationException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDeprecated() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PsiDocComment getDocComment() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasTypeParameters() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PsiTypeParameterList getTypeParameterList() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiTypeParameter[] getTypeParameters() {
|
||||
return PsiTypeParameter.EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PsiModifierList getModifierList() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasModifierProperty(@NotNull String name) {
|
||||
return PsiModifier.PUBLIC.equals(name) || PsiModifier.FINAL.equals(name);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PsiJavaToken getLBrace() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PsiJavaToken getRBrace() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private <T extends PsiElement> T[] findChildren(final Class<T> memberClass, final T[] emptyArray) {
|
||||
final T[] members = PsiTreeUtil.getChildrenOfType(this, memberClass);
|
||||
return members != null ? members : emptyArray;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.psi.impl.source.tree;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.lang.java.JShellLanguage;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.tree.ILazyParseableElementType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 24-Jun-17
|
||||
*/
|
||||
public abstract class IJShellElementType extends ILazyParseableElementType{
|
||||
public IJShellElementType(@NotNull String debugName) {
|
||||
super(debugName, JShellLanguage.INSTANCE);
|
||||
}
|
||||
|
||||
public abstract PsiElement createPsi(ASTNode node);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.psi.impl.source.tree;
|
||||
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.lang.java.JShellLanguage;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.impl.source.PsiJShellHolderMethodImpl;
|
||||
import com.intellij.psi.impl.source.PsiJShellImportHolderImpl;
|
||||
import com.intellij.psi.impl.source.PsiJShellRootClassImpl;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.tree.IFileElementType;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 21-Jun-17
|
||||
*/
|
||||
public interface JShellElementType {
|
||||
IFileElementType FILE = new IFileElementType("JSHELL_FILE", JShellLanguage.INSTANCE);
|
||||
|
||||
IElementType ROOT_CLASS = new IJShellElementType("JSHELL_ROOT_CLASS") {
|
||||
private final AtomicInteger ourClassCounter = new AtomicInteger();
|
||||
@Override
|
||||
public PsiElement createPsi(ASTNode node) {
|
||||
return new PsiJShellRootClassImpl(node, ourClassCounter.getAndIncrement());
|
||||
}
|
||||
};
|
||||
|
||||
IElementType STATEMENTS_HOLDER = new IJShellElementType("JSHELL_STATEMENTS_HOLDER") {
|
||||
private final AtomicInteger ourMethodCounter = new AtomicInteger();
|
||||
@Override
|
||||
public PsiElement createPsi(ASTNode node) {
|
||||
return new PsiJShellHolderMethodImpl(node, ourMethodCounter.getAndIncrement());
|
||||
}
|
||||
};
|
||||
|
||||
IElementType IMPORT_HOLDER = new IJShellElementType("JSHELL_IMPORT_HOLDER") {
|
||||
@Override
|
||||
public PsiElement createPsi(ASTNode node) {
|
||||
return new PsiJShellImportHolderImpl(node);
|
||||
}
|
||||
};
|
||||
}
|
||||
Binary file not shown.
@@ -205,6 +205,7 @@ filetype.description.gui.designer.form=GUI Designer forms
|
||||
filetype.description.html=HTML files
|
||||
filetype.description.class=Java class files
|
||||
filetype.description.java=Java source files
|
||||
filetype.description.jshell=JShell snippet files
|
||||
filetype.description.jspx=JSPx files
|
||||
filetype.description.idea.module=Idea Module
|
||||
filetype.description.jsp=Java Server Page files
|
||||
|
||||
@@ -353,6 +353,15 @@ public class PathManager {
|
||||
return url != null ? extractRoot(url, path) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to detect classpath entry which contains given resource.
|
||||
*/
|
||||
@Nullable
|
||||
public static String getResourceRoot(@NotNull ClassLoader cl, String resourcePath) {
|
||||
final URL url = cl.getResource(resourcePath);
|
||||
return url != null ? extractRoot(url, resourcePath) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to extract classpath entry part from passed URL.
|
||||
*/
|
||||
@@ -375,8 +384,8 @@ public class PathManager {
|
||||
}
|
||||
else if (URLUtil.JAR_PROTOCOL.equals(protocol)) {
|
||||
Pair<String, String> paths = URLUtil.splitJarUrl(resourceURL.getFile());
|
||||
if (paths != null) {
|
||||
resultPath = paths.first;
|
||||
if (paths != null && paths.first != null) {
|
||||
resultPath = FileUtil.toSystemDependentName(paths.first);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -361,6 +361,8 @@
|
||||
<!--<expectedTypesProvider implementation="com.intellij.codeInsight.JavaExpectedTypesProvider"/>-->
|
||||
|
||||
<customPropertyScopeProvider implementation="com.intellij.psi.impl.search.SimpleAccessorScopeProvider"/>
|
||||
<editorNotificationProvider implementation="com.intellij.execution.jshell.SnippetEditorDecorator"/>
|
||||
<lang.psiAugmentProvider implementation="com.intellij.psi.impl.source.JShellPsiAugmentProvider"/>
|
||||
|
||||
<referencesSearch implementation="com.intellij.psi.impl.search.PsiAnnotationMethodReferencesSearcher"/>
|
||||
<referencesSearch implementation="com.intellij.psi.impl.search.ConstructorReferencesSearcher"/>
|
||||
@@ -1242,6 +1244,7 @@
|
||||
</intentionAction>
|
||||
|
||||
<lang.parserDefinition language="JAVA" implementationClass="com.intellij.lang.java.JavaParserDefinition"/>
|
||||
<lang.parserDefinition language="JShellLanguage" implementationClass="com.intellij.lang.java.JShellParserDefinition"/>
|
||||
|
||||
<lang.refactoringSupport language="JAVA" implementationClass="com.intellij.lang.java.JavaRefactoringSupportProvider"/>
|
||||
<lang.refactoringSupport.classMembersRefactoringSupport language="JAVA" implementationClass="com.intellij.lang.java.JavaClassMembersRefactoringSupport"/>
|
||||
@@ -1996,6 +1999,8 @@
|
||||
|
||||
<deadCode implementation="com.intellij.codeInspection.java19modules.Java9ModuleEntryPoint"/>
|
||||
|
||||
<scratch.rootType implementation="com.intellij.execution.jshell.JShellRootType"/>
|
||||
|
||||
<javaModuleSystem implementation="com.intellij.psi.impl.JavaPlatformModuleSystem"/>
|
||||
</extensions>
|
||||
|
||||
@@ -2026,6 +2031,11 @@
|
||||
<action id="MethodOverloadSwitchUp" class="com.intellij.codeInsight.editorActions.JavaMethodOverloadSwitchUpAction"/>
|
||||
<action id="MethodOverloadSwitchDown" class="com.intellij.codeInsight.editorActions.JavaMethodOverloadSwitchDownAction" />
|
||||
|
||||
<action id="JShell.Console"
|
||||
class="com.intellij.execution.jshell.LaunchJShellConsoleAction"
|
||||
text="JShell Console..." description="Launch JShell Console">
|
||||
<add-to-group group-id="ToolsMenu" anchor="last"/>
|
||||
</action>
|
||||
</actions>
|
||||
|
||||
</idea-plugin>
|
||||
|
||||
Reference in New Issue
Block a user