diff --git a/CHANGELOG.md b/CHANGELOG.md index dac4576..a6d460c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ Leafdown uses lightweight [Keep a Changelog](https://keepachangelog.com/en/1.1.0 ### Fixed +- Open documents with many list items faster. Reading each item's indentation searched back toward the start of the file, so opening took longer with every item and with the file's size, adding about a second to a 1 MB document and much more to larger ones. - Draw the scrollbars of wide code blocks, tables, and display math in the same thin, rounded style as the rest of Leafdown instead of the system default. Help code samples, Find in folder's skipped-file lists, the code block language and wiki link suggestion lists, and menus cut short by a small window match it too. - Show a file opened from File Explorer, File > Open, recent files, or a drop as soon as it is read instead of after its whole folder has been scanned. A file in a large folder such as Documents could leave the window on the welcome screen for several seconds, looking as if the file had not opened. The article navigator shows placeholder rows until the folder is ready, and a folder that cannot be scanned reports its error without closing the document. - Show a heading's caret-based marker only while the editor has focus, so opening a heading-first document does not show the marker before you enter the editor. Hover markers and section folding remain available. diff --git a/src/features/editor/plugins/listForm.ts b/src/features/editor/plugins/listForm.ts index 22ad498..d81504d 100644 --- a/src/features/editor/plugins/listForm.ts +++ b/src/features/editor/plugins/listForm.ts @@ -58,8 +58,11 @@ const readListItemIndent = (item: MarkdownNode, source: string) => { return undefined; } - const lineStart = - Math.max(source.lastIndexOf("\n", start - 1), source.lastIndexOf("\r", start - 1)) + 1; + let lineStart = start; + + while (lineStart > 0 && source[lineStart - 1] !== "\n" && source[lineStart - 1] !== "\r") { + lineStart -= 1; + } return source.slice(lineStart, start); }; diff --git a/src/features/editor/tests/markdownCompatibility.test.ts b/src/features/editor/tests/markdownCompatibility.test.ts index b5c3f14..431d180 100644 --- a/src/features/editor/tests/markdownCompatibility.test.ts +++ b/src/features/editor/tests/markdownCompatibility.test.ts @@ -3151,6 +3151,24 @@ describe("List item indentation", () => { expect(reopened.view.state.doc.toJSON()).toEqual(mounted.view.state.doc.toJSON()); }); + it.each([ + { lineEnding: "\n", name: "line feeds" }, + { lineEnding: "\r\n", name: "carriage returns and line feeds" }, + { lineEnding: "\r", name: "carriage returns" }, + ])( + "reads each item's prefix off its own line in a file ending lines with $name", + async ({ lineEnding }) => { + const authored = + "- parent\n\n\t- child\n\t - sibling\n\nText\n\n> - quoted\n>\n> \t- nested\n"; + const { mounted, reopened, saved } = await saveAndReopen( + authored.replaceAll("\n", lineEnding), + ); + + expect(saved).toBe(authored); + expect(reopened.view.state.doc.toJSON()).toEqual(mounted.view.state.doc.toJSON()); + }, + ); + // A marker written even one column past the item before it falls inside that item, so a list // standing right after another gives way: the file the record came from cannot have held that, // and the columns the containers write are no longer the ones the file wrote.