How to create snippet subfolders in textmate bundle - textmate

I've just discovered textmate and I love it. I would love to use it as a way of storing my own snippets. I know how to do this in textmate but as I want to add loads of snippets I don't want them to become disorganised. I would like to add them into organised subfolders under the relevant bundle. eg under the shell script bundle I would like to add a folder that keeps all my networking snippets together. I cant find anywhere how to do this but I know it can be done as some bundles are organised like this.....Help

I managed to figure this out with a lot of trial and error and starting with this Superuser answer.
The only way to do it in TextMate 2.0 is to manually edit the info.plist file for your bundle. I suggest doing this on an exported copy of the bundle and reloading it into textmate. To export a bundle right click on the bundle in bundle editor and click Export Bundle....
Start by adding a mainMenu section at the top level of the plist file:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
...
<key>mainMenu</key>
<dict>
</dict>
</dict>
</plist>
From what I can tell, the mainMenu dict supports 3 keys: excludedItems, items, and submenus. The excludedItems and items are arrays containing a list of UUIDs of either bundle items (snippets, commands, etc.) or submenus. You can get the UUID of a command or snippet by opening it in textmate and finding the uuid key; it'll look like:
<key>uuid</key>
<string>0A2DB1AC-3049-4BD5-8931-641E716990F9</string>
Once you have the UUIDs of your items you can list them in items to populate the bundle menu in the order you wish, e.g.:
<key>items</key>
<array>
<string>409b0e74-9ab5-4d35-b957-9ddf23a71c0c</string>
<string>------------------------------------</string>
<string>d2c991dc-a00e-4247-8479-f2d29f387319</string>
</array>
If you use a series of - characters in lieu of a UUID, it will create a separator in the menu. Likewise, if there are snippets you don't want to display in the bundle's menu you can add them to excludedItems.
To create submenus you have to define them inside submenus, like so:
<key>submenus</key>
<dict>
<key>71BE58B2-E486-4B21-93F1-C208D4914099</key>
<dict>
<key>items</key>
<array>
<string>6D0B2B9D-62C7-4842-BA28-F3379E887D93</string>
<string>CADC55BD-0D0A-48C8-B296-35FA7AAE09CA</string>
</array>
<key>name</key>
<string>C++ Snippets</string>
</dict>
</dict>
Each submenu needs to have an associated UUID inside <key>...</key>. I created one from an online UUID generator. You can then add the submenu's UUID to the top-level items array to add the submenu to your bundle's menu.
Finally, when loading your bundle into textmate you must first delete all cached instances of the bundle from:
~/Library/Application Support/Avian/Bundles
~/Library/Application Support/Avian/Pristine Copy/Bundles
If you don't, textmate will sometimes ignore the newly loaded bundle. Not sure if there's a cleaner way to reload a bundle, but deleting it worked for me.
For a complete example see this commit in the ROS bundle on my Github.

Just some extra info on the excellent answer above
As of TM2 rc23, you can access the UUID of an existing item by right-clicking on it in the bundle editor window (accessed with cntrl-option-command-B)
You can create a UUID in terminal.app with the command uuidgen (you could also make this into a command if you use this often)
TM2 doesn't need the cache clearing - it watches for changes in the plist.
#user96157 is clear about this, but note you have to also add your new submenu to the mainMenu. So:
<key>mainMenu</key>
<dict>
<key>items</key>
<array>
<string>COPY-UUID-FOR-YOUR-NEW-SUB-MENU-HERE!</string>

Related

com.automator.runner.xpc is not allowed assistive access - cannot click when running a quick action

I have a Quick Action that runs an AppleScript program which needs to click a button. However, when it gets to the clicking stage, it displays an error message:
com.automator.runner.xpc is not allowed assistive access
I've tried to give it permissions under System Preferences > Security and Privacy > Full Disk Access, but it only lets me add applications to the list, whereas this is a Quick Action (service).
tell application "System Events"
tell process "NotificationCenter"
click button "End" of window 1
end tell
end tell
It should have just clicked the button, but returned the error message as given above.
Any ideas as to why this doesn't work? Is there a way for me to give com.automator.runner.xpc full disk access?
This is a known problem with automator services that have AppleScript actions in them. I suppose Gatekeeper doesn't like them because it looks like code injection.
The workaround (until Apple does something to fix the problem) is to take the AppleScript in your action and turn it into a stand-alone AppleScript application: copy the code into Script Editor and save the file, choosing Application from the File Format menu. Add this script app to the Accessibility Security pane — System Preferences->Security & Privacy->Privacy->Accessibility — and it should pass GateKeeper's muster. Then you have a choice, depending on your setup:
Create a Quick Action in Automator that calls the app.
Create a Quick Action as normal, and use the Launch Application action to run the script app. This should work as a service or as a Quick Action in the Finder preview pane
Turn the script app into a service in its own right.
In the Finder, find the script app, then select "Show Package Contents" from the contextual menu. Drill down to the file "info.plist", open it in a plain-text editor and edit in a new key-value unit that looks like:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
[...]
<key>NSServices</key>
<array>
<dict>
<key>NSBackgroundColorName</key>
<string>background</string>
<key>NSMenuItem</key>
<dict>
<key>default</key>
<string>Service Name</string>
</dict>
<key>NSMessage</key>
<string>run</string>
</dict>
</array>
</dict>
</plist>
... making sure not to delete or damage any of the default xml that Script Editor generates for script apps. Save the revised info.plist file, place the script app in ~/Library/Services. This only seems to work as a service (I can't get them to show up in the Extensions preference pane).
When I simply disconnected my external monitor today I noticed that the script that I was using that triggered this alert started working. So I believe it is directly related to that.

Can I use Applescript to find the current iTunes media location and other iTunes options

Can I use Applescript to find the current iTunes media location and other iTunes options.There doesnt seem to be such options when I read the iTunes Applescript Dictionary within Script Editor but surely there is a way to do it.
I read in the past that something is stored in com.itunes.plist but its not plaintext and my plist file did not change when I created a new libary so Im not convinced it is still used, or if it is kept up to date.
Yes, #PaulTaylor, you can get the media folder location of the current user in AppleScript using the Apple-provided ​iTunes​Library framework. (documentation at iTunesLibrary at Apple)
Here's a working AppleScript to do it:
use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "iTunesLibrary"
set lib to current application's ITLibrary's libraryWithAPIVersion:"1.0" |error|:(missing value)
set mediaFolderPath to POSIX path of (lib's mediaFolderLocation as alias)
--> "/Volumes/LaCie 6/iTunes Library/"
The media location is not saved in the global iTunes preference file. Because you can have multiple libraries, and each library defines its own media location, this is actually saved in the the library preferences. The default library is located at ~/Music/iTunes/iTunes Library.itl. I'm not sure what kind of file this is. It does not seem to be a plist/xml file, nor an sqlite file. It seems to just be a proprietary binary file.
Inside the same folder, I also found iTunes Music Library.xml (after some testing around, that file is now missing, so YMMV for the rest of this explanation). Here is a truncated example:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Major Version</key><integer>1</integer>
<key>Minor Version</key><integer>1</integer>
<key>Application Version</key><string>12.3.3.17</string>
<key>Date</key><date>2016-04-14T19:35:27Z</date>
<key>Features</key><integer>5</integer>
<key>Show Content Ratings</key><true/>
<key>Library Persistent ID</key><string>1AEAB6C2057C2167</string>
<key>Tracks</key>
<dict>
</dict>
<key>Playlists</key>
<array>
</array>
<key>Music Folder</key><string>file:///Users/<username>/Music/iTunes/iTunes%20Media/</string>
</dict>
</plist>
Note the key Music Folder. This is the setting you are looking for to find the library's media location. There are also some library settings, such as a list of playlists and track information.

How to keep list of files or folders on Mac sandboxed app?

I wonder is it possible to keep list of files or folders opened before on sandboxed app without re-opening them or copying to it's own library ?
Thanks in advance
To keep track of files being accessed by the user, you should create security bookmarks for each file, then that will allow your application to access these files on future runs of the application without getting permission everytime.
I've made this class that wraps up persisting permissions you already have from a using opening a file via NSOpenPanel, and then you can use the class to access that file in the future.
https://github.com/leighmcculloch/AppSandboxFileAccess
At this time only using temporary entitlements.
You should use something like
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
<key>com.apple.security.temporary-exception.files.absolute-path.read-write</key>
<array>
<string>absolute path to use</string>
</array>
</dict>
</plist>
I hope Apple will clarify how this can be done without 'temporary' solutions because it breaks many many apps

Mac OSX: folder extension association programmatically

Is it possible to to register a folder extension on Mac to be opened with a specific application (something like .app folders behave in a special way)? If it's possible, then how?
I'm looking for a solution similar to this: related question, only for folders, not files.
I had a look at the reference of the UTIs UTIs, but I did not find any identifier that seems suitable (e.g. something like public.folder-extension).
Is it possible to do this at all? On the GUI I did not see any way to do it either (for a folder with a specific extension, there is no "Open With..." option). [Important: I do not want to do this on the GUI, this was only a remark to say why I think it might be impossible.]
I found out a way that works for me (in case somebody else also encounters this problem):
Add the following snippet in the Info.plist file of the application bundle:
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>ext1</string>
<string>ext2</string>
</array>
<key>CFBundleTypeIconFile</key>
<string>documentlogo.icns</string>
<key>CFBundleTypeName</key>
<string>My Bundle Type Name</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
<key>LSTypeIsPackage</key>
<true />
</dict>
</array>
Replace ext1, ext2 with the extensions you would like to support, documentlogo.icns with the name of the icon of the document (which must be located in Application Bundle.app/Contents/Resources/documentlogo.icns), and My Bundle Type Name with a sensible name for your bundle)
In this example, any folder, to be recognized as a bundle of our application, must have the extension ext1 or ext2, and must contain a Contents/PkgInfo file, with 8 "?"s. All the other contents are up to you.
I base my solution on these sources, Document Packages, Information Property List Key Reference, Document Packages Examples.
Please, correct me if there is a better/more efficient way to do it, because I still have some doubts (e.g.: as I see, this should work also for normal files, not just Packages. Then why do we need the LaunchServices way as well? Is the application bundle the default, and the LaunchServices the way each user customizes it?)
I found how to do this manually, which I will list here for others to find, and to do this programmatically you can combine this info with the answer at: https://superuser.com/questions/273756/how-to-change-default-app-for-all-files-of-particular-file-type-through-terminal
You must have XCode installed. Open Terminal or iTerm and:
cd ~/Library/Preferences
open com.apple.LaunchServices.plist
Add or overwrite the following entry (use Cmd+F to search for "folder"):
LSHandlerContentType String public.folder
LSHandlerRoleAll String com.somecompany.someproduct
Replace the com.somecompany.someproduct with an existing name - you can see these in the same directory (~/Library/Preferences) - they end with .plist - e.g. com.macromates.textmate or com.sublimetext.2.
Alternative if you use Quicksilver: add a custom keyboard trigger for "Current Selection (Proxy Object) -> Open With -> Your App Here". I found that this also creates (and vigorously re-creates) the above association whenever you use the newly created keyboard shortcut on a folder in Finder.

Be notified when a file is dropped into a folder Mac OS X

I want to write a little script on my Mac. This script will basically look for new files in a particular folder, and move them to another location when some are found.
So I was about to write something very basic, with an infinite loop, and I was wondering if something a bit more nice already exist ? Like a Listener or something I could use ?
Thanks !
You want to look into Folder Actions
http://www.simplehelp.net/2007/01/30/folder-actions-for-os-x-explained-with-real-world-examples/
An alternative way, slightly more low-level than folder actions, but I suspect more flexible, is to use launchd to watch a folder.
See launchd.plist(5), or the overview documentation for launchd (unfortunately, this overview documentation is primarily concerned with daemons, but the principle is the same; the key you're interested in is WatchPaths, so searching for that might find something more like a tutorial).
If you go this route, you need to create a .plist like the following, which runs the command /path/to/virus/scanner.sh /Junk/Downloads whenever the /Junk/Downloads directory is modified.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>localhost.clamav.clamscan</string>
<key>LowPriorityIO</key>
<true/>
<key>Nice</key>
<integer>1</integer>
<key>ProgramArguments</key>
<array>
<string>/path/to/virus/scanner.sh</string>
<string>/Junk/Downloads</string>
</array>
<key>WatchPaths</key>
<array>
<string>/Junk/Downloads</string>
</array>
</dict>
</plist>
Put that in $HOME/Library/LaunchAgents/foo.plist, and the command launchctl load $HOME/Library/LaunchAgents/foo.plist will start it going.
Thanks Lou.
I had a look at your link and figured out how to create my own folder action doing what I want.
Just sharing the action in case someone want to use it :
It works fine for now !

Resources