Why does this return empty sometimes

lately, noticing that this code returns {} when you run the script while taskpaper is not active. (never a problem while taskpaper is active front window). just when you have taskpaper open, and chrome open, and u switch to chrome (which TP is open in another screen, but not focused as active app). when it works, it returns the contents of the items visible in the app.

(() => {
  const TaskPaper = Application('TaskPaper');
  const args = $.NSProcessInfo.processInfo.arguments;
  const hidePrivate = args.containsObject('--hide-private');

  // Assuming there is at least one open window
  if (!TaskPaper.windows.length) return '{}';
  const frontWindow = TaskPaper.windows[0];
  const document = frontWindow.document();
  if (!document) return '{}';

  // Retrieve the entire subtree of the focused item with proper indentation
  const focusedItemSubtree = document.evaluate({
    script: `function(editor, options) {
      const focusedItem = editor.focusedItem;
      if (!focusedItem) return '';
      const hidePrivate = options.hidePrivate;

      function getSubtree(item, depth = 0) {
        const indent = ' '.repeat(depth * 2);
        let subtree = '';

        const isPrivate = item.bodyString.includes('#private');  // TODO: use regex, which doesnt seem to work.
        const shouldHide = hidePrivate && isPrivate;
        if (!shouldHide) {
          subtree += indent + item.bodyString;
          item.children.forEach((child) => {
            const childSubtree = getSubtree(child, depth + 1);
            if (childSubtree) {
              subtree += '\\n' + childSubtree;
            }
          });
        }

        return subtree;
      }

      return getSubtree(focusedItem);
    }`,
    withOptions: { hidePrivate: hidePrivate }
  });


  return JSON.stringify(focusedItemSubtree);
})();

Since it’s returning {} I guess that means there are only two places in the code to look? Can you adjust the return values to figure out which of these it’s returning on?

  • if (!TaskPaper.windows.length) return '{}';
  • if (!document) return '{}';.

I think it might be that you have some non-document window open (like preferences) in TaskPaper. Also I think you could instead just use:

  • const document = TaskPaper.document[0];

To get the front document. The application documents collection is ordered to always have the front document first.

if you mean TaskPaper.documents[0] then yup that seems to work great. thanks!

1 Like

For what it’s worth, document references in JXA and AppleScript have an .exists() method, which returns true if (and only if) the referenced document does, in fact, exist.

i.e. you can, if you prefer, write conditional expressions like:

const document = TaskPaper.documents.at(0);

return document.exists()
    ? document.evaluate({
        script: `${TaskPaperContext}`,
        withOptions: {
            hidePrivate
        }
    })
    : "";

e.g. perhaps

Expand disclosure triangle to view JS source
(() => {

    // ---------------- TASKPAPER CONTEXT ----------------
    const TaskPaperContext = (editor, options) => {

        const subTreeLines = indentUnit =>
            exclusionHash => item => {

                const go = indent =>
                    row => {
                        const s = row.bodyString;

                        return exclusionHash && s.includes(
                            exclusionHash
                        )
                            ? []
                            : [
                                `${indent}${s}`, ...(
                                    row.hasChildren
                                        ? row.children.flatMap(
                                            go(`${indentUnit}${indent}`)
                                        )
                                        : []
                                )
                            ];
                    };

                return go('')(item)
            };

        const focusedItem = editor.focusedItem;

        return focusedItem
            ? subTreeLines(
                options.indentUnit
            )(
                options.hidePrivate
                    ? '#private'
                    : ''
            )(focusedItem).join('\n')
            : '(no focus in TaskPaper editor)';
    };

    // ------------------- JXA CONTEXT -------------------
    const main = () => {
        const
            hidePrivate = $.NSProcessInfo.processInfo.arguments
                .containsObject('--hide-private'),
            indentUnit = ' '.repeat(2),
            document = Application('TaskPaper')
                .documents.at(0);

        return document.exists()
            ? document.evaluate({
                script: `${TaskPaperContext}`,
                withOptions: {
                    hidePrivate,
                    indentUnit
                }
            })
            : "";
    };

    return main();
    // return JSON.stringify(main())
})();
3 Likes