43 import java.util.List; |
43 import java.util.List; |
44 import java.util.Locale; |
44 import java.util.Locale; |
45 import java.util.Map; |
45 import java.util.Map; |
46 import java.util.Objects; |
46 import java.util.Objects; |
47 import java.util.Optional; |
47 import java.util.Optional; |
|
48 import java.util.concurrent.atomic.AtomicBoolean; |
48 import java.util.function.Function; |
49 import java.util.function.Function; |
49 import java.util.stream.Collectors; |
50 import java.util.stream.Collectors; |
50 import java.util.stream.Stream; |
51 import java.util.stream.Stream; |
51 |
52 |
52 import jdk.internal.shellsupport.doc.JavadocFormatter; |
53 import jdk.internal.shellsupport.doc.JavadocFormatter; |
55 import jdk.internal.jline.TerminalFactory; |
56 import jdk.internal.jline.TerminalFactory; |
56 import jdk.internal.jline.TerminalSupport; |
57 import jdk.internal.jline.TerminalSupport; |
57 import jdk.internal.jline.WindowsTerminal; |
58 import jdk.internal.jline.WindowsTerminal; |
58 import jdk.internal.jline.console.ConsoleReader; |
59 import jdk.internal.jline.console.ConsoleReader; |
59 import jdk.internal.jline.console.KeyMap; |
60 import jdk.internal.jline.console.KeyMap; |
|
61 import jdk.internal.jline.console.Operation; |
60 import jdk.internal.jline.console.UserInterruptException; |
62 import jdk.internal.jline.console.UserInterruptException; |
61 import jdk.internal.jline.console.completer.Completer; |
63 import jdk.internal.jline.console.completer.Completer; |
62 import jdk.internal.jline.console.history.History; |
64 import jdk.internal.jline.console.history.History; |
63 import jdk.internal.jline.console.history.MemoryHistory; |
65 import jdk.internal.jline.console.history.MemoryHistory; |
64 import jdk.internal.jline.extra.EditingHistory; |
66 import jdk.internal.jline.extra.EditingHistory; |
88 term = new JShellWindowsTerminal(input); |
90 term = new JShellWindowsTerminal(input); |
89 } else { |
91 } else { |
90 term = new JShellUnixTerminal(input); |
92 term = new JShellUnixTerminal(input); |
91 } |
93 } |
92 term.init(); |
94 term.init(); |
93 in = new ConsoleReader(cmdin, cmdout, term); |
95 AtomicBoolean allowSmart = new AtomicBoolean(); |
|
96 in = new ConsoleReader(cmdin, cmdout, term) { |
|
97 @Override public KeyMap getKeys() { |
|
98 return new CheckCompletionKeyMap(super.getKeys(), allowSmart); |
|
99 } |
|
100 }; |
94 in.setExpandEvents(false); |
101 in.setExpandEvents(false); |
95 in.setHandleUserInterrupt(true); |
102 in.setHandleUserInterrupt(true); |
96 List<String> persistenHistory = Stream.of(repl.prefs.keys()) |
103 List<String> persistenHistory = Stream.of(repl.prefs.keys()) |
97 .filter(key -> key.startsWith(HISTORY_LINE_PREFIX)) |
104 .filter(key -> key.startsWith(HISTORY_LINE_PREFIX)) |
98 .sorted() |
105 .sorted() |
104 } |
111 } |
105 }); |
112 }); |
106 in.setBellEnabled(true); |
113 in.setBellEnabled(true); |
107 in.setCopyPasteDetection(true); |
114 in.setCopyPasteDetection(true); |
108 in.addCompleter(new Completer() { |
115 in.addCompleter(new Completer() { |
109 private String lastTest; |
|
110 private int lastCursor; |
|
111 private boolean allowSmart = false; |
|
112 @Override public int complete(String test, int cursor, List<CharSequence> result) { |
116 @Override public int complete(String test, int cursor, List<CharSequence> result) { |
113 int[] anchor = new int[] {-1}; |
117 int[] anchor = new int[] {-1}; |
114 List<Suggestion> suggestions; |
118 List<Suggestion> suggestions; |
115 if (prefix.isEmpty() && test.trim().startsWith("/")) { |
119 if (prefix.isEmpty() && test.trim().startsWith("/")) { |
116 suggestions = repl.commandCompletionSuggestions(test, cursor, anchor); |
120 suggestions = repl.commandCompletionSuggestions(test, cursor, anchor); |
117 } else { |
121 } else { |
118 int prefixLength = prefix.length(); |
122 int prefixLength = prefix.length(); |
119 suggestions = repl.analysis.completionSuggestions(prefix + test, cursor + prefixLength, anchor); |
123 suggestions = repl.analysis.completionSuggestions(prefix + test, cursor + prefixLength, anchor); |
120 anchor[0] -= prefixLength; |
124 anchor[0] -= prefixLength; |
121 } |
125 } |
122 if (!Objects.equals(lastTest, test) || lastCursor != cursor) |
126 boolean smart = allowSmart.get() && |
123 allowSmart = true; |
|
124 |
|
125 boolean smart = allowSmart && |
|
126 suggestions.stream() |
127 suggestions.stream() |
127 .anyMatch(Suggestion::matchesType); |
128 .anyMatch(Suggestion::matchesType); |
128 |
129 |
129 lastTest = test; |
130 allowSmart.set(!allowSmart.get()); |
130 lastCursor = cursor; |
|
131 allowSmart = !allowSmart; |
|
132 |
131 |
133 suggestions.stream() |
132 suggestions.stream() |
134 .filter(s -> !smart || s.matchesType()) |
133 .filter(s -> !smart || s.matchesType()) |
135 .map(Suggestion::continuation) |
134 .map(Suggestion::continuation) |
136 .forEach(result::add); |
135 .forEach(result::add); |
734 public InputStream wrapInIfNeeded(InputStream in) throws IOException { |
733 public InputStream wrapInIfNeeded(InputStream in) throws IOException { |
735 return input.setInputStream(super.wrapInIfNeeded(in)); |
734 return input.setInputStream(super.wrapInIfNeeded(in)); |
736 } |
735 } |
737 |
736 |
738 } |
737 } |
|
738 |
|
739 private static final class CheckCompletionKeyMap extends KeyMap { |
|
740 |
|
741 private final KeyMap del; |
|
742 private final AtomicBoolean allowSmart; |
|
743 |
|
744 public CheckCompletionKeyMap(KeyMap del, AtomicBoolean allowSmart) { |
|
745 super(del.getName(), del.isViKeyMap()); |
|
746 this.del = del; |
|
747 this.allowSmart = allowSmart; |
|
748 } |
|
749 |
|
750 @Override |
|
751 public void bind(CharSequence keySeq, Object function) { |
|
752 del.bind(keySeq, function); |
|
753 } |
|
754 |
|
755 @Override |
|
756 public void bindIfNotBound(CharSequence keySeq, Object function) { |
|
757 del.bindIfNotBound(keySeq, function); |
|
758 } |
|
759 |
|
760 @Override |
|
761 public void from(KeyMap other) { |
|
762 del.from(other); |
|
763 } |
|
764 |
|
765 @Override |
|
766 public Object getAnotherKey() { |
|
767 return del.getAnotherKey(); |
|
768 } |
|
769 |
|
770 @Override |
|
771 public Object getBound(CharSequence keySeq) { |
|
772 Object res = del.getBound(keySeq); |
|
773 |
|
774 if (res != Operation.COMPLETE) { |
|
775 allowSmart.set(true); |
|
776 } |
|
777 |
|
778 return res; |
|
779 } |
|
780 |
|
781 @Override |
|
782 public void setBlinkMatchingParen(boolean on) { |
|
783 del.setBlinkMatchingParen(on); |
|
784 } |
|
785 |
|
786 @Override |
|
787 public String toString() { |
|
788 return "check: " + del.toString(); |
|
789 } |
|
790 } |
739 } |
791 } |