|
| 1 | +# Closure Cursor Bar - Deferred Ideas |
| 2 | + |
| 3 | +## Collapsing Recursive Runs |
| 4 | + |
| 5 | +**Concept:** When you have a run of recursive function applications (e.g., `map` called repeatedly), collapse them into something like `map ↻5` with a count. |
| 6 | + |
| 7 | +**Considerations:** |
| 8 | +- For built-in HOFs (map, fold, filter): Makes more sense since intermediate calls are structurally identical |
| 9 | +- For general recursion: Trickier - different recursive calls might represent different states/arguments |
| 10 | +- UX question: What does clicking a collapsed run do? Which call do you jump to? |
| 11 | + - Name click → outer call site (the actual calling of the function, not inner recursive calls) |
| 12 | + - Number/arrow click → expand to show all? |
| 13 | +- Could be a toggleable option, perhaps off by default |
| 14 | +- The inner recursive calls don't correspond to the same application site |
| 15 | + |
| 16 | +**Status:** Holding off. Current display with blue color + 0.7 opacity already visually subordinates ghost entries. Revisit if deep recursive stacks prove cluttered in practice. |
| 17 | + |
| 18 | +--- |
| 19 | + |
| 20 | +## Ghost Entry Toggle |
| 21 | + |
| 22 | +**Concept:** Double chevron (`❯❯`) before first ghost entry that toggles visibility of ghost entries. |
| 23 | + |
| 24 | +**What we tried:** |
| 25 | +- Double chevron replacing the separator before first ghost entry |
| 26 | +- Clicking it would: jump to location + set index + toggle visibility |
| 27 | + |
| 28 | +**Why we removed it:** |
| 29 | +- Conflicting behaviors on single click (navigate vs toggle) |
| 30 | +- Modifier key (shift+click) felt awkward |
| 31 | +- Separate toggle button added clutter |
| 32 | + |
| 33 | +**Current state:** Double chevron visual indicator disabled. Ghost entries always shown with 0.7 opacity + blue color coding. |
| 34 | + |
| 35 | +**Status:** Removed for now. Could revisit with a cleaner interaction model if needed. |
| 36 | + |
| 37 | +--- |
| 38 | + |
| 39 | +## Indicated Entry Highlighting (Red Outline) |
| 40 | + |
| 41 | +**Concept:** Show a red outline/border on a breadcrumb entry when the editor cursor is "related" to that function call - similar to how indicated samples get a red border. |
| 42 | + |
| 43 | +### Option 1: Cursor on the app expression |
| 44 | +- Check if `indicated_id == app_id` |
| 45 | +- **Difficulty: Easy** - we already have `app_id` for each entry, just need to pass `indicated_id` to the view function |
| 46 | + |
| 47 | +### Option 2: Cursor on the function name/variable |
| 48 | +- Check if `indicated_id == fn_id` (the ID of the function expression in the app) |
| 49 | +- **Difficulty: Easy** - we already extract `fn_id` in `get_fn_info` |
| 50 | + |
| 51 | +### Option 3: Cursor inside the function body |
| 52 | +- Get the binding site of the function via `Info.get_binding_site` |
| 53 | +- Check if `indicated_id` is a descendant/contained within that body |
| 54 | +- **Difficulty: Medium** - needs parent traversal or containment check |
| 55 | +- Note: There may already be helpers for this - auto-probe mechanism likely uses something similar. Check `ProbePerform.re` or related files for existing "is inside function" helpers. May want to extract to a shared helper location. |
| 56 | + |
| 57 | +### Option 4: Cursor inside lexical extent of the let binding |
| 58 | +- Similar to #3 but includes the pattern side too |
| 59 | +- **Difficulty: Medium** - same containment check approach |
| 60 | + |
| 61 | +### Implementation Notes: |
| 62 | +- `Indicated.piece(zipper)` or similar gives the indicated ID |
| 63 | +- For #3-4, look for existing helpers in auto-probe code before writing new ones |
| 64 | +- Could start with #1 (easiest) and expand later |
| 65 | + |
| 66 | +**Status:** Option 1 implemented. Options 2-4 deferred. |
| 67 | + |
| 68 | +--- |
| 69 | + |
| 70 | +## Separator Click / Sample Indication Sync (TODO - Investigate) |
| 71 | + |
| 72 | +**Observed issue:** When clicking a separator in the closure cursor bar, the breadcrumb entry gets the red "indicated" outline (because the syntax cursor moves to the app_id), but the corresponding **sample** in the probe doesn't get indicated. |
| 73 | + |
| 74 | +**Possible cause:** Sample indication is tied to `indicated_call` in `sample_cursor`, which only gets set when clicking directly on a sample (via `Capture` action). Clicking the separator only calls `SetIndex` + `jump_to` - it doesn't set `indicated_call`. |
| 75 | + |
| 76 | +**Possible off-by-one aspect:** The sample cursor index might be at a different depth than expected, causing the "wrong" sample to appear indicated (or none at all). |
| 77 | + |
| 78 | +**To investigate:** |
| 79 | +- How does `indicated_call` interact with sample display? |
| 80 | +- Should separator clicks set `indicated_call`? |
| 81 | +- Is there an index mismatch between breadcrumb position and sample filtering? |
| 82 | + |
| 83 | +**Status:** Needs investigation. Noted late at night when too tired to fully diagnose. |
| 84 | + |
| 85 | +--- |
| 86 | + |
| 87 | +## Dropdown Menus Showing Branching Paths |
| 88 | + |
| 89 | +**Concept:** Dropdown menus on breadcrumb entries that show different call paths from the sample data. |
| 90 | + |
| 91 | +### Example |
| 92 | +``` |
| 93 | +let double = fun x -> x * 2 |
| 94 | +let process = fun y -> double(y) + double(y + 1) |
| 95 | +process(5) |
| 96 | +``` |
| 97 | + |
| 98 | +Call stacks from samples inside `double`: |
| 99 | +- `[process_app, double_app_1]` → first call, `double(5)` |
| 100 | +- `[process_app, double_app_2]` → second call, `double(6)` |
| 101 | + |
| 102 | +Dropdown on `double` entry could show: |
| 103 | +``` |
| 104 | +┌─────────────┐ |
| 105 | +│ double(5) │ ← from first call site |
| 106 | +│ double(6) │ ← from second call site |
| 107 | +└─────────────┘ |
| 108 | +``` |
| 109 | + |
| 110 | +### For map/fold iterations |
| 111 | +``` |
| 112 | +map(fun x -> x + 1, [1, 2, 3]) |
| 113 | +``` |
| 114 | + |
| 115 | +Dropdown could show iteration index or input value: |
| 116 | +``` |
| 117 | +┌───────────┐ |
| 118 | +│ map @ [1] │ |
| 119 | +│ map @ [2] │ |
| 120 | +│ map @ [3] │ |
| 121 | +└───────────┘ |
| 122 | +``` |
| 123 | + |
| 124 | +### Tree Structure Observation |
| 125 | +All sample call stacks form a tree - they share common prefixes. The closure cursor bar shows one **path** through this tree. Dropdowns would show **siblings** at each node. |
| 126 | + |
| 127 | +### Data Source |
| 128 | +- Use all collected samples from evaluation |
| 129 | +- Each sample has call_stack, step_start, step_end (temporal ordering) |
| 130 | +- The step ranges give partial order on expression evaluation durations |
| 131 | + |
| 132 | +**Limitations:** |
| 133 | +- Works well when there are distinct, meaningful branches |
| 134 | +- For deep recursion with many similar calls, could get unwieldy |
| 135 | +- Best for: small numbers of distinct call sites, built-in HOFs where iteration context is meaningful |
| 136 | + |
| 137 | +**Status:** Deferred. Explore if dropdown navigation proves useful for debugging workflows. |
| 138 | + |
| 139 | +--- |
| 140 | + |
| 141 | +## Investigation Breadcrumbs / Backtracking Debugging |
| 142 | + |
| 143 | +**Concept:** A debugging history system separate from the call stack, allowing you to mark "investigation points" and backtrack when pursuing one path doesn't pan out. |
| 144 | + |
| 145 | +### Motivation |
| 146 | +When debugging, you often: |
| 147 | +1. Trace down through function calls following a wrong value |
| 148 | +2. Find an expression that's giving the wrong result |
| 149 | +3. That expression might have multiple variable references - each potentially the bug source |
| 150 | +4. You want to pursue one, and if it doesn't pan out, backtrack and try another |
| 151 | + |
| 152 | +### Example |
| 153 | +``` |
| 154 | +let a = 5 |
| 155 | +let b = 10 |
| 156 | +let c = a + b // result is 15, but expected 20 |
| 157 | +``` |
| 158 | + |
| 159 | +Debugging flow: |
| 160 | +1. Mark `a + b` as an "investigation point" |
| 161 | +2. Pursue `a` → trace back, see it's 5, looks fine |
| 162 | +3. **Backtrack** to investigation point |
| 163 | +4. Pursue `b` → trace back, find the bug |
| 164 | + |
| 165 | +### Conceptual Model |
| 166 | +An "investigation stack" separate from call stack: |
| 167 | +``` |
| 168 | +Investigation Stack: |
| 169 | +├─ [1] a + b at line 3 (problem is in dynamic extent of this) |
| 170 | +│ ├─ [1.1] pursuing `a` → checked, looks fine |
| 171 | +│ └─ [1.2] pursuing `b` → (current investigation) |
| 172 | +``` |
| 173 | + |
| 174 | +### Key Distinction from Current Pin |
| 175 | +- Pin filters which samples are shown |
| 176 | +- Investigation breadcrumbs track **your debugging path** (where you've looked), not just the **program's call path** (what executed) |
| 177 | + |
| 178 | +### Possible UI |
| 179 | +- Mark expressions as "investigation points" (separate from pin) |
| 180 | +- Small panel or dropdown showing investigation history |
| 181 | +- Keyboard shortcuts: mark point, go back, go forward |
| 182 | +- Closure cursor bar indicator if you're "inside" an investigation |
| 183 | + |
| 184 | +### Related Concept: Multiple Pins |
| 185 | +Could also be implemented as multiple pins with a stack/tree structure, rather than just one pin. |
| 186 | + |
| 187 | +**Status:** Deferred. This is a more general debugging workflow enhancement. Could be valuable for complex debugging scenarios. |
| 188 | + |
| 189 | +--- |
| 190 | + |
| 191 | +## Keyboard Navigation |
| 192 | + |
| 193 | +**Concept:** Navigate the closure cursor bar with keyboard. |
| 194 | + |
| 195 | +### MVP (Implemented) |
| 196 | +- Left/Right arrow keys to move between breadcrumb entries |
| 197 | +- Enter to jump to the current entry's definition (then refocuses main editor) |
| 198 | + |
| 199 | +### Focus Shortcut (TODO) |
| 200 | +Need a keyboard shortcut to focus the closure cursor bar from the main editor. |
| 201 | + |
| 202 | +**Candidate shortcuts:** |
| 203 | +- `Ctrl+;` - ergonomic, usually unbound |
| 204 | +- `Ctrl+Shift+K` - mnemonic for "call stacK" |
| 205 | +- `Ctrl+Shift+D` - mnemonic for "Dynamic cursor" |
| 206 | + |
| 207 | +**TODO:** Check with team on preferred shortcut to avoid conflicts with existing bindings. |
| 208 | + |
| 209 | +### Extension: Dropdown Navigation |
| 210 | +- Down arrow opens a dropdown showing function applications within the current function body |
| 211 | +- Could show applications that are lexically inside the function definition |
| 212 | +- Selecting one would jump to it (and possibly add a probe if needed) |
| 213 | +- This would allow keyboard-based navigation through the entire call structure |
| 214 | + |
| 215 | +### Data Source Questions |
| 216 | +- Should dropdowns be populated from dynamics (what actually executed) or lexically (what apps exist in the function body)? |
| 217 | +- Lexical: Always shows all possible calls, even if not executed this run |
| 218 | +- Dynamic: Only shows calls that actually happened, with sample data |
| 219 | +- Could be a combination: lexical structure, annotated with dynamic info |
| 220 | + |
| 221 | +**Status:** MVP implemented. Focus shortcut pending. Dropdown extension deferred. |
| 222 | + |
| 223 | +--- |
| 224 | + |
| 225 | +## Bidirectional Hover Highlighting |
| 226 | + |
| 227 | +**Concept:** Highlight matching elements when hovering. |
| 228 | + |
| 229 | +### Breadcrumb → Sample |
| 230 | +When hovering a breadcrumb entry, highlight the corresponding sample(s) in probes. |
| 231 | + |
| 232 | +### Sample → Breadcrumb |
| 233 | +When hovering a sample in a probe, highlight the matching breadcrumb entry. |
| 234 | + |
| 235 | +### Implementation Thoughts |
| 236 | +- Would likely need a `hover_cursor` field separate from the committed `sample_cursor` |
| 237 | +- Both probes and closure cursor bar would check this for highlighting |
| 238 | +- Similar infrastructure to indicated highlighting, but triggered by hover instead of syntax cursor |
| 239 | + |
| 240 | +**Status:** Deferred. Useful for understanding correspondence between bar and samples. |
| 241 | + |
| 242 | +--- |
| 243 | + |
| 244 | +## Argument Values in Tooltips |
| 245 | + |
| 246 | +**Concept:** Show argument values in breadcrumb tooltips, e.g., `map([1,2,3])` instead of just `map`. |
| 247 | + |
| 248 | +### Implementation Challenges |
| 249 | +- Need to probe the argument expressions to capture their values |
| 250 | +- Would require adding app argument IDs to sample targets before evaluation |
| 251 | +- Closure cursor bar currently only receives statics info, would need dynamics too |
| 252 | +- Need to fish out the argument values from samples and format them |
| 253 | + |
| 254 | +### Alternative: Lighter Version |
| 255 | +- Just show the argument expressions (syntax), not their values |
| 256 | +- This is available from statics without additional probing |
| 257 | + |
| 258 | +**Status:** Deferred. Requires infrastructure changes. Consider lighter syntax-only version first. |
| 259 | + |
| 260 | +--- |
| 261 | + |
| 262 | +## Copy Call Stack |
| 263 | + |
| 264 | +**Concept:** Button to copy the current call stack for debugging/sharing. |
| 265 | + |
| 266 | +### Possible Formats |
| 267 | +- Human-readable: `λ > map > filter > f` |
| 268 | +- With locations: `λ > map (line 5) > filter (line 12) > f (line 3)` |
| 269 | +- JSON for tooling integration |
| 270 | + |
| 271 | +**Status:** Deferred. Low priority but potentially useful for bug reports. |
| 272 | + |
| 273 | +--- |
| 274 | + |
| 275 | +## Multiple Sample Selection |
| 276 | + |
| 277 | +**Concept:** Allow selecting multiple samples for comparison/analysis. |
| 278 | + |
| 279 | +### Use Cases |
| 280 | +- Compare two execution paths: "Why did `process(5)` work but `process(6)` fail?" |
| 281 | +- Call stack diff: highlight where two samples' call stacks diverge |
| 282 | +- Side-by-side value comparison |
| 283 | + |
| 284 | +### Connection to Investigation Breadcrumbs |
| 285 | +- Investigation breadcrumbs track exploration history (where you've looked) |
| 286 | +- Multiple selection tracks comparison targets (what you're analyzing) |
| 287 | +- Could potentially unify: investigation points become selectable samples |
| 288 | + |
| 289 | +**Status:** Deferred. Interesting direction but adds complexity. Revisit when single-cursor workflows feel limiting. |
| 290 | + |
| 291 | +--- |
| 292 | + |
| 293 | +## Time Travel Slider |
| 294 | + |
| 295 | +**Concept:** Scrub through execution using step_start/step_end data. |
| 296 | + |
| 297 | +### How It Would Work |
| 298 | +- Slider representing evaluation steps |
| 299 | +- As you scrub, highlight samples whose step ranges contain the current step |
| 300 | +- Shows "program state at step N" |
| 301 | + |
| 302 | +### Limitations |
| 303 | +- With probe_all: many samples, rich scrubbing experience |
| 304 | +- Without probe_all: limited to collected samples only |
| 305 | +- May need UI to indicate "no data at this step" |
| 306 | + |
| 307 | +**Status:** Deferred. Interesting but depends on probe density. |
| 308 | + |
| 309 | +--- |
| 310 | + |
| 311 | +## Evaluation Context Stepping (Exploratory) |
| 312 | + |
| 313 | +**Concept:** Capture evaluation context within function calls, enabling finer-grained stepping. |
| 314 | + |
| 315 | +### Current State |
| 316 | +Call stack entries represent function application boundaries. Within a function body, we don't track intermediate evaluation steps in the cursor. |
| 317 | + |
| 318 | +### Possible Extension |
| 319 | +- Capture evaluation context frames (what's being evaluated within a function) |
| 320 | +- Alternating sequence: call stack entry → eval context → call stack entry → ... |
| 321 | +- Would allow stepping through entire program at expression granularity |
| 322 | + |
| 323 | +### Open Questions |
| 324 | +- What exactly constitutes an "evaluation context frame"? |
| 325 | +- How to represent in UI without overwhelming? |
| 326 | +- Relationship to step_start/step_end data we already have? |
| 327 | + |
| 328 | +**Status:** Very exploratory. Needs more thought on what this would look like concretely. |
| 329 | + |
| 330 | +--- |
| 331 | + |
| 332 | +## Pin from Dynamic Cursor UI |
| 333 | + |
| 334 | +**Concept:** Allow pinning directly from the closure cursor bar, not just from sample dropdowns. |
| 335 | + |
| 336 | +### Possible Affordances |
| 337 | +- Right-click or long-press on breadcrumb entry shows context menu with "Pin here" |
| 338 | +- Small pin icon appears on hover (like current unpin icon, but for pinning) |
| 339 | +- Clicking would pin the call stack up to and including that entry |
| 340 | + |
| 341 | +### Could We Show Full Sample Context Menu? |
| 342 | + |
| 343 | +Analysis of what we'd need: |
| 344 | + |
| 345 | +| Feature | Required Data | Currently Available? | |
| 346 | +|---------|--------------|---------------------| |
| 347 | +| Pin action | `app_id`, call stack | ✅ Yes - construct from `sample_cursor.call_stack` trimmed to entry index | |
| 348 | +| Step Into | Full `Sample.t` | ❌ No - needs dynamics passed in | |
| 349 | +| Environment | `sample.env`, `view_seg`, `utility` | ❌ No - needs dynamics + rendering utilities | |
| 350 | + |
| 351 | +**Current ClosureCursorBar inputs:** `globals`, `refractors` (has `sample_cursor`), `info_map` (statics only) |
| 352 | + |
| 353 | +**What's missing:** `Dynamics.Info.t`, samples list, `view_seg`/`utility` |
| 354 | + |
| 355 | +**Verdict:** Simplified context menu with just Pin is doable now. Full menu (Step Into + Environment) requires threading dynamics through. |
| 356 | + |
| 357 | +**Status:** Deferred. Pin-only version could be quick; full menu needs more plumbing. |
0 commit comments