7.7 KiB
BEdit Agent Guide
This file is the handoff context for coding agents working in this repository. Read it before making changes.
Working agreement
- Make only the changes the user requested.
- Keep completely out of unrelated code. Do not reformat, reorder, rename, clean up, or “improve” code that is outside the task.
- Preserve existing user changes and assume a dirty worktree belongs to the user.
- Inspect the relevant files before deciding on an implementation.
- Prefer small, modular changes over growing
MainWindow, a controller, or another file into a monolith. - When the user asks why something happens, diagnose and explain it without editing files unless they also ask for a fix.
- Do not create commits unless explicitly requested.
Code style
Follow the local style in the file being edited, with these user preferences taking priority:
- Prefer compact, readable one-line imports. Do not introduce parenthesized multiline imports.
- Avoid spreading short function calls, conditions, and expressions across multiple lines.
- Do not run broad formatters or import sorters.
- Do not use a lint autofix over the project.
- Keep classes and functions focused. Extract a controller, service, command, model, or reusable widget when a feature would otherwise make an existing file large.
- Generated modules contain no handwritten application behavior.
The project uses Ruff, but import sorting is intentionally not enforced during scoped checks:
.venv/bin/ruff check --ignore I001 path/to/changed_file.py
Project structure and dependency direction
Relevant GUI structure:
src/bedit_gui/
├── application.py
├── commands/
├── controllers/
├── documents/
├── models.py
├── services/
├── ui/
│ ├── forms/
│ └── generated/
├── resources/
│ └── generated/
├── utils/
└── views/
└── models/
Responsibilities:
application.py: composition root. Create and connect the application, document, window, services, and controllers here.documents/document.py: editable document facade. Owns the core model, path, mainQUndoStack, modified state, and high-level operations.commands/:QUndoCommandimplementations. Persistent changes to the document model go through commands.controllers/: connect actions and widgets to document/service operations. Keep workflow logic out ofMainWindow.views/: handwritten widget/window/graphics behavior.views/models/: Qt item models used by views.services/: non-visual functionality such as files, clipboard, logging, and settings.models.py: GUI metadata persisted inside the core document, currently including icons and shapes.bedit_core: domain model and serialization. It must never import frombedit_gui.
Preferred direction:
views/controllers
↓
documents/services
↓
commands
↓
bedit_core
Avoid introducing imports from bedit_gui into bedit_core or circular dependencies between services and documents.
Qt Designer and generated files
Raw forms are in:
src/bedit_gui/ui/forms/
Generated Python is in:
src/bedit_gui/ui/generated/
Never add handwritten behavior to generated UI modules. Change the .ui form and regenerate with:
.venv/bin/python scripts/generate_qt_files.py
The generation script also fixes the package-qualified resource import. Calling pyside6-uic directly without the script can produce a broken resources_rc import.
Raw resources and the QRC file live under src/bedit_gui/resources/. Generated resource Python lives under src/bedit_gui/resources/generated/.
Undo and document changes
- The main application document owns the main undo stack.
- The icon editor owns a separate local undo stack.
- The
Documentfacade should expose high-level methods that push commands. Controllers should normally call those methods rather than construct commands. - Commands mutate the model in
redo()/undo()and emit the appropriate document signals. - Multi-object user operations should be one command or one undo macro.
- Allocate stable IDs and final names before pushing a command so redo reproduces the same result.
- Component names must be unique within their destination component dictionary. Conflicts use
_0,_1, and so on. - Copy/paste must generate new component, port, parameter, connection, and icon-shape IDs and rewrite references.
Document tree
DocumentTreeModel has two columns:
- Column 0: editable document/component name.
- Column 1: rendered component icon.
Use selectedRows(0) for multi-selection; selectedIndexes() returns both columns. Filter selected descendants when an ancestor is also selected.
The tree uses extended row selection. Delete, cut, and copy may operate on multiple components. Paste targets either:
- the document root, or
- the component dictionary of a selected graph component.
The controller listens to document model/icon signals and refreshes the tree/icon cache.
Clipboard architecture
Clipboard support is intentionally extensible:
services/clipboard.py: systemQClipboardand MIME/JSON handling.services/component_clipboard.py: component payload serialization and ID remapping.controllers/clipboard_controller.py: focus-based action router and handlers.
ClipboardHandler is the base implementation for future editors. Add a graph-editor handler later by subclassing it and registering that handler in application.py.
Text widgets use their native copy(), cut(), and paste() methods. Component clipboard data uses the custom BEdit MIME type and JSON; never use pickle or live object references.
Icon editor conventions
- Icons are GUI metadata stored in
document.metadata["icon_database"]. - Shapes currently include rectangles, text, and lines.
- Shape changes use the icon editor’s local undo stack.
- Shapes are selectable, movable, resizable, pixel-snapped, and constrained to the icon scene.
- Ports are separate 16×16 items: black for inputs and white for outputs. They can be moved but are not ordinary deletable/copyable shapes.
- Colors are serialized as
#rrggbbaa. - The icon scene is currently
(-64, -64, 128, 128). - The grid spacing is 8 scene pixels and is drawn only inside the scene rectangle.
- Keep reusable widgets such as the RGBA color button independent of the icon editor.
- Static icon previews belong in rendering utilities, not in the interactive editor scene.
Actions and shortcut routing
- Put visible actions in Designer menus/toolbars.
- An action that only exists as a child object may not have an active shortcut; attach it to the relevant widget or place it in a menu/toolbar.
- Route application-wide Copy/Cut/Paste by focused widget through
ClipboardController. - Scope destructive shortcuts to the relevant widget where appropriate.
- Always guard the operation itself even when an action is disabled for presentation.
Verification
The old test suite and its VS Code/packaging references were deliberately removed. Do not recreate a test suite unless asked.
Use checks proportional to the change:
.venv/bin/ruff check --ignore I001 path/to/changed_files.py
For Qt smoke checks in a headless environment:
QT_QPA_PLATFORM=minimal QT_QPA_PLATFORMTHEME= QT_STYLE_OVERRIDE=Fusion .venv/bin/python ...
Prefer focused model, serialization, signal, command undo/redo, and offscreen rendering checks. Do not launch a GUI during verification unless explicitly requested or approved.
Handoff expectations
At the end of a task, report:
- the outcome,
- the files or subsystem changed,
- relevant behavior and limitations,
- checks that actually passed.
Do not claim tests passed when only a lint or smoke check was run.