Terminal
De Terminal component is een interactieve terminalemulator die zich gedraagt als een traditionele systeemconsole. Het beheert tekstuitvoer, gebruikersinvoer, controle- en escape-sequenties, en schermbuffers, waardoor het geschikt is voor het bouwen van hulpmiddelen voor externe toegang, tekstdashboards, ingebedde commando-shells of debugconsoles.
Een terminal aanmaken
Om de Terminal component in je app te gebruiken, zorg ervoor dat je de volgende afhankelijkheid in je pom.xml opneemt.
<dependency>
<groupId>com.webforj</groupId>
<artifactId>webforj-terminal</artifactId>
</dependency>
Het volgende voorbeeld bouwt een interactieve opdracht-shell met getypte opdrachten, navigatie in de geschiedenis en aangepaste uitvoer.
Toon Code
- TerminalView.java
- TerminalCommand.java
- ClearCommand.java
- DateCommand.java
- HelpCommand.java
- MsgCommand.java
- PromptCommand.java
- TimeCommand.java
- terminal-view.css
Hoe het werkt
De terminal beheert een grid van tekstcellen, verwerkt inkomende tekenstromen en reageert op gebruikersacties zoals typen of tekst selecteren. Het interpreteert automatisch controlekarakters en escape-sequenties voor cursorbeweging, kleuraanpassingen en het wissen van het scherm.
De kernfunctionaliteiten omvatten:
- Gegevensinvoer: Het schrijven van gegevens naar de terminal werkt het scherm bij, waarbij zowel tekst als controle-sequenties worden verwerkt.
- Gegevensuitvoer: Vangt gebruikersinvoer van toetsen en geeft deze weer als gestructureerde gebeurtenissen.
- Schermbeheer: Behoudt een scrollbare geschiedenisbuffer en de huidige schermstatus.
- Cursorbeheer: Houdt de cursorpositie bij voor tekstinvoer en reacties op controle-sequenties.
De terminal is stateful, wat betekent dat deze multibyte-tekens goed reconstrueert en continuïteit behoudt bij gefragmenteerde invoer.
Gegevens naar de terminal sturen
Gegevens worden naar de terminal gestuurd met de methoden write en writeln:
write(Object data): Stuurt gegevens in de terminalstroom.writeln(Object data): Stuurt gegevens gevolgd door een newline.
De terminal verwerkt alle inkomende gegevens als UTF-16-strings. Het verwerkt automatisch multibyte-tekens, zelfs wanneer de invoer in gefragmenteerde stukken arriveert.
Voorbeeld
terminal.write("echo Hello World\n");
terminal.writeln("Klaar.");
Je kunt ook een callback toevoegen die wordt uitgevoerd zodra het gegevensfragment is verwerkt:
terminal.write("Lang uitvoer van opdracht", e -> {
System.out.println("Gegevens verwerkt.");
});
Ontvangen van gebruikersinvoer
De terminal vangt door de gebruiker gegenereerde invoer via twee evenementen:
- Gegevens evenement (
onData): Vindt plaats wanneer textinvoer plaatsvindt, met Unicode-tekens. - Toetsenbord evenement (
onKey): Vindt plaats bij elke toetsdruk, inclusief informatie over toetsaanslagen en modifiers zoals Ctrl of Alt.
Deze evenementen kunnen worden gebruikt om gebruikersinvoer naar een backend door te geven, UI-elementen bij te werken, of aangepaste acties te activeren.
Voorbeeld
terminal.onData(event -> {
String userInput = event.getValue();
backend.send(userInput);
});
terminal.onKey(event -> {
if (event.isControlKey() && "C".equals(event.getKey())) {
backend.send("SIGINT");
}
});
Alle door de terminal vastgelegde gebruikersinvoer (zoals van onData-evenementen) wordt uitgezonden als UTF-16-strings.
Als je backend een andere codering verwacht (zoals UTF-8-bytes), moet je de gegevens handmatig transcoderend.
Behandelen van grote gegevensstromen
Omdat de terminal niet in staat is om onbeperkte invoer onmiddellijk weer te geven, onderhoudt het een interne invoerbuffer. Als deze buffer te groot groeit (standaard ongeveer 50MB), kunnen nieuwe inkomende gegevens worden verworpen om de systeemperformance te beschermen.
Om snel datastromen goed te beheren, moet je flow control implementeren.
Basisvoorbeeld van flow control
Pauzeer je backend totdat de terminal de verwerking van een fragment heeft voltooid:
pty.onData(chunk -> {
pty.pause();
terminal.write(chunk, result -> {
pty.resume();
});
});
Watermark flow control voorbeeld
Voor efficiëntere controle, gebruik hoge/lage watermerken:
int HIGH_WATERMARK = 100_000;
int LOW_WATERMARK = 10_000;
int bufferedBytes = 0;
pty.onData(chunk -> {
bufferedBytes += chunk.length;
terminal.write(chunk, e -> {
bufferedBytes -= chunk.length;
if (bufferedBytes < LOW_WATERMARK) {
pty.resume();
}
});
if (bufferedBytes > HIGH_WATERMARK) {
pty.pause();
}
});
Toon Code
- ServerLogsView.java
Aanpassing
Terminal opties
De TerminalOptions klasse stelt je in staat om gedrag te configureren:
- Cursor knipperen.
- Lettertype-instellingen (familie, grootte, gewicht).
- Scrollback buffer grootte.
- Regelhoogte en letterafstand.
- Toegankelijkheidsinstellingen (schermlezer-modus).
Voorbeeld:
TerminalOptions options = new TerminalOptions()
.setCursorBlink(true)
.setFontFamily("Courier New, monospace")
.setFontSize(13)
.setScrollback(5000);
terminal.setOptions(options);
Terminal thema
Je kunt de terminal stylen met TerminalTheme, dat het volgende definieert:
- Achtergrond- en voorgrondkleuren.
- Standaard
ANSIkleurenpalet. - Cursor- en selectieachtergrondkleuren.
Voorbeeld:
TerminalTheme theme = new TerminalTheme();
theme.setBackground("#1e1e1e");
theme.setForeground("#cccccc");
terminal.setTheme(theme);
Toon Code
- TerminalThemePickerView.java
Ondersteunde sequenties
De terminal ondersteunt een breed scala aan standaard controle sequenties die worden gebruikt voor cursorbeweging, schermupdates en tekstformattering.
Herkenbare groepen:
C0controlecodes (enkele byte 7-bits commando's,\x00,\x1F, zoals backspace en line feed)C1controlecodes (enkele byte 8-bits commando's,\x80,\x9F)ESCsequenties (beginnen metESC(\x1B), zoals cursor opslaan/herstellen, schermuitlijning)CSIsequenties (Control Sequence Introducer,ESC [ofCSI (\x9B), voor operaties zoals scrollen, wissen, en stylen)DCSsequenties (Device Control Strings,ESC PofDCS (\x90))OSCsequenties (Operating System Commands,ESC ]ofOSC (\x9D), voor het instellen van venstertitel, hyperlinks, en kleuren)
Sommige exotische sequentietypes zoals APC,PM, en SOS worden herkend maar stilletjes genegeerd.
Aangepaste sequenties kunnen indien nodig worden ondersteund via integraties.