Skip to content

Commit 6f975c8

Browse files
committed
refactor: . Move getTasksFromFileContent() to new FileParser.ts file
1 parent 8de988f commit 6f975c8

File tree

3 files changed

+127
-119
lines changed

3 files changed

+127
-119
lines changed

src/Obsidian/Cache.ts

Lines changed: 2 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1+
import type { CachedMetadata, EventRef, HeadingCache, ListItemCache, SectionCache, Workspace } from 'obsidian';
12
import { MetadataCache, Notice, TAbstractFile, TFile, Vault } from 'obsidian';
2-
import type { CachedMetadata, EventRef, Workspace } from 'obsidian';
3-
import type { HeadingCache, ListItemCache, SectionCache } from 'obsidian';
43
import { Mutex } from 'async-mutex';
54
import { TasksFile } from '../Scripting/TasksFile';
65
import { ListItem } from '../Task/ListItem';
@@ -9,131 +8,16 @@ import { Task } from '../Task/Task';
98
import { DateFallback } from '../DateTime/DateFallback';
109
import { getSettings } from '../Config/Settings';
1110
import { Lazy } from '../lib/Lazy';
12-
import { TaskLocation } from '../Task/TaskLocation';
1311
import { Logger, logging } from '../lib/logging';
1412
import type { TasksEvents } from './TasksEvents';
13+
import { getTasksFromFileContent2 } from './FileParser';
1514

1615
export enum State {
1716
Cold = 'Cold',
1817
Initializing = 'Initializing',
1918
Warm = 'Warm',
2019
}
2120

22-
export function getTasksFromFileContent2(
23-
filePath: string,
24-
fileContent: string,
25-
listItems: ListItemCache[] | undefined,
26-
logger: Logger,
27-
fileCache: CachedMetadata,
28-
errorReporter: (e: any, filePath: string, listItem: ListItemCache, line: string) => void,
29-
) {
30-
const tasks: Task[] = [];
31-
if (listItems === undefined) {
32-
// When called via Cache, this function would never be called or files without list items.
33-
// It is useful for tests to be act gracefully on sample Markdown files with no list items, however.
34-
return tasks;
35-
}
36-
37-
const tasksFile = new TasksFile(filePath, fileCache);
38-
const fileLines = fileContent.split('\n');
39-
const linesInFile = fileLines.length;
40-
41-
// Lazily store date extracted from filename to avoid parsing more than needed
42-
// this.logger.debug(`getTasksFromFileContent() reading ${file.path}`);
43-
const dateFromFileName = new Lazy(() => DateFallback.fromPath(filePath));
44-
45-
// We want to store section information with every task so
46-
// that we can use that when we post process the markdown
47-
// rendered lists.
48-
let currentSection: SectionCache | null = null;
49-
let sectionIndex = 0;
50-
const line2ListItem: Map<number, ListItem> = new Map();
51-
for (const listItem of listItems) {
52-
const lineNumber = listItem.position.start.line;
53-
if (lineNumber >= linesInFile) {
54-
/*
55-
Obsidian CachedMetadata has told us that there is a task on lineNumber, but there are
56-
not that many lines in the file.
57-
58-
This was the underlying cause of all the 'Stuck on "Loading Tasks..."' messages,
59-
as it resulted in the line 'undefined' being parsed.
60-
61-
Somehow the file had been shortened whilst Obsidian was closed, meaning that
62-
when Obsidian started up, it got the new file content, but still had the old cached
63-
data about locations of list items in the file.
64-
*/
65-
logger.debug(
66-
`${filePath} Obsidian gave us a line number ${lineNumber} past the end of the file. ${linesInFile}.`,
67-
);
68-
return tasks;
69-
}
70-
if (currentSection === null || currentSection.position.end.line < lineNumber) {
71-
// We went past the current section (or this is the first task).
72-
// Find the section that is relevant for this task and the following of the same section.
73-
currentSection = Cache.getSection(lineNumber, fileCache.sections);
74-
sectionIndex = 0;
75-
}
76-
77-
if (currentSection === null) {
78-
// Cannot process a task without a section.
79-
continue;
80-
}
81-
82-
const line = fileLines[lineNumber];
83-
if (line === undefined) {
84-
logger.debug(`${filePath}: line ${lineNumber} - ignoring 'undefined' line.`);
85-
continue;
86-
}
87-
88-
if (listItem.task !== undefined) {
89-
let task;
90-
try {
91-
task = Task.fromLine({
92-
line,
93-
taskLocation: new TaskLocation(
94-
tasksFile,
95-
lineNumber,
96-
currentSection.position.start.line,
97-
sectionIndex,
98-
Cache.getPrecedingHeader(lineNumber, fileCache.headings),
99-
),
100-
fallbackDate: dateFromFileName.value,
101-
});
102-
103-
if (task !== null) {
104-
// listItem.parent could be negative if the parent is not found (in other words, it is a root task).
105-
// That is not a problem, as we never put a negative number in line2ListItem map, so parent will be null.
106-
const parentListItem: ListItem | null = line2ListItem.get(listItem.parent) ?? null;
107-
if (parentListItem !== null) {
108-
task = new Task({
109-
...task,
110-
parent: parentListItem,
111-
});
112-
}
113-
114-
line2ListItem.set(lineNumber, task);
115-
}
116-
} catch (e) {
117-
errorReporter(e, filePath, listItem, line);
118-
continue;
119-
}
120-
121-
if (task !== null) {
122-
sectionIndex++;
123-
tasks.push(task);
124-
}
125-
} else {
126-
const lineNumber = listItem.position.start.line;
127-
128-
const parentListItem: ListItem | null = line2ListItem.get(listItem.parent) ?? null;
129-
130-
line2ListItem.set(lineNumber, new ListItem(fileLines[lineNumber], parentListItem));
131-
}
132-
}
133-
134-
return tasks;
135-
}
136-
13721
export class Cache {
13822
logger = logging.getLogger('tasks.Cache');
13923

src/Obsidian/FileParser.ts

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import type { CachedMetadata, ListItemCache, SectionCache } from 'obsidian';
2+
import type { Logger } from '../lib/logging';
3+
import { Task } from '../Task/Task';
4+
import { TasksFile } from '../Scripting/TasksFile';
5+
import { Lazy } from '../lib/Lazy';
6+
import { DateFallback } from '../DateTime/DateFallback';
7+
import { ListItem } from '../Task/ListItem';
8+
import { TaskLocation } from '../Task/TaskLocation';
9+
import { Cache } from './Cache';
10+
11+
export function getTasksFromFileContent2(
12+
filePath: string,
13+
fileContent: string,
14+
listItems: ListItemCache[] | undefined,
15+
logger: Logger,
16+
fileCache: CachedMetadata,
17+
errorReporter: (e: any, filePath: string, listItem: ListItemCache, line: string) => void,
18+
) {
19+
const tasks: Task[] = [];
20+
if (listItems === undefined) {
21+
// When called via Cache, this function would never be called or files without list items.
22+
// It is useful for tests to be act gracefully on sample Markdown files with no list items, however.
23+
return tasks;
24+
}
25+
26+
const tasksFile = new TasksFile(filePath, fileCache);
27+
const fileLines = fileContent.split('\n');
28+
const linesInFile = fileLines.length;
29+
30+
// Lazily store date extracted from filename to avoid parsing more than needed
31+
// this.logger.debug(`getTasksFromFileContent() reading ${file.path}`);
32+
const dateFromFileName = new Lazy(() => DateFallback.fromPath(filePath));
33+
34+
// We want to store section information with every task so
35+
// that we can use that when we post process the markdown
36+
// rendered lists.
37+
let currentSection: SectionCache | null = null;
38+
let sectionIndex = 0;
39+
const line2ListItem: Map<number, ListItem> = new Map();
40+
for (const listItem of listItems) {
41+
const lineNumber = listItem.position.start.line;
42+
if (lineNumber >= linesInFile) {
43+
/*
44+
Obsidian CachedMetadata has told us that there is a task on lineNumber, but there are
45+
not that many lines in the file.
46+
47+
This was the underlying cause of all the 'Stuck on "Loading Tasks..."' messages,
48+
as it resulted in the line 'undefined' being parsed.
49+
50+
Somehow the file had been shortened whilst Obsidian was closed, meaning that
51+
when Obsidian started up, it got the new file content, but still had the old cached
52+
data about locations of list items in the file.
53+
*/
54+
logger.debug(
55+
`${filePath} Obsidian gave us a line number ${lineNumber} past the end of the file. ${linesInFile}.`,
56+
);
57+
return tasks;
58+
}
59+
if (currentSection === null || currentSection.position.end.line < lineNumber) {
60+
// We went past the current section (or this is the first task).
61+
// Find the section that is relevant for this task and the following of the same section.
62+
currentSection = Cache.getSection(lineNumber, fileCache.sections);
63+
sectionIndex = 0;
64+
}
65+
66+
if (currentSection === null) {
67+
// Cannot process a task without a section.
68+
continue;
69+
}
70+
71+
const line = fileLines[lineNumber];
72+
if (line === undefined) {
73+
logger.debug(`${filePath}: line ${lineNumber} - ignoring 'undefined' line.`);
74+
continue;
75+
}
76+
77+
if (listItem.task !== undefined) {
78+
let task;
79+
try {
80+
task = Task.fromLine({
81+
line,
82+
taskLocation: new TaskLocation(
83+
tasksFile,
84+
lineNumber,
85+
currentSection.position.start.line,
86+
sectionIndex,
87+
Cache.getPrecedingHeader(lineNumber, fileCache.headings),
88+
),
89+
fallbackDate: dateFromFileName.value,
90+
});
91+
92+
if (task !== null) {
93+
// listItem.parent could be negative if the parent is not found (in other words, it is a root task).
94+
// That is not a problem, as we never put a negative number in line2ListItem map, so parent will be null.
95+
const parentListItem: ListItem | null = line2ListItem.get(listItem.parent) ?? null;
96+
if (parentListItem !== null) {
97+
task = new Task({
98+
...task,
99+
parent: parentListItem,
100+
});
101+
}
102+
103+
line2ListItem.set(lineNumber, task);
104+
}
105+
} catch (e) {
106+
errorReporter(e, filePath, listItem, line);
107+
continue;
108+
}
109+
110+
if (task !== null) {
111+
sectionIndex++;
112+
tasks.push(task);
113+
}
114+
} else {
115+
const lineNumber = listItem.position.start.line;
116+
117+
const parentListItem: ListItem | null = line2ListItem.get(listItem.parent) ?? null;
118+
119+
line2ListItem.set(lineNumber, new ListItem(fileLines[lineNumber], parentListItem));
120+
}
121+
}
122+
123+
return tasks;
124+
}

tests/Obsidian/SimulatedFile.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { CachedMetadata } from 'obsidian';
22
import { logging } from '../../src/lib/logging';
3-
import { getTasksFromFileContent2 } from '../../src/Obsidian/Cache';
3+
import { getTasksFromFileContent2 } from '../../src/Obsidian/FileParser';
44
import { setCurrentCacheFile } from '../__mocks__/obsidian';
55

66
export interface SimulatedFile {

0 commit comments

Comments
 (0)