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: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ jobs:
runs-on: windows-latest
timeout-minutes: 30
env:
PACKAGE_VERSION: 1.0.0
PACKAGE_VERSION: 1.0.1
steps:
- uses: actions/checkout@v4
with:
Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Changelog

## 1.0.1 - 2026-09-18

- Fix shutdown cleanup so Notepad++ can exit normally with CSV Visual Editor loaded.
- Add a production-host regression check for clean Notepad++ shutdown.

## 1.0.0 - 2026-09-18

- First stable Windows x64 release.
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ A 64-bit Notepad++ plugin for viewing, editing, filtering and inspecting CSV dat

## Version

The first stable release is **1.0.0** for 64-bit Notepad++ on Windows. The
production release gate is tested with Notepad++ 8.9.8 x64.
The current stable maintenance line is **1.0.1** for 64-bit Notepad++ on Windows.
The production release gate is tested with Notepad++ 8.9.8 x64.

## Installation

Expand Down
4 changes: 2 additions & 2 deletions docs/building.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@ All commands above must succeed before publishing a build. The seven maintained

## Stable release and Plugins Admin

The stable product version is `1.0.0`. Project code is GPL-3.0-only; do not
The current stable maintenance version is `1.0.1`. Project code is GPL-3.0-only; do not
remove `LICENSE` or `THIRD_PARTY_NOTICES.txt` from a distributed package.

The complete Windows release gate is:

```powershell
pwsh -NoProfile -File tools/build-local.ps1 -PackageVersion 1.0.0
pwsh -NoProfile -File tools/build-local.ps1 -PackageVersion 1.0.1
```

It runs release-policy tests in addition to localization, Core, Native AOT and
Expand Down
6 changes: 3 additions & 3 deletions packaging/nppPluginList/entry.template.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"folder-name": "CsvVisualEditor",
"display-name": "CSV Visual Editor",
"version": "1.0.0",
"version": "1.0.1",
"npp-compatible-versions": "[8.9.8,]",
"id": "<SHA256_OF_CsvVisualEditor-1.0.0-win-x64.zip>",
"repository": "https://github.com/zzsolt/notepadplusplus-csv-visual-editor/releases/download/v1.0.0/CsvVisualEditor-1.0.0-win-x64.zip",
"id": "<SHA256_OF_CsvVisualEditor-1.0.1-win-x64.zip>",
"repository": "https://github.com/zzsolt/notepadplusplus-csv-visual-editor/releases/download/v1.0.1/CsvVisualEditor-1.0.0-win-x64.zip",
"description": "View, edit, filter and inspect CSV data in a docked table with conflict-checked Apply and Notepad++ undo.",
"author": "Zolnai Zsolt",
"homepage": "https://github.com/zzsolt/notepadplusplus-csv-visual-editor"
Expand Down
6 changes: 3 additions & 3 deletions packaging/nppPluginList/entry.x64.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"folder-name": "CsvVisualEditor",
"display-name": "CSV Visual Editor",
"version": "1.0.0",
"version": "1.0.1",
"npp-compatible-versions": "[8.9.8,]",
"id": "e513b9316806662dd358853c7f0a718ba78c50ca5b2992d3db23c4c0d77bd351",
"repository": "https://github.com/zzsolt/notepadplusplus-csv-visual-editor/releases/download/v1.0.0/CsvVisualEditor-1.0.0-win-x64.zip",
"id": "2405357696cca26f6887701ab6d4e58c7c8671a201796c7a454048b521b29978",
"repository": "https://github.com/zzsolt/notepadplusplus-csv-visual-editor/releases/download/v1.0.1/CsvVisualEditor-1.0.1-win-x64.zip",
"description": "View, edit, filter and inspect CSV data in a docked table with conflict-checked Apply and Notepad++ undo.",
"author": "Zolnai Zsolt",
"homepage": "https://github.com/zzsolt/notepadplusplus-csv-visual-editor"
Expand Down
19 changes: 19 additions & 0 deletions packaging/release-manifest-1.0.1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"version": "1.0.1",
"zip": "CsvVisualEditor-1.0.1-win-x64.zip",
"zipSha256": "2405357696cca26f6887701ab6d4e58c7c8671a201796c7a454048b521b29978",
"dll": "CsvVisualEditor.dll",
"dllSha256": "f1340be31577ea443199de43844b6170bcd72e05d34229a93f546d973fd542b8",
"pluginAdminList": "src/pl.x64.json",
"pluginAdminEntry": {
"folder-name": "CsvVisualEditor",
"display-name": "CSV Visual Editor",
"version": "1.0.1",
"npp-compatible-versions": "[8.9.8,]",
"id": "2405357696cca26f6887701ab6d4e58c7c8671a201796c7a454048b521b29978",
"repository": "https://github.com/zzsolt/notepadplusplus-csv-visual-editor/releases/download/v1.0.1/CsvVisualEditor-1.0.1-win-x64.zip",
"description": "View, edit, filter and inspect CSV data in a docked table with conflict-checked Apply and Notepad++ undo.",
"author": "Zolnai Zsolt",
"homepage": "https://github.com/zzsolt/notepadplusplus-csv-visual-editor"
}
}
13 changes: 13 additions & 0 deletions packaging/release-notes-1.0.1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# CSV Visual Editor 1.0.1

Maintenance release fixing clean Notepad++ shutdown with CSV Visual Editor loaded.

- Fix plugin shutdown cleanup so Plugins Admin restart-based operations can proceed.
- Add production-host regression coverage for normal Notepad++ exit.
- Preserve the 1.0 feature set, package layout and Notepad++ 8.9.8 compatibility floor.

Validated release package:

- `CsvVisualEditor-1.0.1-win-x64.zip`
- ZIP SHA-256: `2405357696cca26f6887701ab6d4e58c7c8671a201796c7a454048b521b29978`
- DLL SHA-256: `f1340be31577ea443199de43844b6170bcd72e05d34229a93f546d973fd542b8`
2 changes: 1 addition & 1 deletion src/CsvVisualEditor/CsvVisualEditor.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<IsPackable>false</IsPackable>
<AssemblyName>CsvVisualEditor</AssemblyName>
<RootNamespace>CsvVisualEditor</RootNamespace>
<Version>1.0.0</Version>
<Version>1.0.1</Version>
<Authors>Zolnai Zsolt</Authors>
<Copyright>Copyright © 2026 Zolnai Zsolt</Copyright>
<Description>A 64-bit Notepad++ plugin for viewing, editing, filtering and inspecting CSV data in a docked table.</Description>
Expand Down
9 changes: 4 additions & 5 deletions src/CsvVisualEditor/Main.cs
Original file line number Diff line number Diff line change
Expand Up @@ -452,11 +452,10 @@ private void PluginCleanUp()

PluginData.FuncItems.Dispose();

if (PluginData.PluginNamePtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(PluginData.PluginNamePtr);
PluginData.PluginNamePtr = IntPtr.Zero;
}
// PluginNamePtr's setter owns the allocation and frees the previous pointer.
// Assigning zero is sufficient; freeing it manually first would double-free
// the unmanaged string during Notepad++ shutdown.
PluginData.PluginNamePtr = IntPtr.Zero;
}
}

8 changes: 6 additions & 2 deletions tests/host-review/Invoke-HostReview.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -232,8 +232,12 @@ try {
$aboutText=@([CsvHostWindows]::Children($about) | ForEach-Object { [CsvHostWindows]::ControlText($_) }) -join "`n"
if(!$aboutText.Contains('Zolnai Zsolt') -or !$aboutText.Contains('zzsolt@gmail.com') -or !$aboutText.Contains($env:PACKAGE_VERSION)) {throw 'Production About content or package version mismatch'}
Send-Native $about 0x10 ([IntPtr]::Zero) ([IntPtr]::Zero) | Out-Null
[ordered]@{ NotepadVersion=(Get-Item $exe).VersionInfo.ProductVersion; Windows=[Environment]::OSVersion.VersionString; Dpi=[CsvHostWindows]::GetDpiForWindow($form); DllSha256=(Get-FileHash $library -Algorithm SHA256).Hash; ProductionDllLoaded=$true; SearchCountObserved=$true; SearchClearObserved=$true; AboutObserved=$true; PackageVersion=$env:PACKAGE_VERSION; DockWidths=$resizes; DataFilterPreviewObserved=$true; DataFilterApplied=$true; DataSummaryObserved=$true; DataCancelPreserved=$true; DataResetObserved=$true; SourceBufferUnchanged=$true; Scope='Automated production-host load/search/resize/About and data filter/preview/apply/cancel/reset/summary, exact source buffer preservation. Not manual acceptance or editing Apply/Undo coverage.' } | ConvertTo-Json | Set-Content (Join-Path $output 'host-evidence.json')
Write-Host 'Real Notepad++ production-DLL load/render/search review completed.'
$evidence = [ordered]@{ NotepadVersion=(Get-Item $exe).VersionInfo.ProductVersion; Windows=[Environment]::OSVersion.VersionString; Dpi=[CsvHostWindows]::GetDpiForWindow($form); DllSha256=(Get-FileHash $library -Algorithm SHA256).Hash; ProductionDllLoaded=$true; SearchCountObserved=$true; SearchClearObserved=$true; AboutObserved=$true; PackageVersion=$env:PACKAGE_VERSION; DockWidths=$resizes; DataFilterPreviewObserved=$true; DataFilterApplied=$true; DataSummaryObserved=$true; DataCancelPreserved=$true; DataResetObserved=$true; SourceBufferUnchanged=$true; CleanShutdownObserved=$false; Scope='Automated production-host load/search/resize/About and data filter/preview/apply/cancel/reset/summary, exact source buffer preservation, and normal Notepad++ shutdown with the production plugin loaded. Not manual acceptance or editing Apply/Undo coverage.' }
[CsvHostWindows]::PostMessage($window,0x10,[IntPtr]::Zero,[IntPtr]::Zero) | Out-Null
if (!$process.WaitForExit(10000)) { throw 'Notepad++ did not exit cleanly with the production plugin loaded' }
$evidence.CleanShutdownObserved = $true
$evidence | ConvertTo-Json | Set-Content (Join-Path $output 'host-evidence.json')
Write-Host 'Real Notepad++ production-DLL load/render/search/shutdown review completed.'
} finally {
if($process -and !$process.HasExited) { $process.Kill(); $process.WaitForExit() }
Remove-Item -LiteralPath $homeDir -Recurse -Force
Expand Down
22 changes: 15 additions & 7 deletions tests/release/test_release_package.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@

class ReleasePackageTests(unittest.TestCase):
def test_entry_matches_plugins_admin_contract(self):
entry = release.plugin_admin_entry("1.0.0", "a" * 64)
entry = release.plugin_admin_entry("1.0.1", "a" * 64)
self.assertEqual("CsvVisualEditor", entry["folder-name"])
self.assertEqual("CSV Visual Editor", entry["display-name"])
self.assertEqual("1.0.0", entry["version"])
self.assertEqual("1.0.1", entry["version"])
self.assertEqual("[8.9.8,]", entry["npp-compatible-versions"])
self.assertEqual("a" * 64, entry["id"])
self.assertTrue(entry["repository"].endswith(
"/releases/download/v1.0.0/CsvVisualEditor-1.0.0-win-x64.zip"
"/releases/download/v1.0.1/CsvVisualEditor-1.0.1-win-x64.zip"
))
self.assertEqual("Zolnai Zsolt", entry["author"])

Expand All @@ -36,7 +36,7 @@ def test_archive_requires_root_dll_and_notices(self):
archive.writestr("CsvVisualEditor.dll", dll.read_bytes())
archive.writestr("LICENSE.txt", "GPL")
archive.writestr("THIRD_PARTY_NOTICES.txt", "third-party")
zip_hash, dll_hash = release.verify_archive(package, dll, "1.0.0")
zip_hash, dll_hash = release.verify_archive(package, dll, "1.0.1")
self.assertEqual(64, len(zip_hash))
self.assertEqual(release.sha256_bytes(dll.read_bytes()), dll_hash)

Expand All @@ -49,14 +49,14 @@ def test_nested_dll_is_rejected(self):
archive.writestr("LICENSE.txt", "GPL")
archive.writestr("THIRD_PARTY_NOTICES.txt", "third-party")
with self.assertRaises(ValueError):
release.verify_archive(package, None, "1.0.0")
release.verify_archive(package, None, "1.0.1")

def test_repository_declares_stable_gpl_release(self):
project = (ROOT / "src/CsvVisualEditor/CsvVisualEditor.csproj").read_text(encoding="utf-8")
self.assertIn("<Version>1.0.0</Version>", project)
self.assertIn("<Version>1.0.1</Version>", project)
self.assertIn("<PackageLicenseExpression>GPL-3.0-only</PackageLicenseExpression>", project)
workflow = (ROOT / ".github/workflows/ci.yml").read_text(encoding="utf-8")
self.assertIn("PACKAGE_VERSION: 1.0.0", workflow)
self.assertIn("PACKAGE_VERSION: 1.0.1", workflow)
build = (ROOT / "tools/build-local.ps1").read_text(encoding="utf-8")
self.assertIn("Join-Path $layout 'CsvVisualEditor.dll'", build)
self.assertIn("LICENSE.txt", build)
Expand All @@ -68,6 +68,14 @@ def test_repository_declares_stable_gpl_release(self):
self.assertIn("Npp.DotNet.Plugin 1.0.0-alpha.10", notices)
self.assertIn(".NET Runtime / Native AOT 10.0.12", notices)

def test_shutdown_does_not_double_free_plugin_name(self):
main = (ROOT / "src/CsvVisualEditor/Main.cs").read_text(encoding="utf-8")
self.assertIn("PluginData.PluginNamePtr = IntPtr.Zero;", main)
self.assertNotIn("Marshal.FreeHGlobal(PluginData.PluginNamePtr)", main)
host_review = (ROOT / "tests/host-review/Invoke-HostReview.ps1").read_text(encoding="utf-8")
self.assertIn("WaitForExit(10000)", host_review)
self.assertIn("CleanShutdownObserved=$false", host_review)

def test_template_has_required_plugins_admin_fields(self):
data = json.loads((ROOT / "packaging/nppPluginList/entry.template.json").read_text(encoding="utf-8"))
for key in ("folder-name", "display-name", "version", "npp-compatible-versions",
Expand Down
2 changes: 1 addition & 1 deletion tools/build-local.ps1
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
param(
[string] $PackageVersion = ("1.0.0-local." + [DateTime]::UtcNow.ToString('yyyyMMddHHmmss'))
[string] $PackageVersion = ("1.0.1-local." + [DateTime]::UtcNow.ToString('yyyyMMddHHmmss'))
)

$ErrorActionPreference = 'Stop'
Expand Down