Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,7 @@ Fall back to `Bash`/`Grep`/`Read` only when the MCP tool reports an error or the

## Asking blind-mouse

Before doing significant research on a "how do I X?" / "what's the pattern for Y?" / "why does Z behave this way?" question, ask `mouse__ask`. blind-mouse (`utils/mouse/`) is a personal Q&A cache backed by curated `.md` answers — full vision in `utils/mouse/OVERVIEW.md`. Same deferred-tool dance as the daslang MCP: `ToolSearch select:mcp__mouse__<tool>` → invoke.

**During plan mode / planning phase, ask the mouse early and often.** Planning is exactly the phase where prior-session research has the highest leverage: each "what's the pattern for X" / "where do we usually put Y" / "why did we pick Z" answer that's already in the cache saves a research detour, and each new finding worth keeping is one `mouse__add` away from being free next time. Concrete planning-phase prompts: design questions ("what's the right pattern for adding a new `[sql_*]` annotation?"), prior-art questions ("have we hit this glob-vs-rfind path bug before?"), gotcha-recall ("what's the const-stripping reinterpret incantation?"), trade-off recall ("why did we pick (a) over (b) last time?"). If the cache has nothing useful, do the research yourself — then `mouse__add` the answer before moving on, even if rough. The cost of writing a brief `.md` is far smaller than re-researching the same thing.
Before doing significant research on a "how do I X?" / "what's the pattern for Y?" / "why does Z behave this way?" question, ask `mouse__ask`. blind-mouse (`utils/mouse/`) is a personal Q&A cache backed by curated `.md` answers. Operational manual: `skills/mouse.md`. Design vision: `utils/mouse/OVERVIEW.md`.

| Reach for the mouse when… | Don't, when… |
|---|---|
Expand All @@ -48,8 +46,6 @@ Before doing significant research on a "how do I X?" / "what's the pattern for Y
| Discovered facts that don't fit any `skills/*.md` slot | project state, branch status, who's doing what — use git/issues/memory |
| Recurring questions you remember answering before but forget the answer | |

If `mouse__ask` returns nothing relevant and you do the research yourself, finish with `mouse__add` so the next session doesn't redo the work. If a returned answer is stale or wrong, edit the `.md` directly under `mouse-data/docs/` (it's a regular file, `Edit` works) and bump `last_verified`.

## Skill Files (REQUIRED)

Task-specific instructions are split into skill files under `skills/`. You MUST read the relevant skill file(s) before performing the corresponding task.
Expand All @@ -59,6 +55,7 @@ Task-specific instructions are split into skill files under `skills/`. You MUST
| `skills/project_overview.md` | First significant task — design philosophy, three execution tiers, macros-as-design-lens |
| `skills/build_and_debug.md` | Build flags, AOT build commands, exit-code/crash diagnosis, `options log_infer_passes` |
| `skills/mcp_tools.md` | Full MCP tool table + live-API reference |
| `skills/mouse.md` | Asking, adding, or curating blind-mouse cards (`mouse__ask` / `mouse__add`) — operational manual behind the MOUSE FIRST rule |
| `skills/das_formatting.md` | Creating or modifying any `.das` file |
| `skills/writing_tests.md` | Writing or editing test files under `tests/` |
| `skills/writing_cpp_tests.md` | Writing or editing C++ tests under `tests-cpp/` (doctest, leak guards, ctest wiring) |
Expand Down
4 changes: 2 additions & 2 deletions daslib/delegate.das
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def private build_invoke_call(at : LineInfo; var targetExpr : ExpressionPtr; fun

// ── template: non-void return ──────────────────────────────────────────

struct template DelegateReturn {
struct template public DelegateReturn {
private invocation_list : array<DelegateLambda>

def DelegateReturn {}
Expand Down Expand Up @@ -122,7 +122,7 @@ struct template DelegateReturn {

// ── template: void return ──────────────────────────────────────────────

struct template DelegateVoid {
struct template public DelegateVoid {
private invocation_list : array<DelegateLambda>

def DelegateVoid {}
Expand Down
10 changes: 10 additions & 0 deletions install/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ Task-specific instructions are in skill files under `skills/`. Read the relevant
|---|---|
| `skills/project_overview.md` | First significant task — design philosophy, three execution tiers, macros-as-design-lens |
| `skills/mcp_tools.md` | Full MCP tool table + live-API reference |
| `skills/mouse.md` | Asking, adding, or curating blind-mouse cards (`mouse__ask` / `mouse__add`) — operational manual for the personal Q&A cache |
| `skills/das_formatting.md` | Creating or modifying any `.das` file |
| `skills/cpp_integration.md` | Embedding daslang in C++; binding types/functions/enums |
| `skills/daslib_modules.md` | Using `daslib/` modules (linq, json, regex, etc.) |
Expand Down Expand Up @@ -244,6 +245,7 @@ For path/filename ops use `fio` helpers (`base_name`/`dir_name`/`path_join`/etc.
- `tutorials/` — Language, integration, and module tutorials
- `dastest/` — Test framework (usable for testing your own code)
- `utils/mcp/` — MCP server for AI coding assistants (stdio transport, no extra deps)
- `utils/mouse/` — Personal Q&A cache MCP server (BM25 + Jaccard retrieval over a per-project `mouse-data/docs/` corpus)
- `utils/detect-dupe/` — Cross-file duplicate-function detector (also exposed via the `export_corpus` and `detect_duplicates` MCP tools)
- `utils/daspkg/` — Package manager
- `utils/dascov/` — Code coverage tool
Expand All @@ -268,3 +270,11 @@ See `skills/daspkg.md` for `.das_package` manifest format and package structure.
`utils/mcp/` contains a [Model Context Protocol](https://modelcontextprotocol.io/) server that exposes compiler diagnostics and program introspection to AI coding assistants. Stdio transport — no extra build dependencies. **Prefer MCP tools** over manual compilation and grep — `grep_usage` is parse-aware (tree-sitter), `find_references` resolves cross-module symbols, and `live_*` tools talk to `daslang-live` directly instead of curl.

Full tool table (including `detect_duplicates`/`judge_duplicates`/`find_dupe`), live-API caveats, and `.mcp.json` configuration: **`skills/mcp_tools.md`**.

## Personal Q&A Cache (blind-mouse)

`utils/mouse/` is a separate MCP server backing a per-project Q&A cache — `.md` cards under `mouse-data/docs/`, retrieved via BM25 + Jaccard ranking. Built for the long tail that doesn't fit the other channels: "how do I X?" / "what's the pattern for Y?" / "why does Z behave this way?" — discovered facts that don't belong in `skills/*.md` (categorical) or symbol-lookup tools (live).

Before researching such a question yourself, ask `mouse__ask` first. After answering one through your own research, `mouse__add` the answer so the next session doesn't redo the work.

Operational manual (asking, adding, frontmatter, dupe-on-add gate, edit flow, carve-outs): **`skills/mouse.md`**. Design vision and FTS5 internals: **`utils/mouse/OVERVIEW.md`**.
1 change: 1 addition & 0 deletions install/skills.list
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ json.md
linq.md
mcp_tools.md
memory_leak_detection.md
mouse.md
project_overview.md
regex.md
strudel_port.md
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
slug: dasimgui-container-annotation-and-hierarchical-path-keys
title: How does the dasImgui [container] annotation work — what's the difference from [widget] and how does the body get path-stack push/pop?
created: 2026-05-10
last_verified: 2026-05-10
links: []
---

`[container]` is a sibling function annotation to `[widget]` (Phase 0b.3, `modules/dasImgui/widgets/imgui_boost.das`). Same widget_ident injection, same dotted-flag parsing, same auto-emit gate. Two differences:

1. **Last param must be `blk : block`** — validated in `ContainerFunctionMacro.apply` (else compile-time error 'requires the last parameter to be `blk : block`').
2. **Body gets path-stack wraps**: `apply_widget_or_container(..., is_container=true)` prepends `container_path_push($i("widget_ident"))` to `body.list` and appends `container_path_pop()` to `body.finalList`. The pop is in finalList so it runs on normal scope exit (panic still skips it — same risk surface as widget_finalize).

The CallMacro is shared (`WidgetCallMacro`) — same `kind(IDENT, ...)` → `kind(IDENT_VAR, "IDENT", ...)` rewrite. The body wrapping is the only macro-side difference.

Runtime side (`imgui_boost_runtime.das`):
- `g_container_path : array<string>` — outermost-first chain of currently-open containers.
- `g_container_path_str : string` — cached "/"-joined form, kept in sync by push/pop so leaf path-key construction is one string interpolation, not an O(depth) per-leaf join.
- `widget_path_key(widget_ident)` — for leaves: `g_container_path_str + "/" + widget_ident` (or bare ident if path is empty).
- `container_path_key()` — for containers: just `g_container_path_str` (self already at the chain's tail, since the macro pushed in `body.list` before user body runs).
- Both leaf `widget_finalize` and the new `container_finalize` use these keys for `g_registry` AND `g_dispatchers`. Sibling `RPS` idents under different windows resolve as `MAIN/RPS` vs `OTHER/RPS` — collision-safe.

User-side calls follow the same named-tuple convention as `[widget]`:
```das
window(MAIN_WIN, (text="Main", closable=false, flags=ImGuiWindowFlags.None)) {
button(SAVE, (text="Save")) // registers under "MAIN_WIN/SAVE"
}
```

Container kind names that ship in 0b.3: window / child / group / menu_bar / menu / popup / popup_modal / tab_bar / tab_item / tooltip / item_tooltip / tree_node / collapsing_header / combo_select / list_box_select.

`begin_frame()` defensively clears `g_container_path` + `g_container_path_str` — a panic mid-frame the prior tick would otherwise leak the chain into the next frame.

## Questions
- How does the dasImgui [container] annotation work — what's the difference from [widget] and how does the body get path-stack push/pop?

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
slug: dasimgui-widget-state-struct-field-defaults-fire
title: Do dasImgui [widget] state struct field defaults fire on the auto-emitted module global?
created: 2026-05-10
last_verified: 2026-05-10
links: []
---

**Yes**, since dasImgui commit `111f7dc` on `bbatkin/dasimgui-widget-auto-init`. The `[widget]` macro now emits `var IDENT : T = T()` (via `ExprMakeStruct(useInitializer)` attached to the auto-emitted Variable's `init`) instead of the bare `var IDENT : T` it emitted previously. The state struct's default constructor runs, so source-declared field defaults take effect on the per-ident global.

Confirmed for: `int / float / bool` numeric defaults; vector struct-ctor defaults like `float3(0.5, 0.6, 0.7)`; string defaults like `caption : string = "default-label"`; enum value defaults like `mode : ImGuiButtonFlags = ImGuiButtonFlags.MouseButtonRight`. See `modules/dasImgui/tests/integration/test_widget_init_defaults.das` (the canonical e2e check) and `modules/dasImgui/examples/features/widget_init_defaults.das` (the feature it drives).

**Practical effect on existing 0b state structs** (commit `e3a7ff7` swept these post-fix):
- `InputTextState.capacity = 256` (the body's `if (state.capacity == 0) { state.capacity = 256 }` workaround is gone).
- `InputTextState.value = "" / pending_value = ""` — the `@safe_when_uninitialized` annotations are dropped; `= ""` does the same job.
- `ComboState.value = -1 / ListBoxState.value = -1` — first frame matches the "selected index, -1 = none" docstring (was zero-init = 0 = first item before the fix).
- `WindowState.open = true / TabItemState.open = true` — closable windows + tabs render from frame 1; X-button + `imgui_close` still flip false. `PopupState.open` intentionally stays false (popups stay closed until triggered).

**Rule of thumb when designing a `[widget]` state struct**, post-fix:
- Persistent `@live` values the user wants preserved across reloads → state, with whatever default makes the first frame correct.
- Zero-init that genuinely is the right starting state (slider/drag values, bounds when ImGui's `min==max=unclamped` semantics apply, all `pending_*`/`changed`/`has_pending` transient flags, `flags` fields where `None=0` is the natural default) → no default needed.
- String fields → either `= ""` default or `@safe_when_uninitialized`; the former is the common case.

**Behaviour changes vs pre-fix** (consequences of `e3a7ff7`):
- A combo or list_box with no per-frame `set_value` shows "no selection" on frame 1 instead of the first item.
- A closable window or closable tab is visible from frame 1 without explicit `STATE.open = true` in init.
- An InputText with no explicit capacity uses 256 bytes from frame 1 (was: same value, but reached via the body workaround).

## Questions
- Do dasImgui [widget] state struct field defaults fire on the auto-emitted module global?
34 changes: 34 additions & 0 deletions mouse-data/docs/daslang-block-last-arg-blocks-default-arg-fill.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
slug: daslang-block-last-arg-blocks-default-arg-fill
title: In daslang gen2, why do default args after a positional `; blk : block` not work with the block-as-last-arg sugar?
created: 2026-05-10
last_verified: 2026-05-10
links: []
---

**Pitfall confirmed 2026-05-10 (dasImgui Phase 0b.3).** A function with shape `def foo(a, b=def, c=def, blk : block)` called via the trailing-block sugar `foo(arg) <| ${body}` does **NOT** auto-fill the b/c defaults so blk lands at param position 3. Instead daslang's positional resolution goes left-to-right: arg 0=a, arg 1=BLOCK → mismatched against b's type. Compile error of the shape `invalid argument 'b' (1). expecting 'bool const', passing 'block<void> const'`.

**Why**: the block-as-last-arg sugar appends BLOCK at the trailing positional slot of the *call*, after macro expansion. Daslang then matches positionally to the function's params left-to-right. There's no "shift defaults backwards to align a trailing block" logic.

**Fixes** (in priority order):

1. **Drop the defaults — make all per-call config args required.** User specifies them all via the named-tuple. This is the convention dasImgui's 0b.3 [container] defs use:
```das
[container]
def window(var state : WindowState; text : string; closable : bool;
flags : ImGuiWindowFlags; blk : block) { ... }
// Caller:
window(MAIN, (text="Main", closable=false, flags=ImGuiWindowFlags.None)) { ... }
```
The CallMacro destructures the named-tuple positionally (per `dasimgui-widget-named-tuple-args-positional-not-named`), so the call ends up `window(state, "MAIN", "Main", false, None) <| BLOCK` → 6 args total → matches the 6-param signature.

2. **Move "optional" config to state struct fields**, function takes only required args. User sets `MY_WIN.flags = ...` once in init, function reads `state.flags`. Loses ergonomics for one-shot configs.

3. **Two function definitions with different arities** — does NOT work for `[widget]`/`[container]`: the macro registers a CallMacro under the kind name once, and a duplicate registration panics in `add_call_macro` (C++ side).

4. **ExprNamedCall emission from the macro** — could let daslang's named-arg dispatch handle defaults. Confirmed unused in dasImgui (Boris explicitly preferred named-tuple); not the right tool here.

**`[widget]` (no block)** is unaffected — defaults at the end fill normally because there's no block to displace them. Only `[container]` (block-required) hits this.

## Questions
- In daslang gen2, why do default args after a positional `; blk : block` not work with the block-as-last-arg sugar?
Loading
Loading