FT scripting from Yosemite Javascript (rather than Applescript)


#1

The OS X 10.10 Script Editor can now run Javascript as well as Applescript

(See https://developer.apple.com/library/mac/releasenotes/InterapplicationCommunication/RN-JavaScriptForAutomation/index.html )

and in some ways it is now simpler to run scripts in FoldingText by calling document.evaluate() and document.debug() from Javascript rather than bilingually from Applescript.

In particular, the Applescript method requires us to place the .js code in a string variable, and doing that imposes some double-escaping complexities with special characters, especially in regexes.

The FoldingText > Help > Software Development Kit > Create Scripts page gives us a helpful example of how to evaluate an FT script from Applescript.

Here is one way of rewriting that example entirely in Javascript, so that we can avoid the complexities of typing out our FoldingText code inside a long Applescript string variable:

// REFERENCES:
//	https://developer.apple.com/library/mac/releasenotes/InterapplicationCommunication/RN-JavaScriptForAutomation/index.html

//  
//	file:///Applications/FoldingText.app/Contents/Resources/dist/sdk/docs/tutorial-Scripts.html
//  


// Bracket all your code in the top level run() event by default:

// 	1. Useful if you save as a standalone .app, and
// 	2. keeps your variables separate from Javascript's globals

function run() {
	
	// Define the FoldingText code to be evaluated as a javascript function
	// (this makes it easier to edit, and we can automatically convert it later
	// to a string which can be passed from the Script Editor into FoldingText
	
	var fnScript =
	
		function(editor, options) {
		
			var strNewText=	options.start +
         			editor.selectedText() +
           			options.end;
			
			editor.replaceSelection(strNewText);
			
        	        return strNewText;	
		};
	
	// The FoldingText document.evaluate() function needs the 'text' of your code
	
	var strScript = fnScript.toString();
	
	
	////// GET A REFERENCE TO FOLDINGTEXT, AND CHECK THAT THERE IS AN ACTIVE DOCUMENT /////

	var	appFT=Application("FoldingText"),
		lstDocs = appFT.documents(),
		lngDocs = lstDocs.length,
		varResult = null;
		
		// THEN SUBMIT YOUR SCRIPT AS A STRING, SUPPLYING AND NAMING ANY OPTION STRINGS WHICH YOU NEED
		
		if (lngDocs) {	
			varResult = lstDocs[0].evaluate({script:strScript, withOptions:{start:"A", end:"B"}});
		}
		
		// AND RETURN A RESULT
		return varResult;
}



#2

For an FTJS TextExpander snippet:

function run() {
	var fnScript =
		function(editor, options) {
			// FoldingText code here

			return options.msg;
		};
	
	// Check that we have an active FT document,
	// and supply+name any option strings
	var	appFT=Application("FoldingText"),
		lstDocs = appFT.documents(),
		lngDocs = lstDocs.length,
		varResult = null;
		
	if (lngDocs) {	
		varResult = lstDocs[0].evaluate(
			{
				script:fnScript.toString(),
				withOptions:{
					msg:"hello world"
				}
			});
	}
	return varResult;
}

#3

(+ Javascript idiom for basic display dialog and choose from list OS X UI scripting)

function run() {
	//'use strict'
	var	pTitle = "Some Script",
		pVer = "0.1",
		pAuthor = "",
		pSite = "";

	var fnScript =
		function(editor, options) {
			// FoldingText code here
			
			//var tree=editor.tree(),
			//	lstNodes = tree.evaluateNodePath('');

			return options.msg;
		};
	
	// Check that we have an active FT document,
	// and supply+name any option strings
	var	appFT=Application("FoldingText"),
		lstChoice = [],
		lstDocs = appFT.documents(),
		lngDocs = lstDocs.length,
		varChoice = false,
		varResult = null;
		
	appFT.includeStandardAdditions = true;
	
	if (lngDocs) {	
		varResult = lstDocs[0].evaluate(
			{
				script:fnScript.toString(),
				withOptions:{
					msg:"hello world !"
				}
			});
	} else return;
	
	// DIALOG
	appFT.activate();
	appFT.displayDialog(varResult.toString(),{
				withTitle: [pTitle, pVer].join('\t'),
				buttons:["OK"],
				defaultButton:"OK"
			});
	
	// CHOOSE FROM LIST
	lstChoice = ['delta', 'epsilon', 'zeta', varResult].sort();
	appFT.activate();
	varChoice = appFT.chooseFromList(
		lstChoice,
		{
			withTitle: [pTitle, pVer].join('\t'),
			withPrompt: "Choose:",
			defaultItems: varResult,
			multipleSelectionsAllowed: true
		}
	);
	if (varChoice)
		varResult = varChoice;
	
	return varResult;
}


#4
Calling Yosemite JXA Javascripts for FoldingText from Keyboard Maestro

OS X 10.10 Javascript for Automation still uses the .applescript text file extension and the .scpt compiled script extension, but the Keyboard Maestro Execute an Applescript action can’t use files containing Javascript.

Instead you can use an Execute Shell Script action.

For example, if you have installed Jesse’s Toggle Empty lines plugin, and want to assign a keystroke to it from Keyboard Maestro, one approach would be to use a KM action like this:


#5

The simplest boiler-plate for a TextExpander shortcut might look something like:

function run() {

	var fn = function (editor, options) {
			return options.msg;
		},

		docsFT = Application("FoldingText").documents(),
		varResult = docsFT.length && docsFT[0].evaluate({
			script: fn.toString(),
			withOptions: {
				msg: "Hello 世界 !"
			}
		});

	return varResult;
}

Or, to run a built-in or plugin defined command:

function run() {

	var fn = function (editor, options) {
			performAction(options.action);
		},

		docsFT = Application("FoldingText").documents(),
		varResult = docsFT.length && docsFT[0].evaluate({
			script: fn.toString(),
			withOptions: {
				action: 'toggle empty lines'
			}
		});

	return varResult;
}