From ba31e557f690e03101934ba1ddfc134025f93fd0 Mon Sep 17 00:00:00 2001 From: Brendan Campbell-Hartzell <50385408+b-camphart@users.noreply.github.com> Date: Sun, 23 Feb 2025 16:11:51 -0800 Subject: [PATCH 1/7] write basic scene index to note on draft change --- src/model/draft-utils.ts | 12 +++++++++-- src/model/note-utils.ts | 7 ++++++- src/model/store-vault-sync.ts | 38 +++++++++++++++++++++++++++++++---- src/model/types.ts | 2 ++ 4 files changed, 52 insertions(+), 7 deletions(-) diff --git a/src/model/draft-utils.ts b/src/model/draft-utils.ts index bcbbfe6..270a777 100644 --- a/src/model/draft-utils.ts +++ b/src/model/draft-utils.ts @@ -18,11 +18,12 @@ type SceneInsertionLocation = { export async function createScene( app: App, path: string, + index: number, draft: MultipleSceneDraft, open: boolean ): Promise { const template = draft.sceneTemplate ?? get(pluginSettings).sceneTemplate; - createNoteWithPotentialTemplate(app, path, template); + await createNoteWithPotentialTemplate(app, path, index, template); if (open) { app.workspace.openLinkText(path, "/", false); } @@ -63,7 +64,14 @@ export async function insertScene( return d; }); }); - await createScene(app, newScenePath, draft, open); + + await createScene( + app, + newScenePath, + draft.scenes.findIndex((s) => s.title === sceneName), + draft, + open + ); } export function setDraftOnFrontmatterObject( diff --git a/src/model/note-utils.ts b/src/model/note-utils.ts index f844f21..cc2c172 100644 --- a/src/model/note-utils.ts +++ b/src/model/note-utils.ts @@ -16,10 +16,12 @@ export function fileNameFromPath(path: string): string { export async function createNoteWithPotentialTemplate( app: App, path: string, + index: number, template: string | null ): Promise { const file = await createNote(app, path); - if (template && file) { + if (!file) return; + if (template) { let contents = ""; let pluginUsed = ""; try { @@ -37,6 +39,9 @@ export async function createNoteWithPotentialTemplate( await app.vault.adapter.write(path, contents); } } + await app.fileManager.processFrontMatter(file, (fm) => { + fm["longform-order"] = index; + }); } /** diff --git a/src/model/store-vault-sync.ts b/src/model/store-vault-sync.ts index 7fdd037..5696807 100644 --- a/src/model/store-vault-sync.ts +++ b/src/model/store-vault-sync.ts @@ -10,15 +10,18 @@ import { cloneDeep, isEqual } from "lodash"; import { get, type Unsubscriber } from "svelte/store"; import type { Draft } from "./types"; -import { drafts as draftsStore, selectedDraftVaultPath } from "./stores"; +import { + drafts as draftsStore, + pluginSettings, + waitingForSync, + selectedDraftVaultPath, +} from "./stores"; import { arraysToIndentedScenes, setDraftOnFrontmatterObject, } from "src/model/draft-utils"; import { fileNameFromPath } from "./note-utils"; -import { findScene, sceneFolderPath } from "./scene-navigation"; -import { pluginSettings } from "./stores"; -import { waitingForSync } from "./stores"; +import { findScene, sceneFolderPath, scenePath } from "./scene-navigation"; type FileWithMetadata = { file: TFile; @@ -568,6 +571,33 @@ export class StoreVaultSync { await this.app.fileManager.processFrontMatter(file, (fm) => { setDraftOnFrontmatterObject(fm, draft); }); + + // for multi-scene projects, optionally set a property on each scene that holds its order within the project + if (get(pluginSettings).writeProperty) { + if (draft.format === "scenes") { + const writes: Promise[] = []; + draft.scenes.forEach((indentedScene, index) => { + const sceneFilePath = scenePath( + indentedScene.title, + draft, + this.app.vault + ); + + const sceneFile = this.app.vault.getAbstractFileByPath(sceneFilePath); + // false if a folder, or not found + if (!(sceneFile instanceof TFile)) { + return; + } + writes.push( + this.app.fileManager.processFrontMatter(sceneFile, (fm) => { + fm["longform-order"] = index; + }) + ); + }); + + await Promise.all(writes); + } + } } } diff --git a/src/model/types.ts b/src/model/types.ts index 74a2d07..7fb994d 100644 --- a/src/model/types.ts +++ b/src/model/types.ts @@ -98,6 +98,7 @@ export interface LongformPluginSettings { waitForSync: boolean; fallbackWaitEnabled: boolean; fallbackWaitTime: number; + writeProperty: boolean; // DEPRECATED. To be removed in future, needed now for migrations. projects: { [path: string]: { @@ -126,6 +127,7 @@ export const DEFAULT_SETTINGS: LongformPluginSettings = { sessionFile: DEFAULT_SESSION_FILE, numberScenes: false, sceneTemplate: null, + writeProperty: false, projects: {}, waitForSync: false, fallbackWaitEnabled: true, From b2ad149c54cb6a120e55901084ea2110b9e70544 Mon Sep 17 00:00:00 2001 From: Brendan Campbell-Hartzell <50385408+b-camphart@users.noreply.github.com> Date: Sun, 23 Feb 2025 16:24:53 -0800 Subject: [PATCH 2/7] sync scene indices when setting is enabled --- src/model/store-vault-sync.ts | 21 +++++++++++++++++++++ src/view/settings/LongformSettings.ts | 19 +++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/src/model/store-vault-sync.ts b/src/model/store-vault-sync.ts index 5696807..8fba1c8 100644 --- a/src/model/store-vault-sync.ts +++ b/src/model/store-vault-sync.ts @@ -601,6 +601,27 @@ export class StoreVaultSync { } } +export function syncSceneIndices(app: App): void | Promise { + const writes: Promise[] = []; + get(draftsStore).forEach((draft) => { + if (draft.format !== "scenes") return; + draft.scenes.map((indentedScene, index) => { + const sceneFilePath = scenePath(indentedScene.title, draft, app.vault); + + const sceneFile = app.vault.getAbstractFileByPath(sceneFilePath); + // false if a folder, or not found + if (!(sceneFile instanceof TFile)) { + return; + } + return app.fileManager.processFrontMatter(sceneFile, (fm) => { + fm["longform-order"] = index; + }); + }); + }); + if (writes.length === 0) return; + return Promise.all(writes); +} + const ESCAPED_CHARACTERS = new Set("/&$^+.()=!|[]{},".split("")); function ignoredPatternToRegex(pattern: string): RegExp { let regex = ""; diff --git a/src/view/settings/LongformSettings.ts b/src/view/settings/LongformSettings.ts index aa5b12e..aadc0b6 100644 --- a/src/view/settings/LongformSettings.ts +++ b/src/view/settings/LongformSettings.ts @@ -13,6 +13,7 @@ import { pluginSettings, userScriptSteps } from "src/model/stores"; import { FolderSuggest } from "./folder-suggest"; import { DEFAULT_SESSION_FILE } from "src/model/types"; import { FileSuggest } from "./file-suggest"; +import { syncSceneIndices } from "src/model/store-vault-sync"; export class LongformSettingsTab extends PluginSettingTab { plugin: LongformPlugin; @@ -65,6 +66,24 @@ export class LongformSettingsTab extends PluginSettingTab { }); }); + new Setting(containerEl) + .setName("Write scene index to frontmatter") + .setDesc( + "If enabled, will add an index number to the frontmatter of scene files." + ) + .addToggle((toggle) => { + toggle.setValue(settings.writeProperty); + toggle.onChange((value) => { + pluginSettings.update((settings) => ({ + ...settings, + writeProperty: value, + })); + if (value) { + syncSceneIndices(this.app); + } + }); + }); + new Setting(containerEl).setName("Compile").setHeading(); new Setting(containerEl) From ad67f3fdc31bba715e265cb232f8e32b98745362 Mon Sep 17 00:00:00 2001 From: Brendan Campbell-Hartzell <50385408+b-camphart@users.noreply.github.com> Date: Sun, 23 Feb 2025 16:50:04 -0800 Subject: [PATCH 3/7] write scene number to file --- src/model/store-vault-sync.ts | 36 +++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/src/model/store-vault-sync.ts b/src/model/store-vault-sync.ts index 8fba1c8..c37bf34 100644 --- a/src/model/store-vault-sync.ts +++ b/src/model/store-vault-sync.ts @@ -18,6 +18,8 @@ import { } from "./stores"; import { arraysToIndentedScenes, + formatSceneNumber, + numberScenes, setDraftOnFrontmatterObject, } from "src/model/draft-utils"; import { fileNameFromPath } from "./note-utils"; @@ -576,9 +578,10 @@ export class StoreVaultSync { if (get(pluginSettings).writeProperty) { if (draft.format === "scenes") { const writes: Promise[] = []; - draft.scenes.forEach((indentedScene, index) => { + const sceneNumbers = numberScenes(draft.scenes); + sceneNumbers.forEach((numberedScene, index) => { const sceneFilePath = scenePath( - indentedScene.title, + numberedScene.title, draft, this.app.vault ); @@ -589,9 +592,12 @@ export class StoreVaultSync { return; } writes.push( - this.app.fileManager.processFrontMatter(sceneFile, (fm) => { - fm["longform-order"] = index; - }) + writeSceneNumbers( + this.app, + sceneFile, + index, + numberedScene.numbering + ) ); }); @@ -605,23 +611,33 @@ export function syncSceneIndices(app: App): void | Promise { const writes: Promise[] = []; get(draftsStore).forEach((draft) => { if (draft.format !== "scenes") return; - draft.scenes.map((indentedScene, index) => { - const sceneFilePath = scenePath(indentedScene.title, draft, app.vault); + numberScenes(draft.scenes).map((numberedScene, index) => { + const sceneFilePath = scenePath(numberedScene.title, draft, app.vault); const sceneFile = app.vault.getAbstractFileByPath(sceneFilePath); // false if a folder, or not found if (!(sceneFile instanceof TFile)) { return; } - return app.fileManager.processFrontMatter(sceneFile, (fm) => { - fm["longform-order"] = index; - }); + return writeSceneNumbers(app, sceneFile, index, numberedScene.numbering); }); }); if (writes.length === 0) return; return Promise.all(writes); } +function writeSceneNumbers( + app: App, + file: TFile, + index: number, + numbering: number[] +) { + return app.fileManager.processFrontMatter(file, (fm) => { + fm["longform-order"] = index; + fm["longform-number"] = formatSceneNumber(numbering); + }); +} + const ESCAPED_CHARACTERS = new Set("/&$^+.()=!|[]{},".split("")); function ignoredPatternToRegex(pattern: string): RegExp { let regex = ""; From 3aa68c77b3f8618a8dc50ef3e4db26dbfb45911f Mon Sep 17 00:00:00 2001 From: Brendan Campbell-Hartzell <50385408+b-camphart@users.noreply.github.com> Date: Sun, 23 Feb 2025 16:56:37 -0800 Subject: [PATCH 4/7] persist "writeProperty" setting --- src/model/types.ts | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/src/model/types.ts b/src/model/types.ts index 7fb994d..4cd202e 100644 --- a/src/model/types.ts +++ b/src/model/types.ts @@ -134,7 +134,7 @@ export const DEFAULT_SETTINGS: LongformPluginSettings = { fallbackWaitTime: 5, }; -export const TRACKED_SETTINGS_PATHS = [ +export const TRACKED_SETTINGS_PATHS: (keyof LongformPluginSettings)[] = [ "version", "projects", "selectedDraftVaultPath", @@ -154,22 +154,25 @@ export const TRACKED_SETTINGS_PATHS = [ "waitForSync", "fallbackWaitEnabled", "fallbackWaitTime", + "writeProperty", ]; -export const PASSTHROUGH_SAVE_SETTINGS_PATHS = [ - "sessionStorage", - "userScriptFolder", - "showWordCountInStatusBar", - "startNewSessionEachDay", - "sessionGoal", - "applyGoalTo", - "notifyOnGoal", - "countDeletionsForGoal", - "keepSessionCount", - "sessionFile", - "numberScenes", - "sceneTemplate", - "waitForSync", - "fallbackWaitEnabled", - "fallbackWaitTime", -]; +export const PASSTHROUGH_SAVE_SETTINGS_PATHS: (keyof LongformPluginSettings)[] = + [ + "sessionStorage", + "userScriptFolder", + "showWordCountInStatusBar", + "startNewSessionEachDay", + "sessionGoal", + "applyGoalTo", + "notifyOnGoal", + "countDeletionsForGoal", + "keepSessionCount", + "sessionFile", + "numberScenes", + "sceneTemplate", + "waitForSync", + "fallbackWaitEnabled", + "fallbackWaitTime", + "writeProperty", + ]; From 82a29f610c57a010da1c6219c44ff62bf8f4b0a4 Mon Sep 17 00:00:00 2001 From: Brendan Campbell-Hartzell <50385408+b-camphart@users.noreply.github.com> Date: Sun, 23 Feb 2025 16:58:02 -0800 Subject: [PATCH 5/7] inform users that two properties will be written to scenes --- src/view/settings/LongformSettings.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/view/settings/LongformSettings.ts b/src/view/settings/LongformSettings.ts index aadc0b6..a1716bc 100644 --- a/src/view/settings/LongformSettings.ts +++ b/src/view/settings/LongformSettings.ts @@ -69,7 +69,7 @@ export class LongformSettingsTab extends PluginSettingTab { new Setting(containerEl) .setName("Write scene index to frontmatter") .setDesc( - "If enabled, will add an index number to the frontmatter of scene files." + "If enabled, will add a scene index, and scene number, to the frontmatter of scene files." ) .addToggle((toggle) => { toggle.setValue(settings.writeProperty); From 24b1363596a012bf103661e2a0f0d52272cafadc Mon Sep 17 00:00:00 2001 From: Brendan Campbell-Hartzell <50385408+b-camphart@users.noreply.github.com> Date: Sat, 22 Mar 2025 08:46:22 -0700 Subject: [PATCH 6/7] check opt-in during scene creation not sure how this got removed during the rebase, but this commit adds the check back in so that the scene index is not written to the new file if the user has not opted-in. --- src/model/note-utils.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/model/note-utils.ts b/src/model/note-utils.ts index cc2c172..6b577d4 100644 --- a/src/model/note-utils.ts +++ b/src/model/note-utils.ts @@ -2,6 +2,8 @@ import { last, sum } from "lodash"; import type { App, TFile } from "obsidian"; import type { Draft, DraftWordCounts } from "./types"; +import { get } from "svelte/store"; +import { pluginSettings } from "./stores"; export function fileNameFromPath(path: string): string { return last(path.split("/")).split(".md")[0]; @@ -39,9 +41,11 @@ export async function createNoteWithPotentialTemplate( await app.vault.adapter.write(path, contents); } } - await app.fileManager.processFrontMatter(file, (fm) => { - fm["longform-order"] = index; - }); + if (get(pluginSettings).writeProperty) { + await app.fileManager.processFrontMatter(file, (fm) => { + fm["longform-order"] = index; + }); + } } /** From 80114e0ea55a56a2e11b35e6609bf4b79b10eaac Mon Sep 17 00:00:00 2001 From: Brendan Campbell-Hartzell <50385408+b-camphart@users.noreply.github.com> Date: Sat, 22 Mar 2025 08:53:11 -0700 Subject: [PATCH 7/7] move writting scene number to draft utils it made more sense for the writing of draft information about the scene to be within the "createScene" usecase code than the note utils file. createNoteWithPotentialTemplate now returns the TFile, if successful. Updated documentation to reflect this new behavior. --- src/model/draft-utils.ts | 10 +++++++++- src/model/note-utils.ts | 15 +++++---------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/model/draft-utils.ts b/src/model/draft-utils.ts index 270a777..ab34d14 100644 --- a/src/model/draft-utils.ts +++ b/src/model/draft-utils.ts @@ -23,7 +23,15 @@ export async function createScene( open: boolean ): Promise { const template = draft.sceneTemplate ?? get(pluginSettings).sceneTemplate; - await createNoteWithPotentialTemplate(app, path, index, template); + const note = await createNoteWithPotentialTemplate(app, path, template); + if (note === null) return; + + if (get(pluginSettings).writeProperty) { + await app.fileManager.processFrontMatter(note, (fm) => { + fm["longform-order"] = index; + }); + } + if (open) { app.workspace.openLinkText(path, "/", false); } diff --git a/src/model/note-utils.ts b/src/model/note-utils.ts index 6b577d4..c1205e9 100644 --- a/src/model/note-utils.ts +++ b/src/model/note-utils.ts @@ -2,8 +2,6 @@ import { last, sum } from "lodash"; import type { App, TFile } from "obsidian"; import type { Draft, DraftWordCounts } from "./types"; -import { get } from "svelte/store"; -import { pluginSettings } from "./stores"; export function fileNameFromPath(path: string): string { return last(path.split("/")).split(".md")[0]; @@ -14,15 +12,16 @@ export function fileNameFromPath(path: string): string { * Prefers Templater, then the core Templates plugin, then a plain note without using the template. * @param path Path to note to create. * @param template Path to template to use. + * + * @returns `null` if it fails to create the note. `TFile` for the new note, if successful. */ export async function createNoteWithPotentialTemplate( app: App, path: string, - index: number, template: string | null -): Promise { +): Promise { const file = await createNote(app, path); - if (!file) return; + if (!file) return null; if (template) { let contents = ""; let pluginUsed = ""; @@ -41,11 +40,7 @@ export async function createNoteWithPotentialTemplate( await app.vault.adapter.write(path, contents); } } - if (get(pluginSettings).writeProperty) { - await app.fileManager.processFrontMatter(file, (fm) => { - fm["longform-order"] = index; - }); - } + return file; } /**