Script: timed sprints with items selected in TaskPaper 3, using Due.app


#1

First draft of a script for timed sprints using due.app (http://www.dueapp.com/) with
items selected in TasksPaper 3

INSTALLATION

See http://guide.taskpaper.com/using_scripts.html

(Copy the whole of the script below)

Also requires the OS X version of http://www.dueapp.com

CUSTOMIZATION

Review and edit the options at the end of this script:

  1. tag to use for Pomodoro units of sprint – (default @pom)
  2. tag to use for specific numbers of minutes – (default @mins)
  3. The number of minutes per pomodoro – (default 25)
  4. The number of minutes to sprint for an untagged item – (default 55)
  5. Minimum mins - the number of minuted for a plain @mins tag with no number

USE

  1. Select one or more items in TaskPaper 3
  2. Run this script
  3. Hit ENTER to confirm the start of the first sprint

Multiple sprints

If you select several items in TaskPaper 3 before running the script

  • or one item with several descendants tagged for pomodoros or numbers of minutes
  • or just one item with several leaf descendants

then when a sprint ends:

  • tap the RIGHT ARROW key to move on to the next sprint in the chain
  • and confirm with ENTER to start the sprint

Selecting the parent item above leads, when the script is first run, to this in Due.app

and then later, when the right arrow key is tapped:

and with the final tap on the right arrow key:

// TIMED SPRINTS USING DUE.APP (http://www.dueapp.com/) WITH
// ITEMS SELECTED IN TASKSPAPER 3

// 0.03
// Rob Trew     Twitter @complexpoint

// INSTALLATION

// See http://guide.taskpaper.com/using_scripts.html

// Also requires the OS X version of http://www.dueapp.com

// CUSTOMIZATION

// Review and edit the options at the end of this script:

// 1. tag to use for Pomodoro units of sprint – (default @pom)
// 2. tag to use for specific numbers of minutes – (default @mins)
// 3. The number of minutes per pomodoro – (default 25)
// 4. The number of minutes to sprint for an untagged item – (default 55)
// 5. Minimum mins - the number of minuted for a plain @minstag with no number

// USE
// 1. Select one or more items in TaskPaper 3
// 2. Run this script
// 3. Hit ENTER to confirm the start of the first sprint

// Multiple sprints
// IF you select several items in TaskPaper 3,
//     or one item with several with pomodoro or minutes tagged descendants
//     or just one item with several leaf descendants
// THEN
//     When the a sprint ends,
//       tap the RIGHT ARROW key to move on to the next sprint in the chain
//     and confirm with ENTER to start the sprint

(function (dctOptions) {

    // TASKPAPER CONTEXT
    function TaskPaperContext(editor, options) {
        // concatMap :: (a -> [b]) -> [a] -> [b]
        function concatMap(f, xs) {
            return [].concat.apply([], xs.map(f));
        }

        // nestURL :: [{text:String, tags:Object}] -> String
        function nestURL(xs) {
            if (xs.length) {
                var h = xs[0],
                    tags = h.tags,
                    t = xs.slice(1),
                    n = Object.keys(tags)

                // Sum of any pomodoro and/or minutes tag values
                .reduce(function (a, k) {
                    return (
                        k === mins && (
                            a += (tags[k] || options.minimumMins)
                        ),
                        k === pom && (
                            a += ((tags[k] || 1) * options.pomMins)
                        ),
                        a
                    );
                }, 0) || options.defaultMins;

                return (
                    'due://x-callback-url/add?title=' +
                    encodeURIComponent(h.text) + (t.length ? (
                        encodeURIComponent('\t\t\t\t' + nestURL(t))
                    ) : '') + '&minslater=' + n.toString()
                );

            } else return '';
        }

        var outline = editor.outline,
            pom = options.pomodoroTag,
            mins = options.minutesTag;

        return nestURL(
            concatMap(
                function (item) {
                    // Descendants of the selected item which are either
                    // leaves or flagged with minutes or pomodoro tags
                    return outline.evaluateItemPath(
                            '(descendant-or-self::(@text!=""' +
                            ' and not (@done or @' +
                            mins + ' or @' + pom + ')) except //*/parent::*)' +
                            ' union descendant-or-self::(@' +
                            mins + ' or @' + pom + ')',
                            item
                        )
                        .map(function (x) {
                            return {
                                text: x.bodyContentString,
                                tags: [pom, mins]
                                    .reduce(function (a, tag) {
                                        var t = 'data-' + tag;
                                        return (
                                            x.hasAttribute(t) &&
                                            (a[tag] =
                                                parseInt(x.getAttribute(t), 10)
                                            ),
                                            a
                                        );
                                    }, {})
                            }
                        });
                },
                editor.selection.selectedItems
            )
        );
    }

    // JAVASCRIPT FOR AUTOMATION CONTEXT
    var ds = Application('Taskpaper')
        .documents,
        strURL = ds.length ? ds[0].evaluate({
            script: TaskPaperContext.toString(),
            withOptions: dctOptions
        }) : undefined;

    //return strURL
    if (strURL) {
        var a = Application.currentApplication(),
            sa = (a.includeStandardAdditions = true, a);

        sa.doShellScript('open "' + strURL + '"');
        return strURL;
    }
})({
    pomodoroTag: 'pom',
    minutesTag: 'mins',
    pomMins: 25,
    defaultMins: 55,
    minimumMins: 2
})

#2

Hi.
If I run it from the script editor the execution is correct and get a record in DUEapp. If I throw from TaskPaper 3.5 I get an error 10004 privileges violated.
How I can solve it?
Thank you very much.


#3

Thank you, @complexpoint. This looks great.

The script throws errors in 3.7.4 (301) too. The one I get is this:

The operation couldn’t be completed. /Users/apkawel/Library/Application Scripts/com.hogbaysoftware.TaskPaper3.direct/pomodoro.scpt:4242:4299: execution error: Error on line 117: Error: Application can’t be found. (-2700)
UP÷nˇa


#4

Version 0.02 was written before the application id of TaskPaper changed.

( Now updated to ver 0.03 above, which uses the release version id )