40 import java.util.HashMap;
41 import java.util.List;
42 import java.util.Locale;
43 import java.util.Map;
44 import java.util.Objects;
45 import java.util.Optional;
46 import java.util.function.Supplier;
47 import java.util.prefs.BackingStoreException;
48 import java.util.stream.Collectors;
49 import java.util.stream.Stream;
50
51 import jdk.internal.jline.NoInterruptUnixTerminal;
52 import jdk.internal.jline.Terminal;
53 import jdk.internal.jline.TerminalFactory;
54 import jdk.internal.jline.TerminalSupport;
55 import jdk.internal.jline.WindowsTerminal;
56 import jdk.internal.jline.console.ConsoleReader;
57 import jdk.internal.jline.console.KeyMap;
58 import jdk.internal.jline.console.UserInterruptException;
59 import jdk.internal.jline.console.completer.Completer;
60 import jdk.internal.jline.extra.EditingHistory;
61 import jdk.internal.jshell.tool.StopDetectingInputStream.State;
62
63 class ConsoleIOContext extends IOContext {
64
65 private static final String HISTORY_LINE_PREFIX = "HISTORY_LINE_";
66
67 final JShellTool repl;
68 final StopDetectingInputStream input;
69 final ConsoleReader in;
70 final EditingHistory history;
71
72 String prefix = "";
73
74 ConsoleIOContext(JShellTool repl, InputStream cmdin, PrintStream cmdout) throws Exception {
75 this.repl = repl;
76 this.input = new StopDetectingInputStream(() -> repl.state.stop(), ex -> repl.hard("Error on input: %s", ex));
77 Terminal term;
78 if (System.getProperty("test.jdk") != null) {
79 term = new TestTerminal(input);
80 } else if (System.getProperty("os.name").toLowerCase(Locale.US).contains(TerminalFactory.WINDOWS)) {
81 term = new JShellWindowsTerminal(input);
82 } else {
83 term = new JShellUnixTerminal(input);
84 }
85 term.init();
86 in = new ConsoleReader(cmdin, cmdout, term);
87 in.setExpandEvents(false);
88 in.setHandleUserInterrupt(true);
89 List<String> persistenHistory = Stream.of(repl.prefs.keys())
90 .filter(key -> key.startsWith(HISTORY_LINE_PREFIX))
282
283 @Override
284 public void suspend() {
285 try {
286 in.getTerminal().restore();
287 } catch (Exception ex) {
288 throw new IllegalStateException(ex);
289 }
290 }
291
292 @Override
293 public void resume() {
294 try {
295 in.getTerminal().init();
296 } catch (Exception ex) {
297 throw new IllegalStateException(ex);
298 }
299 }
300
301 public void beforeUserCode() {
302 input.setState(State.BUFFER);
303 }
304
305 public void afterUserCode() {
306 input.setState(State.WAIT);
307 }
308
309 @Override
310 public void replaceLastHistoryEntry(String source) {
311 history.fullHistoryReplace(source);
312 }
313
314 //compute possible options/Fixes based on the selected FixComputer, present them to the user,
315 //and perform the selected one:
316 private void fixes(FixComputer computer) {
317 String input = prefix + in.getCursorBuffer().toString();
318 int cursor = prefix.length() + in.getCursorBuffer().cursor;
319 FixResult candidates = computer.compute(repl, input, cursor);
320
321 try {
361 int read;
362
363 read = in.readCharacter();
364
365 Fix fix = char2Fix.get((char) read);
366
367 if (fix == null) {
368 in.beep();
369 fix = fixes.get(0);
370 }
371
372 in.println();
373
374 fix.perform(in);
375
376 in.flush();
377 }
378 } catch (IOException ex) {
379 ex.printStackTrace();
380 }
381 }
382
383 /**
384 * A possible action which the user can choose to perform.
385 */
386 public interface Fix {
387 /**
388 * A name that should be shown to the user.
389 */
390 public String displayName();
391 /**
392 * Perform the given action.
393 */
394 public void perform(ConsoleReader in) throws IOException;
395 }
396
397 /**
398 * A factory for {@link Fix}es.
399 */
400 public abstract static class FixComputer {
|
40 import java.util.HashMap;
41 import java.util.List;
42 import java.util.Locale;
43 import java.util.Map;
44 import java.util.Objects;
45 import java.util.Optional;
46 import java.util.function.Supplier;
47 import java.util.prefs.BackingStoreException;
48 import java.util.stream.Collectors;
49 import java.util.stream.Stream;
50
51 import jdk.internal.jline.NoInterruptUnixTerminal;
52 import jdk.internal.jline.Terminal;
53 import jdk.internal.jline.TerminalFactory;
54 import jdk.internal.jline.TerminalSupport;
55 import jdk.internal.jline.WindowsTerminal;
56 import jdk.internal.jline.console.ConsoleReader;
57 import jdk.internal.jline.console.KeyMap;
58 import jdk.internal.jline.console.UserInterruptException;
59 import jdk.internal.jline.console.completer.Completer;
60 import jdk.internal.jline.console.history.History;
61 import jdk.internal.jline.console.history.MemoryHistory;
62 import jdk.internal.jline.extra.EditingHistory;
63 import jdk.internal.jshell.tool.StopDetectingInputStream.State;
64
65 class ConsoleIOContext extends IOContext {
66
67 private static final String HISTORY_LINE_PREFIX = "HISTORY_LINE_";
68
69 final JShellTool repl;
70 final StopDetectingInputStream input;
71 final ConsoleReader in;
72 final EditingHistory history;
73 final MemoryHistory userInputHistory = new MemoryHistory();
74
75 String prefix = "";
76
77 ConsoleIOContext(JShellTool repl, InputStream cmdin, PrintStream cmdout) throws Exception {
78 this.repl = repl;
79 this.input = new StopDetectingInputStream(() -> repl.state.stop(), ex -> repl.hard("Error on input: %s", ex));
80 Terminal term;
81 if (System.getProperty("test.jdk") != null) {
82 term = new TestTerminal(input);
83 } else if (System.getProperty("os.name").toLowerCase(Locale.US).contains(TerminalFactory.WINDOWS)) {
84 term = new JShellWindowsTerminal(input);
85 } else {
86 term = new JShellUnixTerminal(input);
87 }
88 term.init();
89 in = new ConsoleReader(cmdin, cmdout, term);
90 in.setExpandEvents(false);
91 in.setHandleUserInterrupt(true);
92 List<String> persistenHistory = Stream.of(repl.prefs.keys())
93 .filter(key -> key.startsWith(HISTORY_LINE_PREFIX))
285
286 @Override
287 public void suspend() {
288 try {
289 in.getTerminal().restore();
290 } catch (Exception ex) {
291 throw new IllegalStateException(ex);
292 }
293 }
294
295 @Override
296 public void resume() {
297 try {
298 in.getTerminal().init();
299 } catch (Exception ex) {
300 throw new IllegalStateException(ex);
301 }
302 }
303
304 public void beforeUserCode() {
305 synchronized (this) {
306 inputBytes = null;
307 }
308 input.setState(State.BUFFER);
309 }
310
311 public void afterUserCode() {
312 input.setState(State.WAIT);
313 }
314
315 @Override
316 public void replaceLastHistoryEntry(String source) {
317 history.fullHistoryReplace(source);
318 }
319
320 //compute possible options/Fixes based on the selected FixComputer, present them to the user,
321 //and perform the selected one:
322 private void fixes(FixComputer computer) {
323 String input = prefix + in.getCursorBuffer().toString();
324 int cursor = prefix.length() + in.getCursorBuffer().cursor;
325 FixResult candidates = computer.compute(repl, input, cursor);
326
327 try {
367 int read;
368
369 read = in.readCharacter();
370
371 Fix fix = char2Fix.get((char) read);
372
373 if (fix == null) {
374 in.beep();
375 fix = fixes.get(0);
376 }
377
378 in.println();
379
380 fix.perform(in);
381
382 in.flush();
383 }
384 } catch (IOException ex) {
385 ex.printStackTrace();
386 }
387 }
388
389 private byte[] inputBytes;
390 private int inputBytesPointer;
391
392 @Override
393 public synchronized int readUserInput() {
394 while (inputBytes == null || inputBytes.length <= inputBytesPointer) {
395 boolean prevHandleUserInterrupt = in.getHandleUserInterrupt();
396 History prevHistory = in.getHistory();
397
398 try {
399 input.setState(State.WAIT);
400 in.setHandleUserInterrupt(true);
401 in.setHistory(userInputHistory);
402 inputBytes = (in.readLine("") + System.getProperty("line.separator")).getBytes();
403 inputBytesPointer = 0;
404 } catch (IOException ex) {
405 ex.printStackTrace();
406 return -1;
407 } catch (UserInterruptException ex) {
408 repl.state.stop();
409 return -1;
410 } finally {
411 in.setHistory(prevHistory);
412 in.setHandleUserInterrupt(prevHandleUserInterrupt);
413 input.setState(State.BUFFER);
414 }
415 }
416 return inputBytes[inputBytesPointer++];
417 }
418
419 /**
420 * A possible action which the user can choose to perform.
421 */
422 public interface Fix {
423 /**
424 * A name that should be shown to the user.
425 */
426 public String displayName();
427 /**
428 * Perform the given action.
429 */
430 public void perform(ConsoleReader in) throws IOException;
431 }
432
433 /**
434 * A factory for {@link Fix}es.
435 */
436 public abstract static class FixComputer {
|