-
Notifications
You must be signed in to change notification settings - Fork 0
Contributing
Blinki is open to contributions — bug reports, feature requests, documentation improvements, and code. This page explains the workflow, the coding standards, and the quality bar we maintain.
Blinki is highly experimental and under active development. APIs may change frequently. If you are building something on top of the library, open an issue first to discuss your plans before investing significant effort.
Use GitHub Issues at github.com/marcobreveglieri/blinki/issues.
- Delphi / RAD Studio version (e.g. "13.1 Florence, 37.0.52831.7315")
-
Windows version and build (run
winver) -
Exact steps to reproduce — ideally a minimal
.dprthat demonstrates the issue - Expected behaviour vs actual behaviour
- Screenshot or terminal recording if the bug is visual
- A clear use case ("I need X because Y")
- Whether you are willing to implement it yourself (we welcome PRs!)
- Any existing widget or demo that partially covers the scenario
The authoritative reference is STYLE_GUIDE.md
in the repository root. The summary below covers the most critical points.
| Entity | Convention | Examples |
|---|---|---|
| Classes, records, enums |
T prefix + PascalCase |
TMyRecord, TConnectionState
|
| Framework types |
TTui prefix |
TTuiWidget, TTuiCanvas, TTuiKeyEvent
|
| Interfaces |
I or ITui prefix |
ITuiConsoleBackend |
| Exception classes |
E or ETui prefix |
ETuiRenderError |
| Instance fields |
F prefix, strict private
|
FItemCount, FVisible
|
| Method parameters |
A prefix |
AValue, ACanvas, ARect
|
| Local variables |
L prefix |
LText, LIndex
|
- Indentation: 2 spaces per level. Never use tabs.
- Line length: maximum 100 characters.
-
ifbody always on a new line — never inline afterthen:
// Correct
if Assigned(FItems) then
FreeAndNil(FItems);
// Wrong
if Assigned(FItems) then FreeAndNil(FItems);-
No alignment padding — use exactly one space around
:=and after:. - Declaration order — within each visibility section, keep members alphabetical, grouped by kind (fields → helpers → public methods/properties).
Every .pas and .dpr file must be saved as UTF-8 with BOM (EF BB BF) with CRLF line
endings. Without the BOM, DCC32 falls back to Windows-1252 and silently corrupts non-ASCII
characters (e.g. box-drawing glyphs, Unicode labels). RAD Studio will refuse to compile LF-only
files.
When creating files programmatically (e.g. with a script), normalise line endings with:
(Get-Content MyUnit.pas -Raw) -replace '(?<!\r)\n', "`r`n" | Set-Content MyUnit.pas -NoNewlineEvery source file must start with the 22-line ASCII-art banner before the unit/program
keyword. The Unit: field must match the file name exactly. See any existing .pas file for the
exact format.
- Parent owns children: always pass the parent widget as the first constructor argument. The parent's destructor frees all children automatically.
- Use
FreeAndNilto release and nil a field simultaneously, with theif Assignedguard on its own line:
if Assigned(FItems) then
FreeAndNil(FItems);- Use
try..finallyto guarantee cleanup on exception.
-
Inline
varat the point of first use (Delphi 10.3+ syntax); avoid top-of-routinevarblocks for local variables. -
Guard-and-invalidate in every property setter: compare the new value to the current one,
exit early if equal, then assign and call
Invalidate. -
Cardinal overflow: when multiplying
CardinalorIntegerby a constant ≥$80000000, promote all factors toInt64first. -
No hardcoded colours: always read from
Theme.*(e.g.Theme.Primary,Theme.Border) or useTTuiColorsconstants. Never write$FF5733inline in a widget's render method. -
Comments and XML-doc in English: use
///XML-doc on everypublictype and member. Comment the why, not the what.
Custom widgets must follow the TTuiWidget hook protocol (see
Architecture & Advanced Usage → Custom Widgets):
| Hook | Purpose |
|---|---|
DoInit |
One-time setup after the widget tree is built; call SetFocusable(True) here if needed |
DoRender |
Draw the widget onto the provided TTuiCanvas within ARect
|
DoHandleEvent |
Process keyboard / mouse events; return True if consumed |
DoApplyTheme |
React to a theme change; rebuild cached TTuiStyle values |
DoTick |
Drive animations; called every TickMs milliseconds |
All CI checks must pass before a pull request can be merged. Run the same checks locally first.
# From the repository root:
.\do_build.batThis compiles the library, all smoke tests, all demos, and the unit tests in sequence.
& "C:\Program Files (x86)\Embarcadero\Studio\37.0\bin\rsvars.bat"
# Library only
msbuild Source\Blinki.dproj /t:Build /p:Config=Release /p:Platform=Win32
# Smoke tests
msbuild Tests\SmokeTests\Blinki.SmokeTests.groupproj /t:Build /p:Config=Debug /p:Platform=Win32
# Unit tests (DUnitX — requires DUnitX in the Unit Search Path)
msbuild Tests\UnitTests\Core\Blinki.UnitTests.Core.dproj /t:Build /p:Config=Debug /p:Platform=Win32
.\Tests\UnitTests\Core\Win32\Debug\Blinki.UnitTests.Core.exeNote: The unit test runner exits with code
1if any test fails and2on an unhandled exception, so MSBuild or a CI script can detect failures automatically. It requires DUnitX to be present on the search path.
The 12 smoke-test programs in Tests\SmokeTests\ exercise individual layers of the framework
(canvas, layout, widgets, dialogs, FX, emoji, …). Run each .exe and verify it exits without
errors or assertion failures.
git checkout -b feature/my-new-widget
# or
git checkout -b fix/button-focus-lost
Branch name conventions:
| Prefix | Use for |
|---|---|
feature/ |
New widgets, new APIs |
fix/ |
Bug fixes |
refactor/ |
Internal changes with no user-visible effect |
docs/ |
Documentation only |
test/ |
New or improved tests |
- Run the full build before committing (
do_build.bat). - Write or update smoke/unit tests when adding new behaviour.
- Add XML-doc
///comments to every newpublicmember.
Use the imperative mood in the subject line, capitalised, no trailing period, 72 characters or fewer:
Add TTuiSpinnerWidget with configurable frame rate
Fix TTuiTextInput cursor off-by-one on wide characters
Refactor TTuiCanvas.Flush to reduce heap allocations
- Keep each commit atomic: one logical change per commit.
- Reference the GitHub issue number in the body when applicable:
Closes #42.
Push your branch and open a PR against main:
git push origin feature/my-new-widget
In the PR description include:
- What the change does and why it is needed.
- A reference to any related GitHub issue.
- Instructions for how to test / reproduce the new behaviour.
- Screenshots or recordings for visual changes.
All CI checks (build + tests) must be green before the PR can be merged. A maintainer will review the code for correctness and adherence to the style guide.
Blinki v0.1.0 · MIT License · Copyright © 2026 Marco Breveglieri · GitHub · Home · Getting Started · Architecture · Contributing