diff --git a/java/execution/impl/src/com/intellij/execution/jshell/ExecuteJShellAction.java b/java/execution/impl/src/com/intellij/execution/jshell/ExecuteJShellAction.java index fbb8c625e295..9df5c10f1c37 100644 --- a/java/execution/impl/src/com/intellij/execution/jshell/ExecuteJShellAction.java +++ b/java/execution/impl/src/com/intellij/execution/jshell/ExecuteJShellAction.java @@ -19,12 +19,13 @@ 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.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.module.Module; import com.intellij.openapi.project.Project; +import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; @@ -65,7 +66,10 @@ class ExecuteJShellAction extends AnAction{ try { JShellHandler handler = JShellHandler.getAssociatedHandler(vFile); if (handler == null) { - handler = JShellHandler.create(project, vFile, e.getData(LangDataKeys.MODULE)); + final SnippetEditorDecorator.ConfigurationPane config = SnippetEditorDecorator.getJShellConfiguration(e.getDataContext()); + final Module module = config != null ? config.getContextModule() : null; + final Sdk sdk = config != null ? config.getRuntimeSdk() : null; + handler = JShellHandler.create(project, vFile, module, sdk); } if (handler != null) { handler.toFront(); diff --git a/java/execution/impl/src/com/intellij/execution/jshell/JShellHandler.java b/java/execution/impl/src/com/intellij/execution/jshell/JShellHandler.java index d597a3034f3e..0a252a1d6a34 100644 --- a/java/execution/impl/src/com/intellij/execution/jshell/JShellHandler.java +++ b/java/execution/impl/src/com/intellij/execution/jshell/JShellHandler.java @@ -57,12 +57,11 @@ import java.awt.*; import java.io.*; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; -import java.util.LinkedHashSet; +import java.util.*; import java.util.List; -import java.util.Set; -import java.util.UUID; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicReference; /** * @author Eugene Zhuravlev @@ -84,6 +83,7 @@ public class JShellHandler { private final MessageReader myMessageReader; private final MessageWriter myMessageWriter; private final ExecutorService myTaskQueue = new SequentialTaskExecutor("JShell Command Queue", PooledThreadExecutor.INSTANCE); + private final AtomicReference> myEvalClasspathRef = new AtomicReference<>(null); private JShellHandler(@NotNull Project project, RunContentDescriptor descriptor, @@ -145,14 +145,29 @@ public class JShellHandler { 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); + public static JShellHandler create(@NotNull final Project project, + @NotNull final VirtualFile contentFile, + @Nullable Module module, + @Nullable Sdk alternateSdk) throws Exception{ + final OSProcessHandler processHandler = launchProcess(project, module, alternateSdk); + 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); + // init classpath for evaluation + final Set cp = new LinkedHashSet<>(); + final Computable orderEnumerator = module != null ? () -> ModuleRootManager.getInstance(module).orderEntries() + : () -> ProjectRootManager.getInstance(project).orderEntries(); + ApplicationManager.getApplication().runReadAction(() -> { + cp.addAll(orderEnumerator.compute().librariesOnly().recursively().withoutSdk().getPathsList().getPathList()); + }); + if (!cp.isEmpty()) { + jshellHandler.myEvalClasspathRef.set(cp); + } + // must call getComponent before createConsoleActions() final JComponent consoleViewComponent = consoleView.getComponent(); @@ -186,8 +201,12 @@ public class 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(); + private static OSProcessHandler launchProcess(@NotNull Project project, + @Nullable Module module, + @Nullable Sdk alternateSdk) throws Exception{ + final Sdk sdk = alternateSdk != null? alternateSdk : + 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") + @@ -232,17 +251,41 @@ public class JShellHandler { cmdLine.addParameter(launchCp.toString()); } cmdLine.addParameter("com.intellij.execution.jshell.frontend.Main"); - final Set cp = new LinkedHashSet<>(); - final Computable 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); + + // init classpath for evaluation + //final Set cp = new LinkedHashSet<>(); + //final Computable orderEnumerator = module != null ? () -> ModuleRootManager.getInstance(module).orderEntries() + // : () -> ProjectRootManager.getInstance(project).orderEntries(); + //ApplicationManager.getApplication().runReadAction(() -> { + // cp.addAll(orderEnumerator.compute().librariesOnly().recursively().withoutSdk().getPathsList().getPathList()); + //}); + + //final File cpFile; + //if (!cp.isEmpty()) { + // cpFile = FileUtilRt.createTempFile("_jshell_classpath_", "", true); + // try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(cpFile), StandardCharsets.UTF_8))) { + // for (String path : cp) { + // writer.write(path); + // writer.newLine(); + // } + // } + // cmdLine.addParameter("--@class-path"); + // cmdLine.addParameter(cpFile.getAbsolutePath()); + //} + //else { + // cpFile = null; + //} + + final OSProcessHandler processHandler = new OSProcessHandler(cmdLine); + //if (cpFile != null) { + // processHandler.addProcessListener(new ProcessAdapter() { + // @Override + // public void processTerminated(ProcessEvent event) { + // FileUtil.delete(cpFile); + // } + // }); + //} + return processHandler; } private static String findFrontEndLibrary() { @@ -280,6 +323,13 @@ public class JShellHandler { private Response sendInput(final Request request) { final boolean alive = !myProcess.isProcessTerminating() && !myProcess.isProcessTerminated(); if (alive) { + // consume evaluation classpath, if any + final Collection cp = myEvalClasspathRef.getAndSet(null); + if (cp != null) { + for (String path : cp) { + request.addClasspathItem(path); + } + } myConsoleView.performWhenNoDeferredOutput(() -> { try { myMessageWriter.send(request); diff --git a/java/execution/impl/src/com/intellij/execution/jshell/LaunchJShellConsoleAction.java b/java/execution/impl/src/com/intellij/execution/jshell/LaunchJShellConsoleAction.java index ca656844f2dd..ce9d5b42397e 100644 --- a/java/execution/impl/src/com/intellij/execution/jshell/LaunchJShellConsoleAction.java +++ b/java/execution/impl/src/com/intellij/execution/jshell/LaunchJShellConsoleAction.java @@ -19,9 +19,11 @@ 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.FileEditor; import com.intellij.openapi.fileEditor.FileEditorManager; +import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; +import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.vfs.VirtualFile; /** @@ -46,8 +48,18 @@ public class LaunchJShellConsoleAction extends AnAction{ ); assert contentFile != null; try { - FileEditorManager.getInstance(project).openFile(contentFile, true); - JShellHandler.create(project, contentFile, e.getData(LangDataKeys.MODULE)); + final FileEditor[] editors = FileEditorManager.getInstance(project).openFile(contentFile, true); + Sdk alternateSdk = null; + Module module = null; + for (FileEditor editor : editors) { + final SnippetEditorDecorator.ConfigurationPane config = SnippetEditorDecorator.getJShellConfiguration(editor); + if (config != null) { + alternateSdk = config.getRuntimeSdk(); + module = config.getContextModule(); + break; + } + } + JShellHandler.create(project, contentFile, module, alternateSdk); } catch (Exception ex) { JShellDiagnostic.notifyError(ex, project); diff --git a/java/execution/impl/src/com/intellij/execution/jshell/SnippetEditorDecorator.java b/java/execution/impl/src/com/intellij/execution/jshell/SnippetEditorDecorator.java index 2646244dd9bd..01ba4a4f42dc 100644 --- a/java/execution/impl/src/com/intellij/execution/jshell/SnippetEditorDecorator.java +++ b/java/execution/impl/src/com/intellij/execution/jshell/SnippetEditorDecorator.java @@ -15,48 +15,166 @@ */ package com.intellij.execution.jshell; +import com.intellij.ProjectTopics; +import com.intellij.application.options.ModulesComboBox; +import com.intellij.execution.ui.ConfigurationModuleSelector; +import com.intellij.execution.ui.DefaultJreSelector; +import com.intellij.execution.ui.JrePathEditor; 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.actionSystem.*; import com.intellij.openapi.editor.impl.EditorHeaderComponent; import com.intellij.openapi.fileEditor.FileEditor; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.ModuleListener; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.projectRoots.JavaSdk; +import com.intellij.openapi.projectRoots.ProjectJdkTable; +import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.ui.LabeledComponent; import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.EditorNotifications; +import com.intellij.util.Alarm; +import com.intellij.util.Function; +import com.intellij.util.messages.MessageBusConnection; +import com.intellij.util.ui.JBUI; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; +import java.awt.*; +import java.util.List; /** * @author Eugene Zhuravlev * Date: 06-Jun-17 */ -public class SnippetEditorDecorator extends EditorNotifications.Provider{ - public static final Key CONTEXT_KEY = Key.create("jshell.editor.toolbar"); +public class SnippetEditorDecorator extends EditorNotifications.Provider{ + public static final Key CONTEXT_KEY = Key.create("jshell.editor.toolbar"); + private final Project myProject; + public SnippetEditorDecorator(Project project) { + myProject = project; + } + + public static class ConfigurationPane extends EditorHeaderComponent { + private final Alarm myUpdateAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD); + private final JrePathEditor myJreEditor; + private final ConfigurationModuleSelector myModuleSelector; + private MessageBusConnection myBusConnection; + + ConfigurationPane(Project project) { + final DefaultActionGroup actions = new DefaultActionGroup(ExecuteJShellAction.getSharedInstance(), DropJShellStateAction.getSharedInstance()); + final ActionToolbar toolbar = ActionManager.getInstance().createActionToolbar("JShellSnippetEditor", actions, true); + + myJreEditor = new JrePathEditor(DefaultJreSelector.projectSdk(project)); + myJreEditor.setToolTipText("Alternative JRE to run JShell"); + myJreEditor.setPathOrName(null, true); + + LabeledComponent modulePane = new LabeledComponent<>(); + ModulesComboBox modulesCombo = new ModulesComboBox(); + modulePane.setComponent(modulesCombo); + modulePane.setLabelLocation(BorderLayout.WEST); + modulePane.setText("Use classpath of:"); + myModuleSelector = new ConfigurationModuleSelector(project, modulesCombo, ""); + + JPanel mainPane = new JPanel(new GridBagLayout()); + mainPane.add(toolbar.getComponent(), new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, JBUI.insets(2, 3, 0, 0), 0, 0)); + mainPane.add(modulePane, new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, JBUI.insets(2, 3, 0, 0), 0, 0)); + mainPane.add(myJreEditor, new GridBagConstraints(2, 0, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, JBUI.insets(2, 15, 0, 0), 0, 0)); + add(mainPane, BorderLayout.CENTER); + } + + @Override + public void addNotify() { + super.addNotify(); + myBusConnection = myModuleSelector.getProject().getMessageBus().connect(); + myBusConnection.subscribe(ProjectTopics.MODULES, new ModuleListener() { + @Override + public void moduleAdded(@NotNull Project project, @NotNull Module module) { + reloadModules(); + } + + @Override + public void moduleRemoved(@NotNull Project project, @NotNull Module module) { + reloadModules(); + } + + @Override + public void modulesRenamed(@NotNull Project project, @NotNull List modules, @NotNull Function oldNameProvider) { + reloadModules(); + } + }); + reloadModules(); + } + + @Override + public void removeNotify() { + super.removeNotify(); + final MessageBusConnection conn = myBusConnection; + if (conn != null) { + myBusConnection = null; + conn.disconnect(); + myUpdateAlarm.cancelAllRequests(); + } + } + + private void reloadModules() { + myUpdateAlarm.cancelAllRequests(); + myUpdateAlarm.addRequest(()->myModuleSelector.reset(), 300L); + } + + @Nullable + public Module getContextModule() { + return myModuleSelector.getModule(); + } + + @Nullable + public Sdk getRuntimeSdk() { + final String pathOrName = myJreEditor.getJrePathOrName(); + if (pathOrName != null) { + final JavaSdk javaSdkType = JavaSdk.getInstance(); + final ProjectJdkTable jdkTable = ProjectJdkTable.getInstance(); + final Sdk sdkByName = jdkTable.findJdk(pathOrName, javaSdkType.getName()); + if (sdkByName != null) { + return sdkByName; + } + // assuming we have sdk home path + for (Sdk sdk : jdkTable.getSdksOfType(javaSdkType)) { + if (FileUtil.pathsEqual(pathOrName, sdk.getHomePath())) { + return sdk; + } + } + } + return null; + } + } + @NotNull @Override - public Key getKey() { + public Key getKey() { return CONTEXT_KEY; } @Nullable @Override - public JComponent createNotificationPanel(@NotNull VirtualFile file, @NotNull FileEditor fileEditor) { + public ConfigurationPane 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; + if (!(root instanceof JShellRootType)) { + return null; } + return new ConfigurationPane(myProject); + } - return null; + @Nullable + public static ConfigurationPane getJShellConfiguration(DataContext context) { + return getJShellConfiguration(PlatformDataKeys.FILE_EDITOR.getData(context)); + } + + @Nullable + public static ConfigurationPane getJShellConfiguration(FileEditor fileEditor) { + return CONTEXT_KEY.get(fileEditor); } } diff --git a/java/execution/impl/src/com/intellij/execution/ui/ConfigurationModuleSelector.java b/java/execution/impl/src/com/intellij/execution/ui/ConfigurationModuleSelector.java index 243d67511f28..996982bb63f8 100644 --- a/java/execution/impl/src/com/intellij/execution/ui/ConfigurationModuleSelector.java +++ b/java/execution/impl/src/com/intellij/execution/ui/ConfigurationModuleSelector.java @@ -104,12 +104,7 @@ public class ConfigurationModuleSelector { } public void reset(final ModuleBasedConfiguration configuration) { - final Module[] modules = ModuleManager.getInstance(getProject()).getModules(); - final List list = new ArrayList<>(); - for (final Module module : modules) { - if (isModuleAccepted(module)) list.add(module); - } - setModules(list); + reset(); if (myModulesList != null) { myModulesList.setSelectedItem(configuration.getConfigurationModule().getModule()); } @@ -118,6 +113,17 @@ public class ConfigurationModuleSelector { } } + public void reset() { + final Module[] modules = ModuleManager.getInstance(getProject()).getModules(); + final List list = new ArrayList<>(); + for (final Module module : modules) { + if (isModuleAccepted(module)) { + list.add(module); + } + } + setModules(list); + } + public boolean isModuleAccepted(final Module module) { return ModuleTypeManager.getInstance().isClasspathProvider(ModuleType.get(module)); } diff --git a/java/execution/jshell-frontend/src/com/intellij/execution/jshell/frontend/Main.java b/java/execution/jshell-frontend/src/com/intellij/execution/jshell/frontend/Main.java index a1110a16c1a9..c1a31167c509 100644 --- a/java/execution/jshell-frontend/src/com/intellij/execution/jshell/frontend/Main.java +++ b/java/execution/jshell-frontend/src/com/intellij/execution/jshell/frontend/Main.java @@ -3,9 +3,8 @@ 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.io.*; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; import java.util.Locale; @@ -20,6 +19,7 @@ import java.util.function.Consumer; */ public class Main { private static final String ARG_CLASSPATH = "--class-path"; + private static final String ARG_CLASSPATH_FILE = "--@class-path"; private static final Consumer NULL_CONSUMER = s -> {}; //private static Request createTestRequest() { @@ -47,6 +47,14 @@ public class Main { response.setUid(request.getUid()); try { + // first, handle eval classpath if any + final List cp = request.getClassPath(); + if (cp != null && !cp.isEmpty()) { + for (String path : cp) { + shell.addToClasspath(path); + } + } + if (command == Request.Command.DROP_STATE) { shell.snippets().forEach(snippet -> exportEvents(shell, shell.drop(snippet), response)); } @@ -124,13 +132,17 @@ public class Main { } } - private static void configureJShell(String[] args, JShell shell) { + private static void configureJShell(String[] args, JShell shell) throws IOException { // todo: add more parameters if needed boolean cpFound = false; + boolean cpFileFound = false; for (String arg : args) { if (ARG_CLASSPATH.equals(arg)) { cpFound = true; } + else if (ARG_CLASSPATH_FILE.equals(arg)) { + cpFileFound = true; + } else { if (cpFound) { cpFound = false; @@ -138,6 +150,15 @@ public class Main { shell.addToClasspath(path); } } + else if (cpFileFound) { + cpFileFound = false; + final File cpFile = new File(arg); + try (final BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(cpFile), StandardCharsets.UTF_8))) { + for (String line = reader.readLine(); line != null; line = reader.readLine()) { + shell.addToClasspath(line); + } + } + } } } } diff --git a/java/execution/jshell-protocol/src/com/intellij/execution/jshell/protocol/Request.java b/java/execution/jshell-protocol/src/com/intellij/execution/jshell/protocol/Request.java index 37503e1b4648..195fb54cf9b5 100644 --- a/java/execution/jshell-protocol/src/com/intellij/execution/jshell/protocol/Request.java +++ b/java/execution/jshell-protocol/src/com/intellij/execution/jshell/protocol/Request.java @@ -3,6 +3,8 @@ package com.intellij.execution.jshell.protocol; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlEnum; import javax.xml.bind.annotation.XmlRootElement; +import java.util.ArrayList; +import java.util.List; /** * @author Eugene Zhuravlev @@ -12,6 +14,7 @@ import javax.xml.bind.annotation.XmlRootElement; public class Request extends Message{ private Command myCommand; private String myCodeText; + private List myClassPath; @XmlEnum public enum Command{ @@ -44,4 +47,22 @@ public class Request extends Message{ public void setCodeText(String codeText) { myCodeText = codeText; } + + public List getClassPath() { + return myClassPath; + } + + @XmlElement(name = "cp") + public void setClassPath(List classPath) { + myClassPath = classPath; + } + + public void addClasspathItem(String path) { + List cp = myClassPath; + if (cp == null) { + cp = new ArrayList<>(); + myClassPath = cp; + } + cp.add(path); + } } diff --git a/java/execution/jshell-protocol/src/com/intellij/execution/jshell/protocol/Response.java b/java/execution/jshell-protocol/src/com/intellij/execution/jshell/protocol/Response.java index 5097ae2659ac..2c872f570d36 100644 --- a/java/execution/jshell-protocol/src/com/intellij/execution/jshell/protocol/Response.java +++ b/java/execution/jshell-protocol/src/com/intellij/execution/jshell/protocol/Response.java @@ -23,7 +23,6 @@ public class Response extends Message{ Collections.addAll(myEvents = new ArrayList<>(), events); } - @XmlElement public List getEvents() { return myEvents; } diff --git a/java/execution/jshell-protocol/testStrc/com/intellij/execution/jshell/protocol/JShellMessageMarshallingTest.java b/java/execution/jshell-protocol/testStrc/com/intellij/execution/jshell/protocol/JShellMessageMarshallingTest.java index 069a59cca081..8b4d4a1ef79e 100644 --- a/java/execution/jshell-protocol/testStrc/com/intellij/execution/jshell/protocol/JShellMessageMarshallingTest.java +++ b/java/execution/jshell-protocol/testStrc/com/intellij/execution/jshell/protocol/JShellMessageMarshallingTest.java @@ -4,6 +4,7 @@ import junit.framework.TestCase; import java.io.PipedInputStream; import java.io.PipedOutputStream; +import java.util.List; import java.util.UUID; /** @@ -28,10 +29,16 @@ public class JShellMessageMarshallingTest extends TestCase { final Request request = new Request(UUID.randomUUID().toString(), Request.Command.EVAL, "System.out.println(\"Hello, World!\");\n int var = 7 + 7;"); + request.addClasspathItem("C:/work/path1"); + request.addClasspathItem("C:/work/path2"); + final List requestClasspath = request.getClassPath(); + clientWriter.send(request); final Request receivedRequest = serverReader.receive(s -> {}); assertEquals(request.getUid(), receivedRequest.getUid()); assertEquals(request.getCodeText(), receivedRequest.getCodeText()); + final List receivedClasspath = receivedRequest.getClassPath(); + assertEquals(requestClasspath, receivedClasspath); 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); diff --git a/lib/jshell-frontend.jar b/lib/jshell-frontend.jar index afa91957e0dd..a7eab2889253 100644 Binary files a/lib/jshell-frontend.jar and b/lib/jshell-frontend.jar differ