1.1 --- a/jshell.support/src/org/netbeans/modules/jshell/editor/OverrideEditorActions.java Mon Jun 27 11:09:27 2016 +0200
1.2 +++ b/jshell.support/src/org/netbeans/modules/jshell/editor/OverrideEditorActions.java Thu Jun 30 14:20:56 2016 +0200
1.3 @@ -322,7 +322,7 @@
1.4 return;
1.5 }
1.6 ConsoleModel mod = session.getModel();
1.7 - ConsoleSection sec = mod.processInputSection();
1.8 + ConsoleSection sec = mod.processInputSection(false);
1.9 // the interceptor is executed even if a break insertion fails, e.g. is
1.10 // filtered out by DocumentFilter. Accept and process only those inserts,
1.11 // which happen in the input section
1.12 @@ -401,7 +401,7 @@
1.13 return;
1.14 }
1.15 ConsoleModel mod = s.getModel();
1.16 - ConsoleSection sec = mod.processInputSection();
1.17 + ConsoleSection sec = mod.processInputSection(false);
1.18 if (sec == null || sec.isIncomplete()) {
1.19 return;
1.20 }
2.1 --- a/jshell.support/src/org/netbeans/modules/jshell/env/JShellEnvironment.java Mon Jun 27 11:09:27 2016 +0200
2.2 +++ b/jshell.support/src/org/netbeans/modules/jshell/env/JShellEnvironment.java Thu Jun 30 14:20:56 2016 +0200
2.3 @@ -298,9 +298,16 @@
2.4 }
2.5
2.6 private void fireExecuting(ShellSession session, boolean start) {
2.7 + List<ShellListener> ll;
2.8 + synchronized (this) {
2.9 + ll = new ArrayList<>(this.shellListeners);
2.10 + }
2.11 + if (ll.isEmpty()) {
2.12 + return;
2.13 + }
2.14 ShellEvent e = new ShellEvent(this, session,
2.15 start ? ShellStatus.EXECUTE : ShellStatus.READY);
2.16 - shellListeners.stream().forEach(l -> l.shellStatusChanged(e));
2.17 + ll.stream().forEach(l -> l.shellStatusChanged(e));
2.18 }
2.19
2.20 private void doStartAndFire(ShellSession nss) {
3.1 --- a/jshell.support/src/org/netbeans/modules/jshell/launch/DebugExecutionEnvironment.java Mon Jun 27 11:09:27 2016 +0200
3.2 +++ b/jshell.support/src/org/netbeans/modules/jshell/launch/DebugExecutionEnvironment.java Thu Jun 30 14:20:56 2016 +0200
3.3 @@ -69,6 +69,7 @@
3.4 @Override
3.5 protected void shutdown() {
3.6 agent.closeConnection(shellConnection);
3.7 + super.shutdown();
3.8 }
3.9
3.10 @Override
3.11 @@ -216,6 +217,7 @@
3.12 }
3.13 closed = true;
3.14 }
3.15 + shutdown();
3.16 // shellEnv.reportClosedBridge(reportSession, true);
3.17 }
3.18
3.19 @@ -227,6 +229,7 @@
3.20 }
3.21 closed = true;
3.22 }
3.23 + shutdown();
3.24 // shellEnv.reportClosedBridge(reportSession, false);
3.25 }
3.26
4.1 --- a/jshell.support/src/org/netbeans/modules/jshell/model/ConsoleModel.java Mon Jun 27 11:09:27 2016 +0200
4.2 +++ b/jshell.support/src/org/netbeans/modules/jshell/model/ConsoleModel.java Thu Jun 30 14:20:56 2016 +0200
4.3 @@ -70,6 +70,7 @@
4.4 import org.netbeans.api.editor.document.AtomicLockDocument;
4.5 import org.netbeans.api.editor.document.LineDocument;
4.6 import org.netbeans.api.editor.document.LineDocumentUtils;
4.7 +import org.netbeans.api.lexer.Language;
4.8 import org.netbeans.api.lexer.TokenHierarchy;
4.9 import org.netbeans.api.lexer.TokenSequence;
4.10 import org.netbeans.editor.GuardedException;
4.11 @@ -77,6 +78,7 @@
4.12 import org.netbeans.lib.editor.util.swing.DocumentUtilities;
4.13 import org.netbeans.modules.jshell.parsing.JShellParser;
4.14 import org.netbeans.modules.jshell.parsing.ModelAccessor;
4.15 +import org.netbeans.modules.parsing.api.Snapshot;
4.16 import org.openide.util.Exceptions;
4.17 import org.openide.util.RequestProcessor;
4.18 import org.openide.util.Task;
4.19 @@ -96,9 +98,9 @@
4.20 * Use {@link #getInputEndOffset()} to get the current end offset or -1 if no active input section.
4.21 *
4.22 * <p/>
4.23 - * <b>Threading model:</b> all updates must be done in JShell evaluator thread. Synchronization on
4.24 - * the ConsoleModel <b>must be nested</b> in a document read-lock, if document access is necessary - doing
4.25 - * the opposite will deadlock with EDT.
4.26 + * <b>Threading model:</b> all updates must be done either in JSHell evaluator thread, or when the JShell evaluator
4.27 + * thread does not evaluate user code. Calls from Parsing API may perform immediate updates provided that the
4.28 + * evaluator does not evaluate user code.
4.29 *
4.30 * @author sdedic
4.31 */
4.32 @@ -111,6 +113,8 @@
4.33 */
4.34 private JShell shell;
4.35
4.36 + private JShell privateShell;
4.37 +
4.38 /**
4.39 * The document for console contents
4.40 */
4.41 @@ -175,10 +179,10 @@
4.42 }
4.43
4.44 private int getScrollbackEnd() {
4.45 - ConsoleSection s = getInputSection();
4.46 if (isExecute()) {
4.47 return document.getLength();
4.48 }
4.49 + ConsoleSection s = getInputSection();
4.50 if (inputOffset == null) {
4.51 return s != null ? s.getStart() : document.getLength();
4.52 } else {
4.53 @@ -231,6 +235,21 @@
4.54
4.55 private RequestProcessor.Task inputTask;
4.56
4.57 + public void updateIfIdle() {
4.58 + synchronized (this) {
4.59 + if (isExecute()) {
4.60 + return;
4.61 + }
4.62 + }
4.63 + processInputSection(false);
4.64 + }
4.65 +
4.66 + public ConsoleSection parseInputSection(Snapshot snap) {
4.67 + InputReader rdr = new InputReader(snap);
4.68 + rdr.run();
4.69 + return rdr.newSection;
4.70 + }
4.71 +
4.72 /**
4.73 * Returns the input section information. If the data is inaccurate,
4.74 * tries to refresh them before returning from the call. The call may block,
4.75 @@ -238,13 +257,13 @@
4.76 * Document.
4.77 * @return the input section
4.78 */
4.79 - public ConsoleSection processInputSection() {
4.80 + public ConsoleSection processInputSection(boolean force) {
4.81 synchronized (this) {
4.82 - if (inputValid) {
4.83 + if (!shouldRefresh() && !force) {
4.84 return getInputSection();
4.85 }
4.86 }
4.87 - refreshInput(true).waitFinished();
4.88 + refreshInput(force, true).waitFinished();
4.89 return inputSection;
4.90 }
4.91
4.92 @@ -263,29 +282,57 @@
4.93 return null;
4.94 }
4.95 }
4.96 - if (!inputValid) {
4.97 + if (shouldRefresh()) {
4.98 // in evaluator, the refresh happens immediately
4.99 - refreshInput(false);
4.100 + refreshInput(false, false);
4.101 }
4.102 return inputSection;
4.103 }
4.104
4.105 - private Task refreshInput(boolean now) {
4.106 + /**
4.107 + * True, if the thread itself is refreshing the model.
4.108 + */
4.109 + private boolean isRefreshPending() {
4.110 + return refreshPending.get();
4.111 + }
4.112 +
4.113 + private boolean isInputValid() {
4.114 + return inputValid;
4.115 + }
4.116 +
4.117 + private synchronized boolean shouldRefresh() {
4.118 + return !inputValid && inputTask == null;
4.119 + }
4.120 +
4.121 + private Task refreshInput(boolean force, boolean now) {
4.122 Task t;
4.123 boolean wait;
4.124 -
4.125 synchronized (this) {
4.126 - if (executing) {
4.127 - return Task.EMPTY;
4.128 + boolean rp = isRefreshPending();
4.129 + if (rp || executing) {
4.130 + // cannot refresh during execution. Must not refresh if the
4.131 + // thread itself is the refresh one.
4.132 + return Task.EMPTY;
4.133 }
4.134 + // reset the valid flag
4.135 inputValid = false;
4.136 + boolean sched = inputTask == null;
4.137 if (inputTask != null) {
4.138 - inputTask.schedule(now ? 0 : 200);
4.139 - } else {
4.140 - inputTask = evaluator.post(new InputReader(), now ? 0 : 200);
4.141 + if (!force) {
4.142 + return inputTask;
4.143 + }
4.144 + if (inputTask.cancel()) {
4.145 + inputTask.schedule(now ? 0 : 200);
4.146 + sched = true;
4.147 + }
4.148 + }
4.149 + if (sched) {
4.150 + InputReader r = new InputReader();
4.151 + inputTask = evaluator.post(r, now ? 0 : 200);
4.152 + r.myTask = inputTask;
4.153 }
4.154 t = inputTask;
4.155 - wait = !refreshPending && evaluator.isRequestProcessorThread();
4.156 + wait = now && !rp && evaluator.isRequestProcessorThread();
4.157 }
4.158 if (wait) {
4.159 t.waitFinished();
4.160 @@ -293,12 +340,23 @@
4.161 return t;
4.162 }
4.163
4.164 + private synchronized void clearInputTask(Task t) {
4.165 + if (t == inputTask) {
4.166 + inputTask = null;
4.167 + }
4.168 + }
4.169 +
4.170 /**
4.171 * If true, the refresh task is running. Input section is then to be returned
4.172 * immediately, no wait on the refresh task to prevent self-deadlock.
4.173 * Set and reset by the InputReader only.
4.174 */
4.175 - private volatile boolean refreshPending;
4.176 + private ThreadLocal<Boolean> refreshPending = new ThreadLocal<Boolean>() {
4.177 + @Override
4.178 + protected Boolean initialValue() {
4.179 + return false;
4.180 + }
4.181 + };
4.182
4.183 private class InputReader extends EventBuffer implements Runnable {
4.184 private int stage;
4.185 @@ -309,9 +367,18 @@
4.186 private long endSerial;
4.187 private Position endPos;
4.188 private int stalledInput;
4.189 + private Task myTask;
4.190 + private Snapshot processSnapshot;
4.191
4.192 private List<ConsoleSection> updateSections;
4.193
4.194 + private InputReader(Snapshot snapshot) {
4.195 + this.processSnapshot = snapshot;
4.196 + }
4.197 +
4.198 + private InputReader() {
4.199 + }
4.200 +
4.201 @Override
4.202 public void run() {
4.203 switch (stage++) {
4.204 @@ -320,10 +387,14 @@
4.205 doIt();
4.206 break;
4.207 case 1:
4.208 - readContents();
4.209 - if (contents != null) {
4.210 - parseInput();
4.211 - propagateResults();
4.212 + try {
4.213 + readContents();
4.214 + if (contents != null) {
4.215 + parseInput();
4.216 + propagateResults();
4.217 + }
4.218 + } finally {
4.219 + clearInputTask(myTask);
4.220 }
4.221 break;
4.222 }
4.223 @@ -332,14 +403,19 @@
4.224 public void doIt() {
4.225 // stage 0, read the document and serial
4.226 synchronized (ConsoleModel.this) {
4.227 - refreshPending = true;
4.228 + refreshPending.set(true);
4.229 }
4.230 try {
4.231 // stage 1
4.232 - document.render(this);
4.233 + if (processSnapshot != null) {
4.234 + // do not use document lock, get the contents from the snapshot.
4.235 + run();
4.236 + } else {
4.237 + document.render(this);
4.238 + }
4.239 } finally {
4.240 synchronized (ConsoleModel.this) {
4.241 - refreshPending = false;
4.242 + refreshPending.set(false);
4.243 }
4.244 stage = 0;
4.245 }
4.246 @@ -347,11 +423,11 @@
4.247
4.248 private void readContents() {
4.249 stalledInput = getInputOffset();
4.250 - if (isExecute() || stalledInput == -1) {
4.251 + if (isExecute() /* || stalledInput == -1 */) {
4.252 return;
4.253 }
4.254 int is = getScrollbackEnd();
4.255 - if (stalledInput < is) {
4.256 + if (stalledInput >= 0 && stalledInput < is) {
4.257 inputStart = lastSection != null ? lastSection.getStart() : stalledInput;
4.258 LOG.log(Level.FINER, "Detected stale input. Know input at {0} while anchor moved to {1}. LastSection = {2}, inputStart = {3}", new Object[] {
4.259 stalledInput, is, lastSection, inputStart
4.260 @@ -360,10 +436,15 @@
4.261 inputStart = is;
4.262 }
4.263 try {
4.264 - contents = DocumentUtilities.getText(document, inputStart, document.getLength() - inputStart);
4.265 + if (processSnapshot != null) {
4.266 + contents = processSnapshot.getText().subSequence(inputStart,processSnapshot.getText().length()).toString();
4.267 + // intentionally do not fetch document's serial. the results will not update at the end
4.268 + } else {
4.269 + contents = DocumentUtilities.getText(document, inputStart, document.getLength() - inputStart);
4.270 + docSerial = DocumentUtilities.getDocumentVersion(document);
4.271 + }
4.272 } catch (BadLocationException ex) {
4.273 }
4.274 - docSerial = DocumentUtilities.getDocumentVersion(document);
4.275 }
4.276
4.277 private void getPositionAndSerial() {
4.278 @@ -392,13 +473,17 @@
4.279
4.280 inputEndPos = endPos;
4.281 inputValid = true;
4.282 - try {
4.283 - inputOffset = document.createPosition(newSection.getStart(), Position.Bias.Forward);
4.284 - } catch (BadLocationException ex) {
4.285 - // should not happen, running inside readlock.
4.286 + if (newSection != null) {
4.287 + try {
4.288 + inputOffset = document.createPosition(newSection.getStart(), Position.Bias.Forward);
4.289 + } catch (BadLocationException ex) {
4.290 + // should not happen, running inside readlock.
4.291 + }
4.292 }
4.293 - for (ConsoleSection s : updateSections) {
4.294 - addOrUpdate(s);
4.295 + if (updateSections != null) {
4.296 + for (ConsoleSection s : updateSections) {
4.297 + addOrUpdate(s);
4.298 + }
4.299 }
4.300 }
4.301 /*
4.302 @@ -463,11 +548,25 @@
4.303 }
4.304 */
4.305 private void parseInput() {
4.306 - TokenHierarchy th = TokenHierarchy.get(getDocument());
4.307 - TokenSequence seq = th.tokenSequence();
4.308 - assert seq != null;
4.309 - seq.move(inputStart);
4.310 - JShellParser parser2 = new JShellParser(shell, seq, 0, inputStart + contents.length());
4.311 + TokenHierarchy th;
4.312 + TokenSequence seq;
4.313 + int limit = contents.length();
4.314 +
4.315 + if (processSnapshot == null) {
4.316 + th = TokenHierarchy.get(getDocument());
4.317 + seq = th.tokenSequence();
4.318 + seq.move(inputStart);
4.319 + limit += inputStart;
4.320 + } else {
4.321 + th = TokenHierarchy.create(contents, Language.find("text/x-repl"));
4.322 + seq = th.tokenSequence();
4.323 + seq.move(0);
4.324 + }
4.325 +
4.326 + JShellParser parser2 = new JShellParser(
4.327 + (evaluator.isRequestProcessorThread() || !isExecute()) ?
4.328 + shell :
4.329 + createPrivateShell(), seq, 0, limit);
4.330
4.331 parser2.execute();
4.332
4.333 @@ -532,10 +631,6 @@
4.334 }
4.335 }
4.336
4.337 - public void inputChanged() {
4.338 - refreshInput(false);
4.339 - }
4.340 -
4.341 private static final RequestProcessor RP = new RequestProcessor(ConsoleModel.class);
4.342
4.343 private void notifyUpdated(ConsoleSection s) {
4.344 @@ -701,75 +796,6 @@
4.345 return;
4.346 }
4.347
4.348 - List<ConsoleSection> created = new ArrayList<>(sections);
4.349 - ConsoleSection updated = null;
4.350 -
4.351 - /*
4.352 - ConsoleSection l = sections.get(sections.size() - 1);
4.353 - ConsoleSection f = sections.get(0);
4.354 -
4.355 - synchronized (this) {
4.356 - if (lastSection != null) {
4.357 - if (sections.size() > 1) {
4.358 - if (lastSection != last) {
4.359 - // no update
4.360 - scrollbackSections.add(lastSection);
4.361 - } else {
4.362 - updated = created.remove(0);
4.363 - }
4.364 - scrollbackSections.addAll(sections.subList(0, sections.size() - 1));
4.365 - } else {
4.366 - // just 1 section updated, it is the last section.
4.367 - if (last != null && lastSection == last) {
4.368 - lastSection = updated = f;
4.369 - created.clear();
4.370 - } else {
4.371 - scrollbackSections.add(lastSection);
4.372 - }
4.373 - }
4.374 - } else {
4.375 - scrollbackSections.addAll(sections.subList(0, sections.size() - 1));
4.376 - }
4.377 - if (l.getType().input) {
4.378 - if (sections.size() > 1) {
4.379 - ConsoleSection prevLast = sections.get(sections.size() - 2);
4.380 - if (!prevLast.getType().input) {
4.381 - lastSection = prevLast;
4.382 - } else {
4.383 - lastSection = null;
4.384 - }
4.385 - } else {
4.386 - lastSection = null;
4.387 - }
4.388 - } else {
4.389 - lastSection = l;
4.390 - }
4.391 - processed = end;
4.392 - }
4.393 - ConsoleSection execSection;
4.394 -
4.395 - if (l.getType().input) {
4.396 - // prompt was displayed
4.397 - execSection = executingSection;
4.398 - setInputSection(l);
4.399 - } else {
4.400 - lastSection = l;
4.401 - execSection = null;
4.402 - }
4.403 - final ConsoleSection fu = updated;
4.404 - RP.post(() -> {
4.405 - if (fu != null) {
4.406 - notifyUpdated(fu);
4.407 - }
4.408 - if (!created.isEmpty()) {
4.409 - notifyCreated(created);
4.410 - }
4.411 - if (execSection != null) {
4.412 - ConsoleEvent e = new ConsoleEvent(this, execSection, false);
4.413 - listeners.stream().forEach(t -> t.executing(e));
4.414 - }
4.415 - });
4.416 - */
4.417 new EventBuffer() {
4.418 @Override
4.419 protected void doUpdates() {
4.420 @@ -801,7 +827,7 @@
4.421 }
4.422 textAppended(document.getLength() + 1);
4.423 } else if (inputSection != null && inputSection.getStart() < s) {
4.424 - refreshInput(false);
4.425 + refreshInput(true, false);
4.426 }
4.427 }
4.428
4.429 @@ -837,28 +863,48 @@
4.430 * input section to the scrollback
4.431 *
4.432 */
4.433 - synchronized void beforeExecution() {
4.434 - assert !isExecute();
4.435 - ConsoleSection is = getInputSection();
4.436 - executingSection = is;
4.437 - if (is != null) {
4.438 - // the input will be added to the scrollback; if something is still
4.439 - // buffered in the lastSection, add it first:
4.440 - if (lastSection != null) {
4.441 - scrollbackSections.add(lastSection);
4.442 + void beforeExecution() {
4.443 + Task t = null;
4.444 + ConsoleSection is = null;
4.445 + while (true) {
4.446 + // wait after all refreshes are complete, block furthe refreshes by setting up executing flag
4.447 + synchronized (this) {
4.448 + assert !isExecute();
4.449 + t = inputTask;
4.450 }
4.451 - lastSection = null;
4.452 - scrollbackSections.add(executingSection);
4.453 + if (t != null) {
4.454 + t.waitFinished();
4.455 + }
4.456 + is = getInputSection();
4.457 + synchronized (this) {
4.458 + if (inputTask == null) {
4.459 + // no refresh is pending, change mode
4.460 + executingSection = is;
4.461 + executing = true;
4.462 + break;
4.463 + }
4.464 + }
4.465 }
4.466 - executing = true;
4.467 - if (is != null) {
4.468 - RP.post(() -> {
4.469 - // notify that the scrollback has been changed.
4.470 - notifyUpdated(is);
4.471 -
4.472 - ConsoleEvent e = new ConsoleEvent(this, is, true);
4.473 - listeners.stream().forEach(l -> l.executing(e));
4.474 - });
4.475 + synchronized (this) {
4.476 + ConsoleSection finIs = is;
4.477 + if (finIs != null) {
4.478 + // the input will be added to the scrollback; if something is still
4.479 + // buffered in the lastSection, add it first:
4.480 + if (lastSection != null) {
4.481 + scrollbackSections.add(lastSection);
4.482 + }
4.483 + lastSection = null;
4.484 + scrollbackSections.add(executingSection);
4.485 + }
4.486 + if (is != null) {
4.487 + RP.post(() -> {
4.488 + // notify that the scrollback has been changed.
4.489 + notifyUpdated(finIs);
4.490 +
4.491 + ConsoleEvent e = new ConsoleEvent(this, finIs, true);
4.492 + listeners.stream().forEach(l -> l.executing(e));
4.493 + });
4.494 + }
4.495 }
4.496 }
4.497
4.498 @@ -890,6 +936,13 @@
4.499 this.shell = shell;
4.500 snippetSubscription = shell.onSnippetEvent(this::acceptSnippet);
4.501 }
4.502 +
4.503 + private synchronized JShell createPrivateShell() {
4.504 + if (privateShell == null) {
4.505 + privateShell = JShell.create();
4.506 + }
4.507 + return privateShell;
4.508 + }
4.509
4.510 /**
4.511 * Provides mapping between snippets and individual input sections
4.512 @@ -1027,7 +1080,7 @@
4.513
4.514 @Override
4.515 public void removeUpdate(DocumentEvent e) {
4.516 - change(e);
4.517 + //change(e);
4.518 }
4.519
4.520 @Override
4.521 @@ -1305,6 +1358,8 @@
4.522 return shell;
4.523 }
4.524
4.525 + private Task execWaitTask = null;
4.526 +
4.527 static class ModelAccImpl extends ModelAccessor {
4.528
4.529 @Override
4.530 @@ -1380,7 +1435,7 @@
4.531 }
4.532
4.533 void ensureInputSectionAvailable(Supplier<String> promptSupplier) {
4.534 - ConsoleSection s = processInputSection();
4.535 + ConsoleSection s = processInputSection(true);
4.536 if (s != null) {
4.537 return;
4.538 }
5.1 --- a/jshell.support/src/org/netbeans/modules/jshell/parsing/ConsoleEmbeddingProvider.java Mon Jun 27 11:09:27 2016 +0200
5.2 +++ b/jshell.support/src/org/netbeans/modules/jshell/parsing/ConsoleEmbeddingProvider.java Thu Jun 30 14:20:56 2016 +0200
5.3 @@ -45,6 +45,7 @@
5.4 import java.util.Collections;
5.5 import java.util.List;
5.6 import javax.swing.text.Document;
5.7 +import org.netbeans.modules.jshell.model.ConsoleSection;
5.8 import org.netbeans.modules.jshell.support.ShellSession;
5.9 import org.netbeans.modules.parsing.api.Embedding;
5.10 import org.netbeans.modules.parsing.api.Snapshot;
5.11 @@ -77,7 +78,8 @@
5.12 if (model == null) {
5.13 return Collections.emptyList();
5.14 }
5.15 - EmbeddingProcessor p = new EmbeddingProcessor(session, model, snapshot);
5.16 + ConsoleSection inputSection = model.parseInputSection(snapshot);
5.17 + EmbeddingProcessor p = new EmbeddingProcessor(session, model, snapshot, inputSection);
5.18 return p.process();
5.19 }
5.20
6.1 --- a/jshell.support/src/org/netbeans/modules/jshell/parsing/ConsoleMainParser.java Mon Jun 27 11:09:27 2016 +0200
6.2 +++ b/jshell.support/src/org/netbeans/modules/jshell/parsing/ConsoleMainParser.java Thu Jun 30 14:20:56 2016 +0200
6.3 @@ -45,6 +45,7 @@
6.4 import org.netbeans.modules.jshell.model.ConsoleResult;
6.5 import java.util.Collection;
6.6 import javax.swing.event.ChangeListener;
6.7 +import javax.swing.text.BadLocationException;
6.8 import javax.swing.text.Document;
6.9 import org.netbeans.api.editor.mimelookup.MimeRegistration;
6.10 import org.netbeans.modules.jshell.support.ShellSession;
6.11 @@ -54,6 +55,7 @@
6.12 import org.netbeans.modules.parsing.spi.Parser;
6.13 import org.netbeans.modules.parsing.spi.ParserFactory;
6.14 import org.netbeans.modules.parsing.spi.SourceModificationEvent;
6.15 +import org.openide.util.Exceptions;
6.16
6.17 /**
6.18 *
6.19 @@ -71,6 +73,7 @@
6.20 ConsoleModel theModel = null;
6.21 if (ss != null) {
6.22 theModel = ss.getModel();
6.23 + theModel.updateIfIdle();
6.24 }
6.25 this.result = new ConsoleResult(theModel, snapshot);
6.26 }
7.1 --- a/jshell.support/src/org/netbeans/modules/jshell/parsing/EmbeddingProcessor.java Mon Jun 27 11:09:27 2016 +0200
7.2 +++ b/jshell.support/src/org/netbeans/modules/jshell/parsing/EmbeddingProcessor.java Thu Jun 30 14:20:56 2016 +0200
7.3 @@ -72,6 +72,8 @@
7.4 private final JShell shell;
7.5 private final Snapshot snapshot;
7.6 private final ShellSession session;
7.7 + private final ConsoleSection inputSection;
7.8 + private final ConsoleSection modelInputSection;
7.9
7.10 private StringBuilder precedingImports = new StringBuilder();
7.11
7.12 @@ -79,12 +81,14 @@
7.13
7.14 private int snippetIndex;
7.15
7.16 - public EmbeddingProcessor(ShellSession session, ConsoleModel model, Snapshot snapshot) {
7.17 + public EmbeddingProcessor(ShellSession session, ConsoleModel model, Snapshot snapshot, ConsoleSection snapshotInput) {
7.18 this.session = session;
7.19 this.model = model;
7.20 this.snapshot = snapshot;
7.21
7.22 this.shell = model.getShell();
7.23 + this.modelInputSection = model.getInputSection();
7.24 + this.inputSection = snapshotInput != null ? snapshotInput : modelInputSection;
7.25 }
7.26
7.27 @SuppressWarnings("ReturnOfCollectionOrArrayField")
7.28 @@ -121,7 +125,7 @@
7.29 if (snipFile == null) {
7.30 return;
7.31 }
7.32 - ConsoleSection activeInput = model.getInputSection();
7.33 + ConsoleSection activeInput = inputSection;
7.34
7.35 String prologText = contents.substring(0, ts);
7.36
8.1 --- a/jshell.support/src/org/netbeans/modules/jshell/support/JShellLauncher.java Mon Jun 27 11:09:27 2016 +0200
8.2 +++ b/jshell.support/src/org/netbeans/modules/jshell/support/JShellLauncher.java Thu Jun 30 14:20:56 2016 +0200
8.3 @@ -100,13 +100,15 @@
8.4 closeState();
8.5 }
8.6
8.7 - public void evaluate(String command) throws IOException {
8.8 + public void evaluate(String command, boolean prompt) throws IOException {
8.9 ensureLive();
8.10 String trimmed = trimEnd(command);
8.11 if (!trimmed.isEmpty()) {
8.12 prefix = process(prefix, command);
8.13 }
8.14 -// cmdout.append(prompt(!prefix.isEmpty()));
8.15 + if (prompt) {
8.16 + cmdout.append(prompt(!prefix.isEmpty()));
8.17 + }
8.18 }
8.19
8.20 public List<String> completion(String command) {
9.1 --- a/jshell.support/src/org/netbeans/modules/jshell/support/ShellSession.java Mon Jun 27 11:09:27 2016 +0200
9.2 +++ b/jshell.support/src/org/netbeans/modules/jshell/support/ShellSession.java Thu Jun 30 14:20:56 2016 +0200
9.3 @@ -576,13 +576,14 @@
9.4 synchronized (allSessions) {
9.5 allSessions.put(consoleDocument, new WeakReference<>(this));
9.6 }
9.7 + GlobalPathRegistry.getDefault().register(ClassPath.SOURCE, new ClassPath[] {
9.8 + env.getSnippetClassPath()
9.9 + });
9.10 +
9.11 + URL url = URLMapper.findURL(workRoot, URLMapper.INTERNAL);
9.12 + IndexingManager.getDefault().refreshIndexAndWait(url, null, true);
9.13 return Pair.of(previous, evaluator.post(() -> {
9.14 - GlobalPathRegistry.getDefault().register(ClassPath.SOURCE, new ClassPath[] {
9.15 - env.getSnippetClassPath()
9.16 - });
9.17
9.18 - URL url = URLMapper.findURL(workRoot, URLMapper.INTERNAL);
9.19 - IndexingManager.getDefault().refreshIndexAndWait(url, null, true);
9.20 ModelAccessor.INSTANCE.execute(model, () -> {
9.21 try {
9.22 getJShell();
9.23 @@ -724,7 +725,7 @@
9.24 }
9.25
9.26 private void ensureInputSectionAvailable() {
9.27 - ConsoleSection s = model.processInputSection();
9.28 + ConsoleSection s = model.processInputSection(false);
9.29 if (s != null) {
9.30 return;
9.31 }
9.32 @@ -1014,7 +1015,7 @@
9.33 post(() -> {
9.34 String c = command;
9.35 if (c == null) {
9.36 - ConsoleSection s = model.processInputSection();
9.37 + ConsoleSection s = model.processInputSection(true);
9.38 if (s == null) {
9.39 return;
9.40 }
9.41 @@ -1040,7 +1041,7 @@
9.42 "MSG_ErrorExecutingCommand=Note: You may need to restart the Java Shell to resume proper operation"
9.43 })
9.44 private void doExecuteCommands() {
9.45 - ConsoleSection sec = model.processInputSection();
9.46 + ConsoleSection sec = model.processInputSection(true);
9.47 if (sec == null) {
9.48 return;
9.49 }
9.50 @@ -1069,7 +1070,7 @@
9.51 try {
9.52 for (String s : toExec) {
9.53 ModelAccessor.INSTANCE.setSnippetOffset(model, exec.offsetToContents(ranges[index].start, true));
9.54 - launcher.evaluate(s);
9.55 + launcher.evaluate(s, index == toExec.size() - 1);
9.56 if (erroneous) {
9.57 break;
9.58 }
9.59 @@ -1080,6 +1081,7 @@
9.60 reportShellMessage(Bundle.MSG_ErrorExecutingCommand());
9.61 }
9.62 } finally {
9.63 + System.err.println("Bubu");
9.64 erroneous = false;
9.65 }
9.66 }, this::getPromptAfterError);
10.1 --- a/lib.nbjshell/src/org/netbeans/lib/nbjshell/NbExecutionControlBase.java Mon Jun 27 11:09:27 2016 +0200
10.2 +++ b/lib.nbjshell/src/org/netbeans/lib/nbjshell/NbExecutionControlBase.java Thu Jun 30 14:20:56 2016 +0200
10.3 @@ -109,8 +109,8 @@
10.4 try {
10.5 delegate.close();
10.6 } catch (IOException ex) {
10.7 -
10.8 }
10.9 + shutdown();
10.10 }
10.11
10.12 public boolean load(Collection<String> classes) {
10.13 @@ -140,6 +140,9 @@
10.14 protected abstract boolean isClosed();
10.15
10.16 protected void shutdown() {
10.17 + if (remoteIn == null) {
10.18 + return;
10.19 + }
10.20 try {
10.21 remoteIn.close();
10.22 remoteOut.close();
11.1 --- a/lib.nbjshell/src/org/netbeans/lib/nbjshell/RemoteExecutionSupport.java Mon Jun 27 11:09:27 2016 +0200
11.2 +++ b/lib.nbjshell/src/org/netbeans/lib/nbjshell/RemoteExecutionSupport.java Thu Jun 30 14:20:56 2016 +0200
11.3 @@ -507,6 +507,7 @@
11.4 final DemultiplexInput demux[] = new DemultiplexInput[1];
11.5 PipeInputStream pis = new PipeInputStream() {
11.6 public void close() {
11.7 + super.close();
11.8 demux[0].close();
11.9 }
11.10 };