langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java
changeset 40304 0318f4e75c6d
parent 38912 2ddd6171351e
child 40498 f54048be4a57
equal deleted inserted replaced
40303:96a1226aca18 40304:0318f4e75c6d
   971         return fileCompletions(p -> Files.isDirectory(p) ||
   971         return fileCompletions(p -> Files.isDirectory(p) ||
   972                                     p.getFileName().toString().endsWith(".zip") ||
   972                                     p.getFileName().toString().endsWith(".zip") ||
   973                                     p.getFileName().toString().endsWith(".jar"));
   973                                     p.getFileName().toString().endsWith(".jar"));
   974     }
   974     }
   975 
   975 
   976     private CompletionProvider snippetCompletion(Supplier<List<? extends Snippet>> snippetsSupplier) {
   976     private CompletionProvider snippetCompletion(Supplier<Stream<? extends Snippet>> snippetsSupplier) {
   977         return (prefix, cursor, anchor) -> {
   977         return (prefix, cursor, anchor) -> {
   978             anchor[0] = 0;
   978             anchor[0] = 0;
   979             return snippetsSupplier.get()                        .stream()
   979             return snippetsSupplier.get()
   980                         .flatMap(k -> (k instanceof DeclarationSnippet)
   980                         .flatMap(k -> (k instanceof DeclarationSnippet)
   981                                 ? Stream.of(String.valueOf(k.id()), ((DeclarationSnippet) k).name())
   981                                 ? Stream.of(String.valueOf(k.id()), ((DeclarationSnippet) k).name())
   982                                 : Stream.of(String.valueOf(k.id())))
   982                                 : Stream.of(String.valueOf(k.id())))
   983                         .filter(k -> k.startsWith(prefix))
   983                         .filter(k -> k.startsWith(prefix))
   984                         .map(k -> new Suggestion(k, false))
   984                         .map(k -> new Suggestion(k, false))
   985                         .collect(Collectors.toList());
   985                         .collect(Collectors.toList());
   986         };
   986         };
   987     }
   987     }
   988 
   988 
   989     private CompletionProvider snippetKeywordCompletion(Supplier<List<? extends Snippet>> snippetsSupplier) {
   989     private CompletionProvider snippetKeywordCompletion(Supplier<Stream<? extends Snippet>> snippetsSupplier) {
   990         return (code, cursor, anchor) -> {
   990         return (code, cursor, anchor) -> {
   991             List<Suggestion> result = new ArrayList<>();
   991             List<Suggestion> result = new ArrayList<>();
   992             result.addAll(KEYWORD_COMPLETION_PROVIDER.completionSuggestions(code, cursor, anchor));
   992             result.addAll(KEYWORD_COMPLETION_PROVIDER.completionSuggestions(code, cursor, anchor));
   993             result.addAll(snippetCompletion(snippetsSupplier).completionSuggestions(code, cursor, anchor));
   993             result.addAll(snippetCompletion(snippetsSupplier).completionSuggestions(code, cursor, anchor));
   994             return result;
   994             return result;
  1018         };
  1018         };
  1019     }
  1019     }
  1020 
  1020 
  1021     // Snippet lists
  1021     // Snippet lists
  1022 
  1022 
  1023     List<Snippet> allSnippets() {
  1023     Stream<Snippet> allSnippets() {
  1024         return state.snippets();
  1024         return state.snippets();
  1025     }
  1025     }
  1026 
  1026 
  1027     List<PersistentSnippet> dropableSnippets() {
  1027     Stream<PersistentSnippet> dropableSnippets() {
  1028         return state.snippets().stream()
  1028         return state.snippets()
  1029                 .filter(sn -> state.status(sn).isActive() && sn instanceof PersistentSnippet)
  1029                 .filter(sn -> state.status(sn).isActive() && sn instanceof PersistentSnippet)
  1030                 .map(sn -> (PersistentSnippet) sn)
  1030                 .map(sn -> (PersistentSnippet) sn);
  1031                 .collect(toList());
  1031     }
  1032     }
  1032 
  1033 
  1033     Stream<VarSnippet> allVarSnippets() {
  1034     List<VarSnippet> allVarSnippets() {
  1034         return state.snippets()
  1035         return state.snippets().stream()
       
  1036                 .filter(sn -> sn.kind() == Snippet.Kind.VAR)
  1035                 .filter(sn -> sn.kind() == Snippet.Kind.VAR)
  1037                 .map(sn -> (VarSnippet) sn)
  1036                 .map(sn -> (VarSnippet) sn);
  1038                 .collect(toList());
  1037     }
  1039     }
  1038 
  1040 
  1039     Stream<MethodSnippet> allMethodSnippets() {
  1041     List<MethodSnippet> allMethodSnippets() {
  1040         return state.snippets()
  1042         return state.snippets().stream()
       
  1043                 .filter(sn -> sn.kind() == Snippet.Kind.METHOD)
  1041                 .filter(sn -> sn.kind() == Snippet.Kind.METHOD)
  1044                 .map(sn -> (MethodSnippet) sn)
  1042                 .map(sn -> (MethodSnippet) sn);
  1045                 .collect(toList());
  1043     }
  1046     }
  1044 
  1047 
  1045     Stream<TypeDeclSnippet> allTypeSnippets() {
  1048     List<TypeDeclSnippet> allTypeSnippets() {
  1046         return state.snippets()
  1049         return state.snippets().stream()
       
  1050                 .filter(sn -> sn.kind() == Snippet.Kind.TYPE_DECL)
  1047                 .filter(sn -> sn.kind() == Snippet.Kind.TYPE_DECL)
  1051                 .map(sn -> (TypeDeclSnippet) sn)
  1048                 .map(sn -> (TypeDeclSnippet) sn);
  1052                 .collect(toList());
       
  1053     }
  1049     }
  1054 
  1050 
  1055     // Table of commands -- with command forms, argument kinds, helpKey message, implementation, ...
  1051     // Table of commands -- with command forms, argument kinds, helpKey message, implementation, ...
  1056 
  1052 
  1057     {
  1053     {
  1547      * @param defFilter the filter to apply to the arguments if no argument
  1543      * @param defFilter the filter to apply to the arguments if no argument
  1548      * @param rawargs the user's argument to the command, maybe be the empty
  1544      * @param rawargs the user's argument to the command, maybe be the empty
  1549      * string
  1545      * string
  1550      * @return a Stream of referenced snippets or null if no matches are found
  1546      * @return a Stream of referenced snippets or null if no matches are found
  1551      */
  1547      */
  1552     private <T extends Snippet> Stream<T> argsOptionsToSnippets(List<T> snippets,
  1548     private <T extends Snippet> Stream<T> argsOptionsToSnippets(Supplier<Stream<T>> snippetSupplier,
  1553             Predicate<Snippet> defFilter, String rawargs, String cmd) {
  1549             Predicate<Snippet> defFilter, String rawargs, String cmd) {
  1554         ArgTokenizer at = new ArgTokenizer(cmd, rawargs.trim());
  1550         ArgTokenizer at = new ArgTokenizer(cmd, rawargs.trim());
  1555         at.allowedOptions("-all", "-start");
  1551         at.allowedOptions("-all", "-start");
  1556         List<String> args = new ArrayList<>();
  1552         List<String> args = new ArrayList<>();
  1557         String s;
  1553         String s;
  1569             errormsg("jshell.err.conflicting.options", at.whole());
  1565             errormsg("jshell.err.conflicting.options", at.whole());
  1570             return null;
  1566             return null;
  1571         }
  1567         }
  1572         if (at.hasOption("-all")) {
  1568         if (at.hasOption("-all")) {
  1573             // all snippets including start-up, failed, and overwritten
  1569             // all snippets including start-up, failed, and overwritten
  1574             return snippets.stream();
  1570             return snippetSupplier.get();
  1575         }
  1571         }
  1576         if (at.hasOption("-start")) {
  1572         if (at.hasOption("-start")) {
  1577             // start-up snippets
  1573             // start-up snippets
  1578             return snippets.stream()
  1574             return snippetSupplier.get()
  1579                     .filter(this::inStartUp);
  1575                     .filter(this::inStartUp);
  1580         }
  1576         }
  1581         if (args.isEmpty()) {
  1577         if (args.isEmpty()) {
  1582             // Default is all active user snippets
  1578             // Default is all active user snippets
  1583             return snippets.stream()
  1579             return snippetSupplier.get()
  1584                     .filter(defFilter);
  1580                     .filter(defFilter);
  1585         }
  1581         }
  1586         return argsToSnippets(snippets, args);
  1582         return argsToSnippets(snippetSupplier, args);
  1587     }
  1583     }
  1588 
  1584 
  1589     /**
  1585     /**
  1590      * Convert user arguments to a Stream of snippets referenced by those
  1586      * Convert user arguments to a Stream of snippets referenced by those
  1591      * arguments.
  1587      * arguments.
  1592      *
  1588      *
  1593      * @param snippets the base list of possible snippets
  1589      * @param snippetSupplier the base list of possible snippets
  1594      * @param args the user's argument to the command, maybe be the empty list
  1590      * @param args the user's argument to the command, maybe be the empty list
  1595      * @return a Stream of referenced snippets or null if no matches to specific
  1591      * @return a Stream of referenced snippets or null if no matches to specific
  1596      * arg
  1592      * arg
  1597      */
  1593      */
  1598     private <T extends Snippet> Stream<T> argsToSnippets(List<T> snippets,
  1594     private <T extends Snippet> Stream<T> argsToSnippets(Supplier<Stream<T>> snippetSupplier,
  1599             List<String> args) {
  1595             List<String> args) {
  1600         Stream<T> result = null;
  1596         Stream<T> result = null;
  1601         for (String arg : args) {
  1597         for (String arg : args) {
  1602             // Find the best match
  1598             // Find the best match
  1603             Stream<T> st = layeredSnippetSearch(snippets, arg);
  1599             Stream<T> st = layeredSnippetSearch(snippetSupplier, arg);
  1604             if (st == null) {
  1600             if (st == null) {
  1605                 Stream<Snippet> est = layeredSnippetSearch(state.snippets(), arg);
  1601                 Stream<Snippet> est = layeredSnippetSearch(state::snippets, arg);
  1606                 if (est == null) {
  1602                 if (est == null) {
  1607                     errormsg("jshell.err.no.such.snippets", arg);
  1603                     errormsg("jshell.err.no.such.snippets", arg);
  1608                 } else {
  1604                 } else {
  1609                     errormsg("jshell.err.the.snippet.cannot.be.used.with.this.command",
  1605                     errormsg("jshell.err.the.snippet.cannot.be.used.with.this.command",
  1610                             arg, est.findFirst().get().source());
  1606                             arg, est.findFirst().get().source());
  1618             }
  1614             }
  1619         }
  1615         }
  1620         return result;
  1616         return result;
  1621     }
  1617     }
  1622 
  1618 
  1623     private <T extends Snippet> Stream<T> layeredSnippetSearch(List<T> snippets, String arg) {
  1619     private <T extends Snippet> Stream<T> layeredSnippetSearch(Supplier<Stream<T>> snippetSupplier, String arg) {
  1624         return nonEmptyStream(
  1620         return nonEmptyStream(
  1625                 // the stream supplier
  1621                 // the stream supplier
  1626                 () -> snippets.stream(),
  1622                 snippetSupplier,
  1627                 // look for active user declarations matching the name
  1623                 // look for active user declarations matching the name
  1628                 sn -> isActive(sn) && matchingDeclaration(sn, arg),
  1624                 sn -> isActive(sn) && matchingDeclaration(sn, arg),
  1629                 // else, look for any declarations matching the name
  1625                 // else, look for any declarations matching the name
  1630                 sn -> matchingDeclaration(sn, arg),
  1626                 sn -> matchingDeclaration(sn, arg),
  1631                 // else, look for an id of this name
  1627                 // else, look for an id of this name
  1646         }
  1642         }
  1647         if (args.isEmpty()) {
  1643         if (args.isEmpty()) {
  1648             errormsg("jshell.err.drop.arg");
  1644             errormsg("jshell.err.drop.arg");
  1649             return false;
  1645             return false;
  1650         }
  1646         }
  1651         Stream<PersistentSnippet> stream = argsToSnippets(dropableSnippets(), args);
  1647         Stream<PersistentSnippet> stream = argsToSnippets(this::dropableSnippets, args);
  1652         if (stream == null) {
  1648         if (stream == null) {
  1653             // Snippet not found. Error already printed
  1649             // Snippet not found. Error already printed
  1654             fluffmsg("jshell.msg.see.classes.etc");
  1650             fluffmsg("jshell.msg.see.classes.etc");
  1655             return false;
  1651             return false;
  1656         }
  1652         }
  1668                 .forEach(sn -> state.drop(sn).forEach(this::handleEvent));
  1664                 .forEach(sn -> state.drop(sn).forEach(this::handleEvent));
  1669         return true;
  1665         return true;
  1670     }
  1666     }
  1671 
  1667 
  1672     private boolean cmdEdit(String arg) {
  1668     private boolean cmdEdit(String arg) {
  1673         Stream<Snippet> stream = argsOptionsToSnippets(state.snippets(),
  1669         Stream<Snippet> stream = argsOptionsToSnippets(state::snippets,
  1674                 this::mainActive, arg, "/edit");
  1670                 this::mainActive, arg, "/edit");
  1675         if (stream == null) {
  1671         if (stream == null) {
  1676             return false;
  1672             return false;
  1677         }
  1673         }
  1678         Set<String> srcSet = new LinkedHashSet<>();
  1674         Set<String> srcSet = new LinkedHashSet<>();
  1773 
  1769 
  1774     private boolean cmdList(String arg) {
  1770     private boolean cmdList(String arg) {
  1775         if (arg.length() >= 2 && "-history".startsWith(arg)) {
  1771         if (arg.length() >= 2 && "-history".startsWith(arg)) {
  1776             return cmdHistory();
  1772             return cmdHistory();
  1777         }
  1773         }
  1778         Stream<Snippet> stream = argsOptionsToSnippets(state.snippets(),
  1774         Stream<Snippet> stream = argsOptionsToSnippets(state::snippets,
  1779                 this::mainActive, arg, "/list");
  1775                 this::mainActive, arg, "/list");
  1780         if (stream == null) {
  1776         if (stream == null) {
  1781             return false;
  1777             return false;
  1782         }
  1778         }
  1783 
  1779 
  1894                     writer.write("\n");
  1890                     writer.write("\n");
  1895                 }
  1891                 }
  1896             } else if (at.hasOption("-start")) {
  1892             } else if (at.hasOption("-start")) {
  1897                 writer.append(startup);
  1893                 writer.append(startup);
  1898             } else {
  1894             } else {
  1899                 List<Snippet> sns = at.hasOption("-all")
  1895                 String sources = (at.hasOption("-all")
  1900                         ? state.snippets()
  1896                         ? state.snippets()
  1901                         : state.snippets().stream().filter(this::mainActive).collect(toList());
  1897                         : state.snippets().filter(this::mainActive))
  1902                 for (Snippet sn : sns) {
  1898                         .map(Snippet::source)
  1903                     writer.write(sn.source());
  1899                         .collect(Collectors.joining("\n"));
  1904                     writer.write("\n");
  1900                 writer.write(sources);
  1905                 }
       
  1906             }
  1901             }
  1907         } catch (FileNotFoundException e) {
  1902         } catch (FileNotFoundException e) {
  1908             errormsg("jshell.err.file.not.found", "/save", filename, e.getMessage());
  1903             errormsg("jshell.err.file.not.found", "/save", filename, e.getMessage());
  1909             return false;
  1904             return false;
  1910         } catch (Exception e) {
  1905         } catch (Exception e) {
  1913         }
  1908         }
  1914         return true;
  1909         return true;
  1915     }
  1910     }
  1916 
  1911 
  1917     private boolean cmdVars(String arg) {
  1912     private boolean cmdVars(String arg) {
  1918         Stream<VarSnippet> stream = argsOptionsToSnippets(allVarSnippets(),
  1913         Stream<VarSnippet> stream = argsOptionsToSnippets(this::allVarSnippets,
  1919                 this::isActive, arg, "/vars");
  1914                 this::isActive, arg, "/vars");
  1920         if (stream == null) {
  1915         if (stream == null) {
  1921             return false;
  1916             return false;
  1922         }
  1917         }
  1923         stream.forEachOrdered(vk ->
  1918         stream.forEachOrdered(vk ->
  1929         });
  1924         });
  1930         return true;
  1925         return true;
  1931     }
  1926     }
  1932 
  1927 
  1933     private boolean cmdMethods(String arg) {
  1928     private boolean cmdMethods(String arg) {
  1934         Stream<MethodSnippet> stream = argsOptionsToSnippets(allMethodSnippets(),
  1929         Stream<MethodSnippet> stream = argsOptionsToSnippets(this::allMethodSnippets,
  1935                 this::isActive, arg, "/methods");
  1930                 this::isActive, arg, "/methods");
  1936         if (stream == null) {
  1931         if (stream == null) {
  1937             return false;
  1932             return false;
  1938         }
  1933         }
  1939         stream.forEachOrdered(mk
  1934         stream.forEachOrdered(mk
  1941         );
  1936         );
  1942         return true;
  1937         return true;
  1943     }
  1938     }
  1944 
  1939 
  1945     private boolean cmdTypes(String arg) {
  1940     private boolean cmdTypes(String arg) {
  1946         Stream<TypeDeclSnippet> stream = argsOptionsToSnippets(allTypeSnippets(),
  1941         Stream<TypeDeclSnippet> stream = argsOptionsToSnippets(this::allTypeSnippets,
  1947                 this::isActive, arg, "/types");
  1942                 this::isActive, arg, "/types");
  1948         if (stream == null) {
  1943         if (stream == null) {
  1949             return false;
  1944             return false;
  1950         }
  1945         }
  1951         stream.forEachOrdered(ck
  1946         stream.forEachOrdered(ck
  1980         });
  1975         });
  1981         return true;
  1976         return true;
  1982     }
  1977     }
  1983 
  1978 
  1984     private boolean cmdUseHistoryEntry(int index) {
  1979     private boolean cmdUseHistoryEntry(int index) {
  1985         List<Snippet> keys = state.snippets();
  1980         List<Snippet> keys = state.snippets().collect(toList());
  1986         if (index < 0)
  1981         if (index < 0)
  1987             index += keys.size();
  1982             index += keys.size();
  1988         else
  1983         else
  1989             index--;
  1984             index--;
  1990         if (index >= 0 && index < keys.size()) {
  1985         if (index >= 0 && index < keys.size()) {
  2010         }
  2005         }
  2011         return true;
  2006         return true;
  2012     }
  2007     }
  2013 
  2008 
  2014     private boolean rerunHistoryEntryById(String id) {
  2009     private boolean rerunHistoryEntryById(String id) {
  2015         Optional<Snippet> snippet = state.snippets().stream()
  2010         Optional<Snippet> snippet = state.snippets()
  2016             .filter(s -> s.id().equals(id))
  2011             .filter(s -> s.id().equals(id))
  2017             .findFirst();
  2012             .findFirst();
  2018         return snippet.map(s -> {
  2013         return snippet.map(s -> {
  2019             rerunSnippet(s);
  2014             rerunSnippet(s);
  2020             return true;
  2015             return true;
  2133         Snippet sn = ste.snippet();
  2128         Snippet sn = ste.snippet();
  2134         if (sn == null) {
  2129         if (sn == null) {
  2135             debug("Event with null key: %s", ste);
  2130             debug("Event with null key: %s", ste);
  2136             return false;
  2131             return false;
  2137         }
  2132         }
  2138         List<Diag> diagnostics = state.diagnostics(sn);
  2133         List<Diag> diagnostics = state.diagnostics(sn).collect(toList());
  2139         String source = sn.source();
  2134         String source = sn.source();
  2140         if (ste.causeSnippet() == null) {
  2135         if (ste.causeSnippet() == null) {
  2141             // main event
  2136             // main event
  2142             for (Diag d : diagnostics) {
  2137             for (Diag d : diagnostics) {
  2143                 hardmsg(d.isError()? "jshell.msg.error" : "jshell.msg.warning");
  2138                 hardmsg(d.isError()? "jshell.msg.error" : "jshell.msg.warning");
  2210         }
  2205         }
  2211     }
  2206     }
  2212     //where
  2207     //where
  2213     void printUnresolvedException(UnresolvedReferenceException ex) {
  2208     void printUnresolvedException(UnresolvedReferenceException ex) {
  2214         DeclarationSnippet corralled =  ex.getSnippet();
  2209         DeclarationSnippet corralled =  ex.getSnippet();
  2215         List<Diag> otherErrors = errorsOnly(state.diagnostics(corralled));
  2210         List<Diag> otherErrors = errorsOnly(state.diagnostics(corralled).collect(toList()));
  2216         new DisplayEvent(corralled, state.status(corralled), FormatAction.USED, true, null, otherErrors)
  2211         new DisplayEvent(corralled, state.status(corralled), FormatAction.USED, true, null, otherErrors)
  2217                 .displayDeclarationAndValue();
  2212                 .displayDeclarationAndValue();
  2218     }
  2213     }
  2219     //where
  2214     //where
  2220     void printEvalException(EvalException ex) {
  2215     void printEvalException(EvalException ex) {
  2278             this.value = value;
  2273             this.value = value;
  2279             this.errorLines = new ArrayList<>();
  2274             this.errorLines = new ArrayList<>();
  2280             for (Diag d : errors) {
  2275             for (Diag d : errors) {
  2281                 displayDiagnostics(sn.source(), d, errorLines);
  2276                 displayDiagnostics(sn.source(), d, errorLines);
  2282             }
  2277             }
  2283             int unresolvedCount;
  2278             long unresolvedCount;
  2284             if (sn instanceof DeclarationSnippet && (status == Status.RECOVERABLE_DEFINED || status == Status.RECOVERABLE_NOT_DEFINED)) {
  2279             if (sn instanceof DeclarationSnippet && (status == Status.RECOVERABLE_DEFINED || status == Status.RECOVERABLE_NOT_DEFINED)) {
  2285                 resolution = (status == Status.RECOVERABLE_NOT_DEFINED)
  2280                 resolution = (status == Status.RECOVERABLE_NOT_DEFINED)
  2286                         ? FormatResolve.NOTDEFINED
  2281                         ? FormatResolve.NOTDEFINED
  2287                         : FormatResolve.DEFINED;
  2282                         : FormatResolve.DEFINED;
  2288                 unresolved = unresolved((DeclarationSnippet) sn);
  2283                 unresolved = unresolved((DeclarationSnippet) sn);
  2289                 unresolvedCount = state.unresolvedDependencies((DeclarationSnippet) sn).size();
  2284                 unresolvedCount = state.unresolvedDependencies((DeclarationSnippet) sn).count();
  2290             } else {
  2285             } else {
  2291                 resolution = FormatResolve.OK;
  2286                 resolution = FormatResolve.OK;
  2292                 unresolved = "";
  2287                 unresolved = "";
  2293                 unresolvedCount = 0;
  2288                 unresolvedCount = 0;
  2294             }
  2289             }
  2303                         ? FormatErrors.ERROR1
  2298                         ? FormatErrors.ERROR1
  2304                         : FormatErrors.ERROR2;
  2299                         : FormatErrors.ERROR2;
  2305         }
  2300         }
  2306 
  2301 
  2307         private String unresolved(DeclarationSnippet key) {
  2302         private String unresolved(DeclarationSnippet key) {
  2308             List<String> unr = state.unresolvedDependencies(key);
  2303             List<String> unr = state.unresolvedDependencies(key).collect(toList());
  2309             StringBuilder sb = new StringBuilder();
  2304             StringBuilder sb = new StringBuilder();
  2310             int fromLast = unr.size();
  2305             int fromLast = unr.size();
  2311             if (fromLast > 0) {
  2306             if (fromLast > 0) {
  2312                 sb.append(" ");
  2307                 sb.append(" ");
  2313             }
  2308             }