Scripting: Select Paragraph, and Select Block

I needed a way, this morning, of extending the selection (by script) to the previous and following blank lines.

This is not quite the same as selecting a paragraph – a block between empty lines may contain more than one LF-delimited paragraphs.

For the paragraph case we can use Jesse’s rich set of built in commands:

property pstrJS : "

	function(editor) {

		editor.performCommand('selectParagraph');

	}

"
on run
	tell application "FoldingText"
		tell front document to (evaluate script pstrJS)
	end tell
end run

For the other case (selecting back to the previous empty line (or start of doc), and forward to the next empty line, or end of doc), one way is to use nodePaths to find the previous and next gaps in the text:

'//@id=' + idSelnStart + '/preceding::(@type=empty)[-1]',
'//@id=' + idSelnEnd + '/following::(@type=empty)[0]',

[-1] means ‘the last line that matches that pattern’, and
[0] is ‘the first line that matches that pattern’.

The full script might look like this:

property pblnDebug : false

property pstrJS : "

	function(editor, options) {

		function selectBlock(editor) {
			// select back to previous gap (or start of doc)
			// and forward to next gap (or end of doc)

			var	rngSeln = editor.selectedRange(),

			idSelnStart = rngSeln.startNode.id,
			idSelnEnd = rngSeln.endNode.id,

			// PATHS: PREVIOUS GAP, AND NEXT GAP
			strPathPrevGap = '//@id=' + idSelnStart + '/preceding::(@type=empty)[-1]',
			strPathNextGap = '//@id=' + idSelnEnd + '/following::(@type=empty)[0]',

			tree = editor.tree(),
			lstBefore = tree.evaluateNodePath(strPathPrevGap),
			lstAfter = tree.evaluateNodePath(strPathNextGap),

			lngFrom, lngTo, rngNew;

			// most recent empty line, or start of doc
			if (lstBefore.length) {
				lngFrom = lstBefore[0].lineTextStart()+1;
			} else {
				lngFrom = 0;
			}

			// next empty line, or end of doc
			if (lstAfter.length) {
				lngTo = lstAfter[0].lineTextStart()-1;
			} else {
				lngTo = tree.textLength();
			}

			// define the range by start position and length
			rngNew = tree.createRangeFromLocation(lngFrom, lngTo-lngFrom);

			// and select it
			editor.setSelectedRange(rngNew);

			return true;
		}

		return selectBlock(editor);

	}
"

on run
	tell application "FoldingText"
		set varResult to missing value
		if not pblnDebug then
			set lstDocs to documents
			if lstDocs ≠ {} then
				tell item 1 of lstDocs
					set varResult to (evaluate script pstrJS)
				end tell
			end if
		else
			-- debug script automatically refers to the SDK version of the editor
			-- which must be open: FoldingText > Help > SDK > Run Editor
			set varResult to (debug script pstrJS)
		end if
		return varResult
	end tell
end run