expose render state
This commit is contained in:
20
src/main/java/dev/jlibghostty/RenderCell.java
Normal file
20
src/main/java/dev/jlibghostty/RenderCell.java
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
package dev.jlibghostty;
|
||||||
|
|
||||||
|
public record RenderCell(int column, int[] codepoints, boolean selected) {
|
||||||
|
public RenderCell {
|
||||||
|
codepoints = codepoints.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int[] codepoints() {
|
||||||
|
return codepoints.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String text() {
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
for (int codepoint : codepoints) {
|
||||||
|
builder.appendCodePoint(codepoint);
|
||||||
|
}
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
17
src/main/java/dev/jlibghostty/RenderRow.java
Normal file
17
src/main/java/dev/jlibghostty/RenderRow.java
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package dev.jlibghostty;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public record RenderRow(int row, boolean dirty, List<RenderCell> cells) {
|
||||||
|
public RenderRow {
|
||||||
|
cells = List.copyOf(cells);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String text() {
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
for (RenderCell cell : cells) {
|
||||||
|
builder.append(cell.text());
|
||||||
|
}
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
52
src/main/java/dev/jlibghostty/RenderState.java
Normal file
52
src/main/java/dev/jlibghostty/RenderState.java
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
package dev.jlibghostty;
|
||||||
|
|
||||||
|
import dev.jlibghostty.internal.GhosttyLibrary;
|
||||||
|
|
||||||
|
import java.lang.foreign.MemorySegment;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
public final class RenderState implements AutoCloseable {
|
||||||
|
private final GhosttyLibrary library;
|
||||||
|
private final MemorySegment handle;
|
||||||
|
private final AtomicBoolean closed = new AtomicBoolean();
|
||||||
|
|
||||||
|
public RenderState() {
|
||||||
|
this.library = GhosttyLibrary.loadDefault();
|
||||||
|
this.handle = library.renderStateNew();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(Terminal terminal) {
|
||||||
|
ensureOpen();
|
||||||
|
terminal.ensureOpenForPackage();
|
||||||
|
library.renderStateUpdate(handle, terminal.handleForPackage());
|
||||||
|
}
|
||||||
|
|
||||||
|
public RenderStateSnapshot snapshot() {
|
||||||
|
ensureOpen();
|
||||||
|
return new RenderStateSnapshot(
|
||||||
|
library.renderStateGetU16(handle, GhosttyLibrary.RENDER_STATE_DATA_COLS),
|
||||||
|
library.renderStateGetU16(handle, GhosttyLibrary.RENDER_STATE_DATA_ROWS),
|
||||||
|
library.renderStateGetI32(handle, GhosttyLibrary.RENDER_STATE_DATA_DIRTY),
|
||||||
|
rows()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<RenderRow> rows() {
|
||||||
|
ensureOpen();
|
||||||
|
return library.renderStateRows(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
if (closed.compareAndSet(false, true)) {
|
||||||
|
library.renderStateFree(handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ensureOpen() {
|
||||||
|
if (closed.get()) {
|
||||||
|
throw new IllegalStateException("RenderState is closed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
9
src/main/java/dev/jlibghostty/RenderStateSnapshot.java
Normal file
9
src/main/java/dev/jlibghostty/RenderStateSnapshot.java
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
package dev.jlibghostty;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public record RenderStateSnapshot(int columns, int rows, int dirty, List<RenderRow> renderRows) {
|
||||||
|
public RenderStateSnapshot {
|
||||||
|
renderRows = List.copyOf(renderRows);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -48,6 +48,14 @@ public final class Terminal implements AutoCloseable {
|
|||||||
return library.formatTerminal(handle, format.nativeValue());
|
return library.formatTerminal(handle, format.nativeValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RenderStateSnapshot renderSnapshot() {
|
||||||
|
ensureOpen();
|
||||||
|
try (RenderState renderState = new RenderState()) {
|
||||||
|
renderState.update(this);
|
||||||
|
return renderState.snapshot();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void reset() {
|
public void reset() {
|
||||||
ensureOpen();
|
ensureOpen();
|
||||||
library.terminalReset(handle);
|
library.terminalReset(handle);
|
||||||
@@ -115,4 +123,12 @@ public final class Terminal implements AutoCloseable {
|
|||||||
throw new IllegalStateException("Terminal is closed");
|
throw new IllegalStateException("Terminal is closed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ensureOpenForPackage() {
|
||||||
|
ensureOpen();
|
||||||
|
}
|
||||||
|
|
||||||
|
MemorySegment handleForPackage() {
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package dev.jlibghostty.internal;
|
|||||||
import dev.jlibghostty.GhosttyBuildInfo;
|
import dev.jlibghostty.GhosttyBuildInfo;
|
||||||
import dev.jlibghostty.GhosttyException;
|
import dev.jlibghostty.GhosttyException;
|
||||||
import dev.jlibghostty.OptimizeMode;
|
import dev.jlibghostty.OptimizeMode;
|
||||||
|
import dev.jlibghostty.RenderCell;
|
||||||
|
import dev.jlibghostty.RenderRow;
|
||||||
import dev.jlibghostty.SizeReportSize;
|
import dev.jlibghostty.SizeReportSize;
|
||||||
import dev.jlibghostty.TerminalOptions;
|
import dev.jlibghostty.TerminalOptions;
|
||||||
|
|
||||||
@@ -18,6 +20,8 @@ import java.lang.foreign.ValueLayout;
|
|||||||
import java.lang.invoke.MethodHandle;
|
import java.lang.invoke.MethodHandle;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import static java.lang.foreign.ValueLayout.JAVA_BYTE;
|
import static java.lang.foreign.ValueLayout.JAVA_BYTE;
|
||||||
|
|
||||||
@@ -60,6 +64,18 @@ public final class GhosttyLibrary {
|
|||||||
public static final int KITTY_IMAGE_DATA_DATA_PTR = 7;
|
public static final int KITTY_IMAGE_DATA_DATA_PTR = 7;
|
||||||
public static final int KITTY_IMAGE_DATA_DATA_LEN = 8;
|
public static final int KITTY_IMAGE_DATA_DATA_LEN = 8;
|
||||||
|
|
||||||
|
public static final int RENDER_STATE_DATA_COLS = 1;
|
||||||
|
public static final int RENDER_STATE_DATA_ROWS = 2;
|
||||||
|
public static final int RENDER_STATE_DATA_DIRTY = 3;
|
||||||
|
public static final int RENDER_STATE_DATA_ROW_ITERATOR = 4;
|
||||||
|
|
||||||
|
public static final int RENDER_STATE_ROW_DATA_DIRTY = 1;
|
||||||
|
public static final int RENDER_STATE_ROW_DATA_CELLS = 3;
|
||||||
|
|
||||||
|
public static final int RENDER_STATE_ROW_CELLS_DATA_GRAPHEMES_LEN = 3;
|
||||||
|
public static final int RENDER_STATE_ROW_CELLS_DATA_GRAPHEMES_BUF = 4;
|
||||||
|
public static final int RENDER_STATE_ROW_CELLS_DATA_SELECTED = 7;
|
||||||
|
|
||||||
private static final int GHOSTTY_SUCCESS = 0;
|
private static final int GHOSTTY_SUCCESS = 0;
|
||||||
private static final int GHOSTTY_OUT_OF_SPACE = -3;
|
private static final int GHOSTTY_OUT_OF_SPACE = -3;
|
||||||
private static final int GHOSTTY_NO_VALUE = -4;
|
private static final int GHOSTTY_NO_VALUE = -4;
|
||||||
@@ -169,6 +185,18 @@ public final class GhosttyLibrary {
|
|||||||
private final MethodHandle formatterTerminalNew;
|
private final MethodHandle formatterTerminalNew;
|
||||||
private final MethodHandle formatterFormatBuf;
|
private final MethodHandle formatterFormatBuf;
|
||||||
private final MethodHandle formatterFree;
|
private final MethodHandle formatterFree;
|
||||||
|
private final MethodHandle renderStateNew;
|
||||||
|
private final MethodHandle renderStateFree;
|
||||||
|
private final MethodHandle renderStateUpdate;
|
||||||
|
private final MethodHandle renderStateGet;
|
||||||
|
private final MethodHandle renderStateRowIteratorNew;
|
||||||
|
private final MethodHandle renderStateRowIteratorFree;
|
||||||
|
private final MethodHandle renderStateRowIteratorNext;
|
||||||
|
private final MethodHandle renderStateRowGet;
|
||||||
|
private final MethodHandle renderStateRowCellsNew;
|
||||||
|
private final MethodHandle renderStateRowCellsFree;
|
||||||
|
private final MethodHandle renderStateRowCellsNext;
|
||||||
|
private final MethodHandle renderStateRowCellsGet;
|
||||||
private final MethodHandle kittyGraphicsGet;
|
private final MethodHandle kittyGraphicsGet;
|
||||||
private final MethodHandle kittyGraphicsImage;
|
private final MethodHandle kittyGraphicsImage;
|
||||||
private final MethodHandle kittyGraphicsImageGet;
|
private final MethodHandle kittyGraphicsImageGet;
|
||||||
@@ -217,6 +245,30 @@ public final class GhosttyLibrary {
|
|||||||
FunctionDescriptor.of(C_INT, C_POINTER, C_POINTER, C_SIZE_T, C_POINTER));
|
FunctionDescriptor.of(C_INT, C_POINTER, C_POINTER, C_SIZE_T, C_POINTER));
|
||||||
formatterFree = downcall(symbols, "ghostty_formatter_free",
|
formatterFree = downcall(symbols, "ghostty_formatter_free",
|
||||||
FunctionDescriptor.ofVoid(C_POINTER));
|
FunctionDescriptor.ofVoid(C_POINTER));
|
||||||
|
renderStateNew = downcall(symbols, "ghostty_render_state_new",
|
||||||
|
FunctionDescriptor.of(C_INT, C_POINTER, C_POINTER));
|
||||||
|
renderStateFree = downcall(symbols, "ghostty_render_state_free",
|
||||||
|
FunctionDescriptor.ofVoid(C_POINTER));
|
||||||
|
renderStateUpdate = downcall(symbols, "ghostty_render_state_update",
|
||||||
|
FunctionDescriptor.of(C_INT, C_POINTER, C_POINTER));
|
||||||
|
renderStateGet = downcall(symbols, "ghostty_render_state_get",
|
||||||
|
FunctionDescriptor.of(C_INT, C_POINTER, C_INT, C_POINTER));
|
||||||
|
renderStateRowIteratorNew = downcall(symbols, "ghostty_render_state_row_iterator_new",
|
||||||
|
FunctionDescriptor.of(C_INT, C_POINTER, C_POINTER));
|
||||||
|
renderStateRowIteratorFree = downcall(symbols, "ghostty_render_state_row_iterator_free",
|
||||||
|
FunctionDescriptor.ofVoid(C_POINTER));
|
||||||
|
renderStateRowIteratorNext = downcall(symbols, "ghostty_render_state_row_iterator_next",
|
||||||
|
FunctionDescriptor.of(C_BOOL, C_POINTER));
|
||||||
|
renderStateRowGet = downcall(symbols, "ghostty_render_state_row_get",
|
||||||
|
FunctionDescriptor.of(C_INT, C_POINTER, C_INT, C_POINTER));
|
||||||
|
renderStateRowCellsNew = downcall(symbols, "ghostty_render_state_row_cells_new",
|
||||||
|
FunctionDescriptor.of(C_INT, C_POINTER, C_POINTER));
|
||||||
|
renderStateRowCellsFree = downcall(symbols, "ghostty_render_state_row_cells_free",
|
||||||
|
FunctionDescriptor.ofVoid(C_POINTER));
|
||||||
|
renderStateRowCellsNext = downcall(symbols, "ghostty_render_state_row_cells_next",
|
||||||
|
FunctionDescriptor.of(C_BOOL, C_POINTER));
|
||||||
|
renderStateRowCellsGet = downcall(symbols, "ghostty_render_state_row_cells_get",
|
||||||
|
FunctionDescriptor.of(C_INT, C_POINTER, C_INT, 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",
|
||||||
@@ -515,6 +567,238 @@ public final class GhosttyLibrary {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MemorySegment renderStateNew() {
|
||||||
|
try (Arena arena = Arena.ofConfined()) {
|
||||||
|
MemorySegment out = arena.allocate(C_POINTER);
|
||||||
|
int result = (int) renderStateNew.invoke(MemorySegment.NULL, out);
|
||||||
|
checkResult("ghostty_render_state_new", result);
|
||||||
|
|
||||||
|
MemorySegment state = out.get(C_POINTER, 0);
|
||||||
|
if (state.address() == 0) {
|
||||||
|
throw new IllegalStateException("ghostty_render_state_new returned null");
|
||||||
|
}
|
||||||
|
return state;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
return rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void renderStateFree(MemorySegment state) {
|
||||||
|
try {
|
||||||
|
renderStateFree.invoke(state);
|
||||||
|
} catch (Throwable t) {
|
||||||
|
rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void renderStateUpdate(MemorySegment state, MemorySegment terminal) {
|
||||||
|
try {
|
||||||
|
int result = (int) renderStateUpdate.invoke(state, terminal);
|
||||||
|
checkResult("ghostty_render_state_update", result);
|
||||||
|
} catch (Throwable t) {
|
||||||
|
rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int renderStateGetU16(MemorySegment state, int key) {
|
||||||
|
try (Arena arena = Arena.ofConfined()) {
|
||||||
|
MemorySegment out = arena.allocate(C_SHORT);
|
||||||
|
int result = (int) renderStateGet.invoke(state, key, out);
|
||||||
|
checkResult("ghostty_render_state_get", result);
|
||||||
|
return Short.toUnsignedInt(out.get(C_SHORT, 0));
|
||||||
|
} catch (Throwable t) {
|
||||||
|
return rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int renderStateGetI32(MemorySegment state, int key) {
|
||||||
|
try (Arena arena = Arena.ofConfined()) {
|
||||||
|
MemorySegment out = arena.allocate(C_INT);
|
||||||
|
int result = (int) renderStateGet.invoke(state, key, out);
|
||||||
|
checkResult("ghostty_render_state_get", result);
|
||||||
|
return out.get(C_INT, 0);
|
||||||
|
} catch (Throwable t) {
|
||||||
|
return rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<RenderRow> renderStateRows(MemorySegment state) {
|
||||||
|
MemorySegment iterator = renderStateRowIteratorNew();
|
||||||
|
try {
|
||||||
|
renderStatePopulateRowIterator(state, iterator);
|
||||||
|
List<RenderRow> rows = new ArrayList<>();
|
||||||
|
int rowIndex = 0;
|
||||||
|
while (renderStateRowIteratorNext(iterator)) {
|
||||||
|
boolean dirty = renderStateRowGetBoolean(iterator, RENDER_STATE_ROW_DATA_DIRTY);
|
||||||
|
rows.add(new RenderRow(rowIndex, dirty, renderStateRowCells(iterator)));
|
||||||
|
rowIndex++;
|
||||||
|
}
|
||||||
|
return List.copyOf(rows);
|
||||||
|
} finally {
|
||||||
|
renderStateRowIteratorFree(iterator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private MemorySegment renderStateRowIteratorNew() {
|
||||||
|
try (Arena arena = Arena.ofConfined()) {
|
||||||
|
MemorySegment out = arena.allocate(C_POINTER);
|
||||||
|
int result = (int) renderStateRowIteratorNew.invoke(MemorySegment.NULL, out);
|
||||||
|
checkResult("ghostty_render_state_row_iterator_new", result);
|
||||||
|
|
||||||
|
MemorySegment iterator = out.get(C_POINTER, 0);
|
||||||
|
if (iterator.address() == 0) {
|
||||||
|
throw new IllegalStateException("ghostty_render_state_row_iterator_new returned null");
|
||||||
|
}
|
||||||
|
return iterator;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
return rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderStateRowIteratorFree(MemorySegment iterator) {
|
||||||
|
try {
|
||||||
|
renderStateRowIteratorFree.invoke(iterator);
|
||||||
|
} catch (Throwable t) {
|
||||||
|
rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderStatePopulateRowIterator(MemorySegment state, MemorySegment iterator) {
|
||||||
|
try (Arena arena = Arena.ofConfined()) {
|
||||||
|
MemorySegment out = arena.allocate(C_POINTER);
|
||||||
|
out.set(C_POINTER, 0, iterator);
|
||||||
|
int result = (int) renderStateGet.invoke(state, RENDER_STATE_DATA_ROW_ITERATOR, out);
|
||||||
|
checkResult("ghostty_render_state_get", result);
|
||||||
|
} catch (Throwable t) {
|
||||||
|
rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean renderStateRowIteratorNext(MemorySegment iterator) {
|
||||||
|
try {
|
||||||
|
return (boolean) renderStateRowIteratorNext.invoke(iterator);
|
||||||
|
} catch (Throwable t) {
|
||||||
|
return rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean renderStateRowGetBoolean(MemorySegment iterator, int key) {
|
||||||
|
try (Arena arena = Arena.ofConfined()) {
|
||||||
|
MemorySegment out = arena.allocate(C_BOOL);
|
||||||
|
int result = (int) renderStateRowGet.invoke(iterator, key, out);
|
||||||
|
checkResult("ghostty_render_state_row_get", result);
|
||||||
|
return out.get(C_BOOL, 0);
|
||||||
|
} catch (Throwable t) {
|
||||||
|
return rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<RenderCell> renderStateRowCells(MemorySegment rowIterator) {
|
||||||
|
MemorySegment cells = renderStateRowCellsNew();
|
||||||
|
try {
|
||||||
|
renderStatePopulateRowCells(rowIterator, cells);
|
||||||
|
List<RenderCell> result = new ArrayList<>();
|
||||||
|
int column = 0;
|
||||||
|
while (renderStateRowCellsNext(cells)) {
|
||||||
|
result.add(new RenderCell(
|
||||||
|
column,
|
||||||
|
renderStateRowCellGraphemes(cells),
|
||||||
|
renderStateRowCellsGetBoolean(cells, RENDER_STATE_ROW_CELLS_DATA_SELECTED)
|
||||||
|
));
|
||||||
|
column++;
|
||||||
|
}
|
||||||
|
return List.copyOf(result);
|
||||||
|
} finally {
|
||||||
|
renderStateRowCellsFree(cells);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private MemorySegment renderStateRowCellsNew() {
|
||||||
|
try (Arena arena = Arena.ofConfined()) {
|
||||||
|
MemorySegment out = arena.allocate(C_POINTER);
|
||||||
|
int result = (int) renderStateRowCellsNew.invoke(MemorySegment.NULL, out);
|
||||||
|
checkResult("ghostty_render_state_row_cells_new", result);
|
||||||
|
|
||||||
|
MemorySegment cells = out.get(C_POINTER, 0);
|
||||||
|
if (cells.address() == 0) {
|
||||||
|
throw new IllegalStateException("ghostty_render_state_row_cells_new returned null");
|
||||||
|
}
|
||||||
|
return cells;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
return rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderStateRowCellsFree(MemorySegment cells) {
|
||||||
|
try {
|
||||||
|
renderStateRowCellsFree.invoke(cells);
|
||||||
|
} catch (Throwable t) {
|
||||||
|
rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderStatePopulateRowCells(MemorySegment rowIterator, MemorySegment cells) {
|
||||||
|
try (Arena arena = Arena.ofConfined()) {
|
||||||
|
MemorySegment out = arena.allocate(C_POINTER);
|
||||||
|
out.set(C_POINTER, 0, cells);
|
||||||
|
int result = (int) renderStateRowGet.invoke(rowIterator, RENDER_STATE_ROW_DATA_CELLS, out);
|
||||||
|
checkResult("ghostty_render_state_row_get", result);
|
||||||
|
} catch (Throwable t) {
|
||||||
|
rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean renderStateRowCellsNext(MemorySegment cells) {
|
||||||
|
try {
|
||||||
|
return (boolean) renderStateRowCellsNext.invoke(cells);
|
||||||
|
} catch (Throwable t) {
|
||||||
|
return rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int[] renderStateRowCellGraphemes(MemorySegment cells) {
|
||||||
|
int len = renderStateRowCellsGetI32(cells, RENDER_STATE_ROW_CELLS_DATA_GRAPHEMES_LEN);
|
||||||
|
if (len <= 0) {
|
||||||
|
return new int[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
try (Arena arena = Arena.ofConfined()) {
|
||||||
|
MemorySegment out = arena.allocate(C_INT, len);
|
||||||
|
int result = (int) renderStateRowCellsGet.invoke(cells, RENDER_STATE_ROW_CELLS_DATA_GRAPHEMES_BUF, out);
|
||||||
|
checkResult("ghostty_render_state_row_cells_get", result);
|
||||||
|
|
||||||
|
int[] codepoints = new int[len];
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
codepoints[i] = out.getAtIndex(C_INT, i);
|
||||||
|
}
|
||||||
|
return codepoints;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
return rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int renderStateRowCellsGetI32(MemorySegment cells, int key) {
|
||||||
|
try (Arena arena = Arena.ofConfined()) {
|
||||||
|
MemorySegment out = arena.allocate(C_INT);
|
||||||
|
int result = (int) renderStateRowCellsGet.invoke(cells, key, out);
|
||||||
|
checkResult("ghostty_render_state_row_cells_get", result);
|
||||||
|
return out.get(C_INT, 0);
|
||||||
|
} catch (Throwable t) {
|
||||||
|
return rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean renderStateRowCellsGetBoolean(MemorySegment cells, int key) {
|
||||||
|
try (Arena arena = Arena.ofConfined()) {
|
||||||
|
MemorySegment out = arena.allocate(C_BOOL);
|
||||||
|
int result = (int) renderStateRowCellsGet.invoke(cells, key, out);
|
||||||
|
checkResult("ghostty_render_state_row_cells_get", result);
|
||||||
|
return out.get(C_BOOL, 0);
|
||||||
|
} catch (Throwable t) {
|
||||||
|
return rethrow(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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);
|
||||||
|
|||||||
@@ -37,6 +37,12 @@ public final class GhosttySmokeTest {
|
|||||||
if (!terminal.text().contains("hello")) {
|
if (!terminal.text().contains("hello")) {
|
||||||
throw new AssertionError("formatted terminal text should contain written text: " + terminal.text());
|
throw new AssertionError("formatted terminal text should contain written text: " + terminal.text());
|
||||||
}
|
}
|
||||||
|
RenderStateSnapshot renderSnapshot = terminal.renderSnapshot();
|
||||||
|
boolean renderedHello = renderSnapshot.renderRows().stream()
|
||||||
|
.anyMatch(row -> row.text().contains("hello"));
|
||||||
|
if (!renderedHello) {
|
||||||
|
throw new AssertionError("render state should contain written 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