Skip to content

Commit d39fe55

Browse files
committed
added opening notebook in context of project
1 parent 002dce9 commit d39fe55

File tree

13 files changed

+316
-126
lines changed

13 files changed

+316
-126
lines changed

nbcode/notebooks/src/org/netbeans/modules/nbcode/java/notebook/JshellStreamsHandler.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
*/
1616
package org.netbeans.modules.nbcode.java.notebook;
1717

18-
import java.io.ByteArrayOutputStream;
1918
import java.io.IOException;
2019
import java.io.InputStream;
2120
import java.io.PrintStream;

nbcode/notebooks/src/org/netbeans/modules/nbcode/java/notebook/NotebookCommandsHandler.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ public class NotebookCommandsHandler implements CommandProvider {
3434
private static final String NBLS_JSHELL_EXEC = "nbls.jshell.execute.cell";
3535
private static final String NBLS_JSHELL_INTERRUPT = "nbls.jshell.interrupt.cell";
3636
private static final String NBLS_OPEN_PROJECT_JSHELL = "nbls.jshell.project.open";
37-
private static final Set<String> COMMANDS = new HashSet<>(Arrays.asList(NBLS_JSHELL_EXEC, NBLS_OPEN_PROJECT_JSHELL, NBLS_JSHELL_INTERRUPT));
37+
private static final String NBLS_NOTEBOOK_PROJECT_MAPPING = "nbls.notebook.project.context";
38+
private static final Set<String> COMMANDS = new HashSet<>(Arrays.asList(NBLS_JSHELL_EXEC, NBLS_OPEN_PROJECT_JSHELL, NBLS_JSHELL_INTERRUPT, NBLS_NOTEBOOK_PROJECT_MAPPING));
3839

3940
@Override
4041
public Set<String> getCommands() {
@@ -52,6 +53,8 @@ public CompletableFuture<Object> runCommand(String command, List<Object> argumen
5253
return CompletableFuture.completedFuture(CodeEval.getInstance().interrupt(arguments));
5354
case NBLS_OPEN_PROJECT_JSHELL:
5455
return CommandHandler.openJshellInProjectContext(arguments).thenApply(list -> (Object) list);
56+
case NBLS_NOTEBOOK_PROJECT_MAPPING:
57+
return CommandHandler.getNotebookProjectMappingPath(arguments).thenApply(prj -> (Object) prj);
5558
default:
5659
return CompletableFuture.failedFuture(new UnsupportedOperationException("Command not supported: " + command));
5760
}

nbcode/notebooks/src/org/netbeans/modules/nbcode/java/notebook/NotebookConfigs.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,17 @@
3333
*/
3434
public class NotebookConfigs {
3535

36-
private static final String[] NOTEBOOK_CONFIG_LABELS = {"notebook.classpath", "notebook.modulepath", "notebook.addmodules", "notebook.enablePreview", "notebook.implicitImports"};
36+
private static final String[] NOTEBOOK_CONFIG_LABELS = {"notebook.classpath",
37+
"notebook.modulepath",
38+
"notebook.addmodules",
39+
"notebook.enablePreview",
40+
"notebook.implicitImports",
41+
"notebook.projects.mapping"};
3742
private String classPath = null;
3843
private String modulePath = null;
3944
private String addModules = null;
4045
private boolean enablePreview = false;
46+
private JsonObject notebookProjectMapping = new JsonObject();
4147
private List<String> implicitImports = null;
4248
private CompletableFuture<Void> initialized;
4349

@@ -65,6 +71,10 @@ public List<String> getImplicitImports() {
6571
return implicitImports;
6672
}
6773

74+
public JsonObject getNotebookProjectMapping() {
75+
return notebookProjectMapping;
76+
}
77+
6878
private NotebookConfigs() {
6979

7080
}
@@ -121,6 +131,10 @@ private CompletableFuture<Void> initializeConfigs() throws InterruptedException,
121131
implicitImports = ((JsonArray) c.get(4)).asList().stream().map((elem) -> elem.getAsString()).toList();
122132

123133
}
134+
if (c.get(5) != null) {
135+
notebookProjectMapping = (JsonObject) c.get(5);
136+
137+
}
124138
}
125139
});
126140

nbcode/notebooks/src/org/netbeans/modules/nbcode/java/notebook/NotebookSessionManager.java

Lines changed: 123 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,26 @@
1515
*/
1616
package org.netbeans.modules.nbcode.java.notebook;
1717

18+
import com.google.gson.JsonObject;
19+
import java.net.URI;
20+
import java.nio.file.Paths;
1821
import java.util.ArrayList;
22+
import java.util.HashMap;
1923
import java.util.List;
2024
import java.util.Map;
2125
import java.util.concurrent.CancellationException;
2226
import java.util.concurrent.CompletableFuture;
2327
import java.util.concurrent.ConcurrentHashMap;
2428
import java.util.concurrent.ExecutionException;
29+
import java.util.function.BiConsumer;
2530
import java.util.logging.Level;
2631
import java.util.logging.Logger;
2732
import jdk.jshell.JShell;
2833
import org.eclipse.lsp4j.NotebookDocument;
34+
import org.netbeans.api.project.Project;
2935
import static org.netbeans.modules.nbcode.java.notebook.NotebookUtils.checkEmptyString;
36+
import org.netbeans.modules.nbcode.java.project.ProjectConfigurationUtils;
37+
import org.netbeans.modules.nbcode.java.project.ProjectContext;
3038

3139
/**
3240
*
@@ -56,45 +64,41 @@ private static class Singleton {
5664
private static final NotebookSessionManager instance = new NotebookSessionManager();
5765
}
5866

59-
private CompletableFuture<JShell> jshellBuilder(JshellStreamsHandler streamsHandler) {
60-
return CompletableFuture.supplyAsync(() -> {
61-
try {
62-
NotebookConfigs.getInstance().getInitialized().get();
63-
} catch (InterruptedException ex) {
64-
LOG.log(Level.WARNING, "InterruptedException occurred while getting notebook configs: {0}", ex.getMessage());
65-
} catch (ExecutionException ex) {
66-
LOG.log(Level.WARNING, "ExecutionException occurred while getting notebook configs: {0}", ex.getMessage());
67-
}
68-
List<String> compilerOptions = getCompilerOptions();
69-
List<String> remoteOptions = getRemoteVmOptions();
70-
if (compilerOptions.isEmpty()) {
71-
return JShell.builder()
72-
.out(streamsHandler.getPrintOutStream())
73-
.err(streamsHandler.getPrintErrStream())
74-
.in(streamsHandler.getInputStream())
75-
.compilerOptions()
76-
.remoteVMOptions()
77-
.build();
78-
} else {
79-
return JShell.builder()
80-
.out(streamsHandler.getPrintOutStream())
81-
.err(streamsHandler.getPrintErrStream())
82-
.in(streamsHandler.getInputStream())
83-
.compilerOptions(compilerOptions.toArray(new String[0]))
84-
.remoteVMOptions(remoteOptions.toArray(new String[0]))
85-
.build();
86-
}
67+
private CompletableFuture<JShell> jshellBuilder(String notebookUri, JshellStreamsHandler streamsHandler) {
68+
return NotebookConfigs.getInstance().getInitialized()
69+
.thenCompose(v -> getProjectContextForNotebook(notebookUri)
70+
.thenApply(prj -> jshellBuildWithProject(prj, streamsHandler)
71+
)).exceptionally(throwable -> {
72+
LOG.log(Level.WARNING, "Failed to get project context, using default JShell configuration", throwable);
73+
return jshellBuildWithProject(null, streamsHandler);
8774
});
8875
}
8976

77+
private JShell jshellBuildWithProject(Project prj, JshellStreamsHandler streamsHandler) {
78+
List<String> compilerOptions = getCompilerOptions(prj);
79+
List<String> remoteOptions = getRemoteVmOptions(prj);
80+
81+
JShell.Builder builder = JShell.builder()
82+
.out(streamsHandler.getPrintOutStream())
83+
.err(streamsHandler.getPrintErrStream())
84+
.in(streamsHandler.getInputStream());
85+
86+
if (!compilerOptions.isEmpty()) {
87+
builder.compilerOptions(compilerOptions.toArray(new String[0]))
88+
.remoteVMOptions(remoteOptions.toArray(new String[0]));
89+
}
90+
91+
return builder.build();
92+
}
93+
9094
public CompletableFuture<JShell> createSession(NotebookDocument notebookDoc) {
9195
String notebookId = notebookDoc.getUri();
9296

9397
return sessions.computeIfAbsent(notebookId, id -> {
9498
JshellStreamsHandler handler = new JshellStreamsHandler(id, CodeEval.getInstance().outStreamFlushCb, CodeEval.getInstance().errStreamFlushCb);
9599
jshellStreamsMap.put(id, handler);
96100

97-
CompletableFuture<JShell> future = jshellBuilder(handler);
101+
CompletableFuture<JShell> future = jshellBuilder(notebookDoc.getUri(), handler);
98102

99103
future.thenAccept(jshell -> onJshellInit(notebookId, jshell))
100104
.exceptionally(ex -> {
@@ -106,58 +110,85 @@ public CompletableFuture<JShell> createSession(NotebookDocument notebookDoc) {
106110
});
107111
}
108112

109-
private List<String> getCompilerOptions() {
113+
private List<String> getCompilerOptions(Project prj) {
110114
List<String> compilerOptions = new ArrayList<>();
111-
String classpath = NotebookConfigs.getInstance().getClassPath();
112-
String modulePath = NotebookConfigs.getInstance().getModulePath();
113-
String addModules = NotebookConfigs.getInstance().getAddModules();
114-
boolean isEnablePreview = NotebookConfigs.getInstance().isEnablePreview();
115-
String notebookJdkVersion = NotebookConfigs.getInstance().getJdkVersion();
116-
117-
if (!checkEmptyString(classpath)) {
118-
compilerOptions.add(CLASS_PATH);
119-
compilerOptions.add(classpath);
120-
}
121-
if (!checkEmptyString(modulePath)) {
122-
compilerOptions.add(MODULE_PATH);
123-
compilerOptions.add(modulePath);
124-
}
125-
if (!checkEmptyString(addModules)) {
126-
compilerOptions.add(ADD_MODULES);
127-
compilerOptions.add(addModules);
128-
}
129-
if (isEnablePreview) {
115+
NotebookConfigs configs = NotebookConfigs.getInstance();
116+
117+
BiConsumer<String, String> addOption = (flag, value) -> {
118+
if (!checkEmptyString(value)) {
119+
compilerOptions.add(flag);
120+
compilerOptions.add(value);
121+
}
122+
};
123+
124+
addOption.accept(CLASS_PATH, configs.getClassPath());
125+
addOption.accept(MODULE_PATH, configs.getModulePath());
126+
addOption.accept(ADD_MODULES, configs.getAddModules());
127+
128+
if (configs.isEnablePreview()) {
130129
compilerOptions.add(ENABLE_PREVIEW);
131130
compilerOptions.add(SOURCE_FLAG);
132-
compilerOptions.add(notebookJdkVersion);
131+
compilerOptions.add(configs.getJdkVersion());
132+
}
133+
134+
if (prj != null) {
135+
List<String> projOptions = ProjectConfigurationUtils.compilerOptions(prj);
136+
Map<String, String> prjConfigMap = new HashMap<>();
137+
for (int i = 0; i < projOptions.size() - 1; i += 2) {
138+
prjConfigMap.put(projOptions.get(i), projOptions.get(i + 1));
139+
}
140+
141+
if (checkEmptyString(configs.getClassPath()) && prjConfigMap.containsKey(CLASS_PATH)) {
142+
addOption.accept(CLASS_PATH, prjConfigMap.get(CLASS_PATH));
143+
}
144+
if (checkEmptyString(configs.getModulePath()) && prjConfigMap.containsKey(MODULE_PATH)) {
145+
addOption.accept(MODULE_PATH, prjConfigMap.get(MODULE_PATH));
146+
}
147+
if (checkEmptyString(configs.getAddModules()) && prjConfigMap.containsKey(ADD_MODULES)) {
148+
addOption.accept(ADD_MODULES, prjConfigMap.get(ADD_MODULES));
149+
}
133150
}
134151

135152
return compilerOptions;
136153
}
137154

138-
private List<String> getRemoteVmOptions() {
155+
private List<String> getRemoteVmOptions(Project prj) {
139156
List<String> remoteOptions = new ArrayList<>();
140-
String classpath = NotebookConfigs.getInstance().getClassPath();
141-
String modulePath = NotebookConfigs.getInstance().getModulePath();
142-
String addModules = NotebookConfigs.getInstance().getAddModules();
143-
boolean isEnablePreview = NotebookConfigs.getInstance().isEnablePreview();
144-
145-
if (!checkEmptyString(classpath)) {
146-
remoteOptions.add(CLASS_PATH);
147-
remoteOptions.add(classpath);
148-
}
149-
if (!checkEmptyString(modulePath)) {
150-
remoteOptions.add(MODULE_PATH);
151-
remoteOptions.add(modulePath);
152-
}
153-
if (!checkEmptyString(addModules)) {
154-
remoteOptions.add(ADD_MODULES);
155-
remoteOptions.add(addModules);
156-
}
157+
NotebookConfigs configs = NotebookConfigs.getInstance();
158+
boolean isEnablePreview = configs.isEnablePreview();
159+
160+
BiConsumer<String, String> addOption = (flag, value) -> {
161+
if (!checkEmptyString(value)) {
162+
remoteOptions.add(flag);
163+
remoteOptions.add(value);
164+
}
165+
};
166+
167+
addOption.accept(CLASS_PATH, configs.getClassPath());
168+
addOption.accept(MODULE_PATH, configs.getModulePath());
169+
addOption.accept(ADD_MODULES, configs.getAddModules());
170+
157171
if (isEnablePreview) {
158172
remoteOptions.add(ENABLE_PREVIEW);
159173
}
160174

175+
if (prj != null) {
176+
List<String> projOptions = ProjectConfigurationUtils.launchVMOptions(prj);
177+
Map<String, String> prjConfigMap = new HashMap<>();
178+
for (int i = 0; i < projOptions.size() - 1; i += 2) {
179+
prjConfigMap.put(projOptions.get(i), projOptions.get(i + 1));
180+
}
181+
182+
if (checkEmptyString(configs.getClassPath()) && prjConfigMap.containsKey(CLASS_PATH)) {
183+
addOption.accept(CLASS_PATH, prjConfigMap.get(CLASS_PATH));
184+
}
185+
if (checkEmptyString(configs.getModulePath()) && prjConfigMap.containsKey(MODULE_PATH)) {
186+
addOption.accept(MODULE_PATH, prjConfigMap.get(MODULE_PATH));
187+
}
188+
if (checkEmptyString(configs.getAddModules()) && prjConfigMap.containsKey(ADD_MODULES)) {
189+
addOption.accept(ADD_MODULES, prjConfigMap.get(ADD_MODULES));
190+
}
191+
}
161192
return remoteOptions;
162193
}
163194

@@ -205,4 +236,28 @@ public void closeSession(String notebookUri) {
205236
handler.close();
206237
}
207238
}
239+
240+
private CompletableFuture<Project> getProjectContextForNotebook(String notebookUri) {
241+
JsonObject mapping = NotebookConfigs.getInstance().getNotebookProjectMapping();
242+
String notebookPath = URI.create(notebookUri).getPath();
243+
String projectKey = mapping.has(notebookPath)
244+
? Paths.get(mapping.get(notebookPath).getAsString()).toUri().toString()
245+
: notebookUri;
246+
247+
Project prj = ProjectContext.getProject(projectKey);
248+
249+
if (prj == null) {
250+
LOG.log(Level.WARNING, "Project not found or not open in workspace: {0}", projectKey);
251+
return null;
252+
}
253+
254+
return ProjectConfigurationUtils.buildProject(prj).thenApply(buildStatus -> {
255+
if (!buildStatus) {
256+
LOG.log(Level.WARNING, "Error while building project: {0}", projectKey);
257+
return null;
258+
}
259+
return prj;
260+
});
261+
262+
}
208263
}

0 commit comments

Comments
 (0)