Skip to content

Instantly share code, notes, and snippets.

@okay-type
Last active March 8, 2025 20:12
Show Gist options
  • Save okay-type/43dafbd95bb5c3c92cefa4c8988091a1 to your computer and use it in GitHub Desktop.
Save okay-type/43dafbd95bb5c3c92cefa4c8988091a1 to your computer and use it in GitHub Desktop.
# menuTitle: Sort Script Menu
import AppKit
from mojo.tools import CallbackWrapper
from mojo.subscriber import Subscriber, registerRoboFontSubscriber, registerSubscriberEvent, getRegisteredSubscriberEvents
class sort_script_menu(Subscriber):
debug = True
## https://stackoverflow.com/questions/7367438/sort-nsmenuitems-alphabetically-and-by-whether-they-have-submenus-or-not
def sortMenu(self, menu):
itemArray = menu.itemArray().copy()
# Create a descriptor that will sort files alphabetically
alphaDescriptor = AppKit.NSSortDescriptor.alloc().initWithKey_ascending_('title', True)
# itemArray = itemArray.sortedArrayUsingDescriptors_([alphaDescriptor])
# Create a descriptor that will sort files alphabetically and based on existance of submenus
submenuDescriptor = AppKit.NSSortDescriptor.alloc().initWithKey_ascending_('hasSubmenu', False)
itemArray = itemArray.sortedArrayUsingDescriptors_([submenuDescriptor, alphaDescriptor])
topItems = []
middleItems = []
bottomItems = []
lastItems = []
for item in itemArray:
title = item.title()
if title in ['Project', 'Project Scripts']:
topItems.append(item)
continue
elif title in ['Update Menu', 'Reveal Script folder']:
bottomItems.append(item)
continue
elif title in ['Mechanic', 'Mechanic 2']:
lastItems.append(item)
continue
else:
middleItems.append(item)
continue
# The following code fixes NSPopUpButton's confusion that occurs when
# we sort this list. NSPopUpButton listens to the NSMenu's add notifications
# and hides the first item. Sorting this blows it up.
# if item.isHidden():
# item.setHidden_(False)
# While we're looping, if there's a submenu, go ahead and sort that, too.
# if item.hasSubmenu():
# self.sortMenu(item.submenu())
newItemArray = AppKit.NSMutableArray.alloc().init()
for item in topItems:
newItemArray.addObject_(item)
if len(topItems) > 0:
newItemArray.addObject_(AppKit.NSMenuItem.separatorItem())
for item in middleItems:
newItemArray.addObject_(item)
if len(bottomItems) > 0:
newItemArray.addObject_(AppKit.NSMenuItem.separatorItem())
for item in bottomItems:
newItemArray.addObject_(item)
if len(lastItems) > 0:
newItemArray.addObject_(AppKit.NSMenuItem.separatorItem())
for item in lastItems:
newItemArray.addObject_(item)
sorted_menu = AppKit.NSArray.alloc().initWithArray_(newItemArray)
menu.setItemArray_(sorted_menu)
return
def sortExtensionsMenu(self):
# print('sort_script_menu sortExtensionsMenu')
menubar = AppKit.NSApp().mainMenu()
extensionsItem = menubar.itemWithTitle_('Extensions')
extensionsMenu = extensionsItem.submenu()
scriptsItem = menubar.itemWithTitle_('Scripts')
scriptsMenu = scriptsItem.submenu()
try:
self.sortMenu(extensionsMenu)
self.sortMenu(scriptsMenu)
except:
import traceback
print('Err')
print(traceback.format_exc())
def roboFontDidFinishLaunching(self, info):
# print('sort_script_menu roboFontDidFinishLaunching')
self.sortExtensionsMenu()
def extensionDidRemoteInstall(self, info):
# print('sort_script_menu extensionDidRemoteInstall')
self.sortExtensionsMenu()
def extensionDidUninstall(self, info):
# print('sort_script_menu extensionDidUninstall')
self.sortExtensionsMenu()
def scriptsMenuChanged(self, info):
# print('sort_script_menu scriptsMenuChanged')
self.sortExtensionsMenu()
if 'com.ok.sort_script_menu.extensionInstalledEvent' not in getRegisteredSubscriberEvents().keys():
registerSubscriberEvent(
subscriberEventName='com.ok.sort_script_menu.extensionInstalledEvent',
methodName='extensionDidRemoteInstall',
lowLevelEventNames=['com.robofontmechanic.extensionDidRemoteInstall'],
dispatcher='roboFont',
delay=1,
documentation='This is a custom subscriber method that looks for whether an extension installed on Mechanic.'
)
if 'com.ok.sort_script_menu.extensionUninstalledEvent' not in getRegisteredSubscriberEvents().keys():
registerSubscriberEvent(
subscriberEventName='com.ok.sort_script_menu.extensionUninstalledEvent',
methodName='extensionDidUninstall',
lowLevelEventNames=['com.robofontmechanic.extensionDidUninstall'],
dispatcher='roboFont',
delay=1,
documentation='This is a custom subscriber method that looks for whether an extension uninstalled on Mechanic.'
)
if 'com.ok.sort_script_menu.scriptsMenuChangedEvent' not in getRegisteredSubscriberEvents().keys():
registerSubscriberEvent(
subscriberEventName='com.ok.sort_script_menu.scriptsMenuChangedEvent',
methodName='scriptsMenuChanged',
lowLevelEventNames=['scriptsMenuChanged'],
dispatcher='roboFont',
delay=1,
documentation='This is a custom subscriber method for when Update Menu is clicked in the Scripts Menu.'
)
registerRoboFontSubscriber(sort_script_menu)
@ryanbugden
Copy link

FYI: "Mechanic 2" is now "Mechanic" in the menu

@okay-type
Copy link
Author

Great, thanks. I hadn't update to the latest Mechanic. Reconfigured things to handle Mechanic and Mechanic 2. And to add them to the very bottom.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment