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