Skip to content

stepper: add breakpoint navigation#3652

Open
wkc75 wants to merge 7 commits intosource-academy:masterfrom
wkc75:pr/stepper-breakpoints-clean
Open

stepper: add breakpoint navigation#3652
wkc75 wants to merge 7 commits intosource-academy:masterfrom
wkc75:pr/stepper-breakpoints-clean

Conversation

@wkc75
Copy link
Contributor

@wkc75 wkc75 commented Mar 13, 2026

Authors

Wong Kin Chong, wongkinchong75@gmail.com
Raaghul, Raaghulk04@gmail.com

Description

  • derive substitution-stepper breakpoint steps from editor breakpoints
  • make the double-chevron controls jump to previous and next breakpoint steps

Type of change

  • New feature (non-breaking change which adds functionality)

How to test

  1. Open the playground and switch to the substitution stepper.
  2. Enter a Source program with multiple reducible steps on different lines.
  3. Set breakpoints on a few of those lines in the editor gutter.
  4. Run the program.
  5. In the substitution visualizer, use the double-chevron-left and double-chevron-right buttons.
  6. Verify that the controls jump to the previous and next breakpoint-related step instead of only moving to the first or last step.
  7. Verify that normal single-step navigation still works as expected.

Checklist

  • I have tested this code
  • I have updated the documentation

@Raaghulk04 Raaghulk04 requested a review from RichDom2185 March 16, 2026 04:15
@martin-henz martin-henz self-requested a review March 16, 2026 06:16
Copy link
Member

@martin-henz martin-henz left a comment

Choose a reason for hiding this comment

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

Breakpoints don't always seem to work. Example:

function e() {
    return 1;
}

e();

1 + 2;

with breakpoint set to the return statement. stepping with >> goes to the end of the program rather than the breakpoint.

Image

@coveralls
Copy link

Pull Request Test Coverage Report for Build 23145616155

Details

  • 10 of 50 (20.0%) changed or added relevant lines in 2 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage decreased (-0.1%) to 41.195%

Changes Missing Coverage Covered Lines Changed/Added Lines %
src/commons/sideContent/content/SideContentSubstVisualizer.tsx 6 17 35.29%
src/commons/sagas/WorkspaceSaga/helpers/evalCode.ts 4 33 12.12%
Totals Coverage Status
Change from base Build 23145589130: -0.1%
Covered Lines: 5443
Relevant Lines: 12274

💛 - Coveralls

@Raaghulk04 Raaghulk04 force-pushed the pr/stepper-breakpoints-clean branch 2 times, most recently from a700a62 to 56b8e45 Compare March 16, 2026 16:20
@LucasChen1108
Copy link
Contributor

I've noticed a logic edge-case in the current implementation of deriveStepperBreakpointSteps regarding how breakpoints are tracked during execution.

The Issue: Ignored Breakpoints in Loops

The current code uses a firedLines Set to prevent "micro-stepping" (halting multiple times on the same line due to internal trace events).

  • The Logic: When a breakpoint is reached, the line is recorded in firedLines (e.g., "file.js:5"). The condition !firedLines.has(firedKey) then prevents the Stepper from halting on that line again.

  • The Bug: Because firedLines is never cleared during the trace processing, it permanently "mutes" that line for the remainder of the program.

  • Impact: If a breakpoint is inside a while loop or a recurring function, the Stepper only stops on the first iteration. On all subsequent iterations, the breakpoint is ignored because it already exists in the Set.

  • Example:
    Stepper issue
    Here by clicking ">>" the stepper should stop at Step 6 first and then stop at Step 12 as well, but in the end it only stops at Step 6.

Proposed Solution: State-Based Line Transitions

Instead of using a "permanent memory" Set, we can track the transition between lines using a single lastVisitedLine variable. This prevents micro-stepping while allowing loops to work perfectly.

Suggested Refactor:
Replace the firedLines Set with a lastVisitedLine integer to track the immediate execution state.

let lastVisitedLine = -1;

// Inside the execution loop:
if (lines.has(line) && line !== lastVisitedLine) {
  lastVisitedLine = line; // Transitioned to a new breakpoint line
  return true;            // Trigger breakpoint pause
}

lastVisitedLine = line;   // Update tracking for the next micro-step
return false;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants