Make new lines in Plaintext and Math blocks and inherit the indentation from the previous line.

- Adds an indentService to opt certain languages into indentation inheritance.
- Introduces inheritIndentation metadata for languages, defaulted for Plain Text and Math.
- Adds tests
This commit is contained in:
Jonatan Heyman 2026-01-07 19:40:57 +01:00
parent d9f3a4306d
commit 0e0fe0a727
4 changed files with 41 additions and 3 deletions

View File

@ -2,6 +2,10 @@
Here are the most notable changes in each release. For a more detailed list of changes, see the [Github Releases page](https://github.com/heyman/heynote/releases).
## (not yet released)
- New lines in a Plaintext or Math block now inherits the indentation from the previous line
## 2.7.1

View File

@ -1,7 +1,10 @@
import { EditorSelection, EditorState, countColumn } from "@codemirror/state"
import { indentUnit } from "@codemirror/language"
import { indentUnit, indentService } from "@codemirror/language"
import { indentMore } from "@codemirror/commands"
import { getNoteBlockFromPos } from "./block/block"
import { getLanguage } from "./languages"
export function indentation(indentType, tabSize) {
let unit
@ -12,7 +15,17 @@ export function indentation(indentType, tabSize) {
} else {
throw new Error("Invalid indent type")
}
return [unit, EditorState.tabSize.of(tabSize)]
return [
unit,
EditorState.tabSize.of(tabSize),
indentService.of((context, pos) => {
const block = getNoteBlockFromPos(context.state, pos)
if (block && getLanguage(block.language.name)?.inheritIndentation) {
return null
}
return undefined
}),
]
}

View File

@ -46,13 +46,16 @@ class Language {
* @param parser: The Lezer parser used to parse the language
* @param guesslang: The name of the language as used by the guesslang library
* @param prettier: The prettier configuration for the language (if any)
* @param inheritIndentation: If true, the indentService will return null for blocks of this type, which will
* result in the line inheriting the indentation of the one above it
*/
constructor({ token, name, parser, guesslang, prettier }) {
constructor({ token, name, parser, guesslang, prettier, inheritIndentation }) {
this.token = token
this.name = name
this.parser = parser
this.guesslang = guesslang
this.prettier = prettier
this.inheritIndentation = inheritIndentation
}
get supportsFormat() {
@ -66,12 +69,14 @@ export const LANGUAGES = [
name: "Plain Text",
parser: null,
guesslang: null,
inheritIndentation: true,
}),
new Language({
token: "math",
name: "Math",
parser: null,
guesslang: null,
inheritIndentation: true,
}),
new Language({
token: "json",

View File

@ -56,3 +56,19 @@ test("press tab", async ({ page }) => {
await page.locator("body").press("Tab")
expect(await heynotePage.getBlockContent(0)).toBe("H ello\n ")
})
test("indentation is preserved on enter in plain text block", async ({ page }) => {
await page.locator("body").pressSequentially(" Indented line")
await page.locator("body").press("Enter")
await page.locator("body").pressSequentially("Next line")
expect(await heynotePage.getBlockContent(0)).toBe(" Indented line\n Next line")
})
test("python indentation increases after colon on enter", async ({ page }) => {
await heynotePage.setContent(`
python
def func():`)
await heynotePage.setCursorPosition((await heynotePage.getContent()).length)
await page.locator("body").press("Enter")
expect(await heynotePage.getBlockContent(0)).toBe("def func():\n ")
})