From 554cf0bce7b43d83cf76efbfe20c3fdc5b5eb31c Mon Sep 17 00:00:00 2001 From: Abhishek Maran Date: Fri, 5 Jan 2024 23:28:57 +0530 Subject: [PATCH 1/4] fix: cell corruption when deleting block contents --- src/editor/block/commands.js | 22 ++++++++++++++++++++++ src/editor/keymap.js | 3 ++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/editor/block/commands.js b/src/editor/block/commands.js index 7265b37c..44c6e941 100644 --- a/src/editor/block/commands.js +++ b/src/editor/block/commands.js @@ -110,6 +110,28 @@ export const addNewBlockAfterLast = ({ state, dispatch }) => { return true; } +export const deleteBlockContents = ({ state, dispatch }) => { + if (state.readOnly) + return false + + const emptyText = ""; + const block = getActiveNoteBlock(state); + + dispatch(state.update({ + changes: { + from: block.content.from, + to: block.content.to, + insert: emptyText, + }, + selection: EditorSelection.cursor(block.content.from) + }, { + scrollIntoView: true, + userEvent: "delete", + })) + + return true; +} + export function changeLanguageTo(state, dispatch, block, language, auto) { if (state.readOnly) return false diff --git a/src/editor/keymap.js b/src/editor/keymap.js index 05fc7a5c..75d9fcca 100644 --- a/src/editor/keymap.js +++ b/src/editor/keymap.js @@ -14,7 +14,7 @@ import { selectNextBlock, selectPreviousBlock, gotoPreviousParagraph, gotoNextParagraph, selectNextParagraph, selectPreviousParagraph, - newCursorBelow, newCursorAbove, + newCursorBelow, newCursorAbove, deleteBlockContents, } from "./block/commands.js" import { formatBlockContent } from "./block/format-code.js" @@ -51,6 +51,7 @@ export function heynoteKeymap(editor) { ["Alt-Shift-f", formatBlockContent], ["Mod-Alt-ArrowDown", newCursorBelow], ["Mod-Alt-ArrowUp", newCursorAbove], + ["Mod-Shift-k", deleteBlockContents], {key:"Mod-ArrowUp", run:gotoPreviousBlock, shift:selectPreviousBlock}, {key:"Mod-ArrowDown", run:gotoNextBlock, shift:selectNextBlock}, {key:"Ctrl-ArrowUp", run:gotoPreviousParagraph, shift:selectPreviousParagraph}, From 3625b9ac1196409b817c9d1b0c61ec12251708cd Mon Sep 17 00:00:00 2001 From: Abhishek Maran Date: Sun, 7 Jan 2024 23:32:17 +0530 Subject: [PATCH 2/4] customize deleteLine to fix cell corruption --- src/editor/block/commands.js | 48 +++++++++++++++++++++++++----------- src/editor/keymap.js | 4 +-- 2 files changed, 35 insertions(+), 17 deletions(-) diff --git a/src/editor/block/commands.js b/src/editor/block/commands.js index 44c6e941..dd6c0157 100644 --- a/src/editor/block/commands.js +++ b/src/editor/block/commands.js @@ -110,24 +110,42 @@ export const addNewBlockAfterLast = ({ state, dispatch }) => { return true; } -export const deleteBlockContents = ({ state, dispatch }) => { - if (state.readOnly) +function selectedLineBlocks(state) { + let blocks = [], upto = -1 + for (let range of state.selection.ranges) { + let startLine = state.doc.lineAt(range.from), endLine = state.doc.lineAt(range.to) + if (!range.empty && range.to == endLine.from) endLine = state.doc.lineAt(range.to - 1) + if (upto >= startLine.number) { + let prev = blocks[blocks.length - 1] + prev.to = endLine.to + prev.ranges.push(range) + } else { + blocks.push({ from: startLine.from, to: endLine.to, ranges: [range] }) + } + upto = endLine.number + 1 + } + return blocks +} + +export const deleteLine = (view) => { + if (view.state.readOnly) return false - const emptyText = ""; - const block = getActiveNoteBlock(state); + const { state } = view - dispatch(state.update({ - changes: { - from: block.content.from, - to: block.content.to, - insert: emptyText, - }, - selection: EditorSelection.cursor(block.content.from) - }, { - scrollIntoView: true, - userEvent: "delete", - })) + const block = getActiveNoteBlock(view.state) + const selectedLines = selectedLineBlocks(state) + + const changes = state.changes(selectedLines.map(({ from, to }) => { + if(from !== block.content.from || to !== block.content.to) { + if (from > 0) from-- + else if (to < state.doc.length) to++ + } + return { from, to } + })) + + const selection = updateSel(state.selection, range => view.moveVertically(range, true)).map(changes) + view.dispatch({ changes, selection, scrollIntoView: true, userEvent: "delete.line" }) return true; } diff --git a/src/editor/keymap.js b/src/editor/keymap.js index 75d9fcca..d7139550 100644 --- a/src/editor/keymap.js +++ b/src/editor/keymap.js @@ -14,7 +14,7 @@ import { selectNextBlock, selectPreviousBlock, gotoPreviousParagraph, gotoNextParagraph, selectNextParagraph, selectPreviousParagraph, - newCursorBelow, newCursorAbove, deleteBlockContents, + newCursorBelow, newCursorAbove, deleteLine, } from "./block/commands.js" import { formatBlockContent } from "./block/format-code.js" @@ -51,7 +51,7 @@ export function heynoteKeymap(editor) { ["Alt-Shift-f", formatBlockContent], ["Mod-Alt-ArrowDown", newCursorBelow], ["Mod-Alt-ArrowUp", newCursorAbove], - ["Mod-Shift-k", deleteBlockContents], + ["Mod-Shift-k", deleteLine], {key:"Mod-ArrowUp", run:gotoPreviousBlock, shift:selectPreviousBlock}, {key:"Mod-ArrowDown", run:gotoNextBlock, shift:selectNextBlock}, {key:"Ctrl-ArrowUp", run:gotoPreviousParagraph, shift:selectPreviousParagraph}, From 7b7d1411daccaabfb5c8a59b7c3b41c6333c4d5a Mon Sep 17 00:00:00 2001 From: Abhishek Maran Date: Wed, 7 Feb 2024 15:29:38 +0530 Subject: [PATCH 3/4] implemented tests for delete line --- tests/delete-line.spec.js | 50 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 tests/delete-line.spec.js diff --git a/tests/delete-line.spec.js b/tests/delete-line.spec.js new file mode 100644 index 00000000..fb38fc5a --- /dev/null +++ b/tests/delete-line.spec.js @@ -0,0 +1,50 @@ +import { expect, test } from "@playwright/test"; +import { HeynotePage } from "./test-utils.js"; + +let heynotePage + +test.beforeEach(async ({ page }) => { + heynotePage = new HeynotePage(page) + await heynotePage.goto() + + expect((await heynotePage.getBlocks()).length).toBe(1) + await heynotePage.setContent(` +∞∞∞text +Block A +text content 1 +text content 2 +text content 3 +text content 4 +∞∞∞text +Block B +∞∞∞text +Block C`) + + // check that blocks are created + expect((await heynotePage.getBlocks()).length).toBe(3) + + // check that visual block layers are created + await expect(page.locator("css=.heynote-blocks-layer > div")).toHaveCount(3) +}); + +test("delete line on single line in Block A", async ({ page }) => { + for (let i = 0; i < 7; i++) { + await page.locator("body").press("ArrowUp") + } + for (let i = 0; i < 4; i++) { + await page.locator("body").press(`${heynotePage.isMac ? "Meta" : "Control"}+Shift+k`) + } + expect(await heynotePage.getBlockContent(0)).toBe("\ntext content 4"); +}); + +test("delete line on selection in Block B", async ({ page }) => { + for (let i = 0; i < 1; i++) { + await page.locator("body").press("ArrowUp") + } + await page.locator("body").press(`${heynotePage.isMac ? "Meta" : "Control"}+A`) + await page.locator("body").press(`${heynotePage.isMac ? "Meta" : "Control"}+Shift+k`) + expect(await heynotePage.getBlockContent(1)).toBe(''); +}); + + + From a23995bb3b5fe5e1dcc17bf3090e738e5627c15d Mon Sep 17 00:00:00 2001 From: Abhishek Maran Date: Wed, 7 Feb 2024 17:00:29 +0530 Subject: [PATCH 4/4] moved deleteLine and selectedLineBlocks to delete-line.js --- src/editor/block/commands.js | 40 ---------------------------- src/editor/block/delete-line.js | 46 +++++++++++++++++++++++++++++++++ src/editor/keymap.js | 3 ++- 3 files changed, 48 insertions(+), 41 deletions(-) create mode 100644 src/editor/block/delete-line.js diff --git a/src/editor/block/commands.js b/src/editor/block/commands.js index dd6c0157..7265b37c 100644 --- a/src/editor/block/commands.js +++ b/src/editor/block/commands.js @@ -110,46 +110,6 @@ export const addNewBlockAfterLast = ({ state, dispatch }) => { return true; } -function selectedLineBlocks(state) { - let blocks = [], upto = -1 - for (let range of state.selection.ranges) { - let startLine = state.doc.lineAt(range.from), endLine = state.doc.lineAt(range.to) - if (!range.empty && range.to == endLine.from) endLine = state.doc.lineAt(range.to - 1) - if (upto >= startLine.number) { - let prev = blocks[blocks.length - 1] - prev.to = endLine.to - prev.ranges.push(range) - } else { - blocks.push({ from: startLine.from, to: endLine.to, ranges: [range] }) - } - upto = endLine.number + 1 - } - return blocks -} - -export const deleteLine = (view) => { - if (view.state.readOnly) - return false - - const { state } = view - - const block = getActiveNoteBlock(view.state) - const selectedLines = selectedLineBlocks(state) - - const changes = state.changes(selectedLines.map(({ from, to }) => { - if(from !== block.content.from || to !== block.content.to) { - if (from > 0) from-- - else if (to < state.doc.length) to++ - } - return { from, to } - })) - - const selection = updateSel(state.selection, range => view.moveVertically(range, true)).map(changes) - view.dispatch({ changes, selection, scrollIntoView: true, userEvent: "delete.line" }) - - return true; -} - export function changeLanguageTo(state, dispatch, block, language, auto) { if (state.readOnly) return false diff --git a/src/editor/block/delete-line.js b/src/editor/block/delete-line.js new file mode 100644 index 00000000..9066231f --- /dev/null +++ b/src/editor/block/delete-line.js @@ -0,0 +1,46 @@ +import { EditorSelection } from "@codemirror/state" +import { getActiveNoteBlock } from "./block" + +function updateSel(sel, by) { + return EditorSelection.create(sel.ranges.map(by), sel.mainIndex); +} + +function selectedLineBlocks(state) { + let blocks = [], upto = -1 + for (let range of state.selection.ranges) { + let startLine = state.doc.lineAt(range.from), endLine = state.doc.lineAt(range.to) + if (!range.empty && range.to == endLine.from) endLine = state.doc.lineAt(range.to - 1) + if (upto >= startLine.number) { + let prev = blocks[blocks.length - 1] + prev.to = endLine.to + prev.ranges.push(range) + } else { + blocks.push({ from: startLine.from, to: endLine.to, ranges: [range] }) + } + upto = endLine.number + 1 + } + return blocks +} + +export const deleteLine = (view) => { + if (view.state.readOnly) + return false + + const { state } = view + + const block = getActiveNoteBlock(view.state) + const selectedLines = selectedLineBlocks(state) + + const changes = state.changes(selectedLines.map(({ from, to }) => { + if(from !== block.content.from || to !== block.content.to) { + if (from > 0) from-- + else if (to < state.doc.length) to++ + } + return { from, to } + })) + + const selection = updateSel(state.selection, range => view.moveVertically(range, true)).map(changes) + view.dispatch({ changes, selection, scrollIntoView: true, userEvent: "delete.line" }) + + return true; +} \ No newline at end of file diff --git a/src/editor/keymap.js b/src/editor/keymap.js index d7139550..70f49757 100644 --- a/src/editor/keymap.js +++ b/src/editor/keymap.js @@ -14,10 +14,11 @@ import { selectNextBlock, selectPreviousBlock, gotoPreviousParagraph, gotoNextParagraph, selectNextParagraph, selectPreviousParagraph, - newCursorBelow, newCursorAbove, deleteLine, + newCursorBelow, newCursorAbove, } from "./block/commands.js" import { formatBlockContent } from "./block/format-code.js" +import { deleteLine } from "./block/delete-line.js" export function keymapFromSpec(specs) {