Feature request: "Focus selection" / "Unfocus" commands

Please correct me if I’m overlooking this feature already.

I would love the ability to focus the project where my text insertion point is currently. (And to then unfocus back out again while still showing the project that had just been focused.)

I’m picturing a “hide others”/“show all” system.

1 Like

In the meanwhile, to toggle the hoisting of the project containing the cursor, you should be able to attach this to a keystroke (or put it in a Keyboard Maestro JXA action)

// TOGGLE HOISTING OF PROJECT CONTAINING CURSOR
// v 0.3

(function () {
    'use strict';

    // TASKPAPER 3 EVALUATION CONTEXT
    function projectHoistToggle(editor) {

            // selection ?
        var rngSeln = editor.getSelectedItemRange(),
            oSeln = rngSeln ? rngSeln.startItem : null,
            
            // containing project ?
            lstSelnProj = oSeln ? oSeln.evaluateItemPath(
                '(ancestor-or-self::@type=project)[-1]'
            ) : [],
            blnSelnInProj = lstSelnProj.length;

        // toggle hoist state if selection is in project
        if (blnSelnInProj) {
            editor.hoist(
                editor.getHoistedItem().isRoot ? lstSelnProj[0] :
                editor.itemBuffer.outline.root
            );

            // restore selection after toggling hoist
            editor.setSelectedItemRange(rngSeln);
        }
        
        // Let Script Editor context know if we have toggled
        return blnSelnInProj;
    }

    // OS X SCRIPT EDITOR EVALUATION CONTEXT
    var tp = Application("TaskPaper"),
        ds = tp.documents;

    // if selection is in a project, 
    // toggle hoist and then activate TaskPaper app
    return ds.length ? ds[0].evaluate({
        script: projectHoistToggle.toString()
    }) && tp.activate() : false;

})();
1 Like

Yay! Thanks, @RobTrew!

It doesn’t work in my taskpaper 3.3. Does the script need to be updated or other reasons?

Thanks – there are a couple of API details which changed after that script was written. It could now, I think, be written something like the redraft below.

// TOGGLE HOISTING OF PROJECT CONTAINING CURSOR
// v 0.4

(function () {
    'use strict';

    // TASKPAPER 3 EVALUATION CONTEXT
    function projectHoistToggle(editor) {

        var outline = editor.outline,
            selection = editor.selection,
            dctSeln = {
                startItem: selection.startItem,
                startOffset: selection.startOffset,
                endItem: selection.endItem,
                endOffset: selection.endOffset
            }
            
            // containing project ?
            lstSelnProj = dctSeln.startItem ? outline.evaluateItemPath(
                '(ancestor-or-self::@type=project)[-1]',
                dctSeln.startItem
            ) : [],
            blnSelnInProj = lstSelnProj.length;

        // toggle hoist state if selection is in project
        if (blnSelnInProj) {
            editor.hoist(
                editor.hoistedItem.isOutlineRoot ? lstSelnProj[0] :
                outline.root
            );

            // restore selection after toggling hoist
            editor.moveSelectionToItems(
                dctSeln.startItem,
                dctSeln.startOffset,
                dctSeln.endItem,
                dctSeln.endOffset
            );
        }
        
        // Let Script Editor context know if we have toggled
        return blnSelnInProj;
    }

    // OS X SCRIPT EDITOR EVALUATION CONTEXT
    var tp = Application("TaskPaper"),
        ds = tp.documents;

    // if selection is in a project, 
    // toggle hoist and then activate TaskPaper app
    return ds.length ? ds[0].evaluate({
        script: projectHoistToggle.toString()
    }) && tp.activate() : false;

})();

It’s great! Thank you for your work.

There’s a little different from the display of select the project by pressing cmd + L: it doesn’t show the parent project line.

That’s right – this one ‘hoists’, that one ‘focuses’ – 各有所长

In the API docs:

The Chinese idiom is exactly the right. 恰到好处

1 Like

It seems another script Focus on Next (or Previous) Project has the similar issue.

It returns:

TypeError: sln.evaluateItemPath is not a function. (In 'sln.evaluateItemPath(
                'ancestor-or-self::@type=project[-1]'
            )', 'sln.evaluateItemPath' is undefined)

fn
evaluateScript@file:///Applications/TaskPaper.app/Contents/Resources/dist/birch.js:53025:16

	Use the Help > SDKRunner to debug

Well caught – let me know if you spot any others.

I’ve posted an update to the Keyboard Maestro macros, and the updated source text is below.

// Ver 0.4 updated for TaskPaper 3 release version API
// Ver 0.3 updated for TaskPaper 3 Preview build 168
//     0.2 hoist optional, options settable at end

(function (dctOptions) {
    'use strict';

    function fn(editor, options) {

        function next(id, lstID, blnDown) {
            var i = lstID.indexOf(id);

            // one after or one before (down or up)
            return i !== -1 ? (
                lstID[i + (blnDown ? 1 : -1)]
            ) : undefined;
        }

        var outline = editor.outline,
            // selection ?
            sln = editor.selection.startItem,

            // project containing selection ?
            prjs = sln ? outline.evaluateItemPath(
                'ancestor-or-self::@type=project[-1]',
                sln
            ) : [],
            prj = prjs.length ? prjs[0] : undefined;

        // following or preceding project ?
        // (options.down = true or false)
        if (prj) {
            var outline = editor.itemBuffer.outline,
                prjNext = outline.getItemForID(
                    next(
                        prj.id,
                        outline.evaluateItemPath('//@type=project')
                        .map(function (x) {
                            return x.id;
                        }),
                        options.down
                    )
                );

            return prjNext ? (
                editor[(options.hoist ? 'hoist' : 'focus') + 'edItem'] = prjNext,
                editor.moveSelectionToItems(prjNext, prjNext.bodyString.length),
                prjNext.bodyString
            ) : undefined;
        };
    }

    var tp = Application("TaskPaper"),

        ds = tp.documents,
        varResult = ds.length ? ds[0].evaluate({
            script: fn.toString(),
            withOptions: {
                down: dctOptions.down,
                hoist: dctOptions.hoist
            }
        }) : false;

    tp.activate();
    return varResult;

})({
    down: true,
    hoist: false  // hoisting hides the project line - showing just descendants
});

2 Likes

Thanks! It’s so great, one of must-have scripts for taskpaper.

2 Likes