Hiding notes

Hello,
is there a way to hide (partially or totally) notes related to tasks (globally or task by task)?

Thanks

One route is an editor search:

e.g.

//@type!=note

Which you could name and keep as a saved search in the sidebar

(and clear, of course, with ⌘Esc, or Editor > End Search)

2 Likes

thanks a lot!
but I suspect that this cannot be done on a note by note basis…

second: is it possible to show only the first line of a longer note? like in workflowy or omni outliner…
a disclosure triangle, a bullett point?

That would need a script which identifies the selected line, I think.

the first line of a longer note?

Are there multiline notes in TaskPaper ?

Or are we talking about primus inter pares ?

(The first in a sequence of notes should be definable)

If I’ve understood what you’re describing, then it may be worth experimenting with scripts like this, which:

  • assumes that the parent of the relevant note lines is selected, and
  • aims to hide all the children of type note, except for the first.

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

    const TaskPaperContext = editor => {
        const
            followingNotes = editor.outline.evaluateItemPath(
                "@type=note[0]/following-sibling::*",
                editor.selection.startItem
            );

        return (
            editor.forceHidden(
                followingNotes,
                true
            ),
            `${followingNotes.length} notes hidden.`
        );
    };


    // main :: IO ()
    const main = () =>
        Application("TaskPaper").documents.at(0)
        .evaluate({
            script: `${TaskPaperContext}`
        });

    return main();
})();
1 Like

I wrote a script for this. See here:

thanks to all… just to be clear to what I wish




respectively:

  • only first line
  • global notes
  • no notes but displayed note presence

could you give an example of how it works? My fault but I don’t understand it practically :innocent:

(Good choice of poets)

Do you have Keyboard Maestro or FastScripts ?

(It might – I’ll try to experiment at the weekend – be possible to sketch a single key toggle between those three states, though it might be necessary to improvise a bit with the glyph meaning «has notes» tell me if there’s one that feels less noisy than ♪ :spiral_notepad::memo::pencil2: etc)

I like these
image

image

1 Like

I’ll experiment with those. (Not quite as clean-cut in their macOS text rendering as in the browser versions)

Screenshot 2022-01-27 at 13.09.49

choose the better for you, please

1 Like

What ergonomics are you aiming for here ?

For example:

  • toggling the whole outline, regardless of selection
  • toggling a single selected bullet item
  • toggling all selected items of type task (i.e. bulleted)

?

your example is ok

  • toggling the whole outline, regardless of selection, ok
  • toggling a single selected bullet item, ok
  • toggling all selected items of type task (i.e. bulleted), ok but…
    perhaps in this case “project by project”?

Here’s a first sketch of the least ambitious version – a global three-way toggle, independent of selection.

If you attach it to a keystroke with something like FastScripts or Keyboard Maestro you should find that it cycles the editor through three successive states:

  1. (On first use) hiding all notes (leaf nodes), and giving parents with hidden descendants a temporary @N tag (I haven’t found the trick of making emoji characters work in this context). Then, on next use:
  2. Revealing just the first note where there are several (and preserving the @N tag), and finally
  3. Revealing all notes, and clearing the @N tag.
Expand disclosure triangle to view JS Source
(() => {
    "use strict";

    // First sketch of a global three-way toggle:

    // 1. Notes (terminal leaves) all hidden
    // 2. First notes revealed
    // 3. all notes shown

    // --------------- TASKPAPER 3 CONTEXT ---------------
    // eslint-disable-next-line max-lines-per-function
    const TaskPaperContext = editor => {

        // tp3Main :: () -> Either String Result
        const tp3Main = () => {
            const
                outline = editor.outline,
                paths = {
                    leavesHidden: "//*/..*",
                    firstLeaf: "//*/..*/*[0]"
                },
                xs = outline.items,
                hiddenNotes = "data-N",
                parents = outline.evaluateItemPath(
                    paths.leavesHidden
                );

            return Right(
                "" === editor.itemPathFilter ? (
                    editor.itemPathFilter = paths.leavesHidden,
                    parents.forEach(
                        x => x.setAttribute(hiddenNotes, "")
                    ),
                    "Leaves Hidden"
                ) : editor.itemPathFilter === paths.leavesHidden ? (
                    editor.itemPathFilter = paths.firstLeaf,
                    parents.forEach(
                        x => x.setAttribute(hiddenNotes, "")
                    ),
                    "First leaves shown"
                ) : (
                    editor.itemPathFilter = "",
                    editor.setExpanded(xs),
                    parents.forEach(
                        x => x.removeAttribute(hiddenNotes)
                    ),
                    "All visible"
                )
            );
        };

        // ---------- GENERICS FOR TP3 CONTEXT -----------


        // Right :: b -> Either a b
        const Right = x => ({
            type: "Either",
            Right: x
        });


        // ------------------ TP3 MAIN -------------------
        return tp3Main();
    };


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

    // main :: () -> Either MessageString ResultString
    const main = () => {
        const
            ds = Application("TaskPaper")
            .documents;

        return either(x => x)(x => x)(
            bindLR(
                ds.length > 0 ? (
                    Right(ds.at(0))
                ) : Left("No TP3 documents open")
            )(
                d => d.evaluate({
                    script: `${TaskPaperContext}`,
                    withOptions: {
                        glyph: "✏"
                    }
                })
            )
        );
    };

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

    // Left :: a -> Either a b
    const Left = x => ({
        type: "Either",
        Left: x
    });

    // Right :: b -> Either a b
    const Right = x => ({
        type: "Either",
        Right: x
    });

    // bindLR (>>=) :: Either a ->
    // (a -> Either b) -> Either b
    const bindLR = m =>
        mf => m.Left ? (
            m
        ) : mf(m.Right);

    // either :: (a -> c) -> (b -> c) -> Either a b -> c
    const either = fl =>
        // Application of the function fl to the
        // contents of any Left value in e, or
        // the application of fr to its Right value.
        fr => e => e.Left ? (
            fl(e.Left)
        ) : fr(e.Right);

    // JXA MAIN ---
    return main();
})();
2 Likes

For a week I have only my iPhone…
no way to check it out, sorry
many thanks BTW!

1 Like

I’m back…
actually I think, cycling through the three states you defined, your script hides all the leaf notes whether they are notes or tasks

That’s right.

For the next iteration, we can start to introduce expressions like:

  • @type=note
  • @type!=note

into the path expressions, and define a subset of parents.

Perhaps, for a first test, we could edit the paths record to something like:

paths = {
    notesHidden: '//@type!=note union //@text=""',
    // firstLeafNote: "//*/..*/@type=note[0]",
    firstLeafNote: "//*/..*/@type=note[0] union @type!=note",
    noteParents: "//@type=note/..*"
}

And the searches (node path) syntax at TaskPaper documentation: Searches may suggest further adjustments and refinements to you.

Here, to test, is a second version of the code, with the path adjustments above:

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

    // Third sketch of a global three-way toggle:

    // 1. Notes (leaves with @type=note) all hidden
    // 2. First notes revealed
    // 3. all notes shown

    // --------------- TASKPAPER 3 CONTEXT ---------------
    // eslint-disable-next-line max-lines-per-function
    const TaskPaperContext = editor => {

        // tp3Main :: () -> Either String Result
        const tp3Main = () => {
            const
                outline = editor.outline,
                paths = {
                    notesHidden: '//@type!=note union //@text=""',
                    // firstLeafNote: "//*/..*/@type=note[0]",
                    firstLeafNote: "//*/..*/@type=note[0] union @type!=note",
                    noteParents: "//@type=note/..*"
                },
                xs = outline.items,
                hiddenNotes = "data-N",
                parents = outline.evaluateItemPath(
                    paths.notesHidden
                ),
                noteParents = outline.evaluateItemPath(
                    paths.noteParents
                );

            return Right(
                "" === editor.itemPathFilter ? (
                    editor.itemPathFilter = paths.notesHidden,
                    noteParents.forEach(
                        x => x.setAttribute(hiddenNotes, "")
                    ),
                    "Leaves Hidden"
                ) : editor.itemPathFilter === paths.notesHidden ? (
                    editor.itemPathFilter = paths.firstLeafNote,
                    noteParents.forEach(
                        x => x.setAttribute(hiddenNotes, "")
                    ),
                    "First leaves shown"
                ) : (
                    editor.itemPathFilter = "",
                    editor.setExpanded(xs),
                    parents.forEach(
                        x => x.removeAttribute(hiddenNotes)
                    ),
                    "All visible"
                )
            );
        };

        // ---------- GENERICS FOR TP3 CONTEXT -----------


        // Right :: b -> Either a b
        const Right = x => ({
            type: "Either",
            Right: x
        });


        // ------------------ TP3 MAIN -------------------
        return tp3Main();
    };


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

    // main :: () -> Either MessageString ResultString
    const main = () => {
        const
            ds = Application("TaskPaper")
            .documents;

        return either(x => x)(x => x)(
            bindLR(
                ds.length > 0 ? (
                    Right(ds.at(0))
                ) : Left("No TP3 documents open")
            )(
                d => d.evaluate({
                    script: `${TaskPaperContext}`,
                    withOptions: {
                        glyph: "✏"
                    }
                })
            )
        );
    };

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

    // Left :: a -> Either a b
    const Left = x => ({
        type: "Either",
        Left: x
    });


    // Right :: b -> Either a b
    const Right = x => ({
        type: "Either",
        Right: x
    });


    // bindLR (>>=) :: Either a ->
    // (a -> Either b) -> Either b
    const bindLR = m =>
        mf => m.Left ? (
            m
        ) : mf(m.Right);


    // either :: (a -> c) -> (b -> c) -> Either a b -> c
    const either = fl =>
        // Application of the function fl to the
        // contents of any Left value in e, or
        // the application of fr to its Right value.
        fr => e => e.Left ? (
            fl(e.Left)
        ) : fr(e.Right);

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

it works, thanks!
One question: notes new lines are identified by a CR character?

My understanding is that a TaskPaper file is a tab-indented text file (UTF8) in which all lines are delimited by the Unix standard \n
(LF \n linefeed, rather than CR \r carriage return)

A note is just a line without special syntax (no trailing semicolon, and no leading bullet hyphen). A succession of note lines is delimited by \n (LF) in the same way as any other succession of lines.

1 Like