From 0ff2e6726e54c62a8b96ebf582c9a998a1abab0f Mon Sep 17 00:00:00 2001 From: Fons van der Plas Date: Thu, 16 May 2024 12:05:09 +0200 Subject: [PATCH 1/8] =?UTF-8?q?=E2=8C=A8=EF=B8=8F=20Keyboard=20shortcut=20?= =?UTF-8?q?for=20folding=20cell?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/components/CellInput.js | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/frontend/components/CellInput.js b/frontend/components/CellInput.js index 591c306108..180f9d2120 100644 --- a/frontend/components/CellInput.js +++ b/frontend/components/CellInput.js @@ -628,6 +628,20 @@ export const CellInput = ({ return direction === 1 ? moveLineDown(cm) : moveLineUp(cm) } } + const keyMapFold = async (/** @type {EditorView} */ cm) => { + console.log(cm) + await pluto_actions.fold_remote_cells([cell_id], true).catch(console.warn) + const cell = dom_node_ref.current?.closest("pluto-cell") + const next_cell = cell?.nextElementSibling + if (next_cell?.nodeName === "PLUTO-CELL") { + // @ts-ignore + next_cell?.querySelector("button.add_cell.before")?.focus?.() + } else { + // @ts-ignore + cell?.querySelector("button.add_cell.after")?.focus?.() + } + return true + } const plutoKeyMaps = [ { key: "Shift-Enter", run: keyMapSubmit }, @@ -645,6 +659,7 @@ export const CellInput = ({ { key: "Ctrl-Backspace", run: keyMapBackspace }, { key: "Alt-ArrowUp", run: (x) => keyMapMoveLine(x, -1) }, { key: "Alt-ArrowDown", run: (x) => keyMapMoveLine(x, 1) }, + { key: "Alt-Escape", run: keyMapFold }, mod_d_command, ] @@ -1032,10 +1047,11 @@ const InputContextMenu = ({ on_delete, cell_id, run_cell, skip_as_script, runnin }) } - useEventListener(window, "keydown", (e) => { + useEventListener(window, "keydown", (/** @type {KeyboardEvent} */ e) => { if (e.key === "Escape") { setOpen(false) } + e.stopPropagation() }) return html` From e7a073d94b77f858ad344a54c1b4229b35e8122e Mon Sep 17 00:00:00 2001 From: Fons van der Plas Date: Thu, 16 May 2024 13:02:58 +0200 Subject: [PATCH 2/8] change to Cmd+K --- frontend/components/CellInput.js | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/frontend/components/CellInput.js b/frontend/components/CellInput.js index 180f9d2120..2a2f0cc2f3 100644 --- a/frontend/components/CellInput.js +++ b/frontend/components/CellInput.js @@ -630,16 +630,8 @@ export const CellInput = ({ } const keyMapFold = async (/** @type {EditorView} */ cm) => { console.log(cm) - await pluto_actions.fold_remote_cells([cell_id], true).catch(console.warn) - const cell = dom_node_ref.current?.closest("pluto-cell") - const next_cell = cell?.nextElementSibling - if (next_cell?.nodeName === "PLUTO-CELL") { - // @ts-ignore - next_cell?.querySelector("button.add_cell.before")?.focus?.() - } else { - // @ts-ignore - cell?.querySelector("button.add_cell.after")?.focus?.() - } + set_cm_forced_focus(true) + await pluto_actions.fold_remote_cells([cell_id]).catch(console.warn) return true } @@ -659,7 +651,10 @@ export const CellInput = ({ { key: "Ctrl-Backspace", run: keyMapBackspace }, { key: "Alt-ArrowUp", run: (x) => keyMapMoveLine(x, -1) }, { key: "Alt-ArrowDown", run: (x) => keyMapMoveLine(x, 1) }, - { key: "Alt-Escape", run: keyMapFold }, + { key: "Ctrl-k", mac: "Cmd-k", run: keyMapFold }, + { key: "Ctrl-k", run: keyMapFold }, + // Codemirror6 doesn't like capslock + { key: "Ctrl-K", run: keyMapFold }, mod_d_command, ] @@ -932,6 +927,7 @@ export const CellInput = ({ head: cm.state.selection.main.head, }, }) + } else if (cm_forced_focus === true) { } else { let new_selection = { anchor: line_and_ch_to_cm6_position(cm.state.doc, cm_forced_focus[0]), From d3050ed5a24b9195cfb80006673cfbfc2b5f5a98 Mon Sep 17 00:00:00 2001 From: Fons van der Plas Date: Thu, 16 May 2024 13:03:14 +0200 Subject: [PATCH 3/8] also implement Cmd+K on selected cells --- frontend/components/Editor.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/frontend/components/Editor.js b/frontend/components/Editor.js index ef24be4032..18fad0a5e4 100644 --- a/frontend/components/Editor.js +++ b/frontend/components/Editor.js @@ -583,7 +583,7 @@ export class Editor extends Component { fold_remote_cells: async (cell_ids, new_value) => { await update_notebook((notebook) => { for (let cell_id of cell_ids) { - notebook.cell_inputs[cell_id].code_folded = new_value + notebook.cell_inputs[cell_id].code_folded = new_value ?? !notebook.cell_inputs[cell_id].code_folded } }) }, @@ -1188,6 +1188,12 @@ patch: ${JSON.stringify( this.run_selected = () => { return this.actions.set_and_run_multiple(this.state.selected_cells) } + this.fold_selected = () => { + if (_.isEmpty(this.state.selected_cells)) return + const any_unfolded = this.state.selected_cells.some((cell_id) => !this.state.notebook.cell_inputs[cell_id].code_folded) + const new_val = any_unfolded + return this.actions.fold_remote_cells(this.state.selected_cells, new_val) + } this.move_selected = (/** @type {KeyboardEvent} */ e, /** @type {1|-1} */ delta) => { if (this.state.selected_cells.length > 0) { const current_indices = this.state.selected_cells.map((id) => this.state.notebook.cell_order.indexOf(id)) @@ -1253,6 +1259,8 @@ patch: ${JSON.stringify( // TODO: let user know that the notebook autosaves } e.preventDefault() + } else if (e.key?.toLowerCase() === "k" && has_ctrl_or_cmd_pressed(e)) { + this.fold_selected() } else if (e.key === "Backspace" || e.key === "Delete") { if (this.delete_selected("Delete")) { e.preventDefault() From 0fa5704f5dfc9ee0906b90ea373382c639ab3e38 Mon Sep 17 00:00:00 2001 From: Fons van der Plas Date: Thu, 16 May 2024 13:04:28 +0200 Subject: [PATCH 4/8] remove console log --- frontend/components/CellInput.js | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/components/CellInput.js b/frontend/components/CellInput.js index 2a2f0cc2f3..2516b84dd8 100644 --- a/frontend/components/CellInput.js +++ b/frontend/components/CellInput.js @@ -629,7 +629,6 @@ export const CellInput = ({ } } const keyMapFold = async (/** @type {EditorView} */ cm) => { - console.log(cm) set_cm_forced_focus(true) await pluto_actions.fold_remote_cells([cell_id]).catch(console.warn) return true From 732e73b016a6052c8a2a78fbb96fd89579339307 Mon Sep 17 00:00:00 2001 From: Fons van der Plas Date: Thu, 16 May 2024 13:12:56 +0200 Subject: [PATCH 5/8] fix types --- frontend/components/CellInput.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/components/CellInput.js b/frontend/components/CellInput.js index 2516b84dd8..4a7af5ce99 100644 --- a/frontend/components/CellInput.js +++ b/frontend/components/CellInput.js @@ -628,9 +628,9 @@ export const CellInput = ({ return direction === 1 ? moveLineDown(cm) : moveLineUp(cm) } } - const keyMapFold = async (/** @type {EditorView} */ cm) => { + const keyMapFold = (/** @type {EditorView} */ cm) => { set_cm_forced_focus(true) - await pluto_actions.fold_remote_cells([cell_id]).catch(console.warn) + pluto_actions.fold_remote_cells([cell_id]).catch(console.warn) return true } From a52ce8ad9213ecfa0d720122abdbec7302d37c3f Mon Sep 17 00:00:00 2001 From: Fons van der Plas Date: Fri, 17 May 2024 11:32:03 +0200 Subject: [PATCH 6/8] Change to Ctrl-Shift-[ or Cmd-Alt-[ --- frontend/components/CellInput.js | 11 ++++------- frontend/components/Editor.js | 8 +++----- frontend/editor.css | 3 ++- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/frontend/components/CellInput.js b/frontend/components/CellInput.js index 4a7af5ce99..1fcfe61cc5 100644 --- a/frontend/components/CellInput.js +++ b/frontend/components/CellInput.js @@ -628,9 +628,9 @@ export const CellInput = ({ return direction === 1 ? moveLineDown(cm) : moveLineUp(cm) } } - const keyMapFold = (/** @type {EditorView} */ cm) => { + const keyMapFold = (/** @type {EditorView} */ cm, new_value) => { set_cm_forced_focus(true) - pluto_actions.fold_remote_cells([cell_id]).catch(console.warn) + pluto_actions.fold_remote_cells([cell_id], new_value).catch(console.warn) return true } @@ -650,11 +650,8 @@ export const CellInput = ({ { key: "Ctrl-Backspace", run: keyMapBackspace }, { key: "Alt-ArrowUp", run: (x) => keyMapMoveLine(x, -1) }, { key: "Alt-ArrowDown", run: (x) => keyMapMoveLine(x, 1) }, - { key: "Ctrl-k", mac: "Cmd-k", run: keyMapFold }, - { key: "Ctrl-k", run: keyMapFold }, - // Codemirror6 doesn't like capslock - { key: "Ctrl-K", run: keyMapFold }, - + { key: "Ctrl-Shift-[", mac: "Cmd-Alt-[", run: (x) => keyMapFold(x, true) }, + { key: "Ctrl-Shift-]", mac: "Cmd-Alt-]", run: (x) => keyMapFold(x, false) }, mod_d_command, ] diff --git a/frontend/components/Editor.js b/frontend/components/Editor.js index 18fad0a5e4..1e47e3b7e4 100644 --- a/frontend/components/Editor.js +++ b/frontend/components/Editor.js @@ -1188,10 +1188,8 @@ patch: ${JSON.stringify( this.run_selected = () => { return this.actions.set_and_run_multiple(this.state.selected_cells) } - this.fold_selected = () => { + this.fold_selected = (new_val) => { if (_.isEmpty(this.state.selected_cells)) return - const any_unfolded = this.state.selected_cells.some((cell_id) => !this.state.notebook.cell_inputs[cell_id].code_folded) - const new_val = any_unfolded return this.actions.fold_remote_cells(this.state.selected_cells, new_val) } this.move_selected = (/** @type {KeyboardEvent} */ e, /** @type {1|-1} */ delta) => { @@ -1259,8 +1257,8 @@ patch: ${JSON.stringify( // TODO: let user know that the notebook autosaves } e.preventDefault() - } else if (e.key?.toLowerCase() === "k" && has_ctrl_or_cmd_pressed(e)) { - this.fold_selected() + } else if (["BracketLeft", "BracketRight"].includes(e.code) && (is_mac_keyboard ? e.altKey && e.metaKey : e.ctrlKey && e.shiftKey)) { + this.fold_selected(e.code === "BracketLeft") } else if (e.key === "Backspace" || e.key === "Delete") { if (this.delete_selected("Delete")) { e.preventDefault() diff --git a/frontend/editor.css b/frontend/editor.css index f6da96ed1e..c21b9f8d05 100644 --- a/frontend/editor.css +++ b/frontend/editor.css @@ -1887,7 +1887,8 @@ pluto-input > .preview_hidden_code_info { pointer-events: none; } -body:not(.process_waiting_for_permission) pluto-cell.code_folded pluto-input > .preview_hidden_code_info { +body:not(.process_waiting_for_permission) pluto-cell.code_folded pluto-input > .preview_hidden_code_info, +pluto-cell.code_folded:focus-within pluto-input > .preview_hidden_code_info { display: block; } From 8503d4cc4dc4d3cac7e7abd7d78f033b64f15bba Mon Sep 17 00:00:00 2001 From: Fons van der Plas Date: Fri, 17 May 2024 11:40:06 +0200 Subject: [PATCH 7/8] document shortcut --- frontend/components/Editor.js | 47 +++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/frontend/components/Editor.js b/frontend/components/Editor.js index 1e47e3b7e4..0ad3ebafcc 100644 --- a/frontend/components/Editor.js +++ b/frontend/components/Editor.js @@ -1273,29 +1273,32 @@ patch: ${JSON.stringify( // On mac "cmd+shift+?" is used by chrome, so that is why this needs to be ctrl as well on mac // Also pressing "ctrl+shift" on mac causes the key to show up as "/", this madness // I hope we can find a better solution for this later - Dral + + const fold_prefix = is_mac_keyboard ? `⌥${and}⌘` : `Ctrl${and}Shift` + alert( - `Shortcuts 🎹 - - ⇧${and}Enter: run cell - ${ctrl_or_cmd_name}${and}Enter: run cell and add cell below - ${ctrl_or_cmd_name}${and}S: submit all changes - Delete or Backspace: delete empty cell - - page up or fn${and}↑: jump to cell above - page down or fn${and}↓: jump to cell below - ${alt_or_options_name}${and}↑: move line/cell up - ${alt_or_options_name}${and}↓: move line/cell down - - - Select multiple cells by dragging a selection box from the space between cells. - ${ctrl_or_cmd_name}${and}C: copy selected cells - ${ctrl_or_cmd_name}${and}X: cut selected cells - ${ctrl_or_cmd_name}${and}V: paste selected cells - - ${control_name}${and}M: toggle markdown - ${ctrl_or_cmd_name}${and}Q: interrupt notebook - - The notebook file saves every time you run a cell.` + ` +⇧${and}Enter: run cell +${ctrl_or_cmd_name}${and}Enter: run cell and add cell below +${ctrl_or_cmd_name}${and}S: submit all changes +Delete or Backspace: delete empty cell + +PageUp or fn${and}↑: jump to cell above +PageDown or fn${and}↓: jump to cell below +${alt_or_options_name}${and}↑: move line/cell up +${alt_or_options_name}${and}↓: move line/cell down + +${control_name}${and}M: toggle markdown +${fold_prefix}${and}[: hide cell code +${fold_prefix}${and}]: show cell code +${ctrl_or_cmd_name}${and}Q: interrupt notebook + +Select multiple cells by dragging a selection box from the space between cells. +${ctrl_or_cmd_name}${and}C: copy selected cells +${ctrl_or_cmd_name}${and}X: cut selected cells +${ctrl_or_cmd_name}${and}V: paste selected cells + +The notebook file saves every time you run a cell.` ) e.preventDefault() } else if (e.key === "Escape") { From 7d783e96919c5404a2377a17cde6b275823ce2de Mon Sep 17 00:00:00 2001 From: Fons van der Plas Date: Tue, 21 May 2024 15:30:07 +0200 Subject: [PATCH 8/8] fixes --- frontend/components/CellInput.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frontend/components/CellInput.js b/frontend/components/CellInput.js index 1fcfe61cc5..cc6fe4cb06 100644 --- a/frontend/components/CellInput.js +++ b/frontend/components/CellInput.js @@ -630,7 +630,7 @@ export const CellInput = ({ } const keyMapFold = (/** @type {EditorView} */ cm, new_value) => { set_cm_forced_focus(true) - pluto_actions.fold_remote_cells([cell_id], new_value).catch(console.warn) + pluto_actions.fold_remote_cells([cell_id], new_value) return true } @@ -1043,7 +1043,6 @@ const InputContextMenu = ({ on_delete, cell_id, run_cell, skip_as_script, runnin if (e.key === "Escape") { setOpen(false) } - e.stopPropagation() }) return html`