Created
May 18, 2023 16:58
-
-
Save stephancasas/0c9c749efff6bdacd4643a258d126076 to your computer and use it in GitHub Desktop.
Create New Untitled TextMate Document from AppleScript
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env osascript -l JavaScript | |
const $attr = Ref(); | |
const $windows = Ref(); | |
const $children = Ref(); | |
function run(_) { | |
// Get TextMate AXUIElement | |
const textmatePid = | |
$.NSRunningApplication.runningApplicationsWithBundleIdentifier( | |
'com.macromates.TextMate', | |
).firstObject.processIdentifier; | |
const textmateApp = $.AXUIElementCreateApplication(textmatePid); | |
// Quit if TextMate is not running. | |
if (typeof textmatePid != 'number') { | |
console.log('Error: TextMate is not currently running.'); | |
return 1; | |
} | |
// Get Dock AXUIElement | |
const dockPid = | |
$.NSRunningApplication.runningApplicationsWithBundleIdentifier( | |
'com.apple.dock', | |
).firstObject.processIdentifier; | |
const dockApp = $.AXUIElementCreateApplication(dockPid); | |
$.AXUIElementCopyAttributeValue(dockApp, 'AXChildren', $children); | |
// Locate the TextMate dock tile. | |
$.AXUIElementCopyAttributeValue($children[0].js[0], 'AXChildren', $children); | |
const textmateTile = $children[0].js.find((child) => { | |
$.AXUIElementCopyAttributeValue(child, 'AXTitle', $attr); | |
return $attr[0].js == 'TextMate'; | |
}); | |
// Open the TextMate dock tile menu -- delay for draw. | |
$.AXUIElementPerformAction(textmateTile, 'AXShowMenu'); | |
delay(0.1); | |
// Capture the TextMate initial state for await reference and filtering. | |
$.AXUIElementCopyAttributeValue(textmateApp, 'AXWindows', $windows); | |
const initialWindowCount = $windows[0].js.length; | |
const initialWindowTitles = $windows[0].js.map((window) => { | |
$.AXUIElementCopyAttributeValue(window, 'AXTitle', $attr); | |
return $attr[0].js; | |
}); | |
// Locate the "New File" menu item in the TextMate dock tile menu. | |
$.AXUIElementCopyAttributeValue(textmateTile, 'AXChildren', $children); | |
$.AXUIElementCopyAttributeValue($children[0].js[0], 'AXChildren', $children); | |
const newFileMenuItem = $children[0].js.find((child) => { | |
$.AXUIElementCopyAttributeValue(child, 'AXTitle', $attr); | |
return $attr[0].js == 'New File'; | |
}); | |
// Click the "New File" menu item and await new window. | |
$.AXUIElementPerformAction(newFileMenuItem, 'AXPress'); | |
if ( | |
!(() => { | |
const timeout = new Date().getTime() + 5000; | |
while (true) { | |
$.AXUIElementCopyAttributeValue(textmateApp, 'AXWindows', $windows); | |
if ( | |
typeof $windows[0] == 'function' && | |
($windows[0].js.length ?? 0) > initialWindowCount | |
) { | |
return true; | |
} | |
if (new Date().getTime() > timeout) { | |
return false; | |
} | |
delay(0.1); | |
} | |
})() | |
) { | |
console.log('Error: Did not observe new window before timeout.'); | |
return 1; | |
} | |
// Find the window AXUIElement whose title is not in the initial list. | |
const newWindow = $windows[0].js.find((child) => { | |
$.AXUIElementCopyAttributeValue(child, 'AXTitle', $attr); | |
return !initialWindowTitles.includes($attr[0].js); | |
}); | |
// Make the new window frontmost. | |
$.AXUIElementPerformAction(newWindow, 'AXRaise'); | |
return 0; | |
} | |
// prettier-ignore | |
(() => { | |
ObjC.import('Cocoa'); // yes, it's necessary -- stop telling me it isn't | |
ObjC.bindFunction('AXUIElementPerformAction', ['int', ['id', 'id']]); | |
ObjC.bindFunction('AXUIElementCreateApplication', ['id', ['unsigned int']]); | |
ObjC.bindFunction('AXUIElementCopyAttributeValue',['int', ['id', 'id', 'id*']]); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment