Ability to mark items as @done

In the meanwhile, I’m personally using a keystroke bound to a scripted strikethrough and @done(timestamp):

Screenshot 2022-11-07 at 18.27.35

BIKE Outliner – Toggle @done tag in selected rows - Macro Library - Keyboard Maestro Discourse


Expand disclosure triangle to view JS source
(() => {
    "use strict";

    // `@done` tag toggled in selected and non-empty
    // lines of a Bike.app (1.3.1 Preview) outline.
    // Optionally with date-time stamp
    // (for simple `@done`, edit tagValue to "" below)

    // Rob Trew @2022
    // Ver 0.03

    // main :: IO ()
    // eslint-disable-next-line max-lines-per-function
    const main = () => {
        // ------------------- OPTIONS -------------------
        const tagName = "done";

        const tagValue = taskPaperDateString(new Date());
        // OR tagValue = "";

        // ------------------- TOGGLE --------------------
        const
            bike = Application("Bike"),
            doc = bike.documents.at(0);

        return doc.exists() ? (() => {
            const
                selectedRows = doc.rows.where({
                    selected: true,
                    _not: [{
                        name: ""
                    }]
                });

            return Boolean(selectedRows.length) ? (() => {
                const
                    tagRegex = new RegExp(
                        Boolean(tagValue.length) ? (
                            `@${tagName}\\(.*\\)`
                        ) : `@${tagName}`, "u"
                    ),
                    isTagged = Boolean(
                        tagRegex.exec(
                            selectedRows.at(0).name()
                        )
                    ),
                    updated = isTagged ? (
                        clearTag(tagRegex)
                    ) : addTag(tagRegex)(tagName)(tagValue);

                return (
                    selectedRows().forEach(row => (
                        row.name = updated(row.name()),
                        row.textContent.strikethrough = !(
                            isTagged
                        )
                    )),
                    isTagged ? (
                        `@${tagName} cleared`
                    ) : `Tagged @${tagName}`
                );
            })() : "Nothing selected in Bike";
        })() : "No documents open in Bike";
    };

    // ---------------------- TAGS -----------------------

    // clearTag :: Regex -> String -> String
    const clearTag = tagRegex =>
        rowText => {
            const match = tagRegex.exec(rowText);

            return Boolean(match) ? (() => {
                const
                    matchStart = match.index,
                    preTag = rowText.slice(
                        0, matchStart
                    ).trim(),
                    postTag = rowText.slice(
                        matchStart + match[0].length
                    ).trim();

                return `${preTag} ${postTag}`.trim();
            })() : rowText.trim();
        };


    // addTag :: String -> String -> String -> String
    const addTag = tagRegex =>
        tagName => tagValue => txt => {
            const
                affix = Boolean(tagValue.length) ? (
                    `@${tagName}(${tagValue})`
                ) : `@${tagName}`;

            return `${clearTag(tagRegex)(txt)} ${affix}`;
        };


    // --------------------- GENERIC ---------------------

    // iso8601Local :: Date -> String
    const iso8601Local = dte =>
        new Date(dte - (6E4 * dte.getTimezoneOffset()))
        .toISOString();


    // taskPaperDateString :: Date -> String
    const taskPaperDateString = dte => {
        const [d, t] = iso8601Local(dte).split("T");

        return [d, t.slice(0, 5)].join(" ");
    };

    // MAIN ---
    return main();
})();

To test in Script Editor, set the language selector at top left to JavaScript.

See: Using Scripts - Bike

2 Likes