Looking to create a JavaScript that will place the cursor at the end of the first task that is not @done

Hello all,

I am looking to create a JavaScript that will place the cursor at the end of the first task that is not @done

I don’t want to focus in—just move the cursor.

Any ideas are appreciated.

Thanks!

Jim

You may find some bits of it in this draft:

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

    // Rob Trew @2021

    // ------------------- JXA CONTEXT -------------------

    // jxaMain :: IO ()
    const jxaMain = () => {
        const docs = Application("TaskPaper").documents;

        return 0 < docs.length ? (
            docs.at(0).evaluate({
                script: `${TaskPaperContext}`,
                withOptions: {
                    itemPath: "//not @done"
                }
            })
        ) : "No documents open in TaskPaper";
    };

    // ---------------- TASKPAPER CONTEXT ----------------

    // TaskPaperContext :: Editor -> Dict -> IO ()
    const TaskPaperContext = (editor, options) => {

        const cursorToEndOfItem = item => (
            editor.moveSelectionToItems(
                item, item.bodyString.length
            ),
            `Cursor at ${editor.selection.location}`
        );

        const
            outline = editor.outline,
            matches = outline.evaluateItemPath(
                options.itemPath
            )
            // Perhaps ignoring blank lines ?
            .filter(
                item => Boolean(item.bodyString.trim())
            );

        return 0 < matches.length ? (
            cursorToEndOfItem(matches[0]),
            `Cursor at ${editor.selection.location}`
        ) : `No matches for '${options.itemPath}'`;
    };

    return jxaMain();
})();
1 Like

Excellent @complexpoint — In early tests, I cannot find any issues in your draft. Thank you!

If you do want to exclude blank lines, another approach (as an alternative to the .filter above), might be to specify non-blank lines in the itemPath.

@jessegrosjean might be able to think of a more elegant expression, but this at least seems to work:

//not @done and @text matches "."

(i.e. a regular expression that requires at least one character in the line)

1 Like

I presume that the quotes around the period need to be escaped, right?

Example:
itemPath: "//not @done and @text matches \"@\""

This is really good @complexpoint !

Experimenting with:

itemPath: "//not @done and @text matches today"
and
itemPath: "//not @done and @text matches next"

That’s right – quoting allows, for example, for the inclusion of white space in a regex.

JS gives you a couple of options there for the outermost quotes. You could do without escaped inner quote by writing, perhaps:

'//not @done and @text matches "."'

(footnote:: JSON needs double-quoted strings, but within full JS code the notation for a key or string value in a Dictionary/Object, or just a plain string, can use single quotes (or for template notation, back-ticks)

1 Like

Note that:

  • The matches keyword is only really needed if the following string contains some regex syntax
  • simple matches are assumed to be against the @text value anyway

So if you wanted, I think you could pare the itemPath pattern down to things like:

//not @done and today
1 Like