changeset 2276:651386629cea

Shell handles user interrupt with exit prompt Reviewed-by: neugens, jerboaa Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2016-April/018521.html
author Andrew Azores <aazores@redhat.com>
date Mon, 25 Apr 2016 17:13:31 -0400
parents 135bd0d327cb
children a15a2233e4c7
files launcher/src/main/java/com/redhat/thermostat/launcher/internal/LocaleResources.java launcher/src/main/java/com/redhat/thermostat/launcher/internal/ShellCommand.java launcher/src/main/resources/com/redhat/thermostat/launcher/internal/strings.properties
diffstat 3 files changed, 50 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/LocaleResources.java	Thu Apr 21 18:22:45 2016 +0200
+++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/LocaleResources.java	Mon Apr 25 17:13:31 2016 -0400
@@ -74,6 +74,10 @@
     PARSE_ISSUES_CALLED_BEFORE_PARSE,
     PARSER_ERROR,
     PARSER_WARNING,
+
+    QUIT_PROMPT,
+    QUIT_CONFIRM,
+    QUIT_DENY,
     ;
 
     static final String RESOURCE_BUNDLE = "com.redhat.thermostat.launcher.internal.strings";
--- a/launcher/src/main/java/com/redhat/thermostat/launcher/internal/ShellCommand.java	Thu Apr 21 18:22:45 2016 +0200
+++ b/launcher/src/main/java/com/redhat/thermostat/launcher/internal/ShellCommand.java	Mon Apr 25 17:13:31 2016 -0400
@@ -38,6 +38,7 @@
 
 import java.io.IOException;
 import java.util.Arrays;
+import java.util.List;
 import java.util.Map;
 import java.util.logging.Level;
 import java.util.logging.Logger;
@@ -45,6 +46,7 @@
 import jline.Terminal;
 import jline.TerminalFactory;
 import jline.console.ConsoleReader;
+import jline.console.UserInterruptException;
 import jline.console.history.FileHistory;
 import jline.console.history.History;
 import jline.console.history.PersistentHistory;
@@ -72,7 +74,7 @@
     private static final Logger logger = LoggingUtils.getLogger(ShellCommand.class);
     private static final Translate<LocaleResources> t = LocaleResources.createLocalizer();
 
-    private static final String[] exitKeywords = { "exit", "quit", "q" };
+    private static final List<String> exitKeywords = Arrays.asList("exit", "quit", "q" );
 
     private HistoryProvider historyProvider;
     private Version version;
@@ -148,7 +150,7 @@
         }
     }
 
-    private void closeTerminal(Terminal term) throws CommandException {
+    private void closeTerminal(Terminal term) {
         try {
             term.restore();
         } catch (Exception e) {
@@ -158,28 +160,39 @@
 
     private void shellMainLoop(CommandContext ctx, History history, Terminal term) throws IOException, CommandException {
         ConsoleReader reader = new ConsoleReader(ctx.getConsole().getInput(), ctx.getConsole().getOutput(), term);
+        reader.setHandleUserInterrupt(true);
+        reader.setPrompt(shellPrompt.getPrompt());
         if (reader.getCompleters().isEmpty() && commandInfoSource != null && tabCompletion != null) {
             tabCompletion.setupTabCompletion(reader, commandInfoSource, bundleContext, prefs);
         }
         if (history != null) {
             reader.setHistory(history);
         }
-        while (handleConsoleInput(reader, ctx.getConsole())) { /* no-op; the loop conditional performs the action */ }
+        try {
+            while (handleConsoleInput(reader, ctx.getConsole(), shellPrompt.getPrompt())) { /* no-op; the loop conditional performs the action */ }
+        } finally {
+            reader.shutdown();
+        }
     }
 
     /**
      * @return true if the shell should continue accepting more input or false if the shell should quit
      */
-    private boolean handleConsoleInput(ConsoleReader reader, Console console) throws IOException, CommandException {
+    private boolean handleConsoleInput(ConsoleReader reader, Console console, String prompt) throws IOException, CommandException {
         String line;
-        line = reader.readLine(shellPrompt.getPrompt());
+        try {
+            line = reader.readLine(prompt);
+        } catch (UserInterruptException uie) {
+            return handleUserInterrupt(reader, console);
+        }
         if (line == null) {
+            // ex. Ctrl-D on empty line
             return false;
         }
         line = line.trim();
         if (line.equals("")) {
             return true;
-        } else if (Arrays.asList(exitKeywords).contains(line)) {
+        } else if (exitKeywords.contains(line)) {
             return false;
         } else {
             launchCommand(line);
@@ -187,6 +200,28 @@
         }
     }
 
+    private boolean handleUserInterrupt(ConsoleReader reader, Console console) {
+        String prompt = reader.getPrompt();
+        try {
+            console.getOutput().println(t.localize(LocaleResources.QUIT_PROMPT).getContents());
+
+            String confirmChars = t.localize(LocaleResources.QUIT_CONFIRM).getContents();
+            String denyChars = t.localize(LocaleResources.QUIT_DENY).getContents();
+            char[] expectedChars = (confirmChars + denyChars).toCharArray();
+
+            char val;
+            try {
+                val = (char) reader.readCharacter(expectedChars);
+            } catch (IOException ioe) {
+                return false;
+            }
+
+            return confirmChars.indexOf(val) == -1;
+        } finally {
+            reader.setPrompt(prompt);
+        }
+    }
+
     private void launchCommand(String line) throws CommandException {
         ShellArgsParser parser = new ShellArgsParser(line);
         String[] parsed = parser.parse();
--- a/launcher/src/main/resources/com/redhat/thermostat/launcher/internal/strings.properties	Thu Apr 21 18:22:45 2016 +0200
+++ b/launcher/src/main/resources/com/redhat/thermostat/launcher/internal/strings.properties	Mon Apr 25 17:13:31 2016 -0400
@@ -39,4 +39,8 @@
 
 PARSE_ISSUES_CALLED_BEFORE_PARSE = ShellArgsParser#getParseIssues called before ShellArgsParser#parse
 PARSER_ERROR = Could not parse input:\n{0}
-PARSER_WARNING = Malformed input, attempting to proceed anyway:\n{0}
\ No newline at end of file
+PARSER_WARNING = Malformed input, attempting to proceed anyway:\n{0}
+
+QUIT_PROMPT = Quit? (y/n)
+QUIT_CONFIRM = yY
+QUIT_DENY = nN
\ No newline at end of file