langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java
changeset 42972 47ca49eee534
parent 42969 a48d4f74d322
child 43038 7b8b8750a78e
equal deleted inserted replaced
42971:22c8c025a651 42972:47ca49eee534
    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;
   480     private void start(IOContext in, List<String> loadList) {
   477     private void start(IOContext in, List<String> loadList) {
   481         // If startup hasn't been set by command line, set from retained/default
   478         // If startup hasn't been set by command line, set from retained/default
   482         if (startup == null) {
   479         if (startup == null) {
   483             startup = prefs.get(STARTUP_KEY);
   480             startup = prefs.get(STARTUP_KEY);
   484             if (startup == null) {
   481             if (startup == null) {
   485                 startup = DEFAULT_STARTUP;
   482                 startup = defaultStartup();
   486             }
   483             }
   487         }
   484         }
   488 
   485 
   489         configEditor();
   486         configEditor();
   490 
   487 
   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) +
   796         }
   798         }
   797     }
   799     }
   798 
   800 
   799     //where
   801     //where
   800     private void startUpRun(String start) {
   802     private void startUpRun(String start) {
   801         try (IOContext suin = new FileScannerIOContext(new StringReader(start))) {
   803         try (IOContext suin = new ScannerIOContext(new StringReader(start))) {
   802             run(suin);
   804             run(suin);
   803         } catch (Exception ex) {
   805         } catch (Exception ex) {
   804             hardmsg("jshell.err.startup.unexpected.exception", ex);
   806             hardmsg("jshell.err.startup.unexpected.exception", ex);
   805             ex.printStackTrace(cmdout);
   807             ex.printStackTrace(cmdout);
   806         }
   808         }
  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");
  2908 
  2969 
  2909     ScannerIOContext(Scanner scannerIn) {
  2970     ScannerIOContext(Scanner scannerIn) {
  2910         this.scannerIn = scannerIn;
  2971         this.scannerIn = scannerIn;
  2911     }
  2972     }
  2912 
  2973 
       
  2974     ScannerIOContext(Reader rdr) throws FileNotFoundException {
       
  2975         this(new Scanner(rdr));
       
  2976     }
       
  2977 
  2913     @Override
  2978     @Override
  2914     public String readLine(String prompt, String prefix) {
  2979     public String readLine(String prompt, String prefix) {
  2915         if (scannerIn.hasNextLine()) {
  2980         if (scannerIn.hasNextLine()) {
  2916             return scannerIn.nextLine();
  2981             return scannerIn.nextLine();
  2917         } else {
  2982         } else {
  2925     }
  2990     }
  2926 
  2991 
  2927     @Override
  2992     @Override
  2928     public int readUserInput() {
  2993     public int readUserInput() {
  2929         return -1;
  2994         return -1;
  2930     }
       
  2931 }
       
  2932 
       
  2933 class FileScannerIOContext extends ScannerIOContext {
       
  2934 
       
  2935     FileScannerIOContext(String fn) throws FileNotFoundException {
       
  2936         this(new FileReader(fn));
       
  2937     }
       
  2938 
       
  2939     FileScannerIOContext(Reader rdr) throws FileNotFoundException {
       
  2940         super(new Scanner(rdr));
       
  2941     }
  2995     }
  2942 }
  2996 }
  2943 
  2997 
  2944 class ReloadIOContext extends NonInteractiveIOContext {
  2998 class ReloadIOContext extends NonInteractiveIOContext {
  2945     private final Iterator<String> it;
  2999     private final Iterator<String> it;