Skip to content

Commit 4f189cb

Browse files
fix, perf: Trim trailing white-space from headings (#1004)
fix: Use header cache instead of section cache to find headings for shorter loop and greater code readability. (This was mainly a refactoring, which massively simplified the code. However, during testing, we found that the new code strips any whitespace from the end of headings, which if there are duplicate headings differing only in trailing whitespace, would merge the seemingly identical headings in 'group by heading'.) refactor: Only read and parse the file for tasks if there are listItems in Obsidian cache refactor: Match call signatures of getSection and getPrecedingHeader for greater code readability
1 parent e397477 commit 4f189cb

File tree

1 file changed

+40
-63
lines changed

1 file changed

+40
-63
lines changed

src/Cache.ts

Lines changed: 40 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { MetadataCache, TAbstractFile, TFile, Vault } from 'obsidian';
22
import type { CachedMetadata, EventRef } from 'obsidian';
3-
import type { ListItemCache, SectionCache } from 'obsidian';
3+
import type { HeadingCache, ListItemCache, SectionCache } from 'obsidian';
44
import { Mutex } from 'async-mutex';
55

66
import { Task } from './Task';
@@ -201,25 +201,28 @@ export class Cache {
201201
return;
202202
}
203203

204+
const oldTasks = this.tasks.filter((task: Task) => {
205+
return task.path === file.path;
206+
});
207+
204208
let listItems = fileCache.listItems;
209+
let fileContent = '';
210+
let newTasks: Task[] = [];
205211
if (listItems === undefined) {
206212
// When there is no list items cache, there are no tasks.
207213
// Still continue to notify watchers of removal.
208214
listItems = [];
215+
} else {
216+
// Only read the file and process for tasks if there are list items.
217+
fileContent = await this.vault.cachedRead(file);
218+
newTasks = Cache.getTasksFromFileContent(
219+
fileContent,
220+
listItems,
221+
fileCache,
222+
file,
223+
);
209224
}
210225

211-
const oldTasks = this.tasks.filter((task: Task) => {
212-
return task.path === file.path;
213-
});
214-
215-
const fileContent = await this.vault.cachedRead(file);
216-
const newTasks = Cache.getTasksFromFileContent(
217-
fileContent,
218-
listItems,
219-
fileCache,
220-
file,
221-
);
222-
223226
// If there are no changes in any of the tasks, there's
224227
// nothing to do, so just return.
225228
if (Task.tasksListsIdentical(oldTasks, newTasks)) {
@@ -272,10 +275,10 @@ export class Cache {
272275
) {
273276
// We went past the current section (or this is the first task).
274277
// Find the section that is relevant for this task and the following of the same section.
275-
currentSection = Cache.getSection({
276-
lineNumberTask: listItem.position.start.line,
277-
sections: fileCache.sections,
278-
});
278+
currentSection = Cache.getSection(
279+
listItem.position.start.line,
280+
fileCache.sections,
281+
);
279282
sectionIndex = 0;
280283
}
281284

@@ -290,11 +293,10 @@ export class Cache {
290293
path: file.path,
291294
sectionStart: currentSection.position.start.line,
292295
sectionIndex,
293-
precedingHeader: Cache.getPrecedingHeader({
294-
lineNumberTask: listItem.position.start.line,
295-
sections: fileCache.sections,
296-
fileLines,
297-
}),
296+
precedingHeader: Cache.getPrecedingHeader(
297+
listItem.position.start.line,
298+
fileCache.headings,
299+
),
298300
});
299301

300302
if (task !== null) {
@@ -307,13 +309,10 @@ export class Cache {
307309
return tasks;
308310
}
309311

310-
private static getSection({
311-
lineNumberTask,
312-
sections,
313-
}: {
314-
lineNumberTask: number;
315-
sections: SectionCache[] | undefined;
316-
}): SectionCache | null {
312+
private static getSection(
313+
lineNumberTask: number,
314+
sections: SectionCache[] | undefined,
315+
): SectionCache | null {
317316
if (sections === undefined) {
318317
return null;
319318
}
@@ -330,44 +329,22 @@ export class Cache {
330329
return null;
331330
}
332331

333-
private static getPrecedingHeader({
334-
lineNumberTask,
335-
sections,
336-
fileLines,
337-
}: {
338-
lineNumberTask: number;
339-
sections: SectionCache[] | undefined;
340-
fileLines: string[];
341-
}): string | null {
342-
if (sections === undefined) {
332+
private static getPrecedingHeader(
333+
lineNumberTask: number,
334+
headings: HeadingCache[] | undefined,
335+
): string | null {
336+
if (headings === undefined) {
343337
return null;
344338
}
345339

346-
let precedingHeaderSection: SectionCache | undefined;
347-
for (const section of sections) {
348-
if (section.type === 'heading') {
349-
if (section.position.start.line > lineNumberTask) {
350-
// Break out of the loop as the last header was the preceding one.
351-
break;
352-
}
353-
precedingHeaderSection = section;
354-
}
355-
}
356-
if (precedingHeaderSection === undefined) {
357-
return null;
358-
}
359-
360-
const lineNumberPrecedingHeader =
361-
precedingHeaderSection.position.start.line;
362-
363-
const linePrecedingHeader = fileLines[lineNumberPrecedingHeader];
340+
let precedingHeader: string | null = null;
364341

365-
const headerRegex = /^#+ +(.*)/u;
366-
const headerMatch = linePrecedingHeader.match(headerRegex);
367-
if (headerMatch === null) {
368-
return null;
369-
} else {
370-
return headerMatch[1];
342+
for (const heading of headings) {
343+
if (heading.position.start.line > lineNumberTask) {
344+
return precedingHeader;
345+
}
346+
precedingHeader = heading.heading;
371347
}
348+
return precedingHeader;
372349
}
373350
}

0 commit comments

Comments
 (0)