diff --git a/CHANGELOG.md b/CHANGELOG.md
index 998bd682..e80f6088 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,5 @@
+- Fixed diff panel appearing at wrong height (nearly invisible) after Reset Windows or on first use
+- Fixed second diff in the same Claude session being invisible (stale card accumulation)
- Fixed terminal scrolling to the beginning when a choice menu or diff panel appears (regression since 0.20.20)
# 0.21.46 (2026-04-17)
diff --git a/pom.xml b/pom.xml
index c37035e1..8df8b29b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
io.github.nbclaudecodegui
netbeans-claude-code-gui
- 0.22.1-SNAPSHOT
+ 0.22.3-SNAPSHOT
nbm
Netbeans Claude Code GUI
NetBeans plugin that provides a GUI for Claude Code CLI — run claude code sessions directly inside the IDE.
diff --git a/src/main/java/io/github/nbclaudecodegui/ui/ClaudeSessionTab.java b/src/main/java/io/github/nbclaudecodegui/ui/ClaudeSessionTab.java
index 15060dbf..02b3b0a8 100644
--- a/src/main/java/io/github/nbclaudecodegui/ui/ClaudeSessionTab.java
+++ b/src/main/java/io/github/nbclaudecodegui/ui/ClaudeSessionTab.java
@@ -162,9 +162,10 @@ public class ClaudeSessionTab extends TopComponent
private JediTermWidget terminalWidget;
private JSplitPane splitPane;
private JPanel errorPanel;
- private JPanel southCard;
- private CardLayout southCardLayout;
- private String activeCard;
+ JPanel southCard;
+ CardLayout southCardLayout;
+ String activeCard;
+ JPanel currentDiffCard;
private Runnable pendingDiffOnClose;
// -------------------------------------------------------------------------
@@ -741,19 +742,10 @@ private void showChatLayout(JediTermWidget widget) {
public void componentResized(ComponentEvent e) {
int total = splitPane.getHeight();
if (total <= 0) return;
- int bottom;
- if (!savingEnabled[0]) {
- bottom = savedBottomHeight > 0 ? savedBottomHeight
- : southCard.getPreferredSize().height;
- savingEnabled[0] = true;
- } else {
- bottom = NbPreferences.forModule(ClaudeSessionTab.class)
- .getInt(getSavedCardKey(), southCard.getPreferredSize().height);
- }
- int divLoc = total - splitPane.getDividerSize() - bottom;
- LOG.fine(sessionTag + "[splitPane resize] total=" + total
- + " bottom=" + bottom + " divLoc=" + divLoc);
- splitPane.setDividerLocation(divLoc);
+ LOG.fine(sessionTag + "[componentResized] activeCard=" + activeCard
+ + " total=" + total + " savedBottomHeight=" + savedBottomHeight);
+ applyDividerForCard(activeCard, total, savedBottomHeight);
+ savingEnabled[0] = true;
}
});
splitPane.addPropertyChangeListener(JSplitPane.DIVIDER_LOCATION_PROPERTY, e -> {
@@ -893,11 +885,53 @@ private void showStartError(String command, String error,
* @return preference key string
*/
private String getSavedCardKey() {
- if (CARD_PROMPT.equals(activeCard) || activeCard == null) return "bottomHeight";
- return activeCard + "Height";
+ return getSavedCardKeyFor(activeCard);
+ }
+
+ /**
+ * Reads the saved divider height for {@code card}, falls back to sensible defaults,
+ * sets the divider location, and returns the bottom height used.
+ * {@code legacyPromptHeight} is the pre-migration "bottomHeight" value (pass -1 to skip).
+ */
+ private int applyDividerForCard(String card, int total, int legacyPromptHeight) {
+ int saved = NbPreferences.forModule(ClaudeSessionTab.class)
+ .getInt(getSavedCardKeyFor(card), -1);
+ int bottom = computeBottomHeight(card, total, saved, legacyPromptHeight,
+ southCard.getPreferredSize().height);
+ int divLoc = total - splitPane.getDividerSize() - bottom;
+ LOG.fine(sessionTag + "[applyDivider] card=" + card
+ + " total=" + total + " saved=" + saved
+ + " legacy=" + legacyPromptHeight
+ + " preferred=" + southCard.getPreferredSize().height
+ + " bottom=" + bottom + " divLoc=" + divLoc);
+ if (divLoc >= 0) splitPane.setDividerLocation(divLoc);
+ return bottom;
+ }
+
+ /**
+ * Pure function: computes the south-panel height for a given card.
+ * Extracted for unit testing — no Swing state access.
+ *
+ * @param card active card name (CARD_PROMPT or CARD_DIFF)
+ * @param total total splitPane height
+ * @param saved persisted height (negative means not saved)
+ * @param legacyPromptHeight "bottomHeight" pref value for backward-compat (negative to skip)
+ * @param preferredHeight southCard preferred height (fallback)
+ */
+ static int computeBottomHeight(String card, int total, int saved,
+ int legacyPromptHeight, int preferredHeight) {
+ if (saved > 0) return saved;
+ if (CARD_DIFF.equals(card)) return total * 2 / 3;
+ if (CARD_PROMPT.equals(card) && legacyPromptHeight > 0) return legacyPromptHeight;
+ return preferredHeight;
}
- private void switchSouthCard(String card) {
+ String getSavedCardKeyFor(String card) {
+ if (CARD_PROMPT.equals(card) || card == null) return "bottomHeight";
+ return card + "Height";
+ }
+
+ void switchSouthCard(String card) {
if (southCard == null || southCardLayout == null) return;
activeCard = card;
southCardLayout.show(southCard, card);
@@ -912,11 +946,14 @@ private void switchSouthCard(String card) {
if (!CARD_CHOICE.equals(card)) {
// restore divider for this card
int total = splitPane.getHeight();
+ LOG.fine(sessionTag + "[switchSouthCard] card=" + card + " total=" + total);
if (total > 0) {
- int bottom = NbPreferences.forModule(ClaudeSessionTab.class)
- .getInt(getSavedCardKey(), DEFAULT_DIFF_HEIGHT);
- int divLoc = total - splitPane.getDividerSize() - bottom;
- splitPane.setDividerLocation(divLoc);
+ applyDividerForCard(card, total, -1);
+ } else {
+ SwingUtilities.invokeLater(() -> {
+ int t = splitPane != null ? splitPane.getHeight() : 0;
+ if (t > 0) applyDividerForCard(activeCard, t, -1);
+ });
}
} else {
// lock divider for choice menu
@@ -1058,6 +1095,7 @@ private void cleanupChatLayout() {
southCard = null;
southCardLayout = null;
activeCard = null;
+ currentDiffCard = null;
}
if (errorPanel != null) {
remove(errorPanel);
@@ -1124,6 +1162,10 @@ public boolean showEmbeddedDiff(boolean outsideProject, String outsideWarning,
permPanel.showWarning(outsideWarning);
}
+ if (currentDiffCard != null) {
+ southCard.remove(currentDiffCard);
+ currentDiffCard = null;
+ }
JPanel diffCard = new JPanel(new BorderLayout());
if (toolbar != null) {
diffCard.add(toolbar, BorderLayout.NORTH);
@@ -1131,7 +1173,8 @@ public boolean showEmbeddedDiff(boolean outsideProject, String outsideWarning,
diffCard.add(diffComponent, BorderLayout.CENTER);
diffCard.add(permPanel, BorderLayout.SOUTH);
- southCard.add(diffCard, CARD_DIFF);
+ currentDiffCard = diffCard;
+ southCard.add(currentDiffCard, CARD_DIFF);
pendingDiffOnClose = onTabClose;
switchSouthCard(CARD_DIFF);
@@ -1148,6 +1191,10 @@ public void hideEmbeddedDiff() {
pendingDiffOnClose = null;
if (southCard == null) return;
switchSouthCard(CARD_PROMPT);
+ if (currentDiffCard != null) {
+ southCard.remove(currentDiffCard);
+ currentDiffCard = null;
+ }
revalidate();
repaint();
}