expose formatter
This commit is contained in:
@@ -31,6 +31,23 @@ public final class Terminal implements AutoCloseable {
|
|||||||
library.terminalWrite(handle, vtData);
|
library.terminalWrite(handle, vtData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String text() {
|
||||||
|
return format(TerminalFormat.PLAIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String vtText() {
|
||||||
|
return format(TerminalFormat.VT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String html() {
|
||||||
|
return format(TerminalFormat.HTML);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String format(TerminalFormat format) {
|
||||||
|
ensureOpen();
|
||||||
|
return library.formatTerminal(handle, format.nativeValue());
|
||||||
|
}
|
||||||
|
|
||||||
public void reset() {
|
public void reset() {
|
||||||
ensureOpen();
|
ensureOpen();
|
||||||
library.terminalReset(handle);
|
library.terminalReset(handle);
|
||||||
|
|||||||
17
src/main/java/dev/jlibghostty/TerminalFormat.java
Normal file
17
src/main/java/dev/jlibghostty/TerminalFormat.java
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package dev.jlibghostty;
|
||||||
|
|
||||||
|
public enum TerminalFormat {
|
||||||
|
PLAIN(0),
|
||||||
|
VT(1),
|
||||||
|
HTML(2);
|
||||||
|
|
||||||
|
private final int nativeValue;
|
||||||
|
|
||||||
|
TerminalFormat(int nativeValue) {
|
||||||
|
this.nativeValue = nativeValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nativeValue() {
|
||||||
|
return nativeValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -119,6 +119,39 @@ public final class GhosttyLibrary {
|
|||||||
MemoryLayout.paddingLayout(4)
|
MemoryLayout.paddingLayout(4)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
private static final GroupLayout FORMATTER_SCREEN_EXTRA = MemoryLayout.structLayout(
|
||||||
|
C_SIZE_T.withName("size"),
|
||||||
|
C_BOOL.withName("cursor"),
|
||||||
|
C_BOOL.withName("style"),
|
||||||
|
C_BOOL.withName("hyperlink"),
|
||||||
|
C_BOOL.withName("protection"),
|
||||||
|
C_BOOL.withName("kitty_keyboard"),
|
||||||
|
C_BOOL.withName("charsets"),
|
||||||
|
MemoryLayout.paddingLayout(2)
|
||||||
|
);
|
||||||
|
|
||||||
|
private static final GroupLayout FORMATTER_TERMINAL_EXTRA = MemoryLayout.structLayout(
|
||||||
|
C_SIZE_T.withName("size"),
|
||||||
|
C_BOOL.withName("palette"),
|
||||||
|
C_BOOL.withName("modes"),
|
||||||
|
C_BOOL.withName("scrolling_region"),
|
||||||
|
C_BOOL.withName("tabstops"),
|
||||||
|
C_BOOL.withName("pwd"),
|
||||||
|
C_BOOL.withName("keyboard"),
|
||||||
|
MemoryLayout.paddingLayout(2),
|
||||||
|
FORMATTER_SCREEN_EXTRA.withName("screen")
|
||||||
|
);
|
||||||
|
|
||||||
|
private static final GroupLayout FORMATTER_TERMINAL_OPTIONS = MemoryLayout.structLayout(
|
||||||
|
C_SIZE_T.withName("size"),
|
||||||
|
C_INT.withName("emit"),
|
||||||
|
C_BOOL.withName("unwrap"),
|
||||||
|
C_BOOL.withName("trim"),
|
||||||
|
MemoryLayout.paddingLayout(2),
|
||||||
|
FORMATTER_TERMINAL_EXTRA.withName("extra"),
|
||||||
|
C_POINTER.withName("selection")
|
||||||
|
);
|
||||||
|
|
||||||
private final MethodHandle terminalNew;
|
private final MethodHandle terminalNew;
|
||||||
private final MethodHandle terminalFree;
|
private final MethodHandle terminalFree;
|
||||||
private final MethodHandle terminalReset;
|
private final MethodHandle terminalReset;
|
||||||
@@ -133,6 +166,9 @@ public final class GhosttyLibrary {
|
|||||||
private final MethodHandle focusEncode;
|
private final MethodHandle focusEncode;
|
||||||
private final MethodHandle modeReportEncode;
|
private final MethodHandle modeReportEncode;
|
||||||
private final MethodHandle sizeReportEncode;
|
private final MethodHandle sizeReportEncode;
|
||||||
|
private final MethodHandle formatterTerminalNew;
|
||||||
|
private final MethodHandle formatterFormatBuf;
|
||||||
|
private final MethodHandle formatterFree;
|
||||||
private final MethodHandle kittyGraphicsGet;
|
private final MethodHandle kittyGraphicsGet;
|
||||||
private final MethodHandle kittyGraphicsImage;
|
private final MethodHandle kittyGraphicsImage;
|
||||||
private final MethodHandle kittyGraphicsImageGet;
|
private final MethodHandle kittyGraphicsImageGet;
|
||||||
@@ -175,6 +211,12 @@ public final class GhosttyLibrary {
|
|||||||
FunctionDescriptor.of(C_INT, C_INT, C_INT, C_POINTER, C_SIZE_T, C_POINTER));
|
FunctionDescriptor.of(C_INT, C_INT, C_INT, C_POINTER, C_SIZE_T, C_POINTER));
|
||||||
sizeReportEncode = downcall(symbols, "ghostty_size_report_encode",
|
sizeReportEncode = downcall(symbols, "ghostty_size_report_encode",
|
||||||
FunctionDescriptor.of(C_INT, C_INT, SIZE_REPORT_SIZE, C_POINTER, C_SIZE_T, C_POINTER));
|
FunctionDescriptor.of(C_INT, C_INT, SIZE_REPORT_SIZE, C_POINTER, C_SIZE_T, C_POINTER));
|
||||||
|
formatterTerminalNew = downcall(symbols, "ghostty_formatter_terminal_new",
|
||||||
|
FunctionDescriptor.of(C_INT, C_POINTER, C_POINTER, C_POINTER, FORMATTER_TERMINAL_OPTIONS));
|
||||||
|
formatterFormatBuf = downcall(symbols, "ghostty_formatter_format_buf",
|
||||||
|
FunctionDescriptor.of(C_INT, C_POINTER, C_POINTER, C_SIZE_T, C_POINTER));
|
||||||
|
formatterFree = downcall(symbols, "ghostty_formatter_free",
|
||||||
|
FunctionDescriptor.ofVoid(C_POINTER));
|
||||||
kittyGraphicsGet = downcall(symbols, "ghostty_kitty_graphics_get",
|
kittyGraphicsGet = downcall(symbols, "ghostty_kitty_graphics_get",
|
||||||
FunctionDescriptor.of(C_INT, C_POINTER, C_INT, C_POINTER));
|
FunctionDescriptor.of(C_INT, C_POINTER, C_INT, C_POINTER));
|
||||||
kittyGraphicsImage = downcall(symbols, "ghostty_kitty_graphics_image",
|
kittyGraphicsImage = downcall(symbols, "ghostty_kitty_graphics_image",
|
||||||
@@ -461,6 +503,18 @@ public final class GhosttyLibrary {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String formatTerminal(MemorySegment terminal, int format) {
|
||||||
|
MemorySegment formatter = formatterTerminalNew(terminal, format);
|
||||||
|
try {
|
||||||
|
byte[] bytes = encodeBuffer("ghostty_formatter_format_buf", (arena, out, outLen, outWritten) ->
|
||||||
|
(int) formatterFormatBuf.invoke(formatter, out, outLen, outWritten)
|
||||||
|
);
|
||||||
|
return new String(bytes, StandardCharsets.UTF_8);
|
||||||
|
} finally {
|
||||||
|
formatterFree(formatter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void kittyGraphicsPopulatePlacementIterator(MemorySegment graphics, MemorySegment iterator) {
|
public void kittyGraphicsPopulatePlacementIterator(MemorySegment graphics, MemorySegment iterator) {
|
||||||
try (Arena arena = Arena.ofConfined()) {
|
try (Arena arena = Arena.ofConfined()) {
|
||||||
MemorySegment out = arena.allocate(C_POINTER);
|
MemorySegment out = arena.allocate(C_POINTER);
|
||||||
@@ -630,6 +684,48 @@ public final class GhosttyLibrary {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private MemorySegment formatterTerminalNew(MemorySegment terminal, int format) {
|
||||||
|
try (Arena arena = Arena.ofConfined()) {
|
||||||
|
MemorySegment out = arena.allocate(C_POINTER);
|
||||||
|
MemorySegment options = arena.allocate(FORMATTER_TERMINAL_OPTIONS);
|
||||||
|
writeFormatterTerminalOptions(options, format);
|
||||||
|
|
||||||
|
int result = (int) formatterTerminalNew.invoke(MemorySegment.NULL, out, terminal, options);
|
||||||
|
checkResult("ghostty_formatter_terminal_new", result);
|
||||||
|
|
||||||
|
MemorySegment formatter = out.get(C_POINTER, 0);
|
||||||
|
if (formatter.address() == 0) {
|
||||||
|
throw new IllegalStateException("ghostty_formatter_terminal_new returned null");
|
||||||
|
}
|
||||||
|
return formatter;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
return rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void formatterFree(MemorySegment formatter) {
|
||||||
|
try {
|
||||||
|
formatterFree.invoke(formatter);
|
||||||
|
} catch (Throwable t) {
|
||||||
|
rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeFormatterTerminalOptions(MemorySegment options, int format) {
|
||||||
|
options.set(C_SIZE_T, 0, FORMATTER_TERMINAL_OPTIONS.byteSize());
|
||||||
|
options.set(C_INT, 8, format);
|
||||||
|
options.set(C_BOOL, 12, false);
|
||||||
|
options.set(C_BOOL, 13, false);
|
||||||
|
|
||||||
|
long extra = 16;
|
||||||
|
options.set(C_SIZE_T, extra, FORMATTER_TERMINAL_EXTRA.byteSize());
|
||||||
|
|
||||||
|
long screen = extra + 16;
|
||||||
|
options.set(C_SIZE_T, screen, FORMATTER_SCREEN_EXTRA.byteSize());
|
||||||
|
|
||||||
|
options.set(C_POINTER, 48, MemorySegment.NULL);
|
||||||
|
}
|
||||||
|
|
||||||
private boolean buildInfoBoolean(int key) {
|
private boolean buildInfoBoolean(int key) {
|
||||||
try (Arena arena = Arena.ofConfined()) {
|
try (Arena arena = Arena.ofConfined()) {
|
||||||
MemorySegment out = arena.allocate(C_BOOL);
|
MemorySegment out = arena.allocate(C_BOOL);
|
||||||
|
|||||||
@@ -112,6 +112,24 @@
|
|||||||
"void*"
|
"void*"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"returnType": "int",
|
||||||
|
"parameterTypes": [
|
||||||
|
"void*",
|
||||||
|
"void*",
|
||||||
|
"void*",
|
||||||
|
"struct(size_t, int, bool, bool, padding(2), struct(size_t, bool, bool, bool, bool, bool, bool, padding(2), struct(size_t, bool, bool, bool, bool, bool, bool, padding(2))), void*)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"returnType": "int",
|
||||||
|
"parameterTypes": [
|
||||||
|
"void*",
|
||||||
|
"void*",
|
||||||
|
"size_t",
|
||||||
|
"void*"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"returnType": "void*",
|
"returnType": "void*",
|
||||||
"parameterTypes": [
|
"parameterTypes": [
|
||||||
|
|||||||
@@ -34,6 +34,9 @@ public final class GhosttySmokeTest {
|
|||||||
terminal.setKittyImageStorageLimit(1024 * 1024);
|
terminal.setKittyImageStorageLimit(1024 * 1024);
|
||||||
terminal.setKittyImageMediumFile(true);
|
terminal.setKittyImageMediumFile(true);
|
||||||
terminal.write("hello\r\n");
|
terminal.write("hello\r\n");
|
||||||
|
if (!terminal.text().contains("hello")) {
|
||||||
|
throw new AssertionError("formatted terminal text should contain written text: " + terminal.text());
|
||||||
|
}
|
||||||
TerminalSnapshot snapshot = terminal.snapshot();
|
TerminalSnapshot snapshot = terminal.snapshot();
|
||||||
if (snapshot.columns() != 80 || snapshot.rows() != 24) {
|
if (snapshot.columns() != 80 || snapshot.rows() != 24) {
|
||||||
throw new AssertionError("unexpected terminal size: " + snapshot);
|
throw new AssertionError("unexpected terminal size: " + snapshot);
|
||||||
|
|||||||
Reference in New Issue
Block a user