From 7a1315b494754edbeaec0a748363d261af9ad7f8 Mon Sep 17 00:00:00 2001 From: Filip Makowski Date: Fri, 2 Jun 2017 18:41:47 +0200 Subject: [PATCH 1/2] Added additional parameter parsing as new todo item. Fixed bug where no project results in "undefined" project. Added unfinished "importFromTaskwarrior" case. Also generalized few internal tasks into functions. Written working Import from Taskwarrior action. Also updated description in info.json to reflect the changes. --- taskwarrior/info.json | 2 +- taskwarrior/taskwarrior.qml | 120 +++++++++++++++++++++++++++++------- 2 files changed, 99 insertions(+), 23 deletions(-) diff --git a/taskwarrior/info.json b/taskwarrior/info.json index b480e9a..10f4dd9 100644 --- a/taskwarrior/info.json +++ b/taskwarrior/info.json @@ -5,5 +5,5 @@ "version": "0.0.1", "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; + } } } From 3d8396ed2973f9665c880f563233fb2d5cb6b5b2 Mon Sep 17 00:00:00 2001 From: Filip Makowski Date: Fri, 2 Jun 2017 23:32:37 +0200 Subject: [PATCH 2/2] Taskwarrior: Version 0.0.2 --- taskwarrior/info.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/taskwarrior/info.json b/taskwarrior/info.json index 10f4dd9..bfdc0c9 100644 --- a/taskwarrior/info.json +++ b/taskwarrior/info.json @@ -2,7 +2,7 @@ "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\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.)"