Closed jamie9090 closed 1 month ago
For what it's worth, I was able to achieve something similar to this requested feature on a Mac by tweaking the workflow on my own. Here's what I did: I opened the workflow script append-to-note.js (by right-clicking on the name of the Workflow in Alfred preferences and selecting Open in Finder). I then edited the script in two ways, as follows. What I did here was switch around the order, in the "writeToFile" line in the "APPEND TO FILE" section, of the existing content of the note and the new content to be added. The first version just does that; the second version also adds spacing and a date to the prepended content, and that requires altering the "toAppend" constant. To work, the second version requires that you enter {date} in the Prefix field in the workflow's Configuration panel within Alfred preferences.
I'm a novice at coding and Alfred, so this might well be done more elegantly, or there may be concerning use cases, but this works for me!
`//─────────────────────────────────────────────────────────────────────────── // PREPEND TO FILE
if (!notePathHasHeading) {
writeToFile(absolutePath, toAppend + "\n" + noteContent);
return relativePath; // return for opening function
}
// determine heading location to append to
const lines = noteContent.split("\n");
const headingLineNo = lines
.map((line) => {
const lineIsHeading = line.match(/^#+ /);
if (lineIsHeading) return line.replace(/^#+ /gm, "");
return ""; // ensures that a line with the same content as a heading isn't detected
})
.indexOf(heading);
// guard: heading not found
if (headingLineNo === -1) {
app.displayNotification("", { withTitle: "Heading not found.", subtitle: "Appending to the bottom of the note instead." })
writeToFile(absolutePath, toAppend + "\n" + noteContent);
return relativePath; // return for opening function
}
// Appending at last non-empty line of heading-section
let lastNonEmptyLineNo = -1;
for (let i = headingLineNo + 1; i < lines.length; i++) {
const line = lines[i];
if (isHeading(line)) break;
else if (!isEmpty(line)) lastNonEmptyLineNo = i;
}
if (lastNonEmptyLineNo === -1) {
ensureEmptyLineAt(lines, headingLineNo + 1);
lines.splice(headingLineNo + 2, 0, toAppend);
ensureEmptyLineAt(lines, headingLineNo + 3);
} else {
lines.splice(lastNonEmptyLineNo + 1, 0, toAppend);
}
const content = lines.join("\n");
writeToFile(absolutePath, content);
return relativePath; // return for opening function
}`
`/* @type {AlfredRun} / // biome-ignore lint/correctness/noUnusedVariables: Alfred run function run(argv) { const vaultPath = $.getenv("vault_path");
// PREPARE AND READ FILE
let heading = "";
let relativePath = $.getenv("relative_path");
const toAppend1 = $.getenv("prefix");
const toAppend2 = argv[0];
const notePathHasHeading = /#[^ ][^/]*$/.test(relativePath);
if (notePathHasHeading) {
const tempArr = relativePath.split("#");
heading = tempArr.pop();
relativePath = tempArr.join("");
}
let absolutePath = vaultPath + "/" + relativePath;
if (absolutePath.slice(-3) !== ".md") absolutePath += ".md";
if (!fileExists(absolutePath)) return "invalid"; // trigger error notification in Alfred
const noteContent = readFile(absolutePath);
//───────────────────────────────────────────────────────────────────────────
// PREPEND TO FILE
if (!notePathHasHeading) {
writeToFile(absolutePath, toAppend1 + "\n" + toAppend2 + "\n" + "\n" + noteContent);
return relativePath; // return for opening function
}
// determine heading location to append to
const lines = noteContent.split("\n");
const headingLineNo = lines
.map((line) => {
const lineIsHeading = line.match(/^#+ /);
if (lineIsHeading) return line.replace(/^#+ /gm, "");
return ""; // ensures that a line with the same content as a heading isn't detected
})
.indexOf(heading);
// guard: heading not found
if (headingLineNo === -1) {
app.displayNotification("", { withTitle: "Heading not found.", subtitle: "Appending to the bottom of the note instead." })
writeToFile(absolutePath, toAppend1 + "\n" + toAppend2 + "\n" + "\n" + noteContent);
return relativePath; // return for opening function
}
// Appending at last non-empty line of heading-section
let lastNonEmptyLineNo = -1;
for (let i = headingLineNo + 1; i < lines.length; i++) {
const line = lines[i];
if (isHeading(line)) break;
else if (!isEmpty(line)) lastNonEmptyLineNo = i;
}
if (lastNonEmptyLineNo === -1) {
ensureEmptyLineAt(lines, headingLineNo + 1);
lines.splice(headingLineNo + 2, 0, toAppend);
ensureEmptyLineAt(lines, headingLineNo + 3);
} else {
lines.splice(lastNonEmptyLineNo + 1, 0, toAppend);
}
const content = lines.join("\n");
writeToFile(absolutePath, content);
return relativePath; // return for opening function
} `
I am currently using QuickAdd in Obsidian for this, but I believe Shimmering Obsidian could do this even better.
Actually, it's the other way round: It is much easier to implement interactions with note content in an Obsidian plugin than in "Shimmering Obsidian", since the latter is an Alfred plugin and as such does not have direct access to the same Obsidian functionality a plugin has.
For example, when prepending text, plugins can easily check where the yaml frontmatter of a note ends via Obsidian, and add the text at that location. An Alfred workflow has no access to that kind of information, and thus would need to parse the note content itself to determine the correct location.
While not impossible to implement, such interactions are more easily (and more reliably) done via an Obsidian plugin. In this particular case, I'd recommend creating a feature request at QuickAdd to add a URI scheme, so you can use these instructions to trigger QuickAdd via Alfred. Not only is it much less work for the QuickAdd dev to add a URI scheme than for me to implement a prepend feature, you would get all the customizability of Quickadd at once.
Checklist
Feature Requested
Thanks for this app, it's fantastic.
I would love to be able to "prepend" (start of note, but below frontmatter) rather than "append" (end of note).
Bonus points if we can even specify where to add the note after like QuickAdd.
Alternatives considered
I am currently using QuickAdd in Obsidian for this, but I believe Shimmering Obsidian could do this even better.
Relevant Screenshot
Hereis an example of Quickadd