Major codebase rework

This commit is contained in:
alexandrerbb 2024-04-27 14:12:38 +02:00 committed by alexandrerbb
parent 4a9457efd7
commit 0989618723
4 changed files with 96 additions and 90 deletions

View File

@ -1,23 +0,0 @@
export class Heading {
title: string;
hLevel: number;
treeLevel: number;
parent: Heading | null;
constructor(
title: string,
hLevel: number,
treeLevel: number,
parent: Heading | null,
) {
Object.assign(this, { title, hLevel, treeLevel, parent });
}
getParent(hLevel: number): Heading | undefined {
return this.hLevel < hLevel ? this : this.parent?.getParent(hLevel);
}
toMarkdown(): string {
return `${"\t".repeat(this.treeLevel)}- [ ] ${this.title}`;
}
}

View File

@ -10,25 +10,17 @@ import {
type TFile,
type TFolder,
} from "obsidian";
import { Heading } from "src/heading";
import { TaskList, TaskListInterface } from "src/taskList";
interface OutlineTaskListPluginSettings {
maxNoteCreationReties: number;
}
type EditorCallbackFunction<T> = (editor: Editor, view: MarkdownView) => T;
type PluginEditorCallbackFunction<T> = ({
editor,
file,
taskList,
}: {
interface PluginEditorCallbackParameters {
editor: Editor;
file: TFile;
taskList: string;
}) => T;
type Outline = Heading[];
tasks: TaskListInterface;
}
const DEFAULT_SETTINGS: OutlineTaskListPluginSettings = {
maxNoteCreationReties: 200,
@ -40,44 +32,6 @@ export default class OutlineTaskListPlugin extends Plugin {
*/
settings: OutlineTaskListPluginSettings;
/**
* Parse the headings of the specified markdown content.
*/
static parseOutline(makdownContent: string): Outline {
const lines = makdownContent
.split(/\r?\n/)
.filter((line) => line !== null && line.startsWith("#"));
const outline: Outline = [];
for (const line of lines) {
const hLevel = (line.match(/^#+/) as RegExpMatchArray)[0].length;
const prevHeading = outline.at(-1);
let parent = null;
if (prevHeading !== undefined) {
const sign = Math.sign(hLevel - prevHeading.hLevel);
parent =
sign === -1
? (parent = prevHeading.getParent(hLevel) || null)
: sign === 0
? prevHeading.parent
: prevHeading; // sign === 1
}
const treeLevel = parent ? parent.treeLevel + 1 : 0;
outline.push(
new Heading(line.replace(/^#+\s*/, ""), hLevel, treeLevel, parent),
);
}
return outline;
}
/**
* Build the task list from the specified outline.
*/
static buildTasklist(outline: Outline): string {
return outline.map((heading) => heading.toMarkdown()).join("\r\n");
}
/**
* Create an Obsidian note to store the resulting task list.
*/
@ -85,7 +39,7 @@ export default class OutlineTaskListPlugin extends Plugin {
originalName: string,
folder: TFolder | null,
makdownContent: string,
): Promise<TFile | undefined> {
): Promise<TFile> {
const dirPath = folder === null ? "" : folder.path + "/";
for (let index = 1; index < this.settings.maxNoteCreationReties; index++) {
try {
@ -95,45 +49,43 @@ export default class OutlineTaskListPlugin extends Plugin {
makdownContent,
);
} catch (e) {
// File already exists.
continue;
continue; // File already exists.
}
}
throw Error("Maximum note creation retries exceeded.");
}
/**
* Custom editor callback.
*/
pluginEditorCallback<T>(
callback: PluginEditorCallbackFunction<T>,
): EditorCallbackFunction<T | undefined> {
pluginEditorCallback<T = unknown>(
callback: ({ editor, file, tasks }: PluginEditorCallbackParameters) => T,
): (editor: Editor, view: MarkdownView) => T {
return (editor: Editor, view: MarkdownView) => {
const file = view.file;
if (file === null) {
throw Error();
if (!file) {
throw Error("Cannot find the opened note.");
}
const outline = OutlineTaskListPlugin.parseOutline(editor.getValue());
const taskList = OutlineTaskListPlugin.buildTasklist(outline);
return callback({ editor, file, taskList });
const tasks = TaskList();
tasks.parseOutline(editor.getValue());
return callback({ editor, file, tasks });
};
}
async onload() {
await this.loadSettings();
// Insert task list in editor.
this.addCommand({
id: "outline-task-list-insert",
name: "Convert outline to a task list here.",
editorCallback: this.pluginEditorCallback(({ editor, taskList }) => {
editor.replaceRange(taskList, editor.getCursor());
editorCallback: this.pluginEditorCallback(({ editor, tasks }) => {
editor.replaceRange(tasks.toMarkdown(), editor.getCursor());
}),
});
// Insert task list a a new note.
this.addCommand({
id: "outline-task-list-new-note",
name: "Convert outline to a task list in a new note.",
editorCallback: this.pluginEditorCallback(async ({ file, taskList }) => {
await this.createNote(file.basename, file.parent, taskList);
editorCallback: this.pluginEditorCallback(async ({ file, tasks }) => {
await this.createNote(file.basename, file.parent, tasks.toMarkdown());
}),
});
}

31
src/task.ts Normal file
View File

@ -0,0 +1,31 @@
export interface TaskInterface {
title: string;
standardLevel: number;
treeLevel: number;
parent?: TaskInterface;
getParent: (targetLevel: number) => TaskInterface | undefined;
toMarkdown: () => string;
}
export const Task = (
title: string,
standardLevel: number,
treeLevel: number,
parent: TaskInterface | undefined,
): TaskInterface => {
const getParent = (targetLevel: number) =>
standardLevel < targetLevel
? Task(title, standardLevel, treeLevel, parent) // this
: parent?.getParent(targetLevel);
const toMarkdown = () => `${"\t".repeat(treeLevel)}- [ ] ${title}`;
return {
title,
standardLevel,
treeLevel,
parent,
getParent,
toMarkdown,
};
};

46
src/taskList.ts Normal file
View File

@ -0,0 +1,46 @@
import { Task, TaskInterface } from "src/task";
export interface TaskListInterface {
tasks: TaskInterface[];
parseOutline: (makdownContent: string) => void;
toMarkdown: () => string;
}
export const TaskList = (): TaskListInterface => {
const tasks: TaskInterface[] = [];
const getParentTask = (taskLevel: number): TaskInterface | undefined => {
const prevTask = tasks.at(-1);
if (prevTask === undefined) {
return undefined;
}
const sign = Math.sign(taskLevel - prevTask.standardLevel) as -1 | 0 | 1;
switch (sign) {
case -1:
return prevTask.getParent(taskLevel);
case 0:
return prevTask.parent;
case 1:
return prevTask;
}
};
const parseOutline = function (makdownContent: string): void {
const lines = makdownContent
.split(/\r?\n/)
.filter((line) => line && line.startsWith("#"));
for (const line of lines) {
const taskLevel = (line.match(/^#+/) as RegExpMatchArray)[0].length;
const parent = getParentTask(taskLevel);
const treeLevel = parent ? parent.treeLevel + 1 : 0;
tasks.push(
Task(line.replace(/^#+\s*/, ""), taskLevel, treeLevel, parent),
);
}
};
const toMarkdown = () => tasks.map((task) => task.toMarkdown()).join("\r\n");
return { tasks, parseOutline, toMarkdown };
};