Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/components/StatusBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"currentCursorLine",
"currentLanguage",
"currentSelectionSize",
"currentSelectionWordCount",
"currentLanguage",
"currentLanguageAuto",
"currentCreatedTime",
Expand Down Expand Up @@ -109,6 +110,9 @@
Col <span class="num">{{ currentCursorLine?.col }}</span>
<template v-if="currentSelectionSize > 0">
Sel <span class="num">{{ currentSelectionSize }}</span>
<template v-if="currentSelectionWordCount != null">
| Words <span class="num">{{ currentSelectionWordCount }}</span>
</template>
</template>
</div>
<div
Expand Down
11 changes: 11 additions & 0 deletions src/editor/block/block.js
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,12 @@ function getSelectionSize(state, sel) {
return count
}

function getSelectionWordCount(state, sel) {
if (sel.from === sel.to) return 0
const text = state.sliceDoc(sel.from, sel.to)
return (text.trim().split(/\s+/).filter(Boolean).length)
}

export function triggerCursorChange({state, dispatch}) {
// Trigger empty change transaction that is annotated with CURRENCIES_LOADED
// This will make Math blocks re-render so that currency conversions are applied
Expand All @@ -334,10 +340,15 @@ const emitCursorChange = (editor) => {
(sel) => getSelectionSize(update.state, sel)
).reduce((a, b) => a + b, 0)

const selectionWordCount = update.state.selection.ranges.map(
(sel) => getSelectionWordCount(update.state, sel)
).reduce((a, b) => a + b, 0)

const block = getActiveNoteBlock(update.state)
if (block && cursorLine) {
heynoteStore.currentCursorLine = cursorLine
heynoteStore.currentSelectionSize = selectionSize
heynoteStore.currentSelectionWordCount = selectionWordCount
heynoteStore.currentLanguage = block.language.name
heynoteStore.currentLanguageAuto = block.language.auto
heynoteStore.currentBufferName = editor.name
Expand Down
1 change: 1 addition & 0 deletions src/stores/heynote-store.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export const useHeynoteStore = defineStore("heynote", {
currentLanguageAuto: null,
currentCursorLine: null,
currentSelectionSize: null,
currentSelectionWordCount: null,
currentCreatedTime: null,
libraryId: 0,
createBufferParams: {
Expand Down
50 changes: 50 additions & 0 deletions tests/playwright/markdown.spec.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import { test, expect } from "@playwright/test";
import { HeynotePage } from "./test-utils.js";

Expand All @@ -21,6 +21,56 @@
await expect(page.locator("css=.status .status-block.lang")).toHaveText("Markdown")
})

test("selection word count is shown in status bar", async ({ page }) => {
await heynotePage.setContent(`
∞∞∞text
Hello world test
`)
await page.waitForTimeout(200)

await page.evaluate(() => {
const view = window._heynote_editor.view
const text = view.state.doc.toString()
const start = text.indexOf("Hello")
const end = text.indexOf("test") + "test".length
view.dispatch({
selection: { anchor: start, head: end },
scrollIntoView: true,
})
})

await page.waitForTimeout(100)
await expect(page.locator("css=.status .status-block.line-number")).toContainText("Words 3")
})

test("fenced Markdown code blocks are syntax highlighted by language", async ({ page }) => {
await heynotePage.setContent(`
∞∞∞markdown
\`\`\`js
class StrictModel {
static fields = new Set();
}
\`\`\`
\`\`\`py
def strict_function():
return 1
\`\`\`
`)
await page.waitForTimeout(300)

const classToken = await page.locator("css=.cm-content span:has-text('class')").first().evaluate(el => el.className)

Check failure on line 61 in tests/playwright/markdown.spec.js

View workflow job for this annotation

GitHub Actions / Run Playwright Tests

[firefox] › tests/playwright/markdown.spec.js:46:5 › fenced Markdown code blocks are syntax highlighted by language

2) [firefox] › tests/playwright/markdown.spec.js:46:5 › fenced Markdown code blocks are syntax highlighted by language Error: locator.evaluate: Test timeout of 30000ms exceeded. Call log: - waiting for locator('.cm-content span:has-text(\'class\')').first() 59 | await page.waitForTimeout(300) 60 | > 61 | const classToken = await page.locator("css=.cm-content span:has-text('class')").first().evaluate(el => el.className) | ^ 62 | const strictModelToken = await page.locator("css=.cm-content span:has-text('StrictModel')").first().evaluate(el => el.className) 63 | const defToken = await page.locator("css=.cm-content span:has-text('def')").first().evaluate(el => el.className) 64 | at /home/runner/work/heynote/heynote/tests/playwright/markdown.spec.js:61:93

Check failure on line 61 in tests/playwright/markdown.spec.js

View workflow job for this annotation

GitHub Actions / Run Playwright Tests

[chromium] › tests/playwright/markdown.spec.js:46:5 › fenced Markdown code blocks are syntax highlighted by language

1) [chromium] › tests/playwright/markdown.spec.js:46:5 › fenced Markdown code blocks are syntax highlighted by language Retry #3 ─────────────────────────────────────────────────────────────────────────────────────── Error: locator.evaluate: Test timeout of 30000ms exceeded. Call log: - waiting for locator('.cm-content span:has-text(\'class\')').first() 59 | await page.waitForTimeout(300) 60 | > 61 | const classToken = await page.locator("css=.cm-content span:has-text('class')").first().evaluate(el => el.className) | ^ 62 | const strictModelToken = await page.locator("css=.cm-content span:has-text('StrictModel')").first().evaluate(el => el.className) 63 | const defToken = await page.locator("css=.cm-content span:has-text('def')").first().evaluate(el => el.className) 64 | at /home/runner/work/heynote/heynote/tests/playwright/markdown.spec.js:61:93

Check failure on line 61 in tests/playwright/markdown.spec.js

View workflow job for this annotation

GitHub Actions / Run Playwright Tests

[chromium] › tests/playwright/markdown.spec.js:46:5 › fenced Markdown code blocks are syntax highlighted by language

1) [chromium] › tests/playwright/markdown.spec.js:46:5 › fenced Markdown code blocks are syntax highlighted by language Retry #2 ─────────────────────────────────────────────────────────────────────────────────────── Error: locator.evaluate: Test timeout of 30000ms exceeded. Call log: - waiting for locator('.cm-content span:has-text(\'class\')').first() 59 | await page.waitForTimeout(300) 60 | > 61 | const classToken = await page.locator("css=.cm-content span:has-text('class')").first().evaluate(el => el.className) | ^ 62 | const strictModelToken = await page.locator("css=.cm-content span:has-text('StrictModel')").first().evaluate(el => el.className) 63 | const defToken = await page.locator("css=.cm-content span:has-text('def')").first().evaluate(el => el.className) 64 | at /home/runner/work/heynote/heynote/tests/playwright/markdown.spec.js:61:93

Check failure on line 61 in tests/playwright/markdown.spec.js

View workflow job for this annotation

GitHub Actions / Run Playwright Tests

[chromium] › tests/playwright/markdown.spec.js:46:5 › fenced Markdown code blocks are syntax highlighted by language

1) [chromium] › tests/playwright/markdown.spec.js:46:5 › fenced Markdown code blocks are syntax highlighted by language Retry #1 ─────────────────────────────────────────────────────────────────────────────────────── Error: locator.evaluate: Test timeout of 30000ms exceeded. Call log: - waiting for locator('.cm-content span:has-text(\'class\')').first() 59 | await page.waitForTimeout(300) 60 | > 61 | const classToken = await page.locator("css=.cm-content span:has-text('class')").first().evaluate(el => el.className) | ^ 62 | const strictModelToken = await page.locator("css=.cm-content span:has-text('StrictModel')").first().evaluate(el => el.className) 63 | const defToken = await page.locator("css=.cm-content span:has-text('def')").first().evaluate(el => el.className) 64 | at /home/runner/work/heynote/heynote/tests/playwright/markdown.spec.js:61:93

Check failure on line 61 in tests/playwright/markdown.spec.js

View workflow job for this annotation

GitHub Actions / Run Playwright Tests

[chromium] › tests/playwright/markdown.spec.js:46:5 › fenced Markdown code blocks are syntax highlighted by language

1) [chromium] › tests/playwright/markdown.spec.js:46:5 › fenced Markdown code blocks are syntax highlighted by language Error: locator.evaluate: Test timeout of 30000ms exceeded. Call log: - waiting for locator('.cm-content span:has-text(\'class\')').first() 59 | await page.waitForTimeout(300) 60 | > 61 | const classToken = await page.locator("css=.cm-content span:has-text('class')").first().evaluate(el => el.className) | ^ 62 | const strictModelToken = await page.locator("css=.cm-content span:has-text('StrictModel')").first().evaluate(el => el.className) 63 | const defToken = await page.locator("css=.cm-content span:has-text('def')").first().evaluate(el => el.className) 64 | at /home/runner/work/heynote/heynote/tests/playwright/markdown.spec.js:61:93
const strictModelToken = await page.locator("css=.cm-content span:has-text('StrictModel')").first().evaluate(el => el.className)
const defToken = await page.locator("css=.cm-content span:has-text('def')").first().evaluate(el => el.className)

expect(classToken).not.toBe("")
expect(strictModelToken).not.toBe("")
expect(defToken).not.toBe("")

// keyword-like tokens in JS and Python should have same style class and differ from identifiers.
expect(classToken).toBe(defToken)
expect(classToken).not.toBe(strictModelToken)
})

test("checkbox toggle", async ({ page }) => {
await heynotePage.setContent(`
∞∞∞markdown
Expand Down
Loading