Taskpaper 3 and copy displayed


#1

In TP2, to communicate some part of todos with collaborators, I was able to copy a selection and paste it in AppleMail and it will retain bold, italic, etc. Now in TP3, when using Copy Displayed, everything is plain text flat and it’s a bit more complex to read. How come I can’t get the same result as is in TP3 as displayed? with bold, indent, etc? Is there an easy way to achieve that?

Thanks.


#2

Hum… I guess I used to just copy the rich text from the text view onto the clipboard. I don’t remember the tradeoffs in version 2, but in version 3 they would be worse. I’m doing a number of custom layouts and drawing that would get lost on export, so even if I did again copy rich text to the clipboard it likely wouldn’t look right when pasted into another text view.

The two options I can think of are:

  1. File > Print, and then save as PDF. That would make the list look just like in TaskPaper while still allowing others to select text.

  2. There are a number of scripts that export TaskPaper into HTML. Doesn’t look exactly like in the editor, but presents the structure cleanly. I would go to the scripts page and try out the various “HTML” scripts: TaskPaper Extensions Wiki


#3

If we

  • use File > Print > PDF > Open PDF in Preview and then
  • select+copy the Preview display,

we get formatted public.rtf content in the clipboard, which seems to paste well into Mail.


#4

You may find that you can speed up the process (opening the active file as PDF in Preview) by assigning a JavaScript for Automation script like this to a keystroke.

(See: How do I run/install a script?)

(() => {
    'use strict';

    // GENERIC FUNCTIONS --------------------------------------

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

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

    // bindEither (>>=) :: Either a -> (a -> Either b) -> Either b
    const bindEither = (m, mf) =>
        m.Right !== undefined ? (
            mf(m.Right)
        ) : m;

    // enumFromTo :: Enum a => a -> a -> [a]
    const enumFromTo = (m, n) =>
        (typeof m !== 'number' ? (
            enumFromToChar
        ) : enumFromToInt)
        .apply(null, [m, n]);

    // enumFromToInt :: Int -> Int -> [Int]
    const enumFromToInt = (m, n) =>
        n >= m ? Array.from({
            length: Math.floor(n - m) + 1
        }, (_, i) => m + i) : [];

    // JXA FUNCTIONS ---------------------------------------------------------

    // appProcMenuItem :: ApplicationProcess -> [String] 
    //      -> Either String MenuItem
    const appProcMenuItem = (proc, menuPath) => {
        const lng = menuPath.length;
        return lng > 1 ? (
            Right((Application(proc.name())
                .activate(),
                menuPath.slice(1, -1)
                .reduce(
                    (a, x) => a.menuItems[x].menus[x],
                    proc.menuBars[0]
                    .menus.byName(menuPath[0])
                )
                .menuItems[menuPath[lng - 1]]))
        ) : Left('Menu path needs at least two strings');
    };

    // MAIN ------------------------------------------------------------------
    const
        procs = Application('System Events')
        .applicationProcesses.where({
            name: 'TaskPaper'
        }),
        lrProc = procs.length ? (
            Right(procs.at(0))
        ) : Left('TaskPaper not running');

    return bindEither(
        bindEither(
            lrProc,
            proc => proc.windows.length > 0 ? (
                appProcMenuItem(proc, ['File', 'Print…'])
            ) : Left('No windows open in TaskPaper')
        ),
        menuItem => {
            // Effect --------------------------------------------------------
            enumFromTo(1, 4)
                .forEach(_ => menuItem.click());
            // Value ---------------------------------------------------------
            return bindEither(
                bindEither(
                    lrProc,
                    proc => {
                        const sheets = proc.windows.at(0)
                            .sheets;
                        return sheets.length > 0 ? (
                            Right(sheets.at(0))
                        ) : Left('Print dialog not open');
                    }
                ),
                sheet => {
                    const btnPDF = sheet.menuButtons.byName('PDF');
                    return (
                        // Effect --------------------------------------------
                        btnPDF.click(),
                        // Value ---------------------------------------------
                        Right(
                            // Effect ----------------------------------------
                            (btnPDF.menus.at(0)
                                .menuItems.byName('Open PDF in Preview')
                                .click(),
                                // Value -------------------------------------
                                'Clicked (Open PDF in Preview)'
                            )
                        )
                    );
                }
            );
        }
    );
})();