First Contribution¶
Make a small extension change and verify both its pure logic and its VS Code integration.
Set up the workspace¶
just init installs the Node and Python toolchains and the prek git hooks
(pre-commit and pre-push). The hooks run Ruff, Prettier, mdformat, Pyrefly, ESLint,
and the Python tests on commit, and check-types, TypeScript unit tests, and knip on
push, so most regressions surface before you open a pull request. If you skip this
step, your clone has no local hooks and those regressions surface later in CI instead.
The manual equivalent, if you are not using just:
npm install
uv sync --project tools --frozen --all-groups
uv run --project tools prek install --hook-type pre-commit --hook-type pre-push
Choose the source of truth¶
| Change | Primary location |
|---|---|
| Attribute or version metadata | tools/src/htmx_django_intellisense/catalog.py and htmx.catalog.json |
| Name parsing or Django partial recognition | src/scanner.ts |
| Resolution rules | src/catalog.ts |
| Validation behavior | src/diagnostics.ts |
| VS Code provider behavior | src/extension.ts |
| Django snippet | snippets/django-htmx.source.json |
Add or update the focused Node or Python test that fails before the change. Regenerate the HTMX
catalog only when its generator inputs or metadata change. Run npm run build-snippets after a
snippet source change; it updates the packaged JSON and reference page together.
Add a snippet¶
Edit snippets/django-htmx.source.json, not the generated
snippets/django-htmx.json or docs/reference/snippets.md files. Each source
entry has these fields:
{
"name": "HTMX Refresh",
"prefix": "htmx-refresh",
"category": "Requests and forms",
"classification": "common",
"description": "Refresh a Django fragment with HTMX",
"body": [
"<button type=\"button\" hx-get=\"{% url '${1:refresh-view}' %}\" hx-target=\"#${2:content}\" hx-swap=\"${3:innerHTML}\">${4:Refresh}</button>"
],
"usage": "The view returns the fragment that replaces the selected target."
}
The validator requires:
| Field | Rules |
|---|---|
name |
Non-empty and unique across the catalog. |
prefix |
Lowercase htmx-... words separated by hyphens, or one of the Django partial prefixes (partialdef, partialdef-inline, partial); must be unique. |
category |
One of Requests and forms, Loading and navigation, Editing and UI, Server responses, or Django partials. Keep entries in that order. |
classification |
One of common, curated, or django-6. Entries in Django partials must use django-6; other entries must not. |
description and usage |
Non-empty strings. Use description for the catalog summary and usage for the expected view or template response. |
body |
A non-empty array of non-empty strings containing the Django/HTML template to insert. |
Use VS Code snippet placeholders in the body: ${1:default} creates an editable
tab stop with a default value, $0 marks the final cursor position, and repeated
numbers reuse the same value. Keep the markup compatible with both supported HTMX
catalogs; the snippet test suite rejects deprecated or version-specific attributes.
Mutating snippets must use a CSRF-safe Django form. Put every hx-post, hx-put,
or hx-patch control inside a form with method="post", a matching action and
hx-post, and {% csrf_token %}. Delete actions also use this POST pattern.
The validator rejects scripts, inline event handlers, hx-on, JavaScript URLs or
expressions, remote executable embeds, hx-ext, SSE, and WebSocket attributes.
After editing the source:
-
Run the generator:
-
Review the generated entry in
snippets/django-htmx.jsonand the rendered example in Snippets and Examples. -
Confirm the generated files are current:
npm testalso runs this check and the Python generator tests.
Verify¶
npm test runs TypeScript unit tests and Python generator/manifest tests. npm run test:extension launches extension-host smoke tests for both supported language modes. Packaging confirms the installed artifact contains runtime files, catalog, snippets, and presentation assets rather than source and docs.
For a complete walkthrough of F5 debugging, VSIX sideloading, and troubleshooting, see Local Extension Testing.
Refresh demo assets¶
After a UI or UX change, regenerate the committed Marketplace and documentation demos:
The command captures real extension-host states, rewrites images/diagnostics.png, images/partials.png, and the three animated feature GIFs, then mirrors each file under docs/assets/images/. It never changes the hand-designed extension icon or Marketplace banner. GIF generation uses ffmpeg when available, with a macOS ImageIO fallback.
Review catalog changes¶
Commit catalog and generator changes together. The CI workflow repeats regeneration and fails if it produces a diff.