Skip to main content

Terminal Handling

JLine provides a powerful abstraction for terminal handling through its Terminal interface and implementations. This allows your application to interact with different terminal types in a consistent way.

The Terminal component is the foundation of JLine's architecture, providing the low-level interface to the terminal device. It's used by the LineReader to provide advanced line editing capabilities.

Creating a Terminal

The TerminalBuilder class provides a fluent API for creating terminal instances:

TerminalCreationExample.java
import org.jline.terminal.Terminal;
import org.jline.terminal.TerminalBuilder;

import java.io.IOException;
import java.nio.charset.Charset;

public class TerminalCreationExample {
public static void main(String[] args) throws IOException {
// Create a system terminal (auto-detected)
Terminal terminal = TerminalBuilder.builder()
.system(true)
.build();

// Create a dumb terminal (minimal functionality)
Terminal dumbTerminal = TerminalBuilder.builder()
.dumb(true)
.build();

// Create a terminal with specific settings
Terminal customTerminal = TerminalBuilder.builder()
.name("CustomTerminal")
.system(false)
.streams(System.in, System.out)
.encoding(Charset.forName("UTF-8"))
.jansi(true)
.build();
}
}

Terminal Capabilities

Once you have a terminal instance, you can query its capabilities:

TerminalCapabilitiesExample.java
import org.jline.terminal.Size;
import org.jline.terminal.Terminal;

public class TerminalCapabilitiesExample {
public void checkCapabilities(Terminal terminal) {
// Check if the terminal supports ANSI
boolean supportsAnsi = terminal.getType().contains("ansi");

// Get terminal size
Size size = terminal.getSize();
int width = size.getColumns();
int height = size.getRows();

// Check if the terminal is interactive
boolean interactive = terminal.isInteractive();

System.out.printf("Terminal: %s, Size: %dx%d, Interactive: %b%n",
terminal.getType(), width, height, interactive);
}
}

Terminal Output

You can write directly to the terminal:

TerminalOutputExample.java
import org.jline.terminal.Terminal;

import java.io.PrintWriter;

public class TerminalOutputExample {
public void writeOutput(Terminal terminal) {
// Get the terminal writer
PrintWriter writer = terminal.writer();

// Write text
writer.println("Hello, JLine!");
writer.flush();

// Use ANSI escape sequences for formatting (if supported)
writer.println("\u001B[1;31mThis text is bold and red\u001B[0m");
writer.flush();
}
}

Terminal Input

For direct terminal input (without using LineReader):

TerminalInputExample.java
import org.jline.terminal.Terminal;
import org.jline.utils.NonBlockingReader;

import java.io.IOException;

public class TerminalInputExample {
public void readInput(Terminal terminal) throws IOException {
// Get the terminal reader
NonBlockingReader reader = terminal.reader();

// Read a character (blocking)
int c = reader.read();
System.out.println("Read character: " + (char)c);

// Check if input is available
boolean hasInput = reader.available() > 0;

// Read with timeout
int c2 = reader.read(100); // Wait up to 100ms
if (c2 != -1) {
System.out.println("Read character with timeout: " + (char)c2);
}
}
}

Terminal Signals

JLine can handle terminal signals:

TerminalSignalsExample.java
import org.jline.terminal.Size;
import org.jline.terminal.Terminal;
import org.jline.terminal.Terminal.Signal;

public class TerminalSignalsExample {
public void setupSignalHandlers(Terminal terminal) {
terminal.handle(Signal.INT, signal -> {
// Handle Ctrl+C
System.out.println("Received SIGINT");
});

terminal.handle(Signal.WINCH, signal -> {
// Handle terminal resize
Size size = terminal.getSize();
System.out.println("Terminal resized to " + size.getColumns() + "x" + size.getRows());
});
}
}

Closing the Terminal

Always close the terminal when you're done with it:

TerminalCloseExample.java
import org.jline.terminal.Terminal;

public class TerminalCloseExample {
public void closeTerminal(Terminal terminal) {
try {
// Always close the terminal when done
terminal.close();
System.out.println("Terminal closed successfully");
} catch (Exception e) {
System.err.println("Error closing terminal: " + e.getMessage());
}
}
}

Advanced Terminal Features

JLine's terminal handling includes several advanced features:

Raw Mode

RawModeExample.java
import org.jline.terminal.Terminal;

import java.io.IOException;

public class RawModeExample {
public void demonstrateRawMode(Terminal terminal) throws IOException {
try {
// Enter raw mode (disable echo, line buffering, etc.)
terminal.enterRawMode();

System.out.println("Terminal is now in raw mode");
// Do some raw mode operations...

// Exit raw mode
terminal.setAttributes(terminal.getAttributes().copy());
System.out.println("Terminal is back to normal mode");
} catch (Exception e) {
System.err.println("Error with raw mode: " + e.getMessage());
}
}
}

Cursor Manipulation

CursorManipulationExample.java
import org.jline.terminal.Cursor;
import org.jline.terminal.Terminal;

import java.io.IOException;
import java.io.PrintWriter;

public class CursorManipulationExample {
public void manipulateCursor(Terminal terminal) throws IOException {
// Get cursor position
Cursor position = terminal.getCursorPosition(null);
if (position != null) {
System.out.printf("Current cursor position: %d,%d%n",
position.getX(), position.getY());
}

// Get the terminal writer
PrintWriter writer = terminal.writer();

// Move cursor to row 5, column 10
writer.write("\u001B[5;10H");
writer.flush();
}
}

Screen Clearing

JLine provides a more portable way to clear the screen using terminal capabilities:

ScreenClearingExample.java
import org.jline.terminal.Terminal;
import org.jline.utils.InfoCmp.Capability;

public class ScreenClearingExample {
public void clearScreen(Terminal terminal) {
// Clear screen using terminal capabilities
terminal.puts(Capability.clear_screen);

// Clear line using terminal capabilities
terminal.puts(Capability.clr_eol);

// Move cursor to home position
terminal.puts(Capability.cursor_home);

terminal.writer().println("Screen and line cleared");
terminal.flush();
}
}

This approach is preferred over using raw ANSI escape sequences because:

  1. It's more portable across different terminal types
  2. It automatically adapts to the terminal's capabilities
  3. It works even on terminals that don't support ANSI sequences

Mouse Support

JLine supports mouse events in terminals that provide mouse capabilities:

MouseSupportExample.java
import org.jline.terminal.Terminal;
import org.jline.terminal.TerminalBuilder;
import org.jline.terminal.MouseEvent;
import org.jline.terminal.MouseEvent.Type;
import org.jline.utils.InfoCmp.Capability;

import java.io.IOException;
import java.util.function.Consumer;

public class MouseSupportExample {
public static void main(String[] args) throws IOException, InterruptedException {
Terminal terminal = TerminalBuilder.builder().build();

try {
// Clear screen
terminal.puts(Capability.clear_screen);
terminal.flush();

// Enable mouse tracking
terminal.trackMouse(Terminal.MouseTracking.Normal);

terminal.writer().println("Mouse tracking enabled. Click anywhere or press q to quit.");
terminal.writer().println();
terminal.flush();

// Set up mouse event handler
Consumer<MouseEvent> mouseHandler = event -> {
terminal.writer().println(String.format("Mouse event: type=%s, button=%s, x=%d, y=%d",
event.getType(), event.getButton(), event.getX(), event.getY()));
terminal.flush();
};

// Register the mouse handler
terminal.handle(Terminal.Signal.MOUSE, signal -> {
MouseEvent event = terminal.readMouseEvent();
mouseHandler.accept(event);
});

// Wait for 'q' key to exit
while (true) {
int c = terminal.reader().read(1000);
if (c == 'q' || c == 'Q') {
break;
}
}
} finally {
// Disable mouse tracking before exiting
terminal.trackMouse(Terminal.MouseTracking.Off);
terminal.close();
}
}
}

Mouse tracking modes:

  • Terminal.MouseTracking.Off: Disables mouse tracking
  • Terminal.MouseTracking.Normal: Reports button press and release events
  • Terminal.MouseTracking.Button: Reports button press, release, and motion events while buttons are pressed
  • Terminal.MouseTracking.Any: Reports all mouse events, including motion events

Not all terminals support mouse tracking. You can check if mouse tracking is supported:

boolean supportsMouseTracking = terminal.getStringCapability(Capability.key_mouse) != null;

Platform Compatibility

JLine's terminal handling works across different platforms:

  • Windows (using JNA or Jansi)
  • Unix/Linux (using native PTY)
  • macOS (using native PTY)
  • Dumb terminals (minimal functionality)

This cross-platform compatibility makes JLine ideal for applications that need to run in various environments.