How to open a second view

hi :slight_smile: ! I have built a hacky script to focus specific projects but would like to be able to have multiple windows (views) into the same file.

let’s say you have a file named Notes.txt with the following content:

Notes.txt
[Wed 5/25/22 12:27AM] 
	here are some of my favorite things
		favorite foods:
			apples
			bananas
			favorite candies:
				chocolate
				mints
	those are my favorite things.

and you have a script that you use as part of your workflow such that it is given some info about the path to Notes.txt and the lineNum you want to focus in.

lets say the node script looks like this:

Script.js
const {execSync} = require('child_process');
let [filePath, lineNum, charPos] = process.argv[2].split(':');
filePath = filePath.replace(/^~\//, `${process.env['HOME']}/`);

//! TODO: if the file is already open, open it again in a new window with a new view to the specific line.
execSync(`open -a TaskPaper "${filePath}"`);

/** @param {string} lineText */
const focusTaskpaperLine = async lineText => {
  const runJxa = require('run-jxa');
  await runJxa(`
    const main = mainOptions => {
      const taskpaperApp = Application("TaskPaper");
      const {documents} = taskpaperApp;
      if (!documents.length) return false;

      const documentInjectionScript = (editor, options) => {
        editor['focusedItem'] = editor.outline.items[options.lineNum-1];
      };
      const mostRecentDocument = documents[0];
      const result = 
        mostRecentDocument.evaluate({ 
          script: documentInjectionScript.toString(), 
          withOptions: mainOptions
        });

      taskpaperApp.activate();

      return result;
    }

    const [lineText, charPos, lineNum] = args;
    const isSuccess = main({searchText: lineText, charPos, lineNum});

    return isSuccess;
  `, [lineText, charPos, lineNum]);
};

// don't know a way to go to a specific line number, so use a line content grep hack for now
const searchText = execSync(`sed '${lineNum}q;d' "${filePath}"`).toString();
setTimeout(() => focusTaskpaperLine(searchText).then(), 500); // allow time for external edits to be loaded

currently, if the script is triggered for the line “favorite foods:” it will open that file and then focus that specific section, which is beautiful.
then if you invoke it again for “favorite candies”, it will open that file (which is already open, so it reuses that window), and then move the focus to this new section. I end up with one window which shows candies.

however, I want it to be such that if I open “favorite foods:” and that window is open, then I trigger “favorite candies:”, then I would like for it to open a new window (not another instance of the app) and have that new window focus on “favorite candies:”. I would end up with two windows, one showing foods and one showing candies.

how can i tweak my code to accomplish this desire?

thank you in advance :slight_smile:

TaskPaper scripting has two “contexts”.

There is the AppleScript context, which runs from ScriptEditor, and then you can call into TaskPaper’s JavaScript context by passing JavaScript text into the evaluate command. It’s a bit confusing, but I hope that gets us on same page.

Now to your question… you can’t create a new window from TaskPaper’s JavaScript context, but you can do it from the AppleScript context by activating the File > New Window menu item using “UI Scripting”.

Here’s a script showing how to activate that menu item:

var taskPaper = Application('TaskPaper');
var systemEvents = Application('System Events');

taskPaper.activate();

menuItem("File:New Window");

function menuItem(path) {
	var path = path.split(":")

	if (!path.length) return;
  
	var process = systemEvents.processes.whose({"frontmost": true})[0];
	var menu_bar = process.menuBars[0].menuBarItems[path[0]];
	
	var menuItem = menu_bar;
	for (var i=1; i < path.length; i++) {
		menuItem = menuItem.menus[0].menuItems[path[i]];
	}

	menuItem.click();
}

okay thanks! the two contexts makes sense. i have three in my script then (node, apple script, then the eval)

so how would i go about determining if i need to open a new window (basically, how to detect if a taskpaper window is open which is for the same file?