10 Commits

Author SHA1 Message Date
897a76d8cf cleanup repo 2026-06-01 00:26:01 +02:00
5799c800d3 untrack 2026-06-01 00:25:16 +02:00
cc9ac43ffa remove obsolete full-row-repaint debug toggle; document diagnostics
The fullRowRepaint toggle existed only to bisect the black-bar repaint artifact,
which is now fixed, so drop it. Document the two remaining render-debug flags
(profile, debugRepaint) in the README.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 22:31:50 +02:00
93d53fcef6 send backtab (ESC [ Z) for Shift+Tab
KeyEncoder mapped TAB to a plain tab regardless of Shift, so Shift+Tab sent the
same byte as Tab. Apps that use backtab for reverse navigation (fish completion
menu, helix theme picker) never saw it. Emit CSI Z when Shift is held.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 22:27:54 +02:00
b0ec6c7014 update jlibghostty 2026-05-31 22:20:56 +02:00
3c913fefd3 fix black seam bars: opaque base fill instead of clearRect
The persistent black bars in the partial-repaint path were clearRect leaving
the run's fractional edge pixels transparent, which showed the near-black pane
background as a seam against the adjacent un-repainted line. Confirmed with the
debugRepaint toggle: filling the span opaque removed the bars entirely.

Fill the repaint run with PANE_BACKGROUND (the default cell background) instead
of clearing to transparent; per-cell backgrounds paint over it as before. Safe
because the per-column path never runs while kitty graphics are present (those
force a full render), so no below-text image needs a transparent row canvas.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 22:08:57 +02:00
263bcf36b7 add debugRepaint toggle that fills cleared spans red
Diagnostic for the persistent black bars: fills each repaint run's cleared span
red instead of clearing to transparent. If the bars turn red they are spans
repaintColumns clears but never refills; if they stay black those pixels are
never touched by the per-column repaint and the cause is elsewhere.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 22:02:41 +02:00
8e060b27ca Revert "snap repaint clear/fill to integer pixels to kill seam bars"
This reverts commit 6613f1f746.
2026-05-31 21:58:15 +02:00
6613f1f746 snap repaint clear/fill to integer pixels to kill seam bars
cellWidth is fractional, so in repaintColumns the clearRect cleared a run's
edge pixel to full transparency while the background fillRect covered that same
pixel only partially (antialiased), leaving a ~1px part-transparent column that
showed the near-black pane background as a thin bar 1-2 cells before the cursor.
Full-row repaint hid it because the highlighted line is then one contiguous
fill with no internal junction.

Route the clear and the background fills through a shared columnX() that rounds
each column boundary to a whole device pixel, so run edges land on integer
pixels with full single coverage and adjacent runs tile seamlessly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 21:56:01 +02:00
5728733f5f worktrees ignores 2026-05-31 21:52:39 +02:00
10 changed files with 43 additions and 83 deletions

View File

@@ -1,18 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="bin/main" path="src/main/java">
<attributes>
<attribute name="gradle_scope" value="main"/>
<attribute name="gradle_used_by_scope" value="main,test"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="bin/main" path="src/main/resources">
<attributes>
<attribute name="gradle_scope" value="main"/>
<attribute name="gradle_used_by_scope" value="main,test"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-21/"/>
<classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer"/>
<classpathentry kind="output" path="bin/default"/>
</classpath>

View File

@@ -1 +0,0 @@
019e6999-b7c8-7591-a8aa-ea51b89a7f7e

4
.gitignore vendored
View File

@@ -14,3 +14,7 @@ build
build build
.gradle .gradle
bin bin
.worktrees
.classpath
.project
.settings

View File

@@ -1,34 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>jprototerm</name>
<comment>Project jprototerm created by Buildship.</comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.buildship.core.gradleprojectbuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
</natures>
<filteredResources>
<filter>
<id>1779917652126</id>
<name></name>
<type>30</type>
<matcher>
<id>org.eclipse.core.resources.regexFilterMatcher</id>
<arguments>node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__</arguments>
</matcher>
</filter>
</filteredResources>
</projectDescription>

View File

@@ -1,13 +0,0 @@
arguments=--init-script /home/anon/Src/eclipse.jdt.ls/org.eclipse.jdt.ls.product/target/repository/configuration/org.eclipse.osgi/58/0/.cp/gradle/init/init.gradle
auto.sync=false
build.scans.enabled=false
connection.gradle.distribution=GRADLE_DISTRIBUTION(LOCAL_INSTALLATION(/home/anon/.sdkman/candidates/gradle/current))
connection.project.dir=
eclipse.preferences.version=1
gradle.user.home=
java.home=/nix/store/c3pl7bqrx3d2rc3dh98z6yaj0mv1p52g-openjdk-21.0.10+7/lib/openjdk
jvm.arguments=
offline.mode=false
override.workspace.settings=true
show.console.view=true
show.executions.view=true

View File

@@ -132,3 +132,22 @@ open_scrollback = "ALT+S"
Each tab has its own stack of tiled and floating panes; only the active tab is rendered. A Each tab has its own stack of tiled and floating panes; only the active tab is rendered. A
thin tab bar appears at the top when more than one tab is open. Closing the last tiled pane thin tab bar appears at the top when more than one tab is open. Closing the last tiled pane
while floating panes exist promotes the most recently active floating pane to a tiled pane. while floating panes exist promotes the most recently active floating pane to a tiled pane.
## Diagnostics
Two render-debugging flags are off by default and add no overhead unless enabled. Pass them
as JVM system properties (each also has an environment-variable equivalent). With the
packaged binary the JVM picks them up from `JDK_JAVA_OPTIONS`:
```sh
JDK_JAVA_OPTIONS="-Djprototerm.profile=true" ./result/bin/jprototerm
```
- `-Djprototerm.profile=true` (or `JPROTOTERM_PROFILE=1`): print a `[render-profile]` line to
stderr every N renders with the per-frame cost of each render stage — `snapshot` (terminal
state marshalling), `fingerprint` (change detection), `draw` (canvas painting), and the
`frame-total`. Set `-Djprototerm.profile.frames=<N>` to change the dump interval (default
120).
- `-Djprototerm.debugRepaint=true` (or `JPROTOTERM_DEBUG_REPAINT=1`): paint each per-column
repaint run's cleared span red instead of clearing it. Repainted regions flash red, so you
can see exactly which cells are being redrawn each frame.

View File

@@ -1,2 +0,0 @@
jlibghostty - why downcall metadata not propagated ?
jlibghostty - how need to change flake so consuming flakes dont have to depend on same ghostty flake ?

8
flake.lock generated
View File

@@ -70,11 +70,11 @@
"nixpkgs": "nixpkgs" "nixpkgs": "nixpkgs"
}, },
"locked": { "locked": {
"lastModified": 1780256181, "lastModified": 1780258814,
"narHash": "sha256-/saXdnYMbAMfP7u6USSqtNkBIgqZhU+CPr3F8tUQhHU=", "narHash": "sha256-8rxL7xaZ/loYg3zdt0w5+hfNyHFVknDZN360NzrtCsQ=",
"ref": "refs/heads/main", "ref": "refs/heads/main",
"rev": "db5ee5d20daf8855de3a3b2fa9349eced70946f0", "rev": "6a3d5aa0b0b1f738c958e2a2f0249574c07d9c4d",
"revCount": 21, "revCount": 23,
"type": "git", "type": "git",
"url": "https://gitea.gregorlohaus.com/gregor/jlibghostty.git" "url": "https://gitea.gregorlohaus.com/gregor/jlibghostty.git"
}, },

View File

@@ -26,7 +26,7 @@ final class KeyEncoder {
return switch (code) { return switch (code) {
case ENTER -> "\r"; case ENTER -> "\r";
case BACK_SPACE -> "\u007f"; case BACK_SPACE -> "\u007f";
case TAB -> "\t"; case TAB -> event.isShiftDown() ? "\u001b[Z" : "\t";
case ESCAPE -> "\u001b"; case ESCAPE -> "\u001b";
case UP -> "\u001b[A"; case UP -> "\u001b[A";
case DOWN -> "\u001b[B"; case DOWN -> "\u001b[B";

View File

@@ -44,11 +44,12 @@ final class TerminalPaneNode extends Region {
private static final int DIRTY_PARTIAL = 1; private static final int DIRTY_PARTIAL = 1;
private static final int DIRTY_FULL = 2; private static final int DIRTY_FULL = 2;
// Debug toggle: when set, skip the per-column repaint and always repaint the whole row. // Debug toggle: paint each repaint run's cleared span red instead of clearing it to
// Used to bisect partial-repaint artifacts (stale black bars near the cursor). // transparent. If the black bars turn red, they are spans repaintColumns clears but never
private static final boolean FULL_ROW_REPAINT = // refills; if they stay black, those pixels are never touched by repaintColumns at all.
Boolean.getBoolean("jprototerm.fullRowRepaint") private static final boolean DEBUG_REPAINT =
|| "1".equals(System.getenv("JPROTOTERM_FULL_ROW_REPAINT")); Boolean.getBoolean("jprototerm.debugRepaint")
|| "1".equals(System.getenv("JPROTOTERM_DEBUG_REPAINT"));
private static final Color DEFAULT_FOREGROUND = Color.rgb(225, 229, 235); private static final Color DEFAULT_FOREGROUND = Color.rgb(225, 229, 235);
private static final Color SELECTED_BACKGROUND = Color.rgb(52, 92, 140); private static final Color SELECTED_BACKGROUND = Color.rgb(52, 92, 140);
@@ -740,10 +741,6 @@ final class TerminalPaneNode extends Region {
} }
private void renderChanged(RenderRow row) { private void renderChanged(RenderRow row) {
if (FULL_ROW_REPAINT) {
render(row);
return;
}
double oldWidth = canvas.getWidth(); double oldWidth = canvas.getWidth();
double oldHeight = canvas.getHeight(); double oldHeight = canvas.getHeight();
prepareCanvas(row); prepareCanvas(row);
@@ -839,7 +836,15 @@ final class TerminalPaneNode extends Region {
double x = TerminalMetrics.PADDING + startColumn * cellWidth; double x = TerminalMetrics.PADDING + startColumn * cellWidth;
double width = (endColumn - startColumn + 1) * cellWidth; double width = (endColumn - startColumn + 1) * cellWidth;
gc.clearRect(x, 0.0, width, canvas.getHeight()); // Opaque base fill rather than clearRect: a transparent clear leaves the run's
// fractional edge pixels transparent, which show the near-black pane background
// as a thin seam bar against the adjacent (un-repainted) line. Filling opaque
// removes every transparent pixel; per-cell backgrounds then paint on top, and
// default-background cells correctly show PANE_BACKGROUND. Safe because the
// per-column path never runs while kitty graphics (which need a transparent row
// canvas for below-text images) are present.
gc.setFill(DEBUG_REPAINT ? Color.RED : PANE_BACKGROUND);
gc.fillRect(x, 0.0, width, canvas.getHeight());
if (startColumn == 0) { if (startColumn == 0) {
gc.setFill(rowEdgeBackground(row, true)); gc.setFill(rowEdgeBackground(row, true));
gc.fillRect(0.0, 0.0, TerminalMetrics.PADDING, canvas.getHeight()); gc.fillRect(0.0, 0.0, TerminalMetrics.PADDING, canvas.getHeight());