kevboh / longform

A plugin for Obsidian that helps you write and edit novels, screenplays, and other long projects.
Other
610 stars 30 forks source link

Compile Step: Save Scenes #243

Open Servinjesus1 opened 4 months ago

Servinjesus1 commented 4 months ago

What should this step do? Save individual scenes or some intermediate set of scenes to an output directory.

This is useful for projects where the final output of longform should not be a single manuscript. For example, when I export to LaTeX, I have each chapter be its own .tex file to keep the manuscript files small. So, by exporting each chapter (merging subchapter scenes would be nice) to individual chapter .md's, I can run pandoc on each one and be ready to import to latex, rather than having to now apply padoc to the whole manuscript then split up the file manually.

Progress

I made some (messy, I am in no way a js coder) progress in creating an example custom script that would do this, however I don't have access to certain writing functions like resolvePath within a script and I'm not sure how I could do that. Essentially, this replaces target in a typical Save as Note with a list of targets which would then apply to each scene. To get scene concatenation at the sub-* chapter level, I would either need another compile step or more code in this step to do that.

module.exports = {
    description: {
        name: "Save as Note",
        description: "Saves your scenes as a note in your vault.",
        availableKinds: ["Scene"],
        options: [
            {
                id: "target",
                name: "Output path",
                description: "Path for the created scenes note, relative to your project. $1 will be replaced with your scene's title.",
                type: "Text",
                default: "$1.md",
            },
            {
                id: "open-after",
                name: "Open Compiled Scenes",
                description: "If checked, open the compiled scenes in a new pane.",
                type: "Boolean",
                default: true,
            },
        ],
    },

    /** @typedef {Object} sceneObj defined at https://github.com/kevboh/longform/blob/main/docs/COMPILE.md#user-script-steps
     * @property {number=} indentationLevel - The indent level (starting at zero) of the scene
     * @property {object} metadata - Obsidian metadata of scene
     * @property {string} contents - text contents of scene
     * @property {string} path - path to scene
     * @property {string} name - file name of scene
     * @param {sceneObj[]} scenes
     * @param {{ optionValues: { [option: string]: any; }; }} context
     */
    compile(scenes, context) {
        if (context.kind !== "Manuscript") {
            throw new Error("Cannot write non-manuscript as note.");
        }
        else {
            const targets = scenes.map(scene => {
                const scenePath = scene.path;
                const sceneName = scene.name.replace(/\.[^/.]+$/, ""); // Remove file extension
                const replacedTarget = target.replace("$1", sceneName);
                return `${scenePath}/${replacedTarget}`;
            });
            const openAfter = context.optionValues["open-after"];
            if (!targets || targets.length == 0) {
                throw new Error("Invalid path.");
            }
            const filePath = resolvePath(context.projectPath, target);
            writeToFile(context.app, filePath, input.contents).then(() => {
                if (openAfter) {
                    console.log("[Longform] Attempting to open:", filePath);
                    context.app.workspace.openLinkText(filePath, "/", true).catch((err) => {
                        console.error("[Longform] Could not open", filePath, err);
                    });
                }
            });
            return input;
        }
    },
};