langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java
changeset 43363 a4ed2006a4c5
parent 42843 a8d83044a192
child 43583 d16e490ec827
equal deleted inserted replaced
43282:45b751afd11e 43363:a4ed2006a4c5
    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 }