1
0
Fork 0
mirror of https://github.com/marty-oehme/scripts.git synced 2024-06-26 13:47:56 +00:00
qownnotes-scripts/taskwarrior/taskwarrior.qml

204 lines
8.5 KiB
QML
Raw Normal View History

import QtQml 2.0
import QOwnNotesTypes 1.0
/**
* This script is used for manual interaction with Taskwarrior by either
* importing tasks from a certain project, or exporting them from a note.
*/
QtObject {
property string taskPath;
property bool verbose;
property variant settingsVariables: [
{
"identifier": "taskPath",
"name": "Taskwarrior path",
"description": "A path to your Taskwarrior instance",
"type": "string",
"default": "/usr/bin/task",
},
{
"identifier": "verbose",
"name": "Verbose logging",
"description": "Should the script log every action?",
"type": "boolean",
"default": false
}
];
/**
* Initializes the custom actions
*/
function init() {
// export selected data to Taskwarrior
script.registerCustomAction("exportToTaskwarrior", "Export selected list as Taskwarrior tasks", "Export to Taskwarrior");
// create a menu entry "Create meeting note" with a button and a freedesktop theme icon
script.registerCustomAction("importFromTaskwarrior", "Import tasks from Taskwarrior as a list", "Import from Taskwarrior");
}
/**
* Get selected text and separate it by lines.
*
* @returns array of strings representing separate lines
*/
function getSelectedTextAndSeparateByNewline() {
var text = script.noteTextEditSelectedText();
var separatedByLines;
// Consider Windows different newline method.
if (script.platformIsWindows()) {
separatedByLines = text.split('\r\n');
} else {
separatedByLines = text.split('\n');
}
return separatedByLines;
}
/**
* Parse input string to get the project name and run supplied function if found.
*
* @param str input string which may contain project name
* @param func function to be executed if the project name is found
*
* @returns boolean for if the project name was detected or not
*/
function getProjectNameAndRun(str, func) {
// We are trying to get the name of the project.
// To do so, we are getting the substring of a line by using regexp group.
var projectRegExp = /(#+)[\s*]?(.+)?[\s*]?/i;
var isProjectName = projectRegExp.exec(str);
if (isProjectName) {
var projectName = isProjectName[2];
var headerLevel = isProjectName[1].length;
func(projectName, headerLevel);
return true;
}
}
function logIfVerbose(str) {
if (verbose) {
script.log(str);
}
}
/**
* This function is invoked when a custom action is triggered
* in the menu or via button
*
* @param identifier string the identifier defined in registerCustomAction
*/
function customActionInvoked(identifier) {
switch (identifier) {
// export selected lines to Taskwarriors as tasks.
// The project name will be taken from "Project:" keyword detected in first lines.
case "exportToTaskwarrior":
logIfVerbose("Exporting tasks from a note.");
// Starting with an empty default project name.
// We are keeping the project name as a array of strings. We will concatenate them to
// get the final projectName with nesting.
var projectName = [];
var referenceHeaderLevel = 0;
// For each line, we are gathering data to properly create tasks.
getSelectedTextAndSeparateByNewline().forEach(function (line){
if (getProjectNameAndRun(line, function (proName, headerLevel) {
logIfVerbose("Detected project name: " + proName);
logIfVerbose("Detected header level: " + headerLevel);
if (projectName.length === 0) {
referenceHeaderLevel = headerLevel - 1;
}
if (projectName.length + referenceHeaderLevel >= headerLevel) {
var i;
for (i = projectName.length + referenceHeaderLevel - headerLevel + 1; i > 0; i--) {
projectName.pop();
}
}
projectName.push(proName);
// We expect, that the project name would be the only thing in line, hence `return`.
return;
})) return;
// We are trying to get the task description.
// It should be started with either - (minus) or * (asterisk) to indicate list item.
var taskRegExp = /[\*\-][\s*]?(.+)[\s*]?/;
var taskDescription;
var isTask = taskRegExp.exec(line);
if (isTask) {
taskDescription = isTask[1];
logIfVerbose("Detected task: " + taskDescription);
var concatenatedProjectName = projectName.join('.');
logIfVerbose("Executing \"" + taskPath + " add pro:" + concatenatedProjectName + " " + taskDescription + "\"");
script.startDetachedProcess(taskPath,
[
"add",
"pro:" + concatenatedProjectName,
taskDescription
]);
// We expect, that the task description would be the only thing in the line, hence `return`.
return;
}
});
break;
case "importFromTaskwarrior":
// Get selected text to determine the project we want to import from.
var projectNames = [];
getSelectedTextAndSeparateByNewline().forEach(function (line){
if (getProjectNameAndRun(line, function (proName, headerLevel) {
projectNames.push(proName);
})) return;
});
// To avoid overwriting what we have selected, we are simply writing it
script.noteTextEditWrite(script.noteTextEditSelectedText());
projectNames.forEach( function(projectName) {
var result = script.startSynchronousProcess(taskPath,
[
"pro.is:" + projectName,
"rc.report.next.columns=description.desc",
"rc.report.next.labels=Desc"
],
"");
if (result) {
var tasksSeparated;
// The result does not contain any \n, so we are splitting by whitespace.
tasksSeparated = result.toString().split('\n');
tasksSeparated.splice(0, 1); // removing ""
if (tasksSeparated.length === 0) {
logIfVerbose("No entries");
return;
}
tasksSeparated.splice(0, 1); // removing "Desc"
tasksSeparated.splice(0, 1); // removing "----"
tasksSeparated.splice(tasksSeparated.length - 1, 1); // removing ""
tasksSeparated.splice(tasksSeparated.length - 1, 1); // removing "X tasks"
tasksSeparated.splice(tasksSeparated.length - 1, 1); // removing ""
script.noteTextEditWrite("\n");
script.noteTextEditWrite("# " + projectName + "\n\n");
tasksSeparated.forEach( function(taskDesc){
script.noteTextEditWrite("* " + taskDesc + "\n");
});
}
});
break;
}
}
}