Outdent selected line(s) in OS X 10.10 Script Editor
// ROBIN TREW 2015 MIT License
// OSX 10.10 SCRIPT EDITOR – REDUCE INDENTATION OF SELECTED LINES (by Tab or 4 spaces)
// Add remove '// ' from before printing characters
// Depends on a library .scpt being saved at ~/Library/Script Libraries/DraftsSE.scpt
// See: See: http://support.foldingtext.com/t/writing-scripts-which-run-on-both-foldingtext-and-ios-drafts-4/652/7
// INCLUDE ALL OR PART OF LIBRARY OF IOS DRAFTS-COMPATIBLE EDITOR FUNCTIONS:
function run() {
// PART 1: CODE SPECIFIC TO YOSEMITE SCRIPT EDITOR:
// SE implmentations of the basic iOS Drafts functions
// (Implementations of these functions for FoldingText and other editors with .js scripting at:
//
// getText() getSelectedLineRange()
// setText(string) getSelectedRange()
// getSelectedText() setSelectedRange(start, length)
// setSelectedText(string) getClipboard()
// getTextInRange(start, length) setClipboard(string)
// setTextInRange(start, length, string)
var app = Application("Script Editor"),
lstDoc = app.documents(),
oDoc = lstDoc.length ? lstDoc[0] : null;
if (!oDoc) return false;
//either var drafts = Library('DraftsSE'); // Assuming file saved at: ~/Library/Script Libraries/DraftsSE.scpt
// or locally:
drafts = {
getTextInRange: function (iStart, iLength) {
if (oDoc) return oDoc.text().substring(iStart, iStart + iLength);
},
setSelectedRange: function (iStart, iLength) {
if (oDoc) {
oDoc.selection = oDoc.text.characters.slice(iStart, iStart + iLength);
}
},
getSelectedLineRange: function () {
// works, but let me know if you see a shorter route :-)
var rgxLFCR=/[\r\n]/, dct, strFull, iFrom, iTo, lngChars;
if (oDoc) {
dct = oDoc.selection.characterRange();
strFull = oDoc.text();
lngChars = strFull.length;
iFrom = dct.x;
while (iFrom--)
if (strFull[iFrom].match(rgxLFCR)) break;
iFrom += 1;
iTo = dct.y - 1;
while (iTo++ < lngChars)
if (strFull[iTo].match(rgxLFCR)) break;
return [iFrom, (iTo - iFrom)];
}
},
setTextInRange: function (iStart, iLength, strText) {
if (oDoc) { // record the existing selection coordinates
var lngDelta = (strText.length - iLength) - 2,
oSeln = oDoc.selection,
dct = oSeln.characterRange(),
iFrom = dct.x,
iTo = dct.y;
try { // use the selection to edit elsewhere, then restore with any adjustment
oDoc.selection = oDoc.text.characters.slice(iStart, iStart + iLength);
oSeln.contents = strText;
oDoc.selection = oDoc.text.characters.slice(
(iStart < iFrom) ? iFrom + lngDelta : iFrom, ((iStart + iLength) < iTo) ? iTo + lngDelta : iTo
);
} catch (e) {}
}
}
};
// -------------------------------------------------------------------
// PART 2: CODE COMPATIBLE WITH FOLDINGTEXT, DRAFTS, 1WRITER, TEXTWELL
function outdentSelectedLines() {
var strDefaultIndent = '\\t', // tab must be preceded by two backslashes
strIndent,
rgxLeftSpace = /^([ \t]+)(?=\S)/gm,
rgxOut,
lstLinesFromTo = drafts.getSelectedLineRange(),
iFrom = lstLinesFromTo[0],
lngSelnChars = lstLinesFromTo[1],
strLines = drafts.getTextInRange(iFrom, lngSelnChars),
oMatch = rgxLeftSpace.exec(strLines),
strGap = oMatch ? oMatch[1] : null,
i = strGap ? strGap.length : 0,
iTab = 0,
iSpace = 0;
// INDENTED WITH SPACES OR WITH TABS ?
if (strGap) {
while (i--) {
if (strGap[i] === '\t') iTab++;
else iSpace++;
}
strIndent = (iTab > iSpace) ? '\\t' : ' ';
} else strIndent = strDefaultIndent;
// BUILD THE OUT-DENTED TEXT
rgxOut = new RegExp('^' + strIndent, 'gm');
strNew = strLines.replace(rgxOut, '');
// PLACE AND SELECT
drafts.setTextInRange(iFrom, lngSelnChars-1, strNew);
drafts.setSelectedRange(iFrom, strNew.length - 1);
return true;
}
// MAIN
outdentSelectedLines();
}