# CLAUDE.md

This file grounds Claude sessions working on this repository.
Read `docs/specs/mission.md` for full background. Key facts:

## What this is

A permissively-licensed (MIT) PySide6 binding for the Scintilla code editor
component. Built with shiboken6 + CMake + scikit-build-core. The main motivation
is providing a GPL-free alternative to PyQt6-QScintilla.

## What this is NOT

- Not a port of QScintilla's high-level API
- Not affiliated with Riverbank Computing or the QScintilla project
- Not trying to upstream into Scintilla itself

## Stack

- **Language**: C++ (binding glue) + Python (package/API)
- **Binding generator**: shiboken6
- **Build system**: CMake + scikit-build-core
- **Package manager**: uv
- **CI**: GitHub Actions + cibuildwheel
- **Scintilla**: vendored release tarball (not a live hg clone)

## Dev machines

- Windows 11 + WSL (Debian/Ubuntu) — primary
- macOS M1 Mac Mini — secondary

## Platforms targeted

Linux x86_64/aarch64, Windows x86_64, macOS arm64 + x86_64

## Conventions

- Python package name on PyPI: `pyside6-scintilla`
- Import name: `pyside6_scintilla` (underscore, as per PEP 8)
- Versioning: follow Scintilla's version (e.g. Scintilla 5.5.x → this package 5.5.x.N)
- All new code under MIT license; Scintilla vendored code retains HPND license

## Python style

For hand-written Python (anything not generated by shiboken/CMake):

- Prefer bare `Final` over a parameterized `Final[T]` when the type is
  inferable, for module-level constants and attributes that are set once
  and never reassigned:

  ```python
  SC_MARGIN_NUMBER: Final = 1  # not Final[int]
  self.__editor: Final = ScintillaEditBase()
  ```

- Names are either public (`name`) or private (`__name`, name-mangled) —
  no single-underscore "protected" convention. If a method or attribute
  isn't part of a class's external API, make it private.
- Module-level functions are usually public.
- Add brief docstrings — including for private methods/attributes —
  explaining the *why* and *what*. Keep them short; don't restate what a
  well-named identifier already says.
- That terseness rule covers this codebase's own source, not documentation
  aimed at the *end user* of the bindings (e.g. `tools/generate_pyi.py`'s
  `ENUM_DOCS`/`*_DOCS` dicts, which become IDE hover docs for someone using
  `pyside6_scintilla`). For those, be as helpful as possible without being
  verbose — explain numeric values, related constants/messages, and
  platform caveats from `ScintillaDoc.html`; omit a member only if there's
  truly nothing beyond its name to say.

## Where to find things

- `src/scintilla/` — vendored Scintilla source
- `src/pyside6_scintilla/` — shiboken6 typesystem XML and binding glue
- `src/pyside6_scintilla/__init__.py` — public Python API surface
- `.github/workflows/` — CI (build + publish)
- `docs/specs/mission.md` — full project background and decision log
- `docs/specs/` — design specifications and action plans

## Roadmap

The [project board](https://github.com/users/borco/projects/3) is the joint
roadmap for this repo and [lexilla-py](https://github.com/borco/lexilla-py)
(sibling project, same author). Issues/PRs from both repos are auto-added by
`.github/workflows/add-to-project.yml`.

When asked what to work on next, check the project board's "In progress"
lane for an item belonging to this repo (`borco/pyside6-scintilla`). If one
exists, work on it. If there is no item for this repo in "In progress", say
so and stop — don't guess or pull something from Backlog instead.

If this repo has a `continue-prompt.md`, its "Next up" section should point
to the board's "In progress" lane rather than naming a specific issue (so it
can't go stale), while its "Current state" section keeps the detailed,
issue-specific work notes the board can't hold (blockers, decisions, file
paths). Before trusting "Current state", confirm it still describes whatever
issue the board currently shows as "In progress" — if the board has moved on
(or shows nothing), treat the old notes as stale.

## Git

- Never run `git commit` (or `git push`) unless explicitly told to. Stage
  and present changes for review first.
- When starting work on a tracked issue, branch off the *current* branch
  (not always `master`, which may not hold relevant in-progress work) as
  `issue/NN/short-description` (e.g. `issue/1/bind-missing-enums`), and
  prefix commit subject lines with `ref #NN:` (e.g. `ref #1: Bind all
  Scintilla enums`), where `NN` is this repo's issue number.
- These branches merge back with `--no-ff`, preserving their commit
  history as a group on the parent branch. Before merging, check whether
  the parent has moved since branching and flag it -- `--no-ff` doesn't
  replace rebasing onto an advanced parent. Ask before rebasing; don't do
  it automatically.

## Workspace

- At session start, check whether running in a multi-root VSCode workspace
  (see "Additional working directories" in the environment info, e.g. a
  sibling `lexilla-py` checkout) — if so, work may span both repos, and
  `continue-prompt.md` lives in the workspace root (e.g.
  `__SCINTILLA/workspace/`, not `pyside6-scintilla/`) since it covers both.
