diff --git a/.bumpversion.cfg b/.bumpversion.cfg
index 027e002..40343da 100644
--- a/.bumpversion.cfg
+++ b/.bumpversion.cfg
@@ -1,5 +1,5 @@
[bumpversion]
-current_version = 1.2.1
+current_version = 0.0.1
commit = True
message = Bumps version to {new_version}
tag = False
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 25453c7..0d42304 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -1,4 +1,4 @@
-name: Run test jobs
+name: Run salt tests
on:
pull_request:
@@ -7,5 +7,54 @@ concurrency:
cancel-in-progress: true
jobs:
- test:
- uses: plus3it/actions-workflows/.github/workflows/test.yml@ce3cef72cf4ac9605a29350d1d4387dfb86cd7a8
+ windows:
+ uses: plus3it/actions-workflows/.github/workflows/test-salt-windows.yml@00ff10246f901f01818db412fa99124dbed4a00c
+ strategy:
+ matrix:
+ os_version:
+ - windows-2019
+ - windows-2022
+ - windows-2025
+ salt_state:
+ - notepad-plusplus
+ salt_pillar_root:
+ - ./tests/pillar/test-main
+ with:
+ salt-os-version: ${{ matrix.os_version }}
+ salt-state: ${{ matrix.salt_state }}
+ salt-pillar-root: ${{ matrix.salt_pillar_root }}
+
+ lint_powershell:
+ name: PowerShell Linting
+ runs-on: windows-latest
+ steps:
+ - name: Checkout Code
+ uses: actions/checkout@v4
+
+ - name: Run PSScriptAnalyzer
+ shell: pwsh
+ run: |
+ $files = Get-ChildItem -Path ./ -Include *.ps1 -Recurse
+ Write-Host "--- Starting PowerShell Static Analysis ---"
+
+ $anyErrors = $false
+
+ foreach ($file in $files) {
+ $relativePath = $file.FullName.Replace($PWD.ProviderPath, ".")
+ $results = Invoke-ScriptAnalyzer -Path $file.FullName -Severity Warning
+
+ if ($results) {
+ Write-Host "FAIL: $relativePath" -ForegroundColor Red
+ $results | Format-Table -AutoSize
+ $anyErrors = $true
+ } else {
+ Write-Host "PASS: $relativePath" -ForegroundColor Green
+ }
+ }
+
+ if ($anyErrors) {
+ Write-Error "Static analysis failed. Please fix the errors above."
+ exit 1
+ } else {
+ Write-Host "--- All files passed analysis! ---"
+ }
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5caad15..0d55a7b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,37 +4,22 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/).
-### [1.2.1] (https://github.com/plus3it/repo-template/releases/tag/1.2.1)
+### [0.0.1] (https://github.com/plus3it/repo-template/releases/tag/0.0.1)
-**Summary**:
-
-* Updated README.md to include config settings for github
-* Updated LICENSE copyright year
-
-### [1.2.0] (https://github.com/plus3it/repo-template/releases/tag/1.2.0)
+**Released**: 2026.04.14
**Summary**:
-* Updated SHA value for Github Actions Workflows
-* Updated CHANGELOG.template.md file
-* Added Master branch in release workflow logic to make migration to Github Actions more efficient
-
-### 1.1.0
-
-**Commit Delta**: N/A
-
-**Released**: 2023.01.27
-
-**Summary**:
+* Adds all necessary, initial install and configuration content for the Notepad++ application to be installed and ready-to-run
+* Adds all necessary "clean" content for the Notepad++ application to be fully removed (binaries, config-files and registry-settings
+* Activates initial CI content from repo-template repository
-* Updated workflow files to be consumable and reusable, and now points to actions-workflows repo
-### 1.0.0
-**Commit Delta**: N/A
+### [0.0.0] (https://github.com/plus3it/repo-template/releases/tag/0.0.0)
-**Released**: 2023.01.10
+**Released**: 2026.04.09
**Summary**:
-* Initial release of capability
+* "Skeleton" content cloned from [repo-template](https://github.com/plus3it/repo-template) repository
diff --git a/CHANGELOG.template.md b/CHANGELOG.template.md
deleted file mode 100644
index c61f573..0000000
--- a/CHANGELOG.template.md
+++ /dev/null
@@ -1,13 +0,0 @@
-## {{ repo-name }}
-
-All notable changes to this project will be documented in this file.
-
-The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/).
-
-### [{{Major.Minor.Patch}}](https://github.com/plus3it/{{RepoName}}/releases/tag/{{Major.Minor.Patch}})
-
-**Released**: {{ YYYY.MM.DD }}
-
-**Summary**:
-
-* {{ Bulleted descriptions of enhancements, changes, or fixes }}
diff --git a/LICENSE b/LICENSE
index c2f93d6..adad242 100644
--- a/LICENSE
+++ b/LICENSE
@@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.
- Copyright 2024 Maintainers of plus3it/repo-template
+ Copyright 2026 Maintainers of plus3it/repo-template
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
diff --git a/README.md b/README.md
index 5de6c40..be18d42 100644
--- a/README.md
+++ b/README.md
@@ -1,52 +1,40 @@
-# repo-template
-Generic repo template for Plus3IT repositories
-
-To use this template:
-
-1. Select the green "Use this template" button, or [click here](https://github.com/plus3it/repo-template/generate).
-2. Select the repo Owner, give the repo a name, enter a description, select Public or Private, and click "Create repository from template".
-3. Clone the repository and create a new branch.
-4. Configure the following settings on your new repo.
- * `GENERAL`
- * `Features`
- * Turn off Wikis, Sponsorships, Discussions, and Projects
- * `Pull Requests`
- * Turn off Squash Merging
- * Turn off Rebase Merging
- * Turn on Allow Auto-Merge
- * Turn on Automatically delete head branches
- * `Pushes`
- * Limit how many branches can be updated in a single push: 2
- * `COLLABORATORS and TEAMS`
- * `Manage Access`
- * Add relevant team roles, for example
- * `tardigrade-admins` (Admin)
- * `terraform` (Write)
- * `releasebot` (Write)
- * `Branches`
- * `Create Branch Protection rule` for `main`
- * Turn on Require pull request before merging
- * Turn on Require approvals
- * Turn on Dismiss stale pull requests...
- * `Required Status Checks`
- * As relevant to projects, for example
- * WIP
- * lint/actionlint
- * lint/tardigradelint
- * test / mockstacktest
- * Turn on Do not allow bypassing the above settings
-5. Edit the following files to customize them for the new repository:
- * `LICENSE`
- * Near the end of the file, edit the date and change the repository name
- * `CHANGELOG.template.md`
- * Rename to `CHANGELOG.md`, replacing the repo-template changelog
- * Edit templated items for the new repo
- * `.bumpversion.cfg`
- * Edit the version number for the new repo, ask team if not sure what to
- start with
- * `README.md`
- * Replace contents for the new repo
- * `.github/`
- * Inspect dependabot and workflow files in case changes are needed for
- the new repo
-6. Commit the changes and open a pull request
+# notepad-plusplus-formula
+
+A Saltstack formula designed to install and configure the [Notepad++](https://notepad-plus-plus.org/) text-editor (and to uninstall it later).
+
+It is primarily expected that this formula will be run via [P3](https://www.plus3it.com/)'s "[watchmaker](https://watchmaker.readthedocs.io/en/stable/)" framework.
+
+This formula is able to install and configure the Notepad++ text-editor on Windows-based systems. Linux functionality would also have been provided, but there's currently no Linux variant from the same makers.
+
+## Available states
+
+- [notepad-plusplus](#notepad-plusplus)
+- [notepad-plusplus.clean](#notepad-plusplus.clean)
+- [notepad-plusplus.package](#notepad-plusplus.package)
+- [notepad-plusplus.package.clean](#notepad-plusplus.package.clean)
+- [notepad-plusplus.config](#notepad-plusplus.config)
+- [notepad-plusplus.config.clean](#notepad-plusplus.config.clean)
+
+### notepad-plusplus
+
+Executes the `package` and `config` states to install and configure the Notepad++ editor. This includes the editor binaries, as well as some Windows Registry settings and user-configuration template files.
+
+### notepad-plusplus.clean
+
+Executes the `package` and `config` states' `clean` actions to fully uninstall the Notepad++ editor and associated registry entries
+
+### notepad-plusplus.package
+
+Executes _just_ the `package` state to install the Notepad++ package.
+
+### notepad-plusplus.package.clean
+
+Executes _just_ the `package` state's `clean` module to uninstall the Notepad++ binaries.
+
+### notepad-plusplus.config
+
+Executes _just_ the `config` state to install registry-keys and other configuration-items to support the healthy running of the Notepad++ application
+
+### notepad-plusplus.config.clean
+
+Executes _just_ the `config` state's `clean` module to uninstall the Notepad++ application's registry keys and other configuration-items set up during a prior, formula-managed installation.
diff --git a/notepad-plusplus/_mapdata/_mapdata.jinja b/notepad-plusplus/_mapdata/_mapdata.jinja
new file mode 100644
index 0000000..e356b07
--- /dev/null
+++ b/notepad-plusplus/_mapdata/_mapdata.jinja
@@ -0,0 +1,13 @@
+# yamllint disable rule:indentation rule:line-length
+# {{ grains.get("osfinger", grains.os) }}
+---
+{#- use salt.slsutil.serialize to avoid encoding errors on some platforms #}
+{{ salt["slsutil.serialize"](
+ "yaml",
+ map,
+ default_flow_style=False,
+ allow_unicode=True,
+ )
+ | regex_replace("^\s+'$", "'", multiline=True)
+ | trim
+}}
diff --git a/notepad-plusplus/_mapdata/init.sls b/notepad-plusplus/_mapdata/init.sls
new file mode 100644
index 0000000..3529a8d
--- /dev/null
+++ b/notepad-plusplus/_mapdata/init.sls
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+# vim: ft=sls
+---
+{#- Get the `tplroot` from `tpldir` #}
+{%- set tplroot = tpldir.split("/")[0] %}
+{%- from tplroot ~ "/map.jinja" import mapdata with context %}
+
+{%- set _mapdata = {
+ "values": mapdata,
+ } %}
+{%- do salt["log.debug"]("### MAP.JINJA DUMP ###\n" ~ _mapdata | yaml(False)) %}
+
+{%- set output_dir = "/temp" if grains.os_family == "Windows" else "/tmp" %}
+{%- set output_file = output_dir ~ "/salt_mapdata_dump.yaml" %}
+
+{{ tplroot }}-mapdata-dump:
+ file.managed:
+ - name: {{ output_file }}
+ - source: salt://{{ tplroot }}/_mapdata/_mapdata.jinja
+ - template: jinja
+ - context:
+ map: {{ _mapdata | yaml }}
diff --git a/notepad-plusplus/clean.sls b/notepad-plusplus/clean.sls
new file mode 100644
index 0000000..477c179
--- /dev/null
+++ b/notepad-plusplus/clean.sls
@@ -0,0 +1,18 @@
+# -*- coding: utf-8 -*-
+# vim: ft=sls
+
+{%- if grains.os_family == "Windows" %}
+include:
+ - .config.clean
+ - .package.clean
+{%- else %}
+Invalid Platform
+ test.show_notification:
+ - text: |
+ ----------------------------------------
+ The notepad++ application is not
+ published for non-Windows platform.
+ Skipping all further actions.
+ ----------------------------------------
+{%- endif %}
+
diff --git a/notepad-plusplus/config/clean.sls b/notepad-plusplus/config/clean.sls
new file mode 100644
index 0000000..639a82e
--- /dev/null
+++ b/notepad-plusplus/config/clean.sls
@@ -0,0 +1,37 @@
+# -*- coding: utf-8 -*-
+# vim: ft=sls
+
+{#- Get the `tplroot` from `tpldir` #}
+{%- set tplroot = tpldir.split('/')[0] %}
+{%- from tplroot ~ "/map.jinja" import mapdata as notepad_plusplus with context %}
+{%- set npp_admins = notepad_plusplus.config.npp_admins or ['Administrator'] %}
+{%- set npp_dir = 'C:\\Program Files\\Notepad++' %}
+
+{# Map descriptive IDs to their respective Registry paths #}
+{%- set npp_registry_map = {
+ 'NPP Application Path': 'HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\notepad++.exe',
+ 'NPP Context Menu Entry': 'HKEY_CLASSES_ROOT\\*\\shell\\Open with Notepad++',
+ 'NPP MuiCache Entry': 'HKEY_CLASSES_ROOT\\Local Settings\\Software\\Microsoft\\Windows\\Shell\\MuiCache',
+ 'NPP OpenWithList txt': 'HKEY_CLASSES_ROOT\\.txt\\OpenWithList\\notepad++.exe',
+ 'NPP System Notepad Replacement': 'HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Opt
+ions\\notepad.exe'
+ }
+%}
+
+{%- for desc, reg_path in npp_registry_map.items() %}
+Remove {{ desc }}:
+ reg.absent:
+ - name: '{{ reg_path }}'
+{%- endfor %}
+
+{%- for admin in npp_admins %}
+Remove NPP AppData for {{ admin }}:
+ file.absent:
+ - name: 'C:\Users\{{ admin }}\AppData\Roaming\Notepad++'
+{%- endfor %}
+
+Remove NPP System Config Files:
+ file.absent:
+ - names:
+ - '{{ npp_dir }}\updater\gup.xml'
+ - '{{ npp_dir }}\config.model.xml'
diff --git a/notepad-plusplus/config/file.sls b/notepad-plusplus/config/file.sls
new file mode 100644
index 0000000..ffccac8
--- /dev/null
+++ b/notepad-plusplus/config/file.sls
@@ -0,0 +1,122 @@
+# -*- coding: utf-8 -*-
+# vim: ft=sls
+
+{#- Get the `tplroot` from `tpldir` #}
+{%- set tplroot = tpldir.split('/')[0] %}
+{%- set sls_package_install = tplroot ~ '.package.install' %}
+{%- from tplroot ~ "/map.jinja" import mapdata as notepad_plusplus with context %}
+{%- from tplroot ~ "/libtofs.jinja" import files_switch with context %}
+{%- set npp_version = notepad_plusplus.pkg.version %}
+{%- set npp_url = notepad_plusplus.pkg.installer_uri %}
+{%- set npp_admins = notepad_plusplus.config.npp_admins or ['Administrator'] %}
+{%- set npp_dir = 'C:\\Program Files\\Notepad++' %}
+
+
+include:
+ - {{ sls_package_install }}
+
+Add NPP Icon to Context Menu:
+ reg.present:
+ - name: 'HKEY_CLASSES_ROOT\*\shell\Open with Notepad++'
+ - vname: Icon
+ - vdata: 'C:\Program Files\Notepad++\notepad++.exe,0'
+ - vtype: REG_SZ
+ - require:
+ - cmd: 'Install NotePad++'
+
+Add NPP to Context Menu:
+ reg.present:
+ - name: 'HKEY_CLASSES_ROOT\*\shell\Open with Notepad++\command'
+ - vname: ''
+ - vdata: '"C:\Program Files\Notepad++\notepad++.exe" "%1"'
+ - vtype: REG_SZ
+ - require:
+ - cmd: 'Install NotePad++'
+
+Auto-updater disablement notice:
+ test.show_notification:
+ - text: |-
+ ---------------------------------------------
+ Auto-update disabled to prevent users from
+ being nagged to do something outside their
+ ability to effect. Administrators can still
+ login and force an update, if necessary
+ (typically, system will be re-deployed rather
+ than updated)
+ ---------------------------------------------
+ - require:
+ - cmd: 'Install NotePad++'
+
+{% for admin in npp_admins %}
+{% set admin_appdata = 'C:\\Users\\' ~ admin ~ '\\AppData\\Roaming\\Notepad++' %}
+Create NPP Admin Config File for {{ admin }}:
+ file.managed:
+ - name: '{{ admin_appdata }}\config.xml'
+ - contents: |
+
+
+
+ - require:
+ - file: 'Ensure NPP Admin Config Dir for {{ admin }} exists'
+
+Ensure NPP Admin Config Dir for {{ admin }} exists:
+ file.directory:
+ - name: '{{ admin_appdata }}'
+ - makedirs: True
+ - onlyif:
+ - shell: powershell
+ - cmd: |
+ if (Get-LocalUser -Name "{{ admin }}" -ErrorAction SilentlyContinue) {
+ exit 0
+ } else {
+ exit 1
+ }
+{% endfor %}
+
+Manage Notepad++ Updater Config:
+ file.managed:
+ - context:
+ npp_version: {{ npp_version}}
+ - makedirs: True
+ - name: 'C:\Program Files\Notepad++\updater\gup.xml'
+ - require:
+ - test: 'Auto-updater disablement notice'
+ - source: salt://{{ tplroot }}/files/gup.xml
+ - template: jinja
+
+NPP User Template (No nagging for updates):
+ file.managed:
+ - name: {{ npp_dir }}\config.model.xml
+ - contents: |
+
+
+
+ - require:
+ - cmd: 'Install NotePad++'
+
+Replace System Notepad with NPP:
+ reg.present:
+ - name: 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\notepad.exe'
+ - vname: Debugger
+ - vdata: '"C:\Program Files\Notepad++\notepad++.exe" -systemedit'
+ - vtype: REG_SZ
+ - require:
+ - cmd: 'Install NotePad++'
+
+Set NPP App Path:
+ reg.present:
+ - name: 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\notepad++.exe'
+ - vname: ''
+ - vdata: 'C:\Program Files\Notepad++\notepad++.exe'
+ - vtype: REG_SZ
+ - require:
+ - cmd: 'Install NotePad++'
+
+Set NPP App Path Default:
+ reg.present:
+ - name: 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\notepad++.exe'
+ - vname: Path
+ - vdata: 'C:\Program Files\Notepad++'
+ - vtype: REG_SZ
+ - require:
+ - cmd: 'Install NotePad++'
diff --git a/notepad-plusplus/config/init.sls b/notepad-plusplus/config/init.sls
new file mode 100644
index 0000000..465ddfe
--- /dev/null
+++ b/notepad-plusplus/config/init.sls
@@ -0,0 +1,5 @@
+# -*- coding: utf-8 -*-
+# vim: ft=sls
+
+include:
+ - .file
diff --git a/notepad-plusplus/files/default/example.tmpl b/notepad-plusplus/files/default/example.tmpl
new file mode 100644
index 0000000..2c9c60f
--- /dev/null
+++ b/notepad-plusplus/files/default/example.tmpl
@@ -0,0 +1,6 @@
+########################################################################
+# File managed by Salt at <{{ source }}>.
+# Your changes will be overwritten.
+########################################################################
+
+This is an example file from SaltStack template-formula.
diff --git a/notepad-plusplus/files/default/example.tmpl.jinja b/notepad-plusplus/files/default/example.tmpl.jinja
new file mode 100644
index 0000000..26a7ef9
--- /dev/null
+++ b/notepad-plusplus/files/default/example.tmpl.jinja
@@ -0,0 +1,11 @@
+########################################################################
+# File managed by Salt at <{{ source }}>.
+# Your changes will be overwritten.
+########################################################################
+
+This is another example file from SaltStack template-formula.
+
+# This is here for testing purposes
+{{ notepad_plusplus | json }}
+
+winner of the merge: {{ notepad_plusplus['winner'] }}
diff --git a/notepad-plusplus/files/gup.xml b/notepad-plusplus/files/gup.xml
new file mode 100644
index 0000000..5b1e381
--- /dev/null
+++ b/notepad-plusplus/files/gup.xml
@@ -0,0 +1,10 @@
+
+
+ /S
+ low
+
+ Notepad++
+ {{ npp_version }}
+
+ http://127.0.0.1/checkUpdate.xml
+
diff --git a/notepad-plusplus/files/npp_install.ps1 b/notepad-plusplus/files/npp_install.ps1
new file mode 100644
index 0000000..4dbcb16
--- /dev/null
+++ b/notepad-plusplus/files/npp_install.ps1
@@ -0,0 +1,65 @@
+# Script to install Notepad++ while still keeping saltstack's output not
+# completely horrific
+#
+################################################################################
+
+# Force PowerShell to stop on errors so we can catch them and report to Salt
+$ErrorActionPreference = 'Stop'
+
+$target = $args[0].Trim("'")
+$tempExe = $args[1].Trim("'")
+
+# Normalize the exe-installer's path
+$tempExe = $tempExe -replace '/', '\'
+
+# Declare registry-keys to be modified
+$paths = @(
+ "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Notepad++",
+ "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Notepad++"
+)
+
+$installed = $false
+
+# Do pre-installation Check of registry-keys
+foreach ($path in $paths) {
+ if (Test-Path $path) {
+ $val = (Get-ItemProperty $path).DisplayVersion
+ if ($val -match $target) { $installed = $true; break }
+ }
+}
+
+# Execute the EXE-based installer
+if (-not $installed) {
+ Write-Output "Version $target not found. Attempting to install from $tempExe..."
+ try {
+ # "remote" files may get marked as blocked. Bypass that nonsense
+ Unblock-File -Path $tempExe -ErrorAction SilentlyContinue
+
+ # Execute the EXE-installer
+ & $tempExe /S | Out-Null
+
+ # Capture the result of the installer
+ $exitCode = $LASTEXITCODE
+
+ # Give the Registry a few seconds to flush changes to disk
+ Start-Sleep -Seconds 5
+
+ # Make sure we did what we tried to do...
+ $verified = $false
+ foreach ($path in $paths) { if (Test-Path $path) { $verified = $true } }
+
+ if ($verified) {
+ Write-Output "Installation successful (Exit Code: $exitCode)."
+ exit 0
+ } else {
+ Write-Error "Installer finished (Exit Code: $exitCode) but registry keys not found."
+ exit 1
+ }
+ } catch {
+ Write-Error "Installation failed: $($_.Exception.Message)"
+ exit 1
+ }
+} else {
+ Write-Output "Notepad++ $target already installed. Skipping."
+ exit 0
+}
diff --git a/notepad-plusplus/files/npp_uninstall.ps1 b/notepad-plusplus/files/npp_uninstall.ps1
new file mode 100644
index 0000000..1c40d89
--- /dev/null
+++ b/notepad-plusplus/files/npp_uninstall.ps1
@@ -0,0 +1,51 @@
+# Setup paths based on standard Notepad++ installation patterns
+$NppPath = "${env:ProgramFiles}\Notepad++"
+$NppExe = Join-Path $NppPath "notepad++.exe"
+
+# PRE-CONDITION (State Check)
+# Check if the main executable exists. If not, we assume it's already gone.
+if (Test-Path $NppExe) {
+ Write-Output "Found Notepad++ binary at '$NppExe'"
+}
+else {
+ # Salt will see this string in 'stdout'; exit 100 identifies "Already Absent"
+ Write-Output "State: Already Absent"
+ exit 100
+}
+
+# EXECUTION
+# Notepad++ stores its uninstaller directly in the install directory
+$Uninstaller = Join-Path $NppPath "uninstall.exe"
+
+if (Test-Path $Uninstaller) {
+ Write-Output "Found uninstaller at '$Uninstaller'"
+ Write-Output "Executing silent uninstallation..."
+
+ # Start the uninstaller and capture the process object
+ $Proc = Start-Process -FilePath "$Uninstaller" -ArgumentList "/S" -Wait -PassThru
+
+ # Use the variable to provide meaningful output and logic
+ Write-Output "Uninstaller exited with code: $($Proc.ExitCode)"
+
+ # Optional: Wait briefly for file system hooks to release
+ Start-Sleep -Seconds 2
+
+ # FINAL VERIFICATION: Check both the file system AND the exit code
+ if (-not (Test-Path $NppExe) -and $Proc.ExitCode -eq 0) {
+ Write-Output "State: Success"
+ exit 0
+ } elseif ($Proc.ExitCode -ne 0) {
+ Write-Error "State: Failed. Uninstaller returned non-zero exit code ($($Proc.ExitCode))"
+ exit 1
+ } else {
+ Write-Error "State: Failed to remove binary"
+ exit 1
+ }
+}
+else {
+ # If binary exists but uninstaller is missing, we have a "dirty" state
+ Write-Error "Binary found but '$Uninstaller' is missing. Manual cleanup required."
+ exit 1
+}
+
+exit 100
diff --git a/notepad-plusplus/init.sls b/notepad-plusplus/init.sls
new file mode 100644
index 0000000..4029724
--- /dev/null
+++ b/notepad-plusplus/init.sls
@@ -0,0 +1,17 @@
+# -*- coding: utf-8 -*-
+# vim: ft=sls
+
+{%- if grains.os_family == "Windows" %}
+include:
+ - .package
+ - .config
+{%- else %}
+Invalid Platform
+ test.show_notification:
+ - text: |
+ ----------------------------------------
+ The notepad++ application is not
+ published for non-Windows platform.
+ Skipping all further actions.
+ ----------------------------------------
+{%- endif %}
diff --git a/notepad-plusplus/libmapstack.jinja b/notepad-plusplus/libmapstack.jinja
new file mode 100644
index 0000000..8f54ef3
--- /dev/null
+++ b/notepad-plusplus/libmapstack.jinja
@@ -0,0 +1,315 @@
+{#- -*- coding: utf-8 -*- #}
+{#- vim: ft=jinja #}
+
+{#- Get the `tplroot` from `tpldir` #}
+{%- set tplroot = tpldir.split("/")[0] %}
+{%- from tplroot ~ "/libmatchers.jinja" import parse_matchers, query_map with context %}
+
+{%- set _default_config_dirs = [
+ "parameters/",
+ tplroot ~ "/parameters"
+ ] %}
+
+{%- macro mapstack(
+ matchers,
+ defaults=None,
+ dirs=_default_config_dirs,
+ log_prefix="libmapstack: "
+ ) %}
+{#-
+ Load configuration in the order of `matchers` and merge
+ successively the values with `defaults`.
+
+ The `matchers` are processed using `libmatchers.jinja` to select
+ the configuration sources from where the values are loaded.
+
+ Parameters:
+
+ - `matchers`: list of matchers in the form
+ `[[: