import Cocoa
// S h o w a n i n f o r m a t i o n a l a l e r t
public func infoAlert ( _ message : String , _ extra : String ? = nil , style : NSAlert . Style = NSAlert . Style . informational ) {
let alert = NSAlert ( )
alert . messageText = message
if extra != nil { alert . informativeText = extra ! }
alert . alertStyle = style
alert . runModal ( )
}
// S h o w a n i n f o r m a t i o n a l a l e r t a n d t h e n q u i t
public func quitAlert ( _ message : String , _ extra : String ? = nil ) {
infoAlert ( message , " The application will now quit. " , style : NSAlert . Style . critical )
NSApp . terminate ( nil )
}
@NSApplicationMain
class AppDelegate : NSObject , NSApplicationDelegate {
// W h e r e t h e o f f i c i a l R i n s t a l l s g o
let macos_r_framework_dir = " /Library/Frameworks/R.framework/Versions "
// G e t t h e b a r s e t u p
let statusItem = NSStatusBar . system . statusItem ( withLength : NSStatusItem . variableLength )
let statusMenu = NSMenu ( )
let quitItem = NSMenuItem ( title : NSLocalizedString ( " Quit " , comment : " Quit menu item " ) , action : #selector ( NSApp . terminate ) , keyEquivalent : " q " )
override init ( ) {
super . init ( )
statusMenu . delegate = self
// d i a l b y I c o n M a r k f r o m t h e N o u n P r o j e c t
statusItem . button ? . image = # imageLiteral ( resourceName : " RSwitch " )
statusItem . menu = statusMenu
}
func applicationDidFinishLaunching ( _ aNotification : Notification ) {
// I n s e r t c o d e h e r e t o i n i t i a l i z e a p p
}
func applicationWillTerminate ( _ aNotification : Notification ) {
// I n s e r t c o d e h e r e t o t e a r d o w n a p p
}
// T h e c o r e w o r k e r f u n c t i o n . R e c e i v e s t h e b a s e n a m e o f t h e s e l e c t e d d i r e c t o r y
// t h e n r e m o v e s t h e c u r r e n t a l i a s a n d c r e a t e s t h e n e w o n e .
@objc func handleSwitch ( _ sender : NSMenuItem ? ) {
let fm = FileManager . default ;
let title = sender ? . title
do {
try fm . removeItem ( atPath : macos_r_framework_dir + " / " + " Current " )
} catch {
infoAlert ( " Failed to remove 'Current' alias " , macos_r_framework_dir + " / " + " Current " )
}
do {
try fm . createSymbolicLink (
at : NSURL ( fileURLWithPath : macos_r_framework_dir + " / " + " Current " ) as URL ,
withDestinationURL : NSURL ( fileURLWithPath : macos_r_framework_dir + " / " + title ! ) as URL
)
} catch {
infoAlert ( " Failed to create alias for " + macos_r_framework_dir + " / " + title ! )
}
}
// S h o w t h e f r a m e w o r k d i r i n a n e w F i n d e r w i n d o w
@objc func openFrameworksDir ( _ sender : NSMenuItem ? ) {
NSWorkspace . shared . openFile ( macos_r_framework_dir , withApplication : " Finder " )
}
}
extension AppDelegate : NSMenuDelegate {
func menuWillOpen ( _ menu : NSMenu ) {
if ( menu != self . statusMenu ) { return }
// c l e a r t h e m e n u
menu . removeAllItems ( )
// a d d s e l e c t i o n t o o p e n f r a m e w o r k s d i r i n F i n d e r
menu . addItem ( NSMenuItem ( title : " Open R Frameworks Directory " , action : #selector ( openFrameworksDir ) , keyEquivalent : " " ) )
menu . addItem ( NSMenuItem . separator ( ) )
// p o p u l a t e i n s t a l l e d v e r s i o n s
let fm = FileManager . default
var targetPath : String ? = nil
do {
// g e t s a d i r e c t o r y l i s t i n g
let entries = try fm . contentsOfDirectory ( atPath : macos_r_framework_dir )
// r e t r i e v e s a l l v e r s i o n s ( e x c l u d e s h i d d e n f i l e s a n d t h e C u r r e n t a l i a s
let versions = entries . sorted ( ) . filter { ! ( $0 . hasPrefix ( " . " ) ) && ! ( $0 = = " Current " ) }
// i f t h e r e w a s a C u r r e n t a l i a s ( p r b l y s h l d a l e r t i f n o t )
if ( ( entries . filter { $0 = = " Current " } ) [ 0 ] = = " Current " ) {
// g e t w h e r e C u r r e n t p o i n t s t o
let furl = NSURL ( fileURLWithPath : macos_r_framework_dir + " / " + " Current " )
if ( furl . fileReferenceURL ( ) != nil ) {
do {
let fdat = try NSURL ( resolvingAliasFileAt : furl as URL , options : [ ] )
targetPath = fdat . lastPathComponent !
} catch {
targetPath = furl . path
}
}
// p o p u l a t e m e n u i t e m s w i t h a l l i n s t a l l e d R v e r s i o n s , e n s u r i n g w e
// p u t a c h e c k b o x n e x t t o t h e o n e t h a t i s C u r r e n t
for version in versions {
let item = NSMenuItem ( title : version , action : #selector ( handleSwitch ) , keyEquivalent : " " )
item . isEnabled = true
if ( version = = targetPath ) { item . state = NSControl . StateValue . on }
item . representedObject = version
menu . addItem ( item )
}
}
} catch {
quitAlert ( " Failed to list contents of R framework directory. You either do not have R installed or have incorrect permissions set on " + macos_r_framework_dir )
}
// A d d a Q u i t i t e m
menu . addItem ( NSMenuItem . separator ( ) )
menu . addItem ( quitItem )
}
}