Skip to content

Commit 3869d95

Browse files
Merge pull request #1737 from nishtha-agarwal-211/fix/playground-keyboard-shortcuts-1716
feat(playground): support keyboard shortcuts Ctrl+Enter to run and Ctrl+Shift+L to clear (#1716)
2 parents e902ed2 + ce63847 commit 3869d95

3 files changed

Lines changed: 92 additions & 18 deletions

File tree

web-app/index.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,8 @@ <h2 class="playground-title">🐍 Python Playground</h2>
382382
<a href="https://pyodide.org" rel="noopener noreferrer" target="_blank">Pyodide</a>. No install, no backend.
383383
</p>
384384
<p class="playground-hint">
385-
<kbd>Ctrl</kbd>+<kbd>Enter</kbd> runs code &nbsp;·&nbsp;
385+
<kbd>Ctrl</kbd>+<kbd>Enter</kbd> / <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>Enter</kbd> runs code &nbsp;·&nbsp;
386+
<kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>L</kbd> clears console &nbsp;·&nbsp;
386387
<kbd>Tab</kbd> inserts 4 spaces
387388
</p>
388389
</div>

web-app/js/playground.js

Lines changed: 66 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,7 @@
480480
...CM.completionKeymap,
481481
/* Search */
482482
...CM.searchKeymap,
483-
/* Ctrl/Cmd + Enter → Run Code */
483+
/* Ctrl/Cmd + Enter or Ctrl/Cmd + Shift + Enter → Run Code */
484484
{
485485
key: "Ctrl-Enter",
486486
mac: "Cmd-Enter",
@@ -489,6 +489,23 @@
489489
return true;
490490
},
491491
},
492+
{
493+
key: "Ctrl-Shift-Enter",
494+
mac: "Cmd-Shift-Enter",
495+
run: function () {
496+
runCode();
497+
return true;
498+
},
499+
},
500+
/* Ctrl/Cmd + Shift + L → Clear Console */
501+
{
502+
key: "Ctrl-Shift-l",
503+
mac: "Cmd-Shift-l",
504+
run: function () {
505+
resetConsole();
506+
return true;
507+
},
508+
},
492509
]),
493510

494511
/* Update listener — keeps `editor.value` semantic alive */
@@ -1004,24 +1021,56 @@
10041021
});
10051022
}
10061023

1007-
// Keyboard shortcut for copy: Ctrl+Shift+C in editor
1008-
if (cmView) {
1009-
document.addEventListener("keydown", function (event) {
1010-
if ((event.ctrlKey || event.metaKey) && event.shiftKey && event.code === "KeyC") {
1011-
// Check if focus is in the editor
1012-
if (
1013-
editorMount &&
1014-
(editorMount.contains(document.activeElement) ||
1015-
document.activeElement === editorMount)
1016-
) {
1017-
event.preventDefault();
1018-
if (copyEditorCodeBtn) {
1019-
copyEditorCodeBtn.click();
1020-
}
1024+
/* ──────────────────────────────────────────────────────────────
1025+
Keyboard Shortcuts — Issue #1716 & Issue #1215
1026+
- Ctrl/Cmd + Enter: Run Python Code
1027+
- Ctrl/Cmd + Shift + L: Clear Output Console
1028+
- Ctrl/Cmd + Shift + C: Copy Code (when focused in editor)
1029+
────────────────────────────────────────────────────────────── */
1030+
document.addEventListener("keydown", function (event) {
1031+
if (event.defaultPrevented) return;
1032+
1033+
// Only process if playground section is active/visible
1034+
if (!playgroundSection || playgroundSection.style.display === "none") return;
1035+
1036+
var isMod = event.ctrlKey || event.metaKey;
1037+
if (!isMod) return;
1038+
1039+
// Ctrl/Cmd + Shift + C: Copy editor code
1040+
if (
1041+
event.shiftKey &&
1042+
(event.key === "c" || event.key === "C" || event.code === "KeyC")
1043+
) {
1044+
if (
1045+
editorMount &&
1046+
(editorMount.contains(document.activeElement) ||
1047+
document.activeElement === editorMount)
1048+
) {
1049+
event.preventDefault();
1050+
if (copyEditorCodeBtn) {
1051+
copyEditorCodeBtn.click();
10211052
}
10221053
}
1023-
});
1024-
}
1054+
return;
1055+
}
1056+
1057+
// Ctrl/Cmd + Enter: Run Code
1058+
if (event.key === "Enter" || event.code === "Enter") {
1059+
event.preventDefault();
1060+
runCode();
1061+
return;
1062+
}
1063+
1064+
// Ctrl/Cmd + Shift + L: Clear Output Console
1065+
if (
1066+
event.shiftKey &&
1067+
(event.key === "l" || event.key === "L" || event.code === "KeyL")
1068+
) {
1069+
event.preventDefault();
1070+
resetConsole();
1071+
return;
1072+
}
1073+
});
10251074
if (saveDraftBtn) {
10261075
saveDraftBtn.addEventListener("click", function () {
10271076
var draftName = prompt("Enter a name for this draft:");

web-app/tests-e2e/playground.spec.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,28 @@ test.describe('Python Playground', () => {
2929
const consoleOutput = page.locator('#consoleOutput');
3030
await expect(consoleOutput).toContainText('Hello, World!');
3131
});
32+
33+
test('should trigger run code via Ctrl+Enter and clear console via Ctrl+Shift+L', async ({ page }) => {
34+
await page.goto('/');
35+
36+
const playgroundTab = page.locator('button[data-sticky-category="playground"]');
37+
await expect(playgroundTab).toBeVisible();
38+
await playgroundTab.click();
39+
40+
const statusText = page.locator('#statusText');
41+
await expect(statusText).toHaveText(/Pyodide Ready/, { timeout: 30000 });
42+
43+
const consoleOutput = page.locator('#consoleOutput');
44+
45+
// Focus editor and press Control+Enter
46+
const editor = page.locator('.cm-content');
47+
await editor.focus();
48+
await page.keyboard.press('Control+Enter');
49+
50+
await expect(consoleOutput).toContainText('Hello, World!');
51+
52+
// Press Control+Shift+L to clear console
53+
await page.keyboard.press('Control+Shift+L');
54+
await expect(consoleOutput).toContainText('Console output will appear here');
55+
});
3256
});

0 commit comments

Comments
 (0)