Browse Source

osx: refactor plugin and add a few features (#9026)

Co-authored-by: Capybara <git.capybara@gmail.com>
Co-authored-by: drootang <drootang@users.noreply.github.com>
Co-authored-by: Augusto Souza <augustorsouza@gmail.com>
Co-authored-by: PatrBal <44707588+PatrBal@users.noreply.github.com>
Marc Cornellà 4 years ago
parent
commit
d47447a5e6
4 changed files with 353 additions and 201 deletions
  1. 6 3
      plugins/osx/README.md
  2. 90 0
      plugins/osx/_security
  3. 170 0
      plugins/osx/music
  4. 87 198
      plugins/osx/osx.plugin.zsh

+ 6 - 3
plugins/osx/README.md

@@ -22,14 +22,17 @@ Original author: [Sorin Ionescu](https://github.com/sorin-ionescu)
 | `pfs`           | Return the current Finder selection                   |
 | `pfs`           | Return the current Finder selection                   |
 | `cdf`           | `cd` to the current Finder directory                  |
 | `cdf`           | `cd` to the current Finder directory                  |
 | `pushdf`        | `pushd` to the current Finder directory               |
 | `pushdf`        | `pushd` to the current Finder directory               |
+| `pxd`           | Return the current Xcode project directory            |
+| `cdx`           | `cd` to the current Xcode project directory           |
 | `quick-look`    | Quick-Look a specified file                           |
 | `quick-look`    | Quick-Look a specified file                           |
 | `man-preview`   | Open a specified man page in Preview app              |
 | `man-preview`   | Open a specified man page in Preview app              |
-| `showfiles`     | Show hidden files                                     |
-| `hidefiles`     | Hide the hidden files                                 |
-| `itunes`        | DEPRECATED. Use `music` from macOS Catalina on        |
+| `showfiles`     | Show hidden files in Finder                           |
+| `hidefiles`     | Hide the hidden files in Finder                       |
+| `itunes`        | _DEPRECATED_. Use `music` from macOS Catalina on      |
 | `music`         | Control Apple Music. Use `music -h` for usage details |
 | `music`         | Control Apple Music. Use `music -h` for usage details |
 | `spotify`       | Control Spotify and search by artist, album, track…   |
 | `spotify`       | Control Spotify and search by artist, album, track…   |
 | `rmdsstore`     | Remove .DS\_Store files recursively in a directory    |
 | `rmdsstore`     | Remove .DS\_Store files recursively in a directory    |
+| `btrestart`     | Restart the Bluetooth daemon                          |
 
 
 ## Acknowledgements
 ## Acknowledgements
 
 

+ 90 - 0
plugins/osx/_security

@@ -0,0 +1,90 @@
+#compdef security
+
+local -a _1st_arguments
+_1st_arguments=(
+  'help:Show all commands, or show usage for a command'
+  'list-keychains:Display or manipulate the keychain search list'
+  'default-keychain:Display or set the default keychain'
+  'login-keychain:Display or set the login keychain'
+  'create-keychain:Create keychains and add them to the search list'
+  'delete-keychain:Delete keychains and remove them from the search list'
+  'lock-keychain:Lock the specified keychain'
+  'lock-keychain:Unlock the specified keychain'
+  'set-keychain-settings:Set settings for a keychain'
+  'set-keychain-password:Set password for a keychain'
+  'show-keychain-info:Show the settings for keychain'
+  'dump-keychain:Dump the contents of one or more keychains'
+  'create-keypair:Create an asymmetric key pair'
+  'add-generic-password:Add a generic password item'
+  'add-internet-password:Add an internet password item'
+  'add-certificates:Add certificates to a keychain'
+  'find-generic-password:Find a generic password item'
+  'delete-generic-password:Delete a generic password item'
+  'find-internet-password:Find an internet password item'
+  'delete-internet-password:Delete an internet password item'
+  'find-certificate:Find a certificate item'
+  'find-identity:Find an identity certificate + private key'
+  'delete-certificate:Delete a certificate from a keychain'
+  'set-identity-preference:Set the preferred identity to use for a service'
+  'get-identity-preference:Get the preferred identity to use for a service'
+  'create-db:Create a db using the DL'
+  'export:Export items from a keychain'
+  'import:Import items into a keychain'
+  'cms:Encode or decode CMS messages'
+  'install-mds:MDS database'
+  'add-trusted-cert:Add trusted certificates:'
+  'remove-trusted-cert:Remove trusted certificates:'
+  'dump-trust-settings:Display contents of trust settings'
+  'user-trust-settings-enable:Display or manipulate user-level trust settings'
+  'trust-settings-export:Export trust settings'
+  'trust-settings-import:Import trust settings'
+  'verify-cert:Verify certificates:'
+  'authorize:Perform authorization operations'
+  'authorizationdb:Make changes to the authorization policy database'
+  'execute-with-privileges:Execute tool with privileges'
+  'leaks:Run /usr/bin/leaks on this process'
+  'error:Display a descriptive message for the given error codes:'
+  'create-filevaultmaster-keychain:"Create a keychain containing a key pair for FileVault recovery use'
+)
+_arguments '*:: :->command'
+
+if (( CURRENT == 1 )); then
+  _describe -t commands "security command" _1st_arguments
+  return
+fi
+
+case "$words[1]" in
+  find-(generic|internet)-password)
+    _values \
+      'Usage: find-[internet/generic]-password [-a account] [-s server] [options...] [-g] [keychain...]' \
+      '-a[Match "account" string]' \
+      '-c[Match "creator" (four-character code)]' \
+      '-C[Match "type" (four-character code)]' \
+      '-D[Match "kind" string]' \
+      '-G[Match "value" string (generic attribute)]' \
+      '-j[Match "comment" string]' \
+      '-l[Match "label" string]' \
+      '-s[Match "service" string]' \
+      '-g[Display the password for the item found]' \
+      '-w[Display only the password on stdout]' ;;
+  add-(generic|internet)-password)
+    _values \
+      'Usage: add-[internet/generic]-password [-a account] [-s server] [-w password] [options...] [-A|-T appPath] [keychain]]' \
+      '-a[Specify account name (required)]' \
+      '-c[Specify item creator (optional four-character code)]' \
+      '-C[Specify item type (optional four-character code)]' \
+      '-d[Specify security domain string (optional)]' \
+      '-D[Specify kind (default is "Internet password")]' \
+      '-j[Specify comment string (optional)]' \
+      '-l[Specify label (if omitted, server name is used as default label)]' \
+      '-p[Specify path string (optional)]' \
+      '-P[Specify port number (optional)]' \
+      '-r[Specify protocol (optional four-character SecProtocolType, e.g. "http", "ftp ")]' \
+      '-s[Specify server name (required)]' \
+      '-t[Specify authentication type (as a four-character SecAuthenticationType, default is "dflt")]' \
+      '-w[Specify password to be added]' \
+      '-A[Allow any application to access this item without warning (insecure, not recommended!)]' \
+      '-T[Specify an application which may access this item (multiple -T options are allowed)]' \
+      '-U[Update item if it already exists (if omitted, the item cannot already exist) ]' \
+      'utils)]' ;;
+esac

+ 170 - 0
plugins/osx/music

@@ -0,0 +1,170 @@
+#!/usr/bin/env zsh
+
+function music itunes() {
+  local APP_NAME=Music sw_vers=$(sw_vers -productVersion 2>/dev/null)
+
+  autoload is-at-least
+  if [[ -z "$sw_vers" ]] || is-at-least 10.15 $sw_vers; then
+    if [[ $0 = itunes ]]; then
+      echo >&2 The itunes function name is deprecated. Use \'music\' instead.
+      return 1
+    fi
+  else
+    APP_NAME=iTunes
+  fi
+
+  local opt=$1 playlist=$2
+  (( $# > 0 )) && shift
+  case "$opt" in
+    launch|play|pause|stop|rewind|resume|quit)
+      ;;
+    mute)
+      opt="set mute to true"
+      ;;
+    unmute)
+      opt="set mute to false"
+      ;;
+    next|previous)
+      opt="$opt track"
+      ;;
+    vol)
+      local new_volume volume=$(osascript -e "tell application \"$APP_NAME\" to get sound volume")
+      if [[ $# -eq 0 ]]; then
+        echo "Current volume is ${volume}."
+        return 0
+      fi
+      case $1 in
+        up) new_volume=$((volume + 10 < 100 ? volume + 10 : 100)) ;;
+        down) new_volume=$((volume - 10 > 0 ? volume - 10 : 0)) ;;
+        <0-100>) new_volume=$1 ;;
+        *) echo "'$1' is not valid. Expected <0-100>, up or down."
+           return 1 ;;
+      esac
+      opt="set sound volume to ${new_volume}"
+      ;;
+    playlist)
+      # Inspired by: https://gist.github.com/nakajijapan/ac8b45371064ae98ea7f
+      if [[ -n "$playlist" ]]; then
+        osascript 2>/dev/null <<EOF
+          tell application "$APP_NAME"
+            set new_playlist to "$playlist" as string
+            play playlist new_playlist
+          end tell
+EOF
+        if [[ $? -eq 0 ]]; then
+          opt="play"
+        else
+          opt="stop"
+        fi
+      else
+        opt="set allPlaylists to (get name of every playlist)"
+      fi
+      ;;
+    playing|status)
+      local currenttrack currentartist state=$(osascript -e "tell application \"$APP_NAME\" to player state as string")
+      if [[ "$state" = "playing" ]]; then
+        currenttrack=$(osascript -e "tell application \"$APP_NAME\" to name of current track as string")
+        currentartist=$(osascript -e "tell application \"$APP_NAME\" to artist of current track as string")
+        echo -E "Listening to ${fg[yellow]}${currenttrack}${reset_color} by ${fg[yellow]}${currentartist}${reset_color}"
+      else
+        echo "$APP_NAME is $state"
+      fi
+      return 0
+      ;;
+    shuf|shuff|shuffle)
+      # The shuffle property of current playlist can't be changed in iTunes 12,
+      # so this workaround uses AppleScript to simulate user input instead.
+      # Defaults to toggling when no options are given.
+      # The toggle option depends on the shuffle button being visible in the Now playing area.
+      # On and off use the menu bar items.
+      local state=$1
+
+      if [[ -n "$state" && "$state" != (on|off|toggle) ]]; then
+        print "Usage: $0 shuffle [on|off|toggle]. Invalid option."
+        return 1
+      fi
+
+      case "$state" in
+        on|off)
+          # Inspired by: https://stackoverflow.com/a/14675583
+          osascript >/dev/null 2>&1 <<EOF
+            tell application "System Events" to perform action "AXPress" of (menu item "${state}" of menu "Shuffle" of menu item "Shuffle" of menu "Controls" of menu bar item "Controls" of menu bar 1 of application process "iTunes" )
+EOF
+          return 0
+          ;;
+        toggle|*)
+          osascript >/dev/null 2>&1 <<EOF
+            tell application "System Events" to perform action "AXPress" of (button 2 of process "iTunes"'s window "iTunes"'s scroll area 1)
+EOF
+          return 0
+          ;;
+      esac
+      ;;
+    ""|-h|--help)
+      echo "Usage: $0 <option>"
+      echo "option:"
+      echo "\t-h|--help\tShow this message and exit"
+      echo "\tlaunch|play|pause|stop|rewind|resume|quit"
+      echo "\tmute|unmute\tMute or unmute $APP_NAME"
+      echo "\tnext|previous\tPlay next or previous track"
+      echo "\tshuf|shuffle [on|off|toggle]\tSet shuffled playback. Default: toggle. Note: toggle doesn't support the MiniPlayer."
+      echo "\tvol [0-100|up|down]\tGet or set the volume. 0 to 100 sets the volume. 'up' / 'down' increases / decreases by 10 points. No argument displays current volume."
+      echo "\tplaying|status\tShow what song is currently playing in Music."
+      echo "\tplaylist [playlist name]\t Play specific playlist"
+      return 0
+      ;;
+    *)
+      print "Unknown option: $opt"
+      return 1
+      ;;
+  esac
+  osascript -e "tell application \"$APP_NAME\" to $opt"
+}
+
+function _music() {
+  local app_name
+  case "$words[1]" in
+    itunes) app_name="iTunes" ;;
+    music|*) app_name="Music" ;;
+  esac
+
+  local -a cmds subcmds
+  cmds=(
+    "launch:Launch the ${app_name} app"
+    "play:Play ${app_name}"
+    "pause:Pause ${app_name}"
+    "stop:Stop ${app_name}"
+    "rewind:Rewind ${app_name}"
+    "resume:Resume ${app_name}"
+    "quit:Quit ${app_name}"
+    "mute:Mute the ${app_name} app"
+    "unmute:Unmute the ${app_name} app"
+    "next:Skip to the next song"
+    "previous:Skip to the previous song"
+    "vol:Change the volume"
+    "playlist:Play a specific playlist"
+    {playing,status}":Show what song is currently playing"
+    {shuf,shuff,shuffle}":Set shuffle mode"
+    {-h,--help}":Show usage"
+  )
+
+  if (( CURRENT == 2 )); then
+    _describe 'command' cmds
+  elif (( CURRENT == 3 )); then
+    case "$words[2]" in
+      vol) subcmds=( 'up:Raise the volume' 'down:Lower the volume' )
+        _describe 'command' subcmds ;;
+      shuf|shuff|shuffle) subcmds=('on:Switch on shuffle mode' 'off:Switch off shuffle mode' 'toggle:Toggle shuffle mode (default)')
+        _describe 'command' subcmds ;;
+    esac
+  elif (( CURRENT == 4 )); then
+    case "$words[2]" in
+      playlist) subcmds=('play:Play the playlist (default)' 'stop:Stop the playlist')
+        _describe 'command' subcmds ;;
+    esac
+  fi
+
+  return 0
+}
+
+compdef _music music itunes

+ 87 - 198
plugins/osx/osx.plugin.zsh

@@ -1,15 +1,22 @@
 # Open the current directory in a Finder window
 # Open the current directory in a Finder window
 alias ofd='open_command $PWD'
 alias ofd='open_command $PWD'
 
 
+# Show/hide hidden files in the Finder
+alias showfiles="defaults write com.apple.finder AppleShowAllFiles -bool true && killall Finder"
+alias hidefiles="defaults write com.apple.finder AppleShowAllFiles -bool false && killall Finder"
+
+# Bluetooth restart
+function btrestart() {
+  sudo kextunload -b com.apple.iokit.BroadcomBluetoothHostControllerUSBTransport
+  sudo kextload -b com.apple.iokit.BroadcomBluetoothHostControllerUSBTransport
+}
+
 function _omz_osx_get_frontmost_app() {
 function _omz_osx_get_frontmost_app() {
-  local the_app=$(
-    osascript 2>/dev/null <<EOF
-      tell application "System Events"
-        name of first item of (every process whose frontmost is true)
-      end tell
+  osascript 2>/dev/null <<EOF
+    tell application "System Events"
+      name of first item of (every process whose frontmost is true)
+    end tell
 EOF
 EOF
-  )
-  echo "$the_app"
 }
 }
 
 
 function tab() {
 function tab() {
@@ -27,7 +34,6 @@ function tab() {
       end tell
       end tell
       tell application "Terminal" to do script "${command}" in front window
       tell application "Terminal" to do script "${command}" in front window
 EOF
 EOF
-
   elif [[ "$the_app" == 'iTerm' ]]; then
   elif [[ "$the_app" == 'iTerm' ]]; then
     osascript <<EOF
     osascript <<EOF
       tell application "iTerm"
       tell application "iTerm"
@@ -41,32 +47,29 @@ EOF
         end tell
         end tell
       end tell
       end tell
 EOF
 EOF
-
   elif [[ "$the_app" == 'iTerm2' ]]; then
   elif [[ "$the_app" == 'iTerm2' ]]; then
-      osascript <<EOF
-        tell application "iTerm2"
-          tell current window
-            create tab with default profile
-            tell current session to write text "${command}"
-          end tell
+    osascript <<EOF
+      tell application "iTerm2"
+        tell current window
+          create tab with default profile
+          tell current session to write text "${command}"
         end tell
         end tell
+      end tell
 EOF
 EOF
   elif [[ "$the_app" == 'Hyper' ]]; then
   elif [[ "$the_app" == 'Hyper' ]]; then
     osascript >/dev/null <<EOF
     osascript >/dev/null <<EOF
-          tell application "System Events"
-            tell process "Hyper" to keystroke "t" using command down
-          end tell
-          delay 1
-          tell application "System Events"
-              keystroke "${command}"
-              key code 36  #(presses enter)
-            end tell
+      tell application "System Events"
+        tell process "Hyper" to keystroke "t" using command down
+      end tell
+      delay 1
+      tell application "System Events"
+        keystroke "${command}"
+        key code 36  #(presses enter)
+      end tell
 EOF
 EOF
-
   else
   else
-    echo "tab: unsupported terminal app: $the_app"
-    false
-
+    echo "$0: unsupported terminal app: $the_app" >&2
+    return 1
   fi
   fi
 }
 }
 
 
@@ -79,7 +82,6 @@ function vsplit_tab() {
   if [[ "$the_app" == 'iTerm' ]]; then
   if [[ "$the_app" == 'iTerm' ]]; then
     osascript <<EOF
     osascript <<EOF
       -- tell application "iTerm" to activate
       -- tell application "iTerm" to activate
-
       tell application "System Events"
       tell application "System Events"
         tell process "iTerm"
         tell process "iTerm"
           tell menu item "Split Vertically With Current Profile" of menu "Shell" of menu bar item "Shell" of menu bar 1
           tell menu item "Split Vertically With Current Profile" of menu "Shell" of menu bar item "Shell" of menu bar 1
@@ -89,37 +91,33 @@ function vsplit_tab() {
         keystroke "${command} \n"
         keystroke "${command} \n"
       end tell
       end tell
 EOF
 EOF
-
   elif [[ "$the_app" == 'iTerm2' ]]; then
   elif [[ "$the_app" == 'iTerm2' ]]; then
-      osascript <<EOF
-        tell application "iTerm2"
-          tell current session of first window
-            set newSession to (split vertically with same profile)
-            tell newSession
-              write text "${command}"
-              select
-            end tell
+    osascript <<EOF
+      tell application "iTerm2"
+        tell current session of first window
+          set newSession to (split vertically with same profile)
+          tell newSession
+            write text "${command}"
+            select
           end tell
           end tell
         end tell
         end tell
+      end tell
 EOF
 EOF
-  
   elif [[ "$the_app" == 'Hyper' ]]; then
   elif [[ "$the_app" == 'Hyper' ]]; then
-      osascript >/dev/null <<EOF
-      tell application "System Events"
-        tell process "Hyper"
-          tell menu item "Split Vertically" of menu "Shell" of menu bar 1
-            click
-          end tell
+    osascript >/dev/null <<EOF
+    tell application "System Events"
+      tell process "Hyper"
+        tell menu item "Split Vertically" of menu "Shell" of menu bar 1
+          click
         end tell
         end tell
-        delay 1
-        keystroke "${command} \n"
       end tell
       end tell
+      delay 1
+      keystroke "${command} \n"
+    end tell
 EOF
 EOF
-
   else
   else
     echo "$0: unsupported terminal app: $the_app" >&2
     echo "$0: unsupported terminal app: $the_app" >&2
-    false
-
+    return 1
   fi
   fi
 }
 }
 
 
@@ -142,44 +140,40 @@ function split_tab() {
         keystroke "${command} \n"
         keystroke "${command} \n"
       end tell
       end tell
 EOF
 EOF
-
   elif [[ "$the_app" == 'iTerm2' ]]; then
   elif [[ "$the_app" == 'iTerm2' ]]; then
-      osascript <<EOF
-        tell application "iTerm2"
-          tell current session of first window
-            set newSession to (split horizontally with same profile)
-            tell newSession
-              write text "${command}"
-              select
-            end tell
+    osascript <<EOF
+      tell application "iTerm2"
+        tell current session of first window
+          set newSession to (split horizontally with same profile)
+          tell newSession
+            write text "${command}"
+            select
           end tell
           end tell
         end tell
         end tell
+      end tell
 EOF
 EOF
-
   elif [[ "$the_app" == 'Hyper' ]]; then
   elif [[ "$the_app" == 'Hyper' ]]; then
-      osascript >/dev/null <<EOF
-      tell application "System Events"
-        tell process "Hyper"
-          tell menu item "Split Horizontally" of menu "Shell" of menu bar 1
-            click
-          end tell
+    osascript >/dev/null <<EOF
+    tell application "System Events"
+      tell process "Hyper"
+        tell menu item "Split Horizontally" of menu "Shell" of menu bar 1
+          click
         end tell
         end tell
-        delay 1
-        keystroke "${command} \n"
       end tell
       end tell
+      delay 1
+      keystroke "${command} \n"
+    end tell
 EOF
 EOF
-
   else
   else
     echo "$0: unsupported terminal app: $the_app" >&2
     echo "$0: unsupported terminal app: $the_app" >&2
-    false
-
+    return 1
   fi
   fi
 }
 }
 
 
 function pfd() {
 function pfd() {
   osascript 2>/dev/null <<EOF
   osascript 2>/dev/null <<EOF
     tell application "Finder"
     tell application "Finder"
-      return POSIX path of (target of window 1 as alias)
+      return POSIX path of (insertion location as alias)
     end tell
     end tell
 EOF
 EOF
 }
 }
@@ -205,6 +199,21 @@ function pushdf() {
   pushd "$(pfd)"
   pushd "$(pfd)"
 }
 }
 
 
+function pxd() {
+  dirname $(osascript 2>/dev/null <<EOF
+    if application "Xcode" is running then
+      tell application "Xcode"
+        return path of active workspace document
+      end tell
+    end if
+EOF
+)
+}
+
+function cdx() {
+  cd "$(pxd)"
+}
+
 function quick-look() {
 function quick-look() {
   (( $# > 0 )) && qlmanage -p $* &>/dev/null &
   (( $# > 0 )) && qlmanage -p $* &>/dev/null &
 }
 }
@@ -218,133 +227,13 @@ function vncviewer() {
   open vnc://$@
   open vnc://$@
 }
 }
 
 
-# iTunes control function
-function itunes music() {
-	local APP_NAME=Music
-
-	autoload is-at-least
-	if is-at-least 10.15 $(sw_vers -productVersion); then
-		if [[ $0 = itunes ]]; then
-			echo >&2 The itunes function name is deprecated. Use \`music\' instead.
-			return 1
-		fi
-	else
-		APP_NAME=iTunes
-	fi
-
-	local opt=$1
-	local playlist=$2
-	shift
-	case "$opt" in
-		launch|play|pause|stop|rewind|resume|quit)
-			;;
-		mute)
-			opt="set mute to true"
-			;;
-		unmute)
-			opt="set mute to false"
-			;;
-		next|previous)
-			opt="$opt track"
-			;;
-		vol)
-			local new_volume volume=$(osascript -e "tell application \"$APP_NAME\" to get sound volume")
-			if [[ $# -eq 0 ]]; then
-				echo "Current volume is ${volume}."
-				return 0
-			fi
-			case $1 in
-				up) new_volume=$((volume + 10 < 100 ? volume + 10 : 100)) ;;
-				down) new_volume=$((volume - 10 > 0 ? volume - 10 : 0)) ;;
-				<0-100>) new_volume=$1 ;;
-				*) echo "'$1' is not valid. Expected <0-100>, up or down."
-				   return 1 ;;
-			esac
-			opt="set sound volume to ${new_volume}"
-			;;
-		playlist)
-			# Inspired by: https://gist.github.com/nakajijapan/ac8b45371064ae98ea7f
-			if [[ ! -z "$playlist" ]]; then
-				osascript -e "tell application \"$APP_NAME\"" -e "set new_playlist to \"$playlist\" as string" -e "play playlist new_playlist" -e "end tell" 2>/dev/null;
-				if [[ $? -eq 0 ]]; then
-					opt="play"
-				else
-					opt="stop"
-				fi
-			else
-				opt="set allPlaylists to (get name of every playlist)"
-			fi
-			;;
-		playing|status)
-			local state=`osascript -e "tell application \"$APP_NAME\" to player state as string"`
-			if [[ "$state" = "playing" ]]; then
-				currenttrack=`osascript -e "tell application \"$APP_NAME\" to name of current track as string"`
-				currentartist=`osascript -e "tell application \"$APP_NAME\" to artist of current track as string"`
-				echo -E "Listening to $fg[yellow]$currenttrack$reset_color by $fg[yellow]$currentartist$reset_color";
-			else
-				echo "$APP_NAME is" $state;
-			fi
-			return 0
-			;;
-		shuf|shuff|shuffle)
-			# The shuffle property of current playlist can't be changed in iTunes 12,
-			# so this workaround uses AppleScript to simulate user input instead.
-			# Defaults to toggling when no options are given.
-			# The toggle option depends on the shuffle button being visible in the Now playing area.
-			# On and off use the menu bar items.
-			local state=$1
-
-			if [[ -n "$state" && ! "$state" =~ "^(on|off|toggle)$" ]]
-			then
-				print "Usage: $0 shuffle [on|off|toggle]. Invalid option."
-				return 1
-			fi
-
-			case "$state" in
-				on|off)
-					# Inspired by: https://stackoverflow.com/a/14675583
-					osascript 1>/dev/null 2>&1 <<-EOF
-					tell application "System Events" to perform action "AXPress" of (menu item "${state}" of menu "Shuffle" of menu item "Shuffle" of menu "Controls" of menu bar item "Controls" of menu bar 1 of application process "iTunes" )
-EOF
-					return 0
-					;;
-				toggle|*)
-					osascript 1>/dev/null 2>&1 <<-EOF
-					tell application "System Events" to perform action "AXPress" of (button 2 of process "iTunes"'s window "iTunes"'s scroll area 1)
-EOF
-					return 0
-					;;
-			esac
-			;;
-		""|-h|--help)
-			echo "Usage: $0 <option>"
-			echo "option:"
-			echo "\tlaunch|play|pause|stop|rewind|resume|quit"
-			echo "\tmute|unmute\tcontrol volume set"
-			echo "\tnext|previous\tplay next or previous track"
-			echo "\tshuf|shuffle [on|off|toggle]\tSet shuffled playback. Default: toggle. Note: toggle doesn't support the MiniPlayer."
-			echo "\tvol [0-100|up|down]\tGet or set the volume. 0 to 100 sets the volume. 'up' / 'down' increases / decreases by 10 points. No argument displays current volume."
-			echo "\tplaying|status\tShow what song is currently playing in Music."
-			echo "\tplaylist [playlist name]\t Play specific playlist"
-			echo "\thelp\tshow this message and exit"
-			return 0
-			;;
-		*)
-			print "Unknown option: $opt"
-			return 1
-			;;
-	esac
-	osascript -e "tell application \"$APP_NAME\" to $opt"
-}
-
-# Spotify control function
-source ${ZSH}/plugins/osx/spotify
-
-# Show/hide hidden files in the Finder
-alias showfiles="defaults write com.apple.finder AppleShowAllFiles -bool true && killall Finder"
-alias hidefiles="defaults write com.apple.finder AppleShowAllFiles -bool false && killall Finder"
-
 # Remove .DS_Store files recursively in a directory, default .
 # Remove .DS_Store files recursively in a directory, default .
 function rmdsstore() {
 function rmdsstore() {
-	find "${@:-.}" -type f -name .DS_Store -delete
+  find "${@:-.}" -type f -name .DS_Store -delete
 }
 }
+
+# Music / iTunes control function
+source "${0:h:A}/music"
+
+# Spotify control function
+source "${0:h:A}/spotify"