Skip to content

refactor: add RTTI-free renderer extension core#407

Merged
forntoh merged 4 commits into
feat/graphical-displayfrom
gd/02-rtti-free-extension-core
Apr 23, 2026
Merged

refactor: add RTTI-free renderer extension core#407
forntoh merged 4 commits into
feat/graphical-displayfrom
gd/02-rtti-free-extension-core

Conversation

@forntoh
Copy link
Copy Markdown
Owner

@forntoh forntoh commented Apr 3, 2026

Summary

  • Add RTTI-free extension hooks to core renderer/item APIs via MenuRenderer::queryExtension() and MenuItem::queryCapability().
  • Introduce optional extension interfaces for frame lifecycle and graphical context/capabilities (FrameLifecycleRenderer, GraphicalRendererContext, GraphicalMenuItem) without adding pixel-specific methods to base classes.
  • Wire frame lifecycle hooks into menu flow: MenuScreen::draw() calls beginFrame() and LcdMenu now calls endFrame() after handled draw-triggering actions (setScreen, show, refresh, handled process).
  • Add unit tests verifying frame flush behavior on refresh() and handled process() commands.
  • Document the extension model in rendering docs.

Verification

  • Attempted to run Arduino unit tests locally (bundle exec arduino_ci.rb --skip-examples-compilation), but local Ruby gem install requires privileged system paths on this machine.
  • Performed static diff review and kept PR scope to extension-core + unit tests + docs only.

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced an extension mechanism allowing renderers to expose optional capabilities and frame lifecycle hooks.
    • Added support for menu items to discover and expose renderer-compatible capabilities.
    • Enabled specialized renderers to participate in frame lifecycle management for optimized buffered drawing.
  • Documentation

    • Added documentation defining the extension mechanism and capability query approach for advanced renderers.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 3, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 9db2652c-ed33-48d7-a450-136934367cd4

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • ✅ Review completed - (🔄 Check again to review again)
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch gd/02-rtti-free-extension-core

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 3, 2026

Memory usage change @ b86a846

Board flash % RAM for global variables %
STMicroelectronics:stm32:GenF1:pnum=BLUEPILL_F103C8 🔺 +124 - +176 +0.19 - +0.27 0 - 0 0.0 - 0.0
arduino:avr:uno 🔺 +162 - +188 +0.5 - +0.58 🔺 +10 - +34 +0.49 - +1.66
arduino:samd:mkr1000 🔺 +132 - +180 +0.05 - +0.07 0 - 0 0.0 - 0.0
esp32:esp32:esp32 🔺 +176 - +232 +0.01 - +0.02 0 - 0 0.0 - 0.0
esp8266:esp8266:huzzah N/A N/A N/A N/A
Click for full report table
Board examples/Basic
flash
% examples/Basic
RAM for global variables
% examples/ButtonAdapter
flash
% examples/ButtonAdapter
RAM for global variables
% examples/Callbacks
flash
% examples/Callbacks
RAM for global variables
% examples/InputRotary
flash
% examples/InputRotary
RAM for global variables
% examples/IntFloatValues
flash
% examples/IntFloatValues
RAM for global variables
% examples/KeyboardAdapter
flash
% examples/KeyboardAdapter
RAM for global variables
% examples/List
flash
% examples/List
RAM for global variables
% examples/SimpleRotary
flash
% examples/SimpleRotary
RAM for global variables
% examples/SSD1803A_I2C
flash
% examples/SSD1803A_I2C
RAM for global variables
% examples/UseByRef
flash
% examples/UseByRef
RAM for global variables
% examples/DynamicMenu
flash
% examples/DynamicMenu
RAM for global variables
% examples/Widgets
flash
% examples/Widgets
RAM for global variables
% examples/RTOS
flash
% examples/RTOS
RAM for global variables
%
STMicroelectronics:stm32:GenF1:pnum=BLUEPILL_F103C8 124 0.19 0 0.0 128 0.2 0 0.0 128 0.2 0 0.0 160 0.24 0 0.0 144 0.22 0 0.0 128 0.2 0 0.0 144 0.22 0 0.0 152 0.23 0 0.0 124 0.19 0 0.0 176 0.27 0 0.0 156 0.24 0 0.0 136 0.21 0 0.0
arduino:avr:uno 162 0.5 10 0.49 162 0.5 12 0.59 164 0.51 12 0.59 188 0.58 16 0.78 172 0.53 20 0.98 164 0.51 12 0.59 170 0.53 18 0.88 172 0.53 22 1.07 162 0.5 10 0.49 186 0.58 34 1.66 188 0.58 14 0.68 170 0.53 18 0.88 168 0.52 16 0.78
arduino:samd:mkr1000 132 0.05 0 0.0 140 0.05 0 0.0 136 0.05 0 0.0 164 0.06 0 0.0 152 0.06 0 0.0 136 0.05 0 0.0 148 0.06 0 0.0 156 0.06 0 0.0 132 0.05 0 0.0 180 0.07 0 0.0 156 0.06 0 0.0 148 0.06 0 0.0
esp32:esp32:esp32 184 0.01 0 0.0 180 0.01 0 0.0 180 0.01 0 0.0 204 0.02 0 0.0 200 0.02 0 0.0 176 0.01 0 0.0 216 0.02 0 0.0 208 0.02 0 0.0 184 0.01 0 0.0 232 0.02 0 0.0 212 0.02 0 0.0 204 0.02 0 0.0 196 0.01 0 0.0
esp8266:esp8266:huzzah N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A
Click for full report CSV
Board,examples/Basic<br>flash,%,examples/Basic<br>RAM for global variables,%,examples/ButtonAdapter<br>flash,%,examples/ButtonAdapter<br>RAM for global variables,%,examples/Callbacks<br>flash,%,examples/Callbacks<br>RAM for global variables,%,examples/InputRotary<br>flash,%,examples/InputRotary<br>RAM for global variables,%,examples/IntFloatValues<br>flash,%,examples/IntFloatValues<br>RAM for global variables,%,examples/KeyboardAdapter<br>flash,%,examples/KeyboardAdapter<br>RAM for global variables,%,examples/List<br>flash,%,examples/List<br>RAM for global variables,%,examples/SimpleRotary<br>flash,%,examples/SimpleRotary<br>RAM for global variables,%,examples/SSD1803A_I2C<br>flash,%,examples/SSD1803A_I2C<br>RAM for global variables,%,examples/UseByRef<br>flash,%,examples/UseByRef<br>RAM for global variables,%,examples/DynamicMenu<br>flash,%,examples/DynamicMenu<br>RAM for global variables,%,examples/Widgets<br>flash,%,examples/Widgets<br>RAM for global variables,%,examples/RTOS<br>flash,%,examples/RTOS<br>RAM for global variables,%
STMicroelectronics:stm32:GenF1:pnum=BLUEPILL_F103C8,124,0.19,0,0.0,128,0.2,0,0.0,128,0.2,0,0.0,160,0.24,0,0.0,144,0.22,0,0.0,128,0.2,0,0.0,144,0.22,0,0.0,152,0.23,0,0.0,124,0.19,0,0.0,176,0.27,0,0.0,156,0.24,0,0.0,136,0.21,0,0.0
arduino:avr:uno,162,0.5,10,0.49,162,0.5,12,0.59,164,0.51,12,0.59,188,0.58,16,0.78,172,0.53,20,0.98,164,0.51,12,0.59,170,0.53,18,0.88,172,0.53,22,1.07,162,0.5,10,0.49,186,0.58,34,1.66,188,0.58,14,0.68,170,0.53,18,0.88,168,0.52,16,0.78
arduino:samd:mkr1000,132,0.05,0,0.0,140,0.05,0,0.0,136,0.05,0,0.0,164,0.06,0,0.0,152,0.06,0,0.0,136,0.05,0,0.0,148,0.06,0,0.0,156,0.06,0,0.0,132,0.05,0,0.0,180,0.07,0,0.0,156,0.06,0,0.0,148,0.06,0,0.0,,,,
esp32:esp32:esp32,184,0.01,0,0.0,180,0.01,0,0.0,180,0.01,0,0.0,204,0.02,0,0.0,200,0.02,0,0.0,176,0.01,0,0.0,216,0.02,0,0.0,208,0.02,0,0.0,184,0.01,0,0.0,232,0.02,0,0.0,212,0.02,0,0.0,204,0.02,0,0.0,196,0.01,0,0.0
esp8266:esp8266:huzzah,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,,,,

@coderabbitai coderabbitai Bot added documentation Improvements or additions to documentation feature New feature labels Apr 23, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/LcdMenu.cpp (1)

100-105: ⚠️ Potential issue | 🟡 Minor

Consider endFrame() after poll() when a polled item redrew.

MenuScreen::poll calls item->draw(renderer) for polling items, but LcdMenu::poll never invokes endFrame(). For buffered renderers, polled updates will accumulate in the frame buffer and never be flushed until the next user event. If this is intentional (relying on the next event to flush), please add a comment; otherwise wire endFrame() here as well, guarded by whether any polled draw actually occurred.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/LcdMenu.cpp` around lines 100 - 105, MenuScreen::poll can redraw polled
items but LcdMenu::poll never flushes those draws; make polled updates call
endFrame() when any draw occurred. Update MenuScreen::poll to return a bool (or
add a MenuScreen::didPollRedraw() accessor) indicating whether any
item->draw(renderer) ran, then in LcdMenu::poll after screen->poll(...) call
renderer.endFrame() (or LcdMenu::endFrame()) only when that flag is true; if you
intentionally rely on next user event to flush, add a clear comment above
LcdMenu::poll explaining that behavior instead.
src/MenuScreen.cpp (1)

64-78: ⚠️ Potential issue | 🟡 Minor

Document the begin/end-frame pairing contract.

MenuScreen::draw is invoked from many paths (setCursor, up, down, reset, RIGHT/LEFT view-shift inside process, empty-items fallback). Each call emits beginFrame(), while LcdMenu only emits a single endFrame() per lifecycle event. As a result, within one user action beginFrame can fire multiple times before endFrame — e.g., process(RIGHT)draw() → later LcdMenu::processendFrame().

This is fine if implementers treat beginFrame as "(re)initialize buffer" (which is typical), but the interface doesn't state it. Please document that implementers must tolerate repeated beginFrame calls without an intervening endFrame, or adjust the call sites to ensure strict pairing.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/MenuScreen.cpp` around lines 64 - 78, MenuScreen::draw currently calls
FrameLifecycleRenderer::beginFrame() on every invocation which can occur
multiple times per user action before a single endFrame() (seen in
LcdMenu::process); to fix either (a) document the lifecycle contract on the
FrameLifecycleRenderer interface/class (add a comment on beginFrame/endFrame
stating beginFrame may be called repeatedly without an intervening endFrame and
implementers must tolerate idempotent/reentrant beginFrame behavior) or (b)
change call sites to enforce strict pairing by adding a frame-active check (add
or use an isFrameActive()/hasBegunFrame() flag on FrameLifecycleRenderer and
only call beginFrame() in MenuScreen::draw when a frame is not already active),
referencing MenuScreen::draw, FrameLifecycleRenderer::beginFrame,
FrameLifecycleRenderer::endFrame and LcdMenu::process so reviewers can find the
affected code.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/LcdMenu.cpp`:
- Around line 30-45: The current LcdMenu::process calls frame->endFrame()
whenever handled is true, which can call endFrame without a matching beginFrame
and double-flush when screen transitions occur; change the logic so endFrame is
only invoked when a frame was actually begun or drawn: either (A) track a "frame
dirty/active" flag set by FrameLifecycleRenderer::beginFrame (or by
MenuScreen::beginFrame) and clear it in endFrame, and in LcdMenu::process only
call frame->endFrame() if that flag is set, or (B) move the beginFrame/endFrame
pairing into MenuScreen::draw (have MenuScreen::draw call beginFrame then do
drawing then call endFrame) and remove per-event endFrame calls from LcdMenu
methods (setScreen, show, refresh, process) so only draw paths perform the
flush; update references to FrameLifecycleRenderer, LcdMenu::process,
MenuScreen::draw, LcdMenu::setScreen, show, and refresh accordingly.

In `@src/MenuItem.h`:
- Around line 87-95: Add a non-const overload of queryCapability on MenuItem to
mirror MenuRenderer::queryExtension so mutable capability interfaces are
reachable; declare virtual void* queryCapability(uint8_t capabilityId) { /*
default returns NULL */ } and implement it to forward to the const variant (or
vice‑versa) while preserving the existing default behavior (return NULL) so
callers with non-const MenuItem pointers can obtain mutable capability pointers.

---

Outside diff comments:
In `@src/LcdMenu.cpp`:
- Around line 100-105: MenuScreen::poll can redraw polled items but
LcdMenu::poll never flushes those draws; make polled updates call endFrame()
when any draw occurred. Update MenuScreen::poll to return a bool (or add a
MenuScreen::didPollRedraw() accessor) indicating whether any
item->draw(renderer) ran, then in LcdMenu::poll after screen->poll(...) call
renderer.endFrame() (or LcdMenu::endFrame()) only when that flag is true; if you
intentionally rely on next user event to flush, add a clear comment above
LcdMenu::poll explaining that behavior instead.

In `@src/MenuScreen.cpp`:
- Around line 64-78: MenuScreen::draw currently calls
FrameLifecycleRenderer::beginFrame() on every invocation which can occur
multiple times per user action before a single endFrame() (seen in
LcdMenu::process); to fix either (a) document the lifecycle contract on the
FrameLifecycleRenderer interface/class (add a comment on beginFrame/endFrame
stating beginFrame may be called repeatedly without an intervening endFrame and
implementers must tolerate idempotent/reentrant beginFrame behavior) or (b)
change call sites to enforce strict pairing by adding a frame-active check (add
or use an isFrameActive()/hasBegunFrame() flag on FrameLifecycleRenderer and
only call beginFrame() in MenuScreen::draw when a frame is not already active),
referencing MenuScreen::draw, FrameLifecycleRenderer::beginFrame,
FrameLifecycleRenderer::endFrame and LcdMenu::process so reviewers can find the
affected code.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 53660bf8-9bb7-420f-9f2d-9faf4e3ded31

📥 Commits

Reviewing files that changed from the base of the PR and between 7b2219b and b86a846.

📒 Files selected for processing (9)
  • docs/source/overview/rendering/index.rst
  • src/LcdMenu.cpp
  • src/MenuItem.h
  • src/MenuScreen.cpp
  • src/renderer/FrameLifecycleRenderer.h
  • src/renderer/GraphicalMenuItem.h
  • src/renderer/GraphicalRendererContext.h
  • src/renderer/MenuRenderer.h
  • test/LcdMenu.cpp

Comment thread src/LcdMenu.cpp
Comment thread src/MenuItem.h
coderabbitai[bot]
coderabbitai Bot previously approved these changes Apr 23, 2026
@github-actions
Copy link
Copy Markdown
Contributor

Memory usage change @ 7ed981f

Board flash % RAM for global variables %
STMicroelectronics:stm32:GenF1:pnum=BLUEPILL_F103C8 🔺 +108 - +208 +0.16 - +0.32 0 - 0 0.0 - 0.0
arduino:avr:uno 🔺 +126 - +210 +0.39 - +0.65 🔺 +10 - +34 +0.49 - +1.66
arduino:samd:mkr1000 🔺 +100 - +188 +0.04 - +0.07 0 - 0 0.0 - 0.0
esp32:esp32:esp32 🔺 +132 - +200 +0.01 - +0.02 0 - 0 0.0 - 0.0
esp8266:esp8266:huzzah N/A N/A N/A N/A
Click for full report table
Board examples/Basic
flash
% examples/Basic
RAM for global variables
% examples/ButtonAdapter
flash
% examples/ButtonAdapter
RAM for global variables
% examples/Callbacks
flash
% examples/Callbacks
RAM for global variables
% examples/InputRotary
flash
% examples/InputRotary
RAM for global variables
% examples/IntFloatValues
flash
% examples/IntFloatValues
RAM for global variables
% examples/KeyboardAdapter
flash
% examples/KeyboardAdapter
RAM for global variables
% examples/List
flash
% examples/List
RAM for global variables
% examples/SimpleRotary
flash
% examples/SimpleRotary
RAM for global variables
% examples/SSD1803A_I2C
flash
% examples/SSD1803A_I2C
RAM for global variables
% examples/UseByRef
flash
% examples/UseByRef
RAM for global variables
% examples/DynamicMenu
flash
% examples/DynamicMenu
RAM for global variables
% examples/Widgets
flash
% examples/Widgets
RAM for global variables
% examples/RTOS
flash
% examples/RTOS
RAM for global variables
%
STMicroelectronics:stm32:GenF1:pnum=BLUEPILL_F103C8 108 0.16 0 0.0 112 0.17 0 0.0 112 0.17 0 0.0 120 0.18 0 0.0 128 0.2 0 0.0 112 0.17 0 0.0 128 0.2 0 0.0 136 0.21 0 0.0 108 0.16 0 0.0 208 0.32 0 0.0 116 0.18 0 0.0 120 0.18 0 0.0
arduino:avr:uno 126 0.39 10 0.49 128 0.4 12 0.59 128 0.4 12 0.59 132 0.41 16 0.78 136 0.42 20 0.98 128 0.4 12 0.59 134 0.42 18 0.88 138 0.43 22 1.07 126 0.39 10 0.49 202 0.63 34 1.66 130 0.4 14 0.68 134 0.42 18 0.88 210 0.65 16 0.78
arduino:samd:mkr1000 100 0.04 0 0.0 104 0.04 0 0.0 104 0.04 0 0.0 112 0.04 0 0.0 120 0.05 0 0.0 104 0.04 0 0.0 116 0.04 0 0.0 124 0.05 0 0.0 100 0.04 0 0.0 188 0.07 0 0.0 104 0.04 0 0.0 116 0.04 0 0.0
esp32:esp32:esp32 132 0.01 0 0.0 136 0.01 0 0.0 136 0.01 0 0.0 132 0.01 0 0.0 156 0.01 0 0.0 136 0.01 0 0.0 136 0.01 0 0.0 148 0.01 0 0.0 132 0.01 0 0.0 200 0.02 0 0.0 132 0.01 0 0.0 136 0.01 0 0.0 164 0.01 0 0.0
esp8266:esp8266:huzzah N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A
Click for full report CSV
Board,examples/Basic<br>flash,%,examples/Basic<br>RAM for global variables,%,examples/ButtonAdapter<br>flash,%,examples/ButtonAdapter<br>RAM for global variables,%,examples/Callbacks<br>flash,%,examples/Callbacks<br>RAM for global variables,%,examples/InputRotary<br>flash,%,examples/InputRotary<br>RAM for global variables,%,examples/IntFloatValues<br>flash,%,examples/IntFloatValues<br>RAM for global variables,%,examples/KeyboardAdapter<br>flash,%,examples/KeyboardAdapter<br>RAM for global variables,%,examples/List<br>flash,%,examples/List<br>RAM for global variables,%,examples/SimpleRotary<br>flash,%,examples/SimpleRotary<br>RAM for global variables,%,examples/SSD1803A_I2C<br>flash,%,examples/SSD1803A_I2C<br>RAM for global variables,%,examples/UseByRef<br>flash,%,examples/UseByRef<br>RAM for global variables,%,examples/DynamicMenu<br>flash,%,examples/DynamicMenu<br>RAM for global variables,%,examples/Widgets<br>flash,%,examples/Widgets<br>RAM for global variables,%,examples/RTOS<br>flash,%,examples/RTOS<br>RAM for global variables,%
STMicroelectronics:stm32:GenF1:pnum=BLUEPILL_F103C8,108,0.16,0,0.0,112,0.17,0,0.0,112,0.17,0,0.0,120,0.18,0,0.0,128,0.2,0,0.0,112,0.17,0,0.0,128,0.2,0,0.0,136,0.21,0,0.0,108,0.16,0,0.0,208,0.32,0,0.0,116,0.18,0,0.0,120,0.18,0,0.0
arduino:avr:uno,126,0.39,10,0.49,128,0.4,12,0.59,128,0.4,12,0.59,132,0.41,16,0.78,136,0.42,20,0.98,128,0.4,12,0.59,134,0.42,18,0.88,138,0.43,22,1.07,126,0.39,10,0.49,202,0.63,34,1.66,130,0.4,14,0.68,134,0.42,18,0.88,210,0.65,16,0.78
arduino:samd:mkr1000,100,0.04,0,0.0,104,0.04,0,0.0,104,0.04,0,0.0,112,0.04,0,0.0,120,0.05,0,0.0,104,0.04,0,0.0,116,0.04,0,0.0,124,0.05,0,0.0,100,0.04,0,0.0,188,0.07,0,0.0,104,0.04,0,0.0,116,0.04,0,0.0,,,,
esp32:esp32:esp32,132,0.01,0,0.0,136,0.01,0,0.0,136,0.01,0,0.0,132,0.01,0,0.0,156,0.01,0,0.0,136,0.01,0,0.0,136,0.01,0,0.0,148,0.01,0,0.0,132,0.01,0,0.0,200,0.02,0,0.0,132,0.01,0,0.0,136,0.01,0,0.0,164,0.01,0,0.0
esp8266:esp8266:huzzah,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,,,,

@forntoh forntoh merged commit 195dcdf into feat/graphical-display Apr 23, 2026
13 of 17 checks passed
@forntoh forntoh deleted the gd/02-rtti-free-extension-core branch April 23, 2026 20:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation feature New feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant