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) { |
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 } |