Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
- Fixed a Warning dialog appearing on NetBeans exit when a diff tab had been opened during the session

# 1.2.8 (2026-05-24)

- Added "Auto Mode" to the edit-mode selector (Claude Code 2.1.83+): file edits in auto mode are auto-approved; when auto mode is selected on an older Claude Code version, the plugin falls back to Bypass Permissions or Accept on Edit
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>io.github.nbplugins</groupId>
<artifactId>netbeans-plugin-claude-code-gui</artifactId>
<version>1.2.12-SNAPSHOT</version>
<version>1.2.14-SNAPSHOT</version>
<packaging>nbm</packaging>
<name>Netbeans Plugin Claude Code GUI</name>
<description>NetBeans plugin that provides a GUI for Claude Code CLI — run claude code sessions directly inside the IDE.</description>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,12 @@ public void restored() {
// Migrate window settings files (must run before window system reads them)
String userDir = System.getProperty("netbeans.user");
if (userDir != null) {
V1MigrationHelper.migrateWindowsSettings(
Paths.get(userDir, "config", "Windows2Local", "Components"));
Path componentsDir = Paths.get(userDir, "config", "Windows2Local", "Components");
V1MigrationHelper.migrateWindowsSettings(componentsDir);
// FileDiffOpener$1 was renamed to FileDiffOpener$DiffTopComponent in 1.2.13;
// delete stale .settings files so NetBeans does not warn about the unknown class.
V1MigrationHelper.removeStaleComponentSettings(componentsDir,
"FileDiffOpener$1");
}

// Migrate preferences from old package paths (one-time, after package rename in 1.0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,34 @@ static void migrateWindowsSettings(Path componentsDir) {
}
}

/**
* Deletes stale .settings files in componentsDir that reference class names matching
* any of the given substrings. Use this when a TopComponent class is renamed or removed
* and its serialized binary data can no longer be deserialized.
*/
static void removeStaleComponentSettings(Path componentsDir, String... classNameSubstrings) {
if (!Files.exists(componentsDir)) return;
try (var stream = Files.list(componentsDir)) {
stream.filter(p -> p.toString().endsWith(".settings"))
.forEach(p -> {
try {
String content = Files.readString(p);
for (String substring : classNameSubstrings) {
if (content.contains(substring)) {
Files.delete(p);
LOG.log(Level.FINE, "Removed stale window settings: {0}", p);
break;
}
}
} catch (IOException e) {
LOG.log(Level.WARNING, "Could not process window settings: " + p, e);
}
});
} catch (IOException e) {
LOG.log(Level.WARNING, "Stale settings cleanup failed", e);
}
}

/** Copies keys from oldPath NbPreferences node to newNode, then removes the old node. */
static void migratePrefsNode(String oldPath, Preferences newNode) {
migratePrefsNode(NbPreferences.root(), oldPath, newNode);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -341,17 +341,7 @@ public static void open(
}

// --- TOPLEVEL branch ---
TopComponent diffTC = new TopComponent() {
@Override
public void componentClosed() {
super.componentClosed();
removeAwtListener[0].run();
if (!decided.get()) {
onClose.run();
activateSessionForFile(filePath);
}
}
};
TopComponent diffTC = new DiffTopComponent(removeAwtListener, decided, onClose, filePath);
closeDiffRef[0] = diffTC::close;
diffTC.setDisplayName(tabName);
diffTC.setLayout(new java.awt.BorderLayout());
Expand Down Expand Up @@ -596,6 +586,36 @@ public static void cancelCurrentPromptForFile(String filePath) {
}
}

static final class DiffTopComponent extends TopComponent {
private final Runnable[] removeAwtListener;
private final AtomicBoolean decided;
private final Runnable onClose;
private final String filePath;

DiffTopComponent(Runnable[] removeAwtListener, AtomicBoolean decided,
Runnable onClose, String filePath) {
this.removeAwtListener = removeAwtListener;
this.decided = decided;
this.onClose = onClose;
this.filePath = filePath;
}

@Override
public int getPersistenceType() {
return TopComponent.PERSISTENCE_NEVER;
}

@Override
public void componentClosed() {
super.componentClosed();
removeAwtListener[0].run();
if (!decided.get()) {
onClose.run();
activateSessionForFile(filePath);
}
}
}

private static StreamSource textSource(String name, String filePath, String content) {
return new StreamSource() {
@Override public String getName() { return name; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
import java.awt.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import org.junit.jupiter.api.Test;
import org.openide.windows.TopComponent;

import static org.junit.jupiter.api.Assertions.*;

Expand Down Expand Up @@ -283,4 +285,14 @@ private static long countCheckItems(JPopupMenu menu, String text) {
}
return count;
}

@Test
void diffTopComponentPersistenceTypeIsNever() {
FileDiffOpener.DiffTopComponent tc = new FileDiffOpener.DiffTopComponent(
new Runnable[]{() -> {}},
new AtomicBoolean(false),
() -> {},
"/tmp/test.java");
assertEquals(TopComponent.PERSISTENCE_NEVER, tc.getPersistenceType());
}
}
Loading