23 * questions. |
23 * questions. |
24 */ |
24 */ |
25 |
25 |
26 package jdk.internal.jshell.tool; |
26 package jdk.internal.jshell.tool; |
27 |
27 |
|
28 import java.io.BufferedReader; |
28 import java.io.BufferedWriter; |
29 import java.io.BufferedWriter; |
29 import java.io.File; |
30 import java.io.File; |
30 import java.io.FileNotFoundException; |
31 import java.io.FileNotFoundException; |
31 import java.io.FileReader; |
32 import java.io.FileReader; |
32 import java.io.IOException; |
33 import java.io.IOException; |
33 import java.io.InputStream; |
34 import java.io.InputStream; |
|
35 import java.io.InputStreamReader; |
34 import java.io.PrintStream; |
36 import java.io.PrintStream; |
35 import java.io.Reader; |
37 import java.io.Reader; |
36 import java.io.StringReader; |
38 import java.io.StringReader; |
|
39 import java.net.URL; |
37 import java.nio.charset.Charset; |
40 import java.nio.charset.Charset; |
38 import java.nio.file.AccessDeniedException; |
41 import java.nio.file.AccessDeniedException; |
39 import java.nio.file.FileSystems; |
42 import java.nio.file.FileSystems; |
40 import java.nio.file.Files; |
43 import java.nio.file.Files; |
41 import java.nio.file.NoSuchFileException; |
44 import java.nio.file.NoSuchFileException; |
194 static final EditorSetting BUILT_IN_EDITOR = new EditorSetting(null, false); |
197 static final EditorSetting BUILT_IN_EDITOR = new EditorSetting(null, false); |
195 |
198 |
196 private boolean debug = false; |
199 private boolean debug = false; |
197 public boolean testPrompt = false; |
200 public boolean testPrompt = false; |
198 private String cmdlineClasspath = null; |
201 private String cmdlineClasspath = null; |
|
202 private String defaultStartup = null; |
199 private String startup = null; |
203 private String startup = null; |
200 private String executionControlSpec = null; |
204 private String executionControlSpec = null; |
201 private EditorSetting editor = BUILT_IN_EDITOR; |
205 private EditorSetting editor = BUILT_IN_EDITOR; |
202 |
206 |
203 private static final String[] EDITOR_ENV_VARS = new String[] { |
207 private static final String[] EDITOR_ENV_VARS = new String[] { |
211 static final String EDITOR_KEY = "EDITOR"; |
215 static final String EDITOR_KEY = "EDITOR"; |
212 static final String FEEDBACK_KEY = "FEEDBACK"; |
216 static final String FEEDBACK_KEY = "FEEDBACK"; |
213 static final String MODE_KEY = "MODE"; |
217 static final String MODE_KEY = "MODE"; |
214 static final String REPLAY_RESTORE_KEY = "REPLAY_RESTORE"; |
218 static final String REPLAY_RESTORE_KEY = "REPLAY_RESTORE"; |
215 |
219 |
216 static final String DEFAULT_STARTUP = |
220 static final String DEFAULT_STARTUP_NAME = "DEFAULT"; |
217 "\n" + |
221 static final Pattern BUILTIN_FILE_PATTERN = Pattern.compile("\\w+"); |
218 "import java.util.*;\n" + |
222 static final String BUILTIN_FILE_PATH_FORMAT = "jrt:/jdk.jshell/jdk/jshell/tool/resources/%s.jsh"; |
219 "import java.io.*;\n" + |
|
220 "import java.math.*;\n" + |
|
221 "import java.net.*;\n" + |
|
222 "import java.util.concurrent.*;\n" + |
|
223 "import java.util.prefs.*;\n" + |
|
224 "import java.util.regex.*;\n" + |
|
225 "void printf(String format, Object... args) { System.out.printf(format, args); }\n"; |
|
226 |
223 |
227 // Tool id (tid) mapping: the three name spaces |
224 // Tool id (tid) mapping: the three name spaces |
228 NameSpace mainNamespace; |
225 NameSpace mainNamespace; |
229 NameSpace startNamespace; |
226 NameSpace startNamespace; |
230 NameSpace errorNamespace; |
227 NameSpace errorNamespace; |
604 } |
601 } |
605 cmdlineClasspath = cps.get(0); |
602 cmdlineClasspath = cps.get(0); |
606 } |
603 } |
607 if (options.has(st)) { |
604 if (options.has(st)) { |
608 List<String> sts = options.valuesOf(st); |
605 List<String> sts = options.valuesOf(st); |
609 if (sts.size() != 1 || options.has("no-startup")) { |
606 if (options.has("no-startup")) { |
610 startmsg("jshell.err.opt.startup.one"); |
607 startmsg("jshell.err.opt.startup.conflict"); |
611 return null; |
608 return null; |
612 } |
609 } |
613 startup = readFile(sts.get(0), "--startup"); |
610 StringBuilder sb = new StringBuilder(); |
614 if (startup == null) { |
611 for (String fn : sts) { |
615 return null; |
612 String s = readFile(fn, "--startup"); |
616 } |
613 if (s == null) { |
|
614 return null; |
|
615 } |
|
616 sb.append(s); |
|
617 } |
|
618 startup = sb.toString(); |
617 } else if (options.has("no-startup")) { |
619 } else if (options.has("no-startup")) { |
618 startup = ""; |
620 startup = ""; |
619 } |
621 } |
620 if ((options.valuesOf(fb).size() + |
622 if ((options.valuesOf(fb).size() + |
621 (options.has("q") ? 1 : 0) + |
623 (options.has("q") ? 1 : 0) + |
1621 } |
1623 } |
1622 |
1624 |
1623 // The sub-command: /set start <start-file> |
1625 // The sub-command: /set start <start-file> |
1624 boolean setStart(ArgTokenizer at) { |
1626 boolean setStart(ArgTokenizer at) { |
1625 at.allowedOptions("-default", "-none", "-retain"); |
1627 at.allowedOptions("-default", "-none", "-retain"); |
1626 String fn = at.next(); |
1628 List<String> fns = new ArrayList<>(); |
|
1629 while (at.next() != null) { |
|
1630 fns.add(at.val()); |
|
1631 } |
1627 if (!checkOptionsAndRemainingInput(at)) { |
1632 if (!checkOptionsAndRemainingInput(at)) { |
1628 return false; |
1633 return false; |
1629 } |
1634 } |
1630 boolean defaultOption = at.hasOption("-default"); |
1635 boolean defaultOption = at.hasOption("-default"); |
1631 boolean noneOption = at.hasOption("-none"); |
1636 boolean noneOption = at.hasOption("-none"); |
1632 boolean retainOption = at.hasOption("-retain"); |
1637 boolean retainOption = at.hasOption("-retain"); |
1633 boolean hasFile = fn != null; |
1638 boolean hasFile = !fns.isEmpty(); |
1634 |
1639 |
1635 int argCount = (defaultOption ? 1 : 0) + (noneOption ? 1 : 0) + (hasFile ? 1 : 0); |
1640 int argCount = (defaultOption ? 1 : 0) + (noneOption ? 1 : 0) + (hasFile ? 1 : 0); |
1636 if (argCount > 1) { |
1641 if (argCount > 1) { |
1637 errormsg("jshell.err.option.or.filename", at.whole()); |
1642 errormsg("jshell.err.option.or.filename", at.whole()); |
1638 return false; |
1643 return false; |
1641 // no options or filename, show current setting |
1646 // no options or filename, show current setting |
1642 showSetStart(); |
1647 showSetStart(); |
1643 return true; |
1648 return true; |
1644 } |
1649 } |
1645 if (hasFile) { |
1650 if (hasFile) { |
1646 String init = readFile(fn, "/set start"); |
1651 StringBuilder sb = new StringBuilder(); |
1647 if (init == null) { |
1652 for (String fn : fns) { |
1648 return false; |
1653 String s = readFile(fn, "/set start"); |
1649 } |
1654 if (s == null) { |
1650 startup = init; |
1655 return false; |
|
1656 } |
|
1657 sb.append(s); |
|
1658 } |
|
1659 startup = sb.toString(); |
1651 } else if (defaultOption) { |
1660 } else if (defaultOption) { |
1652 startup = DEFAULT_STARTUP; |
1661 startup = defaultStartup(); |
1653 } else if (noneOption) { |
1662 } else if (noneOption) { |
1654 startup = ""; |
1663 startup = ""; |
1655 } |
1664 } |
1656 if (retainOption) { |
1665 if (retainOption) { |
1657 // retain startup setting |
1666 // retain startup setting |
1671 } |
1680 } |
1672 |
1681 |
1673 void showSetStart(boolean isRetained, String start) { |
1682 void showSetStart(boolean isRetained, String start) { |
1674 String cmd = "/set start" + (isRetained ? " -retain " : " "); |
1683 String cmd = "/set start" + (isRetained ? " -retain " : " "); |
1675 String stset; |
1684 String stset; |
1676 if (start.equals(DEFAULT_STARTUP)) { |
1685 if (start.equals(defaultStartup())) { |
1677 stset = cmd + "-default"; |
1686 stset = cmd + "-default"; |
1678 } else if (start.isEmpty()) { |
1687 } else if (start.isEmpty()) { |
1679 stset = cmd + "-none"; |
1688 stset = cmd + "-none"; |
1680 } else { |
1689 } else { |
1681 stset = "startup.jsh:\n" + start + "\n" + cmd + "startup.jsh"; |
1690 stset = "startup.jsh:\n" + start + "\n" + cmd + "startup.jsh"; |
2164 } |
2173 } |
2165 |
2174 |
2166 private boolean runFile(String filename, String context) { |
2175 private boolean runFile(String filename, String context) { |
2167 if (!filename.isEmpty()) { |
2176 if (!filename.isEmpty()) { |
2168 try { |
2177 try { |
2169 run(new FileScannerIOContext(toPathResolvingUserHome(filename).toString())); |
2178 Path path = toPathResolvingUserHome(filename); |
|
2179 Reader reader; |
|
2180 String resource; |
|
2181 if (!Files.exists(path) && (resource = getResource(filename)) != null) { |
|
2182 // Not found as file, but found as resource |
|
2183 reader = new StringReader(resource); |
|
2184 } else { |
|
2185 reader = new FileReader(path.toString()); |
|
2186 } |
|
2187 run(new ScannerIOContext(reader)); |
2170 return true; |
2188 return true; |
2171 } catch (FileNotFoundException e) { |
2189 } catch (FileNotFoundException e) { |
2172 errormsg("jshell.err.file.not.found", context, filename, e.getMessage()); |
2190 errormsg("jshell.err.file.not.found", context, filename, e.getMessage()); |
2173 } catch (Exception e) { |
2191 } catch (Exception e) { |
2174 errormsg("jshell.err.file.exception", context, filename, e); |
2192 errormsg("jshell.err.file.exception", context, filename, e); |
2187 * @return contents of file as string |
2205 * @return contents of file as string |
2188 */ |
2206 */ |
2189 String readFile(String filename, String context) { |
2207 String readFile(String filename, String context) { |
2190 if (filename != null) { |
2208 if (filename != null) { |
2191 try { |
2209 try { |
2192 byte[] encoded = Files.readAllBytes(Paths.get(filename)); |
2210 byte[] encoded = Files.readAllBytes(toPathResolvingUserHome(filename)); |
2193 return new String(encoded); |
2211 return new String(encoded); |
2194 } catch (AccessDeniedException e) { |
2212 } catch (AccessDeniedException e) { |
2195 errormsg("jshell.err.file.not.accessible", context, filename, e.getMessage()); |
2213 errormsg("jshell.err.file.not.accessible", context, filename, e.getMessage()); |
2196 } catch (NoSuchFileException e) { |
2214 } catch (NoSuchFileException e) { |
|
2215 String resource = getResource(filename); |
|
2216 if (resource != null) { |
|
2217 // Not found as file, but found as resource |
|
2218 return resource; |
|
2219 } |
2197 errormsg("jshell.err.file.not.found", context, filename); |
2220 errormsg("jshell.err.file.not.found", context, filename); |
2198 } catch (Exception e) { |
2221 } catch (Exception e) { |
2199 errormsg("jshell.err.file.exception", context, filename, e); |
2222 errormsg("jshell.err.file.exception", context, filename, e); |
2200 } |
2223 } |
2201 } else { |
2224 } else { |
2202 errormsg("jshell.err.file.filename", context); |
2225 errormsg("jshell.err.file.filename", context); |
2203 } |
2226 } |
2204 return null; |
2227 return null; |
2205 |
2228 |
|
2229 } |
|
2230 |
|
2231 // Read a built-in file from resources or null |
|
2232 String getResource(String name) { |
|
2233 if (BUILTIN_FILE_PATTERN.matcher(name).matches()) { |
|
2234 try { |
|
2235 return readResource(name); |
|
2236 } catch (Throwable t) { |
|
2237 // Fall-through to null |
|
2238 } |
|
2239 } |
|
2240 return null; |
|
2241 } |
|
2242 |
|
2243 // Read a built-in file from resources |
|
2244 String readResource(String name) throws IOException { |
|
2245 // Attempt to find the file as a resource |
|
2246 String spec = String.format(BUILTIN_FILE_PATH_FORMAT, name); |
|
2247 URL url = new URL(spec); |
|
2248 BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream())); |
|
2249 return reader.lines().collect(Collectors.joining("\n")); |
|
2250 } |
|
2251 |
|
2252 // retrieve the default startup string |
|
2253 String defaultStartup() { |
|
2254 if (defaultStartup == null) { |
|
2255 defaultStartup = ""; // failure case |
|
2256 try { |
|
2257 defaultStartup = readResource(DEFAULT_STARTUP_NAME); |
|
2258 } catch (AccessDeniedException e) { |
|
2259 errormsg("jshell.err.file.not.accessible", "jshell", DEFAULT_STARTUP_NAME, e.getMessage()); |
|
2260 } catch (NoSuchFileException e) { |
|
2261 errormsg("jshell.err.file.not.found", "jshell", DEFAULT_STARTUP_NAME); |
|
2262 } catch (Exception e) { |
|
2263 errormsg("jshell.err.file.exception", "jshell", DEFAULT_STARTUP_NAME, e); |
|
2264 } |
|
2265 } |
|
2266 return defaultStartup; |
2206 } |
2267 } |
2207 |
2268 |
2208 private boolean cmdReset() { |
2269 private boolean cmdReset() { |
2209 live = false; |
2270 live = false; |
2210 fluffmsg("jshell.msg.resetting.state"); |
2271 fluffmsg("jshell.msg.resetting.state"); |