diff --git a/taskwarrior/info.json b/taskwarrior/info.json index b480e9a..bfdc0c9 100644 --- a/taskwarrior/info.json +++ b/taskwarrior/info.json @@ -2,8 +2,8 @@ "name": "Taskwarrior import/export", "identifier": "taskwarrior", "script": "taskwarrior.qml", - "version": "0.0.1", + "version": "0.0.2", "minAppVersion": "17.06.1", "authors": ["@fmakowski"], - "description" : "This script creates menu items and buttons to import and export Taskwarrior tasks.\n\nDependencies\n\nUnix-like OSes only!\nTaskwarrior\n\nUsage\n\nThe script takes selected text from your note and parse it to create task entries based on it. The following rules currently apply for the test to be parsed correctly:\n * the project is defined by writing \"project:\" (case-insensitive) immediately followed by the project name; the rest of the line content is skipped\n * the task is defined by making a list item, using either - (minus) or * (asterisk) at the beginning; the task description taken will be used with the most recently detected project name to create a new task\n\nTo Do\n\n * write \"import\" part of the script\n * foolproof used regexps\n * make project nesting easier\n * use headers to determine project name and nesting\n * Windows support" + "description" : "This script creates menu items and buttons to import and export Taskwarrior tasks.\n\nDependencies\n\nUnix-like OSes only!\nTaskwarrior\n\nUsage\n\nExport:\nThe script takes selected text from your note and parse it to create task entries based on it. The following rules currently apply for the test to be parsed correctly:\n * the project is defined by writing \"project:\" (case-insensitive) immediately followed by the project name; the rest of the line content is skipped\n * the task is defined by making a list item, using either - (minus) or * (asterisk) at the beginning; the task description taken will be used with the most recently detected project name to create a new task\n\nImport:\nThe script takes selected text from your note, parsing it into the project names you want to fetch from Taskwarrior into the note. The tasks will be written as a list right below the selection. The project names will be appended before the lists As \"Project: [projectName]\" to separate lists.To Do\n\n * foolproof used regexps\n * make project nesting easier\n * use headers to determine project name and nesting\n * Windows support\n * Taskwarrior parameter parsing (like tags, dates, priority, etc.)" } diff --git a/taskwarrior/taskwarrior.qml b/taskwarrior/taskwarrior.qml index 397b9a0..57e1908 100644 --- a/taskwarrior/taskwarrior.qml +++ b/taskwarrior/taskwarrior.qml @@ -14,7 +14,43 @@ QtObject { 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"); + 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 = /project:[\s*]?(.+)?[\s*]?/i; + var isProjectName = projectRegExp.exec(str); + if (isProjectName) { + func(isProjectName[1]); + return true; + } } /** @@ -25,35 +61,23 @@ QtObject { */ function customActionInvoked(identifier) { + var pathToTaskwarrior = "/usr/bin/task"; + switch (identifier) { // export selected lines to Taskwarriors as tasks. // The project name will be taken from "Project:" keyword detected in first lines. case "exportToTaskwarrior": - // Get selected text and separate it by lines. - - var text = script.noteTextEditSelectedText(); - var separatedByLines; - // Consider Windows different newline method. - if (script.platformIsWindows()) { - separatedByLines = text.split('\r\n'); - } else { - separatedByLines = text.split('\n'); - } // Starting with an empty default project name. - var projectName; + var projectName = ""; // For each line, we are gathering data to properly create tasks. - separatedByLines.forEach(function (line){ - // 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 = /project:[\s*]?(.+)?[\s*]?/i; - var isProjectNameLine = projectRegExp.exec(line); - if (isProjectNameLine) { - projectName = isProjectNameLine[1]; + getSelectedTextAndSeparateByNewline().forEach(function (line){ + if (getProjectNameAndRun(line, function (proName) { + projectName = 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. @@ -63,8 +87,7 @@ QtObject { var isTask = taskRegExp.exec(line); if (isTask) { taskDescription = isTask[1]; - script.log(taskDescription); - script.startDetachedProcess("/usr/bin/task", + script.startDetachedProcess(pathToTaskwarrior, [ "add", "pro:" + projectName, @@ -74,6 +97,59 @@ QtObject { 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) { + 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(pathToTaskwarrior, + [ + "pro:" + projectName, + "rc.report.next.columns=description", + "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) { + script.log("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("Project: " + projectName + "\n\n"); + tasksSeparated.forEach( function(taskDesc){ + script.noteTextEditWrite("* " + taskDesc + "\n"); + }); + + } + + }); + break; + } } }