Shortcut key to interrupt current computation

260 views
Skip to first unread message

Dario Beraldi

unread,
May 11, 2017, 4:14:46 PM5/11/17
to jline-users
Hello,

First, thanks to the developers for making jline available, great library!

I have a program which receives command line input interactively via jline2.
If the user enters a command that takes a long time to complete, s/he may want to interrupt the computation without killing the entire program. 

Is there a keyboard shortcut that can be used to achieve this? Entering CTRL-C will kill the entire application, I'm looking for a solution to just interrupt 
the current computation and return to the jline prompt. 

For example, in the simple program below entering the command "start" will start an endless loop. How can exit the loop without resorting on CTRL-C and thus exiting the entire program?

Thanks a lot!
Dario

public class Main {

    

    public static void main(String[] args) throws IOException {

        ConsoleReader console= new ConsoleReader();

        console.setPrompt("Enter command>");

        String input= console.readLine();

        if(input.equals("start")){

            while(true){

                // Get me out of here!

            }

        } else{

            // Do something else

        }

    }

}

Guillaume Nodet

unread,
May 11, 2017, 4:24:14 PM5/11/17
to jline...@googlegroups.com
That's a configuration problem.
You need to handle signals and configure the terminal accordingly.

Give a try to the jline demo, you can use ^C, ^Z to interrupt or put jobs in the background.

Basically, what you need to do is to call TerminalBuilder#nativeSignals and use TerminalBuilder#signalHandler(SignalHandler.SIG_IGN)  to make sure the ^C is caught.
then on the terminal, you'll be able to register a handler using the Terminal#handle method and interrupt the job which is running.

--
You received this message because you are subscribed to the Google Groups "jline-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jline-users+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Jason Dillon

unread,
May 11, 2017, 4:52:29 PM5/11/17
to jline...@googlegroups.com
To unsubscribe from this group and stop receiving emails from it, send an email to jline-users...@googlegroups.com.

Dario Beraldi

unread,
May 13, 2017, 2:05:05 PM5/13/17
to jline-users
Hi guys,

Thanks for getting back to me. I've re-written my dumb program using jline3 and following Guillaume hints (see below). However, I'm still stuck...

Once the endless() method is started using the input string "start" at the prompt, Ctrl-C or Ctrl-Z have no effect. That's good I guess. However, I still don't understand how to capture the Ctrl-C signal and make it stop the endless() method (but without killing the entire applications). I'm struggling with Guillaume's suggestion to "register a handler using the Terminal#handle method and interrupt the job which is running".

It would be great if could review the code below and post suggestions.

Thanks again!
Dario

public class Main {

public static void main(String[] args) throws IOException, InterruptedException {

TerminalBuilder builder = TerminalBuilder.builder();

builder.nativeSignals(true); 

builder.signalHandler(SignalHandler.SIG_IGN);

Terminal terminal = builder.build(); 

// Not sure what to do with this...

SignalHandler signalHandler= terminal.handle(Signal.QUIT, SignalHandler.SIG_IGN);

LineReader reader = LineReaderBuilder.builder()

.terminal(terminal)

.build();


String line = reader.readLine("Enter command>", null, null, null);

if(line.equals("start")){

System.out.println("Endless loop started...");

endless(); // Here: capture Ctrl+C to stop endless()

} else{

System.out.println("bye");

System.exit(0);

}

}


private static void endless() throws InterruptedException {

int i= 1;

while(true){

System.out.println("waiting " + i);

i++;

Thread.sleep(1000);

To unsubscribe from this group and stop receiving emails from it, send an email to jline-users...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Jason Dillon

unread,
May 13, 2017, 2:20:00 PM5/13/17
to jline...@googlegroups.com, Dario Beraldi
Here, I hacked up your example slightly to better show how to use a handler:

<snip>
public class Main {
  private static AtomicBoolean running = new AtomicBoolean(true);

  public static void main(String[] args) throws Exception {
    Terminal terminal = TerminalBuilder.builder()
      .nativeSignals(true)
      .signalHandler(Terminal.SignalHandler.SIG_IGN)
      .build();

    Terminal.SignalHandler interruptHandler = terminal.handle(Terminal.Signal.INT, s -> {
      running.set(false);
    });

    LineReader reader = LineReaderBuilder.builder()
      .terminal(terminal)
      .build();

    try {
      while (running.get()) {
        String line = reader.readLine("Enter command> ");
        if (line.equals("start")) {
          System.out.println("Endless loop started...");
          endless(); // Here: capture Ctrl+C to stop endless()
          System.out.println("Loop canceled");
        }
        else {
          System.out.println("bye");
          running.set(false);
        }
      }
    }
    finally {
      terminal.handle(Terminal.Signal.INT, interruptHandler);
    }
  }

  private static void endless() throws InterruptedException {
    int i = 1;
    while (running.get()) {
      System.out.println("waiting " + i);
      i++;
      Thread.sleep(1000);
    }
  }
}
</snip>

This just uses a handler to on ctrl-c set the running flag to false, then the loops only run if running is true.  Hopefully that gives you a better idea of how it works.

—jason

Dario Beraldi

unread,
May 14, 2017, 3:40:31 AM5/14/17
to Jason Dillon, jline...@googlegroups.com
Thanks a lot Jason, this seems to do what I need. I'lll walk through your code to understand what it does, there quite a bit of new stuff in there for me!


To unsubscribe from this group and stop receiving emails from it, send an email to jline-users+unsubscribe@googlegroups.com.

Suresh G

unread,
May 28, 2017, 3:36:32 PM5/28/17
to jline-users, dario....@gmail.com
   finally {
     terminal.handle(Terminal.Signal.INT, interruptHandler);
   }


Jason, 

    Thanks for the example. Why we need to set the handler again in the finally block ??

Jason Dillon

unread,
May 28, 2017, 3:43:28 PM5/28/17
to jline...@googlegroups.com, Suresh G, dario....@gmail.com
It restores the previously handler for the signal.

—jason
Reply all
Reply to author
Forward
0 new messages