Line Reading
The LineReader
is one of JLine's core components, providing sophisticated line editing capabilities for your command-line applications.
Creating a LineReader
Use the LineReaderBuilder
to create a LineReader
instance:
LineReaderCreationExample.java
import org.jline.reader.LineReader;
import org.jline.reader.LineReaderBuilder;
import org.jline.terminal.Terminal;
import org.jline.terminal.TerminalBuilder;
import java.io.IOException;
import java.nio.file.Paths;
public class LineReaderCreationExample {
public static void main(String[] args) throws IOException {
// Create a terminal
Terminal terminal = TerminalBuilder.builder().build();
// Create a basic line reader
LineReader reader = LineReaderBuilder.builder()
.terminal(terminal)
.build();
// Create a line reader with custom configuration
LineReader customReader = LineReaderBuilder.builder()
.terminal(terminal)
.appName("MyApp")
.variable(LineReader.HISTORY_FILE, Paths.get("history.txt"))
.option(LineReader.Option.AUTO_FRESH_LINE, true)
.option(LineReader.Option.HISTORY_BEEP, false)
.build();
}
}
Reading Input
The basic method for reading input is readLine()
:
LineReaderInputExample.java
import org.jline.reader.LineReader;
public class LineReaderInputExample {
public void demonstrateInput(LineReader reader) {
// Read a line with a prompt
String line = reader.readLine("prompt> ");
System.out.println("You entered: " + line);
// Read a line with a right prompt (displayed at the right edge)
String lineWithRightPrompt = reader.readLine("prompt> ", "right prompt", (Character) null);
System.out.println("You entered: " + lineWithRightPrompt);
// Read a masked line (for passwords)
String password = reader.readLine("Password: ", '*');
System.out.println("Password accepted");
}
}
Line Reader Options
JLine's LineReader
supports numerous options to customize behavior:
LineReaderOptionsExample.java
import org.jline.reader.LineReader;
import org.jline.reader.LineReaderBuilder;
import org.jline.terminal.Terminal;
public class LineReaderOptionsExample {
public LineReader configureOptions(Terminal terminal) {
// Configure options during creation
LineReader reader = LineReaderBuilder.builder()
.terminal(terminal)
.option(LineReader.Option.CASE_INSENSITIVE, true)
.option(LineReader.Option.AUTO_REMOVE_SLASH, true)
.build();
// Or set options after creation
reader.setOpt(LineReader.Option.HISTORY_IGNORE_DUPS);
reader.unsetOpt(LineReader.Option.HISTORY_BEEP);
return reader;
}
}
Common options include:
CASE_INSENSITIVE
: Case-insensitive completionAUTO_FRESH_LINE
: Automatically add a newline if the cursor isn't at the start of a lineHISTORY_BEEP
: Beep when navigating past the end of historyHISTORY_IGNORE_DUPS
: Don't add duplicate entries to historyHISTORY_IGNORE_SPACE
: Don't add entries starting with space to historyMENU_COMPLETE
: Cycle through completions on tab
Customizing Prompts
JLine supports rich prompt customization:
CustomPromptExample.java
import org.jline.reader.LineReader;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.function.Supplier;
public class CustomPromptExample {
public void demonstratePrompts(LineReader reader) {
// Simple text prompt
String line1 = reader.readLine("simple> ");
// Colored prompt (ANSI escape sequences)
String line2 = reader.readLine("\u001B[1;32msimple>\u001B[0m ");
// Dynamic prompt
Supplier<String> timePrompt = () -> {
LocalTime now = LocalTime.now();
return now.format(DateTimeFormatter.ofPattern("HH:mm:ss")) + "> ";
};
String line3 = reader.readLine(timePrompt);
System.out.printf("Lines entered: %s, %s, %s%n", line1, line2, line3);
}
}
Handling Special Keys
You can customize how the LineReader
responds to key presses:
KeyBindingExample.java
import org.jline.keymap.Binding;
import org.jline.keymap.KeyMap;
import org.jline.reader.LineReader;
import org.jline.reader.Reference;
public class KeyBindingExample {
public void customizeKeyBindings(LineReader reader) {
// Create a custom key map
KeyMap<Binding> keyMap = reader.getKeyMaps().get(LineReader.MAIN);
// Bind a key to a widget
keyMap.bind(new Reference("clear-screen"), KeyMap.ctrl('L'));
// Bind a key to a custom action
keyMap.bind(
() -> {
System.out.println("Custom action executed!");
return true;
},
KeyMap.alt('X')
);
System.out.println("Key bindings configured");
}
}
Line Editing Features
JLine's LineReader
provides numerous line editing features:
- Navigation: Move by character, word, or line
- Editing: Insert, delete, cut, paste, transpose
- History: Navigate, search, and filter command history
- Completion: Tab completion with customizable behavior
- Search: Incremental search through current line or history
Advanced Usage
Multi-line Input
JLine supports multi-line input with proper continuation:
MultiLineInputExample.java
import org.jline.reader.LineReader;
import org.jline.reader.LineReaderBuilder;
import org.jline.reader.impl.DefaultParser;
import org.jline.terminal.Terminal;
public class MultiLineInputExample {
public String readMultiLineInput(Terminal terminal) {
// Configure multi-line support
LineReader reader = LineReaderBuilder.builder()
.terminal(terminal)
.parser(new DefaultParser())
.variable(LineReader.SECONDARY_PROMPT_PATTERN, "%M> ")
.build();
System.out.println("Enter a multi-line input (e.g., with unclosed quotes or brackets):");
// Read multi-line input
String multiLine = reader.readLine("multi> ");
return multiLine;
}
}
Custom Validators
You can validate input before accepting it:
ValidatorExample.java
import org.jline.reader.LineReader;
import org.jline.reader.LineReaderBuilder;
import org.jline.reader.ValidationException;
import org.jline.reader.Validator;
import org.jline.terminal.Terminal;
public class ValidatorExample {
public LineReader createValidatingReader(Terminal terminal) {
// Create a validator
Validator validator = line -> {
if (line.isEmpty()) {
throw new ValidationException("Input cannot be empty");
}
if (line.length() < 3) {
throw new ValidationException("Input must be at least 3 characters");
}
};
// Use the validator
LineReader reader = LineReaderBuilder.builder()
.terminal(terminal)
.validator(validator)
.build();
return reader;
}
}
Custom Highlighters
JLine can highlight input as it's typed:
HighlighterExample.java
import org.jline.reader.Highlighter;
import org.jline.reader.LineReader;
import org.jline.reader.LineReaderBuilder;
import org.jline.terminal.Terminal;
import org.jline.utils.AttributedString;
import org.jline.utils.AttributedStringBuilder;
import org.jline.utils.AttributedStyle;
import java.util.List;
public class HighlighterExample {
public LineReader createHighlightingReader(Terminal terminal) {
// Create a highlighter
Highlighter highlighter = (reader, buffer, list) -> {
AttributedString highlighted = new AttributedStringBuilder()
.append(buffer.toString(), AttributedStyle.BOLD)
.toAttributedString();
list.add(highlighted);
return highlighted;
};
// Use the highlighter
LineReader reader = LineReaderBuilder.builder()
.terminal(terminal)
.highlighter(highlighter)
.build();
return reader;
}
}
Best Practices
- Always close the terminal when your application exits
- Use try-with-resources for automatic resource management
- Configure history appropriately for your application
- Consider using a parser for complex command syntax
- Provide helpful completion options for better user experience