Skip to content

Commit

Permalink
Address issues identified by @liamcain (obsidianmd/obsidian-releases#…
Browse files Browse the repository at this point in the history
…960 (comment)); miscellaneous refactorings; bump version
  • Loading branch information
therden committed May 21, 2022
1 parent be1b541 commit cbcb5d7
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 111 deletions.
22 changes: 9 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ The above behavior is "alright"; but *completed instances of recurring tasks* te
After some reflection, I realized that my completed recurring tasks fall into three categories:

1. those that I don't care to keep -- they can be deleted
2. those that I want to retain in their original note file -- but moved to the end/bottom
3. those that I want to move to a separate archival note file)
2. those that I want to retain within their original note file, but relocated at the end/bottom
3. those that I want to move to a separate archival note file

By including within your recurring tasks a 'trigger' that identifies which of the above actions you want to apply to your completed instances, we can automate those actions.

Expand All @@ -35,31 +35,27 @@ The *default* "trigger" for each **Packrat** action takes the form of an *html c

I chose to use *comments* because they aren't displayed in **Obsidian**'s Preview mode, and also to keep them out of its *Tag* pane.

However, you can change the trigger values within **Packrat**'s settings -- to #tags, or @values, or any other string (including Unicode characters) that is supported by **Obsidian**.
However, you can change the trigger values within **Packrat**'s settings -- to #tags, or @values, or any other string (including Unicode characters) that **Obsidian** supports.

## Using **Packrat**

**Packrat** adds a single command to the *Command Palette*.
**Packrat** adds a single command to Obsidian.

Assuming that your active note contains one or more completed instances of recurring tasks, open the *Command Palette* and select "Packrat: Process completed recurring Tasks within the active note".
Assuming that you have a markdown file open as your active note, invoke the *Command Palette* and select "Packrat: Process completed recurring Tasks within the active note".

When that command is issued, **Packrat** will scan the file for completed instances of recurring tasks and act upon each based upon any trigger value contained within it.
When that command is issued, **Packrat** will scan the file for completed instances of recurring tasks and act on each depending on the trigger value(s) it contains.

## Default 'archive file'

By default, **Packrat** appends completed recurring tasks that you want to archive to a file named `archive.md` located in the root directory of the vault -- it will create the file if it doesn't already exist.
By default, **Packrat** appends completed recurring tasks that you want to archive to a file named `archive.md` located in the root directory of the vault. It will create the file if it doesn't already exist.

Both the location and name of this "archive file" can be changed in **Packrat**'s settings; the only requirement is that the file have an ".md" extension.
Both the location and name of this "archive file" can be changed in **Packrat**'s settings; the only requirements are that the filepath must exist and the filename must have an ".md" extension.

## Installation

**Packrat** has not yet been reviewed and accepted as a Community Plugin.

Until it is...

(*if* it ever is: because I don't really know Typescript/Javascript, I pretty much hacked this together -- it probably doesn't meet code quality standards, and I may not be capable of doing much about that)

...this plugin can be installed manually as follows:
Until it is, it can be installed manually as follows:

1. Create the following subidirectory of your **Obsidian** vault: `.obsidian/plugins/packrat/`
2. From the most recent Release for the repo, copy the files `main.js`, `styles.css`, `manifest.json` to that subdirectory
Expand Down
187 changes: 94 additions & 93 deletions main.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { App, TFile, Notice, Plugin, PluginSettingTab, Setting } from 'obsidian';
import { App, Notice, Plugin, PluginSettingTab, Setting, TFile } from 'obsidian';

export interface PackratSettings {
deletion_signifier: string;
bottom_signifier: string;
archive_signifier: string;
deletion_trigger: string;
bottom_trigger: string;
archive_trigger: string;
archive_filepath: string;
}

export const DEFAULT_SETTINGS: PackratSettings = {
deletion_signifier: '%%done_del%%',
bottom_signifier: '%%done_end%%',
archive_signifier: '%%done_log%%',
deletion_trigger: '%%done_del%%',
bottom_trigger: '%%done_end%%',
archive_trigger: '%%done_log%%',
archive_filepath: 'archive.md',
}

Expand All @@ -22,25 +22,25 @@ export default class PackratPlugin extends Plugin {

await this.loadSettings();

// This adds a settings tab so the user can configure various aspects of the plugin
this.addSettingTab(new PackratSettingTab(this.app, this));

// This adds a Command to the Command Palette
this.addCommand({
id: 'tasks-run-packrat',
this.addCommand({ // (to the Command Palette)
id: 'run',
name: 'Process completed recurring Tasks within the active note',

checkCallback: (checking: boolean) => {
// Packrat only works on an open markdown (.md) note file
const { workspace } = this.app;
const activeFile = workspace.getActiveFile();
if (!activeFile || activeFile.extension !== "md") {
} else {
if (!checking) {
this.ProcessCompletedRecurringTasks(activeFile);
// Include in Command Palette only when function returns true
if (activeFile && activeFile.extension == "md") {
if (checking) {
return true;
}
// Command Palette will only display this command when the check function returns true
return true;
// Actually execute command
this.ProcessCompletedRecurringTasks(activeFile);
} else {
return false;
}
}
});
Expand All @@ -59,89 +59,90 @@ export default class PackratPlugin extends Plugin {
}

async ProcessCompletedRecurringTasks(activeFile): Promise<void> {
const { vault } = this.app;

const rruleSignifier = "🔁".normalize();
const deleteSignifier = this.settings.deletion_signifier;
const archiveSignifier = this.settings.archive_signifier;
const bottomSignifier = this.settings.bottom_signifier;
const archiveFilename = this.settings.archive_filepath;

let deletedTaskCount = 0;
let movedTaskCount = 0;
let archivedTaskCount = 0;
let thisLine = "";
let writebackLines = [];
let appendLines = [];
let archiveLines = [];
let results = [];

let fileContents = await vault.read(activeFile);
fileContents = fileContents.split("\n");

for (let i = 0; i < fileContents.length; i++) {
thisLine = fileContents[i];
let firstFive = thisLine.substring(0, 5).toUpperCase()
// test if this is a completed task
if (firstFive == "- [X]") {
// test if line includes Tasks' recurrence signifier 🔁
if (0 < thisLine.indexOf(rruleSignifier)) {
// test for 'delete' signifier
if (0 < thisLine.indexOf(deleteSignifier)) {

try {
const { vault } = this.app;
const rruleSignifier = "🔁".normalize();
const deleteTrigger = this.settings.deletion_trigger;
const archiveTrigger = this.settings.archive_trigger;
const bottomTrigger = this.settings.bottom_trigger;
const archiveFilename = this.settings.archive_filepath;
const archiveFile =
(vault.getAbstractFileByPath(archiveFilename)) ||
(await vault.create(archiveFilename, ""));

let deletedTaskCount = 0;
let movedTaskCount = 0;
let archivedTaskCount = 0;
let thisLine = "";
let writebackLines = [];
let appendLines = [];
let archiveLines = [];
let results = [];

let fileContents = await vault.read(activeFile);
fileContents = fileContents.split("\n");

for (let i = 0; i < fileContents.length; i++) {
thisLine = fileContents[i];
let firstFive = thisLine.substring(0, 5).toUpperCase()
// test if this is a completed instance of recurring Task
if (firstFive === "- [X]" && thisLine.indexOf(rruleSignifier) != -1) {
// test for 'delete' trigger
if (0 < thisLine.indexOf(deleteTrigger)) {
deletedTaskCount += 1;
continue;
}
// test for 'archive' signifier
if (0 < thisLine.indexOf(archiveSignifier)) {
// test for 'archive' trigger
if (0 < thisLine.indexOf(archiveTrigger)) {
archiveLines.push(thisLine);
archivedTaskCount += 1;
continue;
}
// test for 'move' signifier
if (0 < thisLine.indexOf(bottomSignifier)) {
// test for 'move' trigger
if (0 < thisLine.indexOf(bottomTrigger)) {
appendLines.push(thisLine);
movedTaskCount += 1;
continue;
}
// no matching signifier
// completed recurring Task with no Packrat triggers
writebackLines.push(thisLine);
}
else {
// not a completed recurring Task
writebackLines.push(thisLine);
}
} else {
writebackLines.push(thisLine);
}
}

// write designated Tasks to archive file
const archiveFile =
vault.getAbstractFileByPath(archiveFilename) ||
(await vault.create(archiveFilename, ""));

if (!(archiveFile instanceof TFile)) {
new Notice(`${archiveFilename} is not a valid markdown file`);
} else {
let archiveFileContents = await vault.read(archiveFile);
archiveFileContents = archiveFileContents.split("\n");
archiveFileContents = archiveFileContents.concat(archiveLines);
vault.modify(archiveFile, archiveFileContents.join("\n"));
}
if (archivedTaskCount > 0) { // otherwise needn't modify archiveFile
let archiveFileContents = await vault.read(archiveFile);
archiveFileContents = archiveFileContents.split("\n");
archiveFileContents = archiveFileContents.concat(archiveLines);
vault.modify(archiveFile, archiveFileContents.join("\n"));
}

// rewrite active Note file with designated Tasks at bottom and Deleted and Archived tasks removed
results = writebackLines.concat(appendLines);
vault.modify(activeFile, results.join("\n"));
var tdMsg = `${deletedTaskCount} tasks deleted\n`;
var tmMsg = `${movedTaskCount} tasks moved to end of note\n`;
var taMsg = `${archivedTaskCount} tasks archived\n`;
const noticeText = tdMsg + tmMsg + taMsg;
new Notice(noticeText);
// rewrite active Note file with designated Tasks at bottom and Deleted and Archived tasks removed
results = writebackLines.concat(appendLines);
vault.modify(activeFile, results.join("\n"));
var tdMsg = `${deletedTaskCount} tasks deleted\n`;
var tmMsg = `${movedTaskCount} tasks moved to end of note\n`;
var taMsg = `${archivedTaskCount} tasks archived\n`;
const noticeText = tdMsg + tmMsg + taMsg;
new Notice(noticeText);
} catch (err) {
new Notice(err);
console.log(err);
return;
}
}
}

class PackratSettingTab extends PluginSettingTab {
plugin: PackratPlugin;

public defaultDeletionsignifier = "%%done_del%%";
public defaultBottomsignifier = "%%done_move%%";
public defaultArchivesignifier = "%%done_log%%";
public defaultDeletionTrigger = "%%done_del%%";
public defaultBottomTrigger = "%%done_move%%";
public defaultArchiveTrigger = "%%done_log%%";
public defaultArchiveFilepath = "logfile.md";

constructor(app: App, plugin: PackratPlugin) {
Expand All @@ -155,38 +156,38 @@ class PackratSettingTab extends PluginSettingTab {
containerEl.createEl('h2', { text: 'Packrat plugin settings' });

new Setting(containerEl)
.setName('Deletion signifier')
.setName('Deletion trigger')
.setDesc('Text to trigger deletion of completed recurring Task instance')
.addText(text => text
.setPlaceholder(this.defaultDeletionsignifier)
.setValue(this.plugin.settings.deletion_signifier)
.setPlaceholder(this.defaultDeletionTrigger)
.setValue(this.plugin.settings.deletion_trigger)
.onChange(async (value) => {
console.log('deletion_signifier: ' + value);
this.plugin.settings.deletion_signifier = value;
console.log('deletion_trigger: ' + value);
this.plugin.settings.deletion_trigger = value;
await this.plugin.saveSettings();
}));

new Setting(containerEl)
.setName('"Move to end of file" signifier')
.setName('"Move to end of file" trigger')
.setDesc('Text to trigger moving completed recurring Task instance to bottom of Active note')
.addText(text => text
.setPlaceholder(this.defaultBottomsignifier)
.setValue(this.plugin.settings.bottom_signifier)
.setPlaceholder(this.defaultbottomTrigger)
.setValue(this.plugin.settings.bottom_trigger)
.onChange(async (value) => {
console.log('bottom_signifier: ' + value);
this.plugin.settings.bottom_signifier = value;
console.log('bottom_trigger: ' + value);
this.plugin.settings.bottom_trigger = value;
await this.plugin.saveSettings();
}));

new Setting(containerEl)
.setName('Archive signifier')
.setName('Archive trigger')
.setDesc('Text to trigger moving completed recurring Task instance to archive note')
.addText(text => text
.setPlaceholder(this.defaultArchivesignifier)
.setValue(this.plugin.settings.archive_signifier)
.setPlaceholder(this.defaultarchiveTrigger)
.setValue(this.plugin.settings.archive_trigger)
.onChange(async (value) => {
console.log('archive_signifier: ' + value);
this.plugin.settings.archive_signifier = value;
console.log('archive_trigger: ' + value);
this.plugin.settings.archive_trigger = value;
await this.plugin.saveSettings();
}));

Expand Down
2 changes: 1 addition & 1 deletion manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"id": "tasks-packrat-plugin",
"name": "Packrat",
"version": "1.0.0",
"version": "1.1.0",
"minAppVersion": "0.12.0",
"description": "Process completed recurring Tasks",
"author": "Thomas Herden",
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "Packrat Plugin",
"version": "1.0.0",
"description": "Process completed recurring Tasks",
"version": "1.1.0",
"description": "Process completed recurring Tasks based on in-line triggers",
"main": "main.js",
"scripts": {
"dev": "node esbuild.config.mjs",
Expand All @@ -10,7 +10,7 @@
},
"keywords": [
"Obsidian.md",
"Tasks plugin",
"Obsidian Tasks plugin extension",
"completed recurring tasks"
],
"author": "therden",
Expand Down
2 changes: 1 addition & 1 deletion versions.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"1.0.0": "0.14.2"
"1.1.0": "0.14.2"
}

0 comments on commit cbcb5d7

Please sign in to comment.