Techsenger JediTermFX is a Terminal Emulator for JavaFX. The project is a result of porting JediTerm (commit 8366f2b) from Swing to JavaFX. JediTermFX exclusively utilizes JavaFX components. Therefore, the Terminal Emulator based on this library can be seamlessly integrated into any JavaFX application. A detailed comparison of terminal libraries is provided below.
- Demo
- Features
- Terminal Comparison
- Usage
- How It Works
- Code Building
- Running the Application
- License
- Contributing
- Support Us
- Local terminal for Unix, Mac and Windows using Pty4J
- Xterm emulation - passes most of tests from vttest
- Xterm 256 colours
- Scrolling
- Copy/Paste
- Mouse support
- Terminal resizing from client or server side
- Terminal tabs
| Terminal | JediTermFX | JediTerm | TerminalFX |
|---|---|---|---|
| GUI Library | JavaFX | Swing | JavaFX |
| Main Component | Canvas | JComponent | WebView |
| Languages | Java | Java, Kotlin | Java, JS |
| JPMS Support | Yes | No | Yes |
It is recommended to start working with JediTermFX by studying and running the BasicTerminalShellExample class. This class contains the minimal code needed to launch a terminal in a JavaFX application.
This project is available on Maven Central:
<dependency>
<groupId>com.techsenger.jeditermfx</groupId>
<artifactId>jeditermfx-core</artifactId>
<version>${jeditermfx.version}</version>
</dependency>
<dependency>
<groupId>com.techsenger.jeditermfx</groupId>
<artifactId>jeditermfx-ui</artifactId>
<version>${jeditermfx.version}</version>
</dependency>
If you need a dark theme, you should override the getDefaultForeground() and getDefaultBackground() methods in
UserSettingsProvider. To run the demo application in dark theme see Using Maven.
JediTermFX provides a wide range of features when working with links. The HighlightMode enumeration specifies multiple
modes of working with links and their colors. In the ALWAYS modes, links are always underlined and always clickable.
In the NEVER modes, links are never underlined and never clickable. In the HOVER modes, links become underlined and
clickable only when hovered over. Now let's clarify the difference between the two types of colors. CUSTOM colors
are those set by the JediTermFX user in the getHyperlinkColor() method of the settings. ORIGINAL colors are those
offered by the program running in the terminal. Thus, links can use either custom colors or the original text colors.
-
Terminal — a text input/output device, not a command-interpreter program.
Historically (1960s-70s), a terminal was standalone physical hardware: a screen and a keyboard wired to a large computer. The user typed text, it travelled down the wire to the computer, and the computer sent text back to be displayed. The terminal itself didn't "understand" anything, it just passed bytes back and forth.
Nowadays almost nobody sees a physical terminal, but the concept survives as three distinct layers that a modern UX blends into a single window.
-
Terminal emulator — a windowed program that draws a grid of characters, interprets ANSI codes (colors, cursor movement) and captures key presses. Examples are gnome-terminal, xterm, konsole, iTerm2, Windows Terminal. This is "the terminal" in the everyday sense, the window itself.
-
PTY (pseudo-terminal) — no longer a program but an operating system kernel mechanism. It is a pair of file descriptors, master and slave, that the kernel creates to give a process the illusion that it is connected to a real terminal device (
isatty() == true, it can query the window size, and so on), even though there is no physical hardware behind it.The slave end is handed to the child process as its stdin/stdout/stderr, from the process's point of view it behaves exactly like a real terminal device. The master end is the other end of the same channel, it is what whoever controls the terminal (Pty4J, and through it JediTermFX) reads from and writes to. They always come as a pair because a PTY is a two-ended channel: whatever is written to the master shows up as input on the slave (this is how key presses reach the shell), and whatever the process on the slave side writes, plain text and ANSI escape sequences alike, shows up as output on the master (this is how JediTermFX receives everything the shell prints).
This is a Unix concept: Linux, macOS and BSD have had a real kernel-level PTY for decades, standardized by POSIX. Windows had nothing equivalent until Windows 10 version 1809 (2018), when Microsoft added ConPTY (the Pseudo Console API), mainly to let Unix-style tools work properly on Windows too. On older Windows versions, Pty4J falls back to WinPTY, a third-party library that emulates PTY-like behavior on top of the old Windows Console subsystem rather than a true kernel PTY.
-
Shell (bash, zsh, PowerShell, cmd.exe) — a command-interpreter program, not a terminal. It does not draw anything itself, it just reads a line of text from its input, parses it as a command, executes it, and writes the result to its output. It has no idea whether the other end is a terminal emulator, a file, or a pipe, it simply writes characters (and, if it detects through
isatty()that its output is a real terminal, it starts adding ANSI codes for readability, as covered below).
JediTermFX does not create PTYs itself, it relies on Pty4J for that. Setting up a terminal session looks like this:
JediTermFX -> Pty4J -> OS pseudo-terminal (PTY: master + slave)
-> child process (e.g. a shell), attached to the PTY slave
Pty4J asks the OS kernel to allocate a PTY, spawns the target program with its stdin/stdout/stderr attached to the
PTY's slave side, and exposes the PTY's master side to Java as a PtyProcess, which is a regular
java.lang.Process. JediTermFX's integration point with this (or any other raw source of terminal I/O) is the
TtyConnector interface; ProcessTtyConnector is a ready-made implementation wrapping a java.lang.Process.
TtyConnector only reads and writes raw characters, it has no knowledge of ANSI escape sequences.
Reading. Everything the child process writes to its output (plain text interleaved with raw ANSI/VT escape sequences, which the child process generates itself) then flows through JediTermFX like this:
child process stdout/stderr -> PTY slave -> PTY master -> TtyConnector.read()
-> TtyBasedArrayDataStream -> TerminalStarter (background thread)
-> JediEmulator (parses ANSI/VT escape sequences)
-> Terminal / JediTerminal, which updates two different sinks:
-> TerminalTextBuffer (printed characters and their style)
-> TerminalDisplay (cursor, window title, selection, mouse mode, and other terminal-device state)
-> TerminalPanel (JavaFX): paints from TerminalTextBuffer and implements TerminalDisplay
ProcessTtyConnectorwraps the process:read()reads fromprocess.getInputStream()through anInputStreamReaderwith the right charset,write()writes toprocess.getOutputStream(). It is just an adapter from a process to theTtyConnectorinterface, there is no ANSI logic here.TtyBasedArrayDataStreamreads from thatTtyConnectorin 1024-character chunks, buffering the raw stream.TerminalStarter.start()spawns a dedicated background thread that runswhile (myEmulator.hasNext()) myEmulator.next();.myEmulatoris aJediEmulator, the actual ANSI/VT100/xterm parser: it reads from theTerminalDataStreamand tells escape sequences (SGR colors, cursor movement, line/screen clearing, scrolling, etc.) apart from plain printable characters.- Parsed commands are dispatched to the
Terminalinterface, implemented byJediTerminal, which routes each one to whichever of its two sinks it belongs to. Printed characters go toTerminalTextBuffer, a plain model of lines with no JavaFX dependency, together with their style, both the foreground/background color and text attributes such as bold, italic, underline or blink. Everything about the terminal as an interactive device, cursor position/shape/visibility, window title, the current selection, mouse tracking mode, the alternate screen buffer toggle and so on, goes toTerminalDisplayinstead. TerminalPanel, the JavaFX UI, implementsTerminalDisplayitself and separately paints whatever is inTerminalTextBuffer. It never sees raw ANSI, by the time state reaches it, it is already resolved into styled glyphs and plain terminal-device state.
Writing. User input flows the same way, but in reverse:
TerminalPanel (key press) -> TerminalKeyEncoder -> TtyConnector.write()
-> PTY master -> PTY slave -> child process's stdin
TerminalKeyEncoder translates a JavaFX key event into the escape sequence the child process expects, and writes
it through the same TtyConnector.
Because ANSI parsing happens once, before the text ever reaches TerminalTextBuffer, any code that reads from the
buffer (rendering, selection, search, etc.) works with plain styled text and never has to deal with escape
sequences itself.
To build the library use standard Git and Maven commands:
git clone https://github.com/techsenger/jeditermfx
cd jeditermfx
mvn clean install
The project contains a demo application that shows how to use this library. There are two ways to run the application.
To run application using maven plugin execute the following commands in the root of the project:
cd jeditermfx-app
mvn javafx:run
Please note, that debugger settings are in jeditermfx-app/pom.xml file. If you want to try a dark theme,
uncomment the following line in the JavaFX plugin configuration in the pom.xml file:
<!--<commandlineArgs>theme=dark</commandlineArgs>-->
This will make JediTermFX use the DarkThemeSettingsProvider.
After building the project, you will find a distribution archive named jeditermfx-app-<version>.tar in the
jeditermfx-app/target directory. Extracting this file will allow you to launch the application
using .sh or .bat scripts depending on your operating system.
JediTermFX is dual-licensed under both the LGPLv3 (found in the LICENSE-LGPL-3.txt file in the root directory) and Apache 2.0 License (found in the LICENSE-APACHE-2.0.txt file in the root directory). You may select, at your option, one of the above-listed licenses.
We welcome all contributions. You can help by reporting bugs, suggesting improvements, or submitting pull requests with fixes and new features. If you have any questions, feel free to reach out — we’ll be happy to assist you.
You can support our open-source work through GitHub Sponsors. Your contribution helps us maintain projects, develop new features, and provide ongoing improvements. Multiple sponsorship tiers are available, each offering different levels of recognition and benefits.




