From 9e42b0ffadbcff7036181b160cf9a15b44bfef22 Mon Sep 17 00:00:00 2001 From: Jonatan Heyman Date: Tue, 17 Jun 2025 11:02:14 +0200 Subject: [PATCH] Add cursorDocStart, cursorDocEnd, selectDocStart and selectDocEnd commands, and bind them to Ctrl-Home, Ctrl-End, Ctrl-Shift-Home and Ctrl-Shift-End --- src/editor/commands.js | 1 + src/editor/keymap.js | 2 + tests/cursor-document-navigation.spec.js | 166 +++++++++++++++++++++++ 3 files changed, 169 insertions(+) create mode 100644 tests/cursor-document-navigation.spec.js diff --git a/src/editor/commands.js b/src/editor/commands.js index ea70bf4..de9b0be 100644 --- a/src/editor/commands.js +++ b/src/editor/commands.js @@ -163,6 +163,7 @@ for (let commandSuffix of [ "SyntaxLeft", "SyntaxRight", "SubwordBackward", "SubwordForward", "LineBoundaryBackward", "LineBoundaryForward", + "DocStart", "DocEnd", ]) { HEYNOTE_COMMANDS[`cursor${commandSuffix}`] = { run: markModeMoveCommand(codeMirrorCommands[`cursor${commandSuffix}`], codeMirrorCommands[`select${commandSuffix}`]), diff --git a/src/editor/keymap.js b/src/editor/keymap.js index 87e3be3..850df96 100644 --- a/src/editor/keymap.js +++ b/src/editor/keymap.js @@ -40,6 +40,8 @@ export const DEFAULT_KEYMAP = [ ...cmdShift("PageDown", "cursorPageDown", "selectPageDown"), ...cmdShift("Home", "cursorLineBoundaryBackward", "selectLineBoundaryBackward"), ...cmdShift("End", "cursorLineBoundaryForward", "selectLineBoundaryForward"), + ...cmdShift("Ctrl-Home", "cursorDocStart", "selectDocStart"), + ...cmdShift("Ctrl-End", "cursorDocEnd", "selectDocEnd"), cmd("Alt-Mod-Shift-ArrowUp", "moveCurrentBlockUp"), cmd("Alt-Mod-Shift-ArrowDown", "moveCurrentBlockDown"), cmd("Alt-Shift-d", "insertDateAndTime"), diff --git a/tests/cursor-document-navigation.spec.js b/tests/cursor-document-navigation.spec.js new file mode 100644 index 0000000..2a42015 --- /dev/null +++ b/tests/cursor-document-navigation.spec.js @@ -0,0 +1,166 @@ +import { test, expect } from "@playwright/test"; +import { HeynotePage } from "./test-utils.js"; + +let heynotePage + +test.beforeEach(async ({ page }) => { + heynotePage = new HeynotePage(page) + await heynotePage.goto() +}); + +test("cursorDocStart moves to beginning of document", async ({ page }) => { + await heynotePage.setContent(` +∞∞∞text +First block content +∞∞∞javascript +console.log("second block") +∞∞∞markdown +# Third block +Some markdown content +`) + + // Move cursor to the end of the document + await page.locator("body").press("Control+End") + + // Move cursor to the beginning of the document + await page.locator("body").press("Control+Home") + + // Verify cursor is at the beginning + const cursorPosition = await heynotePage.getCursorPosition() + expect(cursorPosition).toBe(9) // After the first block delimiter "∞∞∞text\n" +}) + +test("cursorDocEnd moves to end of document", async ({ page }) => { + await heynotePage.setContent(` +∞∞∞text +First block content +∞∞∞javascript +console.log("second block") +∞∞∞markdown +# Third block +Some markdown content +`) + + // Move cursor to the beginning of the document + await page.locator("body").press("Control+Home") + + // Move cursor to the end of the document + await page.locator("body").press("Control+End") + + // Verify cursor is at the end + const content = await heynotePage.getContent() + const cursorPosition = await heynotePage.getCursorPosition() + expect(cursorPosition).toBe(content.length) +}) + +test("selectDocStart selects from cursor to beginning of document", async ({ page }) => { + await heynotePage.setContent(` +∞∞∞text +First block content +∞∞∞javascript +console.log("second block") +∞∞∞markdown +# Third block +Some markdown content +`) + + // Position cursor in the middle of the document (in the second block) + await page.locator("body").press("Control+Home") + for (let i = 0; i < 30; i++) { + await page.locator("body").press("ArrowRight") + } + + // Select from cursor to beginning of document + await page.locator("body").press("Control+Shift+Home") + + // Get selected text + const selectedText = await page.evaluate(() => { + const selection = window.getSelection() + return selection.toString() + }) + + // Should select text from cursor position back to beginning + expect(selectedText.length).toBeGreaterThan(0) + expect(selectedText).toContain("First block content") +}) + +test("selectDocEnd selects from cursor to end of document", async ({ page }) => { + await heynotePage.setContent(` +∞∞∞text +First block content +∞∞∞javascript +console.log("second block") +∞∞∞markdown +# Third block +Some markdown content +`) + + // Position cursor in the middle of the document (in the first block) + await page.locator("body").press("Control+Home") + for (let i = 0; i < 15; i++) { + await page.locator("body").press("ArrowRight") + } + + // Select from cursor to end of document + await page.locator("body").press("Control+Shift+End") + + // Get selected text + const selectedText = await page.evaluate(() => { + const selection = window.getSelection() + return selection.toString() + }) + + // Should select text from cursor position to end + expect(selectedText.length).toBeGreaterThan(0) + expect(selectedText).toContain("console.log") + expect(selectedText).toContain("Some markdown content") +}) + +test("cursor navigation works with empty blocks", async ({ page }) => { + await heynotePage.setContent(` +∞∞∞text + +∞∞∞javascript + +∞∞∞markdown + +`) + + // Test moving to beginning + await page.locator("body").press("Control+End") + await page.locator("body").press("Control+Home") + + const cursorAfterHome = await heynotePage.getCursorPosition() + expect(cursorAfterHome).toBe(9) // After first block delimiter + + // Test moving to end + await page.locator("body").press("Control+End") + + const content = await heynotePage.getContent() + const cursorAfterEnd = await heynotePage.getCursorPosition() + expect(cursorAfterEnd).toBe(content.length) +}) + +test("cursor navigation works in single block", async ({ page }) => { + await heynotePage.setContent(` +∞∞∞text +Single block with some content +`) + + // Move to middle of block + await page.locator("body").press("Control+Home") + for (let i = 0; i < 10; i++) { + await page.locator("body").press("ArrowRight") + } + + // Test Home key + await page.locator("body").press("Control+Home") + const cursorAfterHome = await heynotePage.getCursorPosition() + expect(cursorAfterHome).toBe(9) // After block delimiter + + // Test End key + await page.locator("body").press("Control+End") + const content = await heynotePage.getContent() + const cursorAfterEnd = await heynotePage.getCursorPosition() + expect(cursorAfterEnd).toBe(content.length) +}) \ No newline at end of file