;; Copyright (c) 2017-2020 Ag Ibragimov & Contributors ;; ;;; Author: Ag Ibragimov ;; ;;; Contributors: ;; Jay Zawrotny ;; ;;; URL: https://github.com/agzam/spacehammer ;; ;;; License: MIT ;; (require-macros :lib.macros) (local windows (require :windows)) (local slack (require :slack)) (local vim (require :vim)) (local {:concat concat :logf logf} (require :lib.functional)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; WARNING ;; Make sure you are customizing ~/.spacehammer/config.fnl and not ;; ~/.hammerspoon/config.fnl ;; Otherwise you will lose your customizations on upstream changes. ;; A copy of this file should already exist in your ~/.spacehammer directory. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Table of Contents ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; [x] l - layout/windows ;; [x] |-- w - Last window ;; [x] |-- cmd + hjkl - jumping ;; [x] |-- hjkl - halves ;; [x] |-- alt + hjkl - increments ;; [x] |-- shift + hjkl - resize ;; [x] |-- n, p - next, previous screen ;; [x] |-- shift + n, p - up, down screen ;; [x] |-- g - grid ;; [x] |-- m - maximize ;; [x] |-- c - center ;; [x] |-- u - undo ;; ;; [x] w - windows/apps ;; [x] |-- l - last window ;; [x] |-- r - roam ;; [x] |-- b - chrome ;; [x] |-- w - webstorm ;; [x] |-- s - slack ;; [x] |-- t - texts ;; [x] |-- c - calendar ;; [x] |-- d - discord ;; [x] |-- m - music ;; ;; [x] j - jump ;; ;; [x] m - media ;; [x] |-- h - previous track ;; [x] |-- l - next track ;; [x] |-- k - volume up ;; [x] |-- j - volume down ;; [x] |-- s - play\pause ;; [x] |-- a - launch player ;; ;; [x] cmd-n - next-app ;; [x] cmd-p - prev-app ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Initialize ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; Actions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (fn activator [app-name] " A higher order function to activate a target app. It's useful for quickly binding a modal menu action or hotkey action to launch or focus on an app. Takes a string application name Returns a function to activate that app. Example: (local launch-emacs (activator \"Emacs\")) (launch-emacs) " (fn activate [] (windows.activate-app app-name))) ;; hs.hotkey.bind({}, "F15", function() ;; local app = hs.application.get("kitty") ;; ;; if app then ;; if not app:mainWindow() then ;; app:selectMenuItem({"kitty", "New OS window"}) ;; elseif app:isFrontmost() then ;; app:hide() ;; else ;; app:activate() ;; end ;; else ;; hs.application.launchOrFocus("kitty") ;; app = hs.application.get("kitty") ;; end ;; ;; app:mainWindow():moveToUnit'[100,50,0,0]' ;; app:mainWindow().setShadows(false) ;; end) (fn toggle-app [app-name] (let [app (hs.application.find app-name)] (if (and app (app:isFrontmost)) (app:hide) (do (hs.application.launchOrFocus app-name) (app:unhide))))) (fn toggler [app-name] " A higher order function to toggle a target app. It's useful for quickly binding a modal menu action or hotkey action to launch or focus on an app. Takes a string application name Returns a function to toggle that app. " (fn toggle [] (toggle-app app-name))) (fn toggle-console [] " A simple action function to toggle the hammer spoon console. Change the keybinding in the common keys section of this config file. " (if-let [console (hs.console.hswindow)] (hs.closeConsole) (hs.openConsole))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; General ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; If you would like to customize this we recommend copying this file to ;; ~/.hammerspoon/private/config.fnl. That will be used in place of the default ;; and will not be overwritten by upstream changes when spacehammer is updated. (local music-app "Spotify") (local return {:key :space :title "Back" :action :previous}) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Layouts/Windows ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (local window-jumps [{:mods [:cmd] :key "hjkl" :title "Jump"} {:mods [:cmd] :key :h :action "windows:jump-window-left" :repeatable true} {:mods [:cmd] :key :j :action "windows:jump-window-above" :repeatable true} {:mods [:cmd] :key :k :action "windows:jump-window-below" :repeatable true} {:mods [:cmd] :key :l :action "windows:jump-window-right" :repeatable true}]) (local window-halves [{:key "hjkl" :title "Halves"} {:key :h :action "windows:resize-half-left" :repeatable true} {:key :j :action "windows:resize-half-bottom" :repeatable true} {:key :k :action "windows:resize-half-top" :repeatable true} {:key :l :action "windows:resize-half-right" :repeatable true}]) (local window-increments [{:mods [:alt] :key "hjkl" :title "Increments"} {:mods [:alt] :key :h :action "windows:resize-inc-left" :repeatable true} {:mods [:alt] :key :j :action "windows:resize-inc-bottom" :repeatable true} {:mods [:alt] :key :k :action "windows:resize-inc-top" :repeatable true} {:mods [:alt] :key :l :action "windows:resize-inc-right" :repeatable true}]) (local window-resize [{:mods [:shift] :key "hjkl" :title "Resize"} {:mods [:shift] :key :h :action "windows:resize-left" :repeatable true} {:mods [:shift] :key :j :action "windows:resize-down" :repeatable true} {:mods [:shift] :key :k :action "windows:resize-up" :repeatable true} {:mods [:shift] :key :l :action "windows:resize-right" :repeatable true}]) (local window-move-screens [{:key "n, p" :title "Move next\\previous screen"} {:mods [:shift] :key "n, p" :title "Move up\\down screens"} {:key :n :action "windows:move-south" :repeatable true} {:key :p :action "windows:move-north" :repeatable true} {:mods [:shift] :key :n :action "windows:move-west" :repeatable true} {:mods [:shift] :key :p :action "windows:move-east" :repeatable true}]) (local window-bindings (concat [return {:key :w :title "Last window" :action "windows:jump-to-last-window"}] window-jumps window-halves window-increments window-resize window-move-screens [{:key :m :title "Maximize" :action "windows:maximize-window-frame"} {:key :c :title "Center" :action "windows:center-window-frame"} {:key :g :title "Grid" :action "windows:show-grid"} {:key :u :title "Undo" :action "windows:undo-action"}])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Windows/Apps Menu ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (local app-bindings [return {:key :l :title "Last window" :action "windows:jump-to-last-window"} {:key :b :title "Chrome" :action (activator "Chrome")} {:key :r :title "Roam" :action (activator "Roam")} {:key :w :title "Webstorm" :action (activator "Webstorm")} {:key :s :title "Slack" :action (activator "Slack")} {:key :t :title "Texts" :action (activator "Messages")} {:key :c :title "Calendar" :action (activator "Calendar")} {:key :d :title "Discord" :action (activator "Discord")} {:key :m :title music-app :action (activator music-app)}]) (local media-bindings [return {:key :s :title "Play or Pause" :action "multimedia:play-or-pause"} {:key :h :title "Prev Track" :action "multimedia:prev-track"} {:key :l :title "Next Track" :action "multimedia:next-track"} {:key :j :title "Volume Down" :action "multimedia:volume-down" :repeatable true} {:key :k :title "Volume Up" :action "multimedia:volume-up" :repeatable true} {:key :m :title (.. "Launch " music-app) :action (activator music-app)}]) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Main Menu & Config ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (local menu-items [{:key :space :title "Last window" :action "windows:jump-to-last-window"} {:key :l :title "Layouts" :items window-bindings} {:key :w :title "Windows" :items app-bindings} {:key :j :title "Jump" :action "windows:jump"} {:key :m :title "Media" :items media-bindings} ]) ;; try alt k maybe as toggle for kitty ;; TODO does hammerspoon support double tap? ;; map 'back' to toggle current window rather than go back to previous (local common-keys [{:mods [:cmd] :key :k :repeatable false :action (toggler "Kitty")} {:mods [:cmd] :key :space :action "lib.modal:activate-modal"} {:mods [:cmd] :key :n :action "apps:next-app"} {:mods [:cmd :ctrl] :key :p :action "apps:prev-app"} {:mods [:cmd :ctrl] :key "`" :action toggle-console}]) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; App Specific Config ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (local browser-keys [{:mods [:cmd :shift] :key :l :action "chrome:open-location"} {:mods [:alt] :key :k :action "chrome:next-tab" :repeat true} {:mods [:alt] :key :j :action "chrome:prev-tab" :repeat true}]) (local browser-items (concat menu-items [])) (local chrome-config {:key "Chrome" :keys browser-keys :items browser-items}) (local hammerspoon-config {:key "Hammerspoon" :items (concat menu-items [{:key :r :title "Reload Console" :action hs.reload} {:key :c :title "Clear Console" :action hs.console.clearConsole}]) :keys []}) (local slack-config {:key "Slack" :keys [{:mods [:cmd] :key :g :action "slack:scroll-to-bottom"} {:mods [:ctrl] :key :r :action "slack:add-reaction"} {:mods [:ctrl] :key :h :action "slack:prev-element"} {:mods [:ctrl] :key :l :action "slack:next-element"} {:mods [:ctrl] :key :t :action "slack:thread"} {:mods [:ctrl] :key :p :action "slack:prev-day"} {:mods [:ctrl] :key :n :action "slack:next-day"} {:mods [:ctrl] :key :e :action "slack:scroll-up" :repeat true} {:mods [:ctrl] :key :y :action "slack:scroll-down" :repeat true} {:mods [:ctrl] :key :i :action "slack:next-history" :repeat true} {:mods [:ctrl] :key :o :action "slack:prev-history" :repeat true} {:mods [:ctrl] :key :j :action "slack:down" :repeat true} {:mods [:ctrl] :key :k :action "slack:up" :repeat true}]}) (local apps [ chrome-config hammerspoon-config slack-config]) (local config {:title "Main Menu" :items menu-items :keys common-keys :apps apps :hyper {:key :F18}}) ;; :vim {:enabled true} ;; need a way to toggle vim mode easily or specify apps that shouldn't use it (such as vim) ;; would like to see basic operators - d y p, t/f ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Exports ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; config