NotepadMac is a native macOS text editor (Swift + AppKit) inspired by Notepad++. 12 internal modules, zero external dependencies, Swift Package Manager build.
swift build # Debug build
swift test # Run all tests
bash Scripts/build-app.sh # Build .app bundle (debug)
bash Scripts/build-app.sh release # Build .app bundle (release)
bash Scripts/create-dmg.sh # Build release DMG
bash Scripts/version.sh get # Show current version
bash Scripts/version.sh bump patch # Bump patch version (0.1.0 → 0.1.1)Sources/
├── NotepadNext/ # App shell (AppDelegate, MainWindowController, menus)
├── NotepadNextCore/ # Core logic (macros, plugins, preferences, CLI args)
├── TextCore/ # Piece Table engine, LineIndex, TextBuffer
├── EditorKit/ # EditorTextView, line numbers, minimap, split view
├── SyntaxKit/ # Syntax highlighting (19 langs), code folding
├── ThemeKit/ # Theme system (16 built-in themes)
├── SearchKit/ # Find/Replace, Find in Files, regex
├── FileKit/ # File I/O, encoding detection, file watching
├── TabKit/ # Tab bar UI, tab management
├── MarkdownKit/ # Markdown → HTML renderer, WKWebView preview
├── PanelKit/ # Dockable panel framework (left/right/bottom)
└── CommonKit/ # Shared utilities, extensions, constants
Dependency rule: CommonKit ← TextCore ← everything else. No circular deps.
Version is stored in Sources/NotepadNextCore/Version.swift:
public let appVersion = "0.1.0"
public let appBuild = "1"Use the version script — do NOT edit manually:
bash Scripts/version.sh bump patch # 0.1.0 → 0.1.1
bash Scripts/version.sh bump minor # 0.1.1 → 0.2.0
bash Scripts/version.sh bump major # 0.2.0 → 1.0.0# Bump version
bash Scripts/version.sh bump patch
VERSION=$(bash Scripts/version.sh get)
# Update create-dmg.sh VERSION variable if needed
# (currently hardcoded — keep in sync with Version.swift)
# Commit
git add Sources/NotepadNextCore/Version.swift
git commit -m "Bump version to $VERSION"git tag "v$VERSION"
git push origin main --tagsOnce the tag is pushed, .github/workflows/release.yml automatically:
- Runs
swift test— fails the release if tests break - Runs
bash Scripts/create-dmg.sh— builds the release DMG - Creates a GitHub Release with auto-generated release notes
- Attaches
NotepadMac-{VERSION}.dmgto the release
Users download the DMG from the GitHub Releases page.
Both the app AND the DMG must be signed. Signing only the app causes "image damaged" errors on macOS.
# 1. Sign the app (hardened runtime required for notarization)
codesign --deep --force --options runtime \
--sign "Developer ID Application: Yun Jegal (8USUP9LW76)" \
.build/release/NotepadMac.app
# 2. Create DMG (Scripts/create-dmg.sh)
bash Scripts/create-dmg.sh
# 3. Sign the DMG itself
codesign --force --sign "Developer ID Application: Yun Jegal (8USUP9LW76)" \
--timestamp .build/release/NotepadMac-$VERSION.dmg
# 4. Notarize (uses smackbook keychain profile)
xcrun notarytool submit .build/release/NotepadMac-$VERSION.dmg \
--keychain-profile "smackbook" --wait
# 5. Staple (allows offline Gatekeeper verification)
xcrun stapler staple .build/release/NotepadMac-$VERSION.dmgKeychain profile: smackbook (shared with SmackBook, already stored via notarytool store-credentials)
| Workflow | Trigger | What it does |
|---|---|---|
build.yml |
Push/PR to main | swift build — compile check |
test.yml |
Push/PR to main | swift test --parallel — run all tests |
lint.yml |
Push/PR to main | SwiftLint code quality check |
release.yml |
Tag v* pushed |
Test → Build DMG → Create GitHub Release |
- SwiftFormat config:
.swiftformat(4-space indent, 120 char width) - SwiftLint config:
.swiftlint.yml - No external dependencies — keep it that way
- Each module should be independently testable
Edit Sources/SyntaxKit/BuiltinLanguages.swift — add a new LanguageDefinition.
Edit Sources/ThemeKit/BuiltinThemes.swift — add a new theme JSON string.
- Create a
NSViewControllersubclass - Register it in
MainWindowController.registerPanels()with aPanelDescriptor
- Bundle identifier:
com.notepadmac.app - Minimum macOS: 13.0 (Ventura)
- Swift target name is still
NotepadNext(internal) — display name isNotepadMac - UserDefaults prefix:
NotepadMac. - App Support directory:
~/Library/Application Support/NotepadMac/ Scripts/build-app.shandScripts/create-dmg.shauto-read version fromVersion.swift