Skip to content

Commit

Permalink
🪲 Debug play (#5269)
Browse files Browse the repository at this point in the history
Adds the `play` builtin function to both `run` and  `debug` paths, so now we're able to debug the play command. Also fixes the highlighting of variables within the play command, as well as fixing the highlighting of the lines containing the play command while debugging.

Fixes  #5111 

**How to test**
*  Automated tests should pass
* Go to level 2 and debug this code:

```
note is C1
play note
play C2
```

Also check that the `note` variable is colored blue.
  • Loading branch information
jpelay authored Mar 18, 2024
1 parent 4fa5ce3 commit 179c723
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 21 deletions.
4 changes: 2 additions & 2 deletions hedy.py
Original file line number Diff line number Diff line change
Expand Up @@ -1858,11 +1858,11 @@ def play(self, meta, args):
if isinstance(note, str):
uppercase_note = note.upper()
if uppercase_note in list(notes_mapping.values()) + list(notes_mapping.keys()): # this is a supported note
return self.make_play(uppercase_note, meta)
return self.make_play(uppercase_note, meta) + self.add_debug_breakpoint()

# no note? it must be a variable!
self.add_variable_access_location(note, meta.line)
return self.make_play_var(note, meta)
return self.make_play_var(note, meta) + self.add_debug_breakpoint()

def assign(self, meta, args):
variable_name = args[0]
Expand Down
18 changes: 9 additions & 9 deletions static/js/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1015,6 +1015,15 @@ export function runPythonProgram(this: any, code: string, sourceMap: any, hasTur
code = code_prefix + code;
if (hasPygame) code += pygame_suffix;

(Sk as any).builtins.play = new Sk.builtin.func((notes:any) => {
//const now = Tone.now()
const note_name = notes.v;

//play note_name for the duration of an 16th note
synth.triggerAttackRelease(note_name, "16n");

});

if (run_type === "run") {
Sk.configure({
output: outf,
Expand Down Expand Up @@ -1053,15 +1062,6 @@ export function runPythonProgram(this: any, code: string, sourceMap: any, hasTur
}) ()
});

(Sk as any).builtins.play = new Sk.builtin.func((notes:any) => {
//const now = Tone.now()
const note_name = notes.v;

//play note_name for the duration of an 16th note
synth.triggerAttackRelease(note_name, "16n");

});

const currentProgram: number = Number(sessionStorage.getItem('currentProgram') || 0) + 1;
sessionStorage.setItem('currentProgram', currentProgram.toString());

Expand Down
14 changes: 8 additions & 6 deletions static/js/appbundle.js
Original file line number Diff line number Diff line change
Expand Up @@ -88334,7 +88334,8 @@ notes_mapping = {
"Expression",
"Repeat",
"For",
"Call"
"Call",
"Play"
];
if (level3 > 3)
commands.push("Ask");
Expand Down Expand Up @@ -97125,6 +97126,7 @@ notes_mapping = {
"add",
"remove",
"ask",
"play",
"command"
];
var blockCommands = [
Expand Down Expand Up @@ -97196,7 +97198,7 @@ notes_mapping = {
}
function clean_variables(variables) {
const new_variables = [];
const unwanted_variables = ["random", "time", "int_saver", "int_$rw$", "turtle", "t"];
const unwanted_variables = ["random", "time", "int_saver", "int_$rw$", "turtle", "t", "chosen_note"];
for (const variable in variables) {
if (!variable.includes("__") && !unwanted_variables.includes(variable)) {
let extraStyle = special_style_for_variable(variables[variable]);
Expand Down Expand Up @@ -99391,6 +99393,10 @@ pygame.quit()
code = code_prefix + code;
if (hasPygame)
code += pygame_suffix;
Sk.builtins.play = new Sk.builtin.func((notes) => {
const note_name = notes.v;
synth.triggerAttackRelease(note_name, "16n");
});
if (run_type === "run") {
Sk.configure({
output: outf,
Expand Down Expand Up @@ -99421,10 +99427,6 @@ pygame.quit()
return hasSleep ? 2e4 : 5e3;
}()
});
Sk.builtins.play = new Sk.builtin.func((notes) => {
const note_name = notes.v;
synth.triggerAttackRelease(note_name, "16n");
});
const currentProgram = Number(sessionStorage.getItem("currentProgram") || 0) + 1;
sessionStorage.setItem("currentProgram", currentProgram.toString());
return Sk.misceval.asyncToPromise(() => Sk.importMainWithBody("<stdin>", false, code, true), {
Expand Down
4 changes: 2 additions & 2 deletions static/js/appbundle.js.map

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion static/js/cm-decorations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,8 @@ function highlightVariables(view: EditorView) {
"Expression",
"Repeat",
"For",
"Call"
"Call",
"Play"
]
// in levels 2 and 3 variables are not substitued inside ask
// not sure if that's intended behaviour or not
Expand Down
3 changes: 2 additions & 1 deletion static/js/debugging.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const fullLineCommands = [
'add',
'remove',
'ask',
'play',
'command', // the turtle and clear commands get put in the source map as 'command'
]

Expand Down Expand Up @@ -117,7 +118,7 @@ function special_style_for_variable(variable: Variable) {
//hiding certain variables from the list unwanted for users
function clean_variables(variables: Record<string, Variable>) {
const new_variables = [];
const unwanted_variables = ["random", "time", "int_saver", "int_$rw$", "turtle", "t"];
const unwanted_variables = ["random", "time", "int_saver", "int_$rw$", "turtle", "t", "chosen_note"];
for (const variable in variables) {
if (!variable.includes('__') && !unwanted_variables.includes(variable)) {
let extraStyle = special_style_for_variable(variables[variable]);
Expand Down
44 changes: 44 additions & 0 deletions tests/cypress/e2e/hedy_page/debugger.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,50 @@ describe('Test editor box functionality', () => {

cy.get('#output').should('contain.text', 'a');
});

describe('Test play with no variables', () => {
for (let i = 1; i <= 10; i++) {
it ('Test play no variables level ' + i, () => {
cy.intercept('/parse').as('parse');

visitLevel(i)

cy.focused().type("play C4\nplay D4\nplay E4\n");

cy.get('#debug_button').click();
cy.wait('@parse')

for (let line = 0; line < 3; line++) {
codeMirrorLines()
.eq(line)
.should('have.class', 'cm-debugger-current-line');
cy.get('#debug_continue').click();
}
})
}
})

describe('Test play with variables', () => {
for (let i = 2; i <= 11; i++) {
it ('Test play variables level ' + i, () => {
cy.intercept('/parse').as('parse');

visitLevel(i)

cy.focused().type("note1 is C4\nnote2 is D4\nnote3 is E4\nplay C4\nplay D4\nplay E4\n");

cy.get('#debug_button').click();
cy.wait('@parse')

for (let line = 0; line < 6; line++) {
codeMirrorLines()
.eq(line)
.should('have.class', 'cm-debugger-current-line');
cy.get('#debug_continue').click();
}
})
}
})
});

/**
Expand Down

0 comments on commit 179c723

Please sign in to comment.