Skip to content

Adding a New Plugin

Nikolai Sachok edited this page Jun 24, 2026 · 1 revision

Adding a New Plugin

The collection is built to grow. A new plugin should land at the same standard: native, universal, tested, leak-clean, documented.

1. Choose the type and learn from a sibling

Pick WLX / WCX / WDX / WFX (see WLX Plugin Model). Find the exact entry points and conventions by inspecting an existing plugin of that type that ships with Double Commander:

ls "/Applications/Double Commander.app/Contents/MacOS/plugins/"
nm -gU ".../plugins/<type>/<name>/<file>"        # the required exports
otool -L ".../plugins/<type>/<name>/<file>"      # the frameworks it links

Copy only the ABI slice you need into a local listplug.h-style header. Remember the macOS mapping: handles are NSView*, __stdcall is empty.

2. Scaffold (match the convention)

<name>-<type>/
├── <Name>.m                # implementation
├── listplug.h              # the ABI slice you use
├── build.sh                # universal build + ad-hoc codesign + symbol dump
├── install.sh              # idempotent install + register (+ config backup)
├── assets/                 # vendored runtime assets (attribute in THIRD_PARTY_LICENSES.md)
├── test/                   # headless harnesses that dlopen the built plugin
├── docs/                   # screenshots, plugin notes
├── README.md
└── THIRD_PARTY_LICENSES.md

3. Build it on the platform's strengths

Reach for the best macOS framework for the job — WebKit for HTML-shaped content, Quartz/PDFKit for documents, QuickLook for thumbnails, AppKit for native layout. Manage any Cocoa object returned through the C ABI with CFBridgingRetain/CFBridgingRelease.

4. Test the real binary

Write a test/ host that dlopens the built plugin and asserts an observable outcome (it rendered; a value came back; a key routed correctly). Loading the artifact DC will actually load — not a stand-in — is the point.

5. Register correctly

install.sh must be idempotent, back up doublecmd.xml, and place the entry so detection order is right: DC uses the first registered plugin whose detect string matches, so a specific plugin goes before the catch-all MacPreview (EXT!=""). Quit Double Commander before editing its config — it rewrites the file on exit.

6. Wire into the repo standard

  • Add a row to the root README.md plugins table.
  • Add a CHANGELOG.md entry (plugins version independently).
  • bash scripts/leak-guard.sh must be clean.
  • CI builds every plugin and checks arches + exports — keep build.sh where CI expects it, or extend .github/workflows/ci.yml.
  • Document the design here in the wiki: the why, the tradeoffs, and any instructive bug — that's what makes this collection teaching material, not just code.

Clone this wiki locally