|
/** |
|
* Toggles a task in a file based on the given Dataview task action and the given status or scheduled date. |
|
* |
|
* @param {Object} action - The Dataview task object containing the task details. |
|
* @param {string} status - The status to toggle the task to. |
|
* @param {string} [date=null] - The date to schedule the task, if applicable. |
|
* @return {Promise<void>} A promise that resolves when the task is toggled. |
|
*/ |
|
|
|
async function processFile(file, action, toggledTask) { |
|
const cachedData = await app.vault.cachedRead(file); |
|
return app.vault.process(file, (data) => { |
|
if (cachedData !== data) { |
|
data = cachedData; |
|
} |
|
let lines = data.split("\n"); |
|
lines[action.line] = toggledTask; |
|
data = lines.join("\n"); |
|
return data; |
|
}); |
|
} |
|
|
|
function taskStale(action, lines) { |
|
return lines[action.line] !== action.text; |
|
} |
|
|
|
async function toggleTask(action, status, date = null, newTag = null) { |
|
|
|
const dv = app.plugins.plugins["dataview"].api; |
|
const { DateTime} = dv.luxon; |
|
|
|
const file = app.vault.getFileByPath(action.path); |
|
const data = await app.vault.cachedRead(file); |
|
const lines = data.split("\n"); |
|
|
|
const tasksAPI = app.plugins.plugins["obsidian-tasks-plugin"].apiV1; |
|
|
|
let taskText = ""; |
|
|
|
if (taskStale(action, data)) { |
|
taskText = lines[action.line]; |
|
} else { |
|
taskText = `- [ ] ${action.text}`; |
|
} |
|
|
|
// Regular expressions for task checkboxes, tags and scheduled dates |
|
const checkboxRegex = /\-\s{1}\[.\]/g; |
|
const todoTagRegex = /(\#todo\/\S+)/m; |
|
const scheduledDateRegex = /⏳\s{1}(\d{4}-\d{2}-\d{2})/gu; |
|
|
|
const path = action.path; |
|
|
|
let toggledTask = ""; |
|
|
|
switch(status) { |
|
case "done": |
|
toggledTask = tasksAPI.executeToggleTaskDoneCommand(taskText, path); |
|
break; |
|
case "dropped": |
|
toggledTask = taskText.replace(checkboxRegex, "- [-]").replace(todoTagRegex, ""); |
|
break; |
|
case "half-done": |
|
toggledTask = taskText.replace(checkboxRegex, "- [/]"); |
|
break; |
|
case "schedule": |
|
const scheduledDate = date; |
|
// I had to add .c after scheduled for luxon to be able to parse the date. |
|
const scheduled = action.scheduled ? true : false; |
|
if (scheduled) { |
|
const oldScheduledDate = DateTime.fromObject(action.scheduled.c).toFormat("yyyy-MM-dd"); |
|
if (scheduledDate === oldScheduledDate) { |
|
new Notice("Task already scheduled today"); |
|
return; |
|
} |
|
} |
|
|
|
const regexMatch = taskText.match(scheduledDateRegex); |
|
const caretIndex = taskText.indexOf("^"); |
|
|
|
if (regexMatch) { |
|
toggledTask = taskText.replace(scheduledDateRegex, (match, p1) => { |
|
return match.replace(p1, scheduledDate); |
|
}); |
|
} else if (caretIndex !== -1) { |
|
const beforeCaret = taskText.slice(0, caretIndex); |
|
const afterCaret = taskText.slice(caretIndex); |
|
toggledTask = `${beforeCaret}⏳ ${scheduledDate} ${afterCaret}`; |
|
} else { |
|
toggledTask = taskText + `⏳ ${scheduledDate}`; |
|
} |
|
break; |
|
case "re-tag": |
|
if (!newTag.startsWith("#")) { |
|
newTag = `#${newTag}`; |
|
} |
|
toggledTask = taskText.replace(todoTagRegex, newTag); |
|
break; |
|
default: |
|
new Notice("Status not recognised"); |
|
return; |
|
} |
|
|
|
await processFile(file, action, toggledTask); |
|
} |
|
module.exports = toggleTask; |