SkillAgentSearch skills...

Spacehammer

Spacemacs|Doom inspired Hammerspoon modal toolkit

Install / Use

/learn @agzam/Spacehammer
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

#+title: [[http://www.hammerspoon.org/][Hammerspoon]] Modal Toolkit inspired by [[http://spacemacs.org/][Spacemacs]]|[[https://github.com/doomemacs/doomemacs][Doom]]

** Rationale Keyboard-oriented workflows are often far more efficient and less frustrating than similar mouse-driven techniques. The typical strategy is to use a multitude of keyboard shortcuts. Obviously, that approach is not very scalable. You start adding keyboard shortcuts for various actions - soon you will be blocked by conflicting shortcuts.

Command composability idea of ~Vim~, although does require some initial learning and getting used to, allows you to expand your keyboard-oriented workflow with a minimal effort to memorize keys. There's so much you can do with the home-row keys (~h/j/k/l)~ alone.

However, that "one-dimensional" approach used in vanilla Vim/Neovim, where a single modal (Normal/Insert/Selection modes) is used, has limitations. Fortunately, the basic idea of modality can be expanded further. The [[http://spacemacs.org/][Spacemacs]] project is an excellent example of where that was done. In Spacemacs|Doom there is a single primary "modifier" key - ~SPACE~. To trigger an action, user is required to press a mnemonically recognizable combination e.g., ~SPC w m~ - to maximize current window.

Spacehammer project explores these ideas to allow you to take your keyboard-driven workflow to the next level. Jumping between apps, controlling the size and the position of their windows, searching for things, etc. - everything follows simple, mnemonic semantics. It lets you keep your fingers on the home row and liberates you from having to memorize a myriad of keystrokes, or require you to drag your hand to reach for mouse/touchpad/arrow keys - that inevitably slows you down.

*** Fennel Spacehammer initially was written in Lua - most Hammerspoon configs are, later completely re-written in [[https://fennel-lang.org/][Fennel]] - a tiny Lisp that compiles to Lua. There is nothing wrong with Lua - Lisp simply has too many benefits to ignore (sadly often overlooked by majority of programmers).

** Installation #+begin_src bash brew tap agzam/spacehammer brew install spacehammer #+end_src

If you have your custom config somewhere already:

#+begin_src bash HOMEBREW_SPACEHAMMER_CONFIG=git@github.com:username/my-config.git
brew install spacehammer #+end_src

** LEAD keybinding

=LEAD= is the main and major keybinding (not a key - we can't just use ~SPC~) that invokes the main Spacehammer modal. By default it is set to =Option+SPC=, but it can be customized in =~/.spacehammer/config.fnl= by changing the =:mods= and =:key= bindings for the =lib.modal:activate-modal= action string. You might want to set it, for example, to =Ctrl+Shift+SPC=.

If you want to use =Cmd+SPC= as =LEAD= you will have to rebind it in your system, since it is normally used for Spotlight.

*** Unbinding =Cmd+SPC= in system preferences.

Go to your Preferences/Keyboard, find =Cmd+SPC= keybinding and change it to something else. Unfortunately, often simply disabling it isn't enough. Set it to be something else e.g., =Ctrl+Cmd+Shift+= or whatever, it really doesn't matter since you can then un-check the checkbox to disable it.

** Features *** =LEAD w= - Window management

  • =hjkl= - moving windows around halves of the screen
  • =Ctrl + hjkl= - for jumping between application windows (handy for side by side windows)
  • =w= - jump to previous window
  • =n/p= - moving current window to prev/next monitor
  • =Option + hjkl= - moving in increments (works across monitors)
  • =Shift + hjkl= - re-sizing active window
  • =g= - re-sizing with [[http://www.hammerspoon.org/docs/hs.grid.html][hs.grid]]
  • =m= - maximize active window
  • =c= - center active window
  • =u= - undo last window operation (similar to Spacemacs's =SPC w u=)

*** =LEAD a= - Apps (quick jump)

  • =e= - Emacs

  • =g= - Chrome

  • =i= - iTerm

  • =s= - Slack

    you can add more, also try =LEAD j j=

*** =LEAD SPC= - open Alfred search bar pressing =SPC= in the main modal takes you to Alfred search popup, pressing =SPC= in other modals returns to previous modal.

*** =LEAD m= - multimedia controls Why not use media-keys?

a) because different external keyboards impose their own ways to control media.

b) because Spacehammer allows you to keep fingers on the home row.

By default =LEAD m a= - =jump to music app= is configured to work with Spotify, but you can change that in =~/.spacehammer/config.fnl=

*** Edit anything [with Emacs] You can edit any text in any app =Cmd+Ctrl+O=. Currently, it supports only Emacs. Read more [[docs/emacs.org][here]].

** Other features *** Alternative App Switcher =Option n/p= *** Simple tab switcher for Chrome and iTerm =Option j/k= *** Slack Desktop App enhancements

  • Scroll through current Slack thread =Ctrl-j/Ctrl-k= (slow) or =Ctrl-e/Ctrl-y= (fast)
  • Jump to the end of the thread with =Cmd-g=
  • Add emoji to the last message - =Cmd-r= (Slack's default =Cmd-Shift+= is quite inconvenient)
  • Jump back and forth through history - =Ctrl-o/Ctrl-i=

** Customizing *** Update menus, menu items, bindings, and app-specific features All menu, app, and key bindings are defined in =~/.spacehammer/config.fnl=. That is your custom config and will be safe from any upstream changes to the default config.fnl. /The reason to keep it in its own directory is so that it can be maintained in version-control in your own repo/.

*** Modal Menu Items Menu items are listed when you press =LEAD= and they can be nested.

Items map a key binding to an action, either a function or ="module:function-name"= string.

Menu items may either define an action or a table list of items.

For menu items that should be repeated, add =repeatable: true= to the item table. The repeatable flag keeps the menu option after the action has been triggered. Repeating a menu item is ideal for actions like window layouts where you may wish to move the window from the left third to the right third.

#+begin_src fennel (local launch-alfred {:title "Alfred" :key :SPACE :action (fn [] (hs.appplication.launchOrFocus "Alfred"))}) (local slack-jump {:title "Slack" :key :s :action "slack:quick-switcher"}) (local window-inc {:title "Window Halves" :mods [:cmd] :key :l :action "windows:resize-inc-right"}) (local submenu {:title "Submenu" :key :t :items [{:key :m :title "Show a message" :action (fn [] (alert "I'm a submenu action"))}]}) (local config {:items [launch-alfred slack-jump window-inc submenu]}) #+end_src

**** Lifecycle methods Menu items may also define =:enter= and =:exit= functions or action strings. The parent menu item will call the =enter= function when it is opened and =exit= when it is closed. This may be used to manage more complex or dynamic menus.

**** Global keys Global keys are used to set up universal hot-keys for the actions you specify. Unlike menu items they do not require a title attribute. Additionally you may specify =:repeat true= to repeat the action while the key is held down.

If you place =:hyper= as a mod, it will use a hyper mode that can be configured by the =hyper= config attribute. This can be used to help create bindings that won't interfere with other apps. For instance you may make your hyper trigger the virtual =:F18= key and use a program like [[https://github.com/tekezo/Karabiner-Elements][karabiner-elements]] to map caps-lock to =F18=.

#+begin_src fennel (local config {:hyper {:key :F18} :keys [{:mods [:cmd] :key :space :action "lib.modal:activate-modal"} {:mods [:cmd] :key :h :action "chrome:prev-tab" :repeat true} {:mods [:hyper] :key :f :action (fn [] (alert "Haha you pressed f!"))}]}) #+end_src

**** App specific customizations Configure separate menu options and key bindings while specified apps are active. Additionally, several lifecycle functions or action strings may be provided for each app.

  • ~:activate~ When an application receives keyboard focus
  • ~:deactivate~ When an application loses keyboard focus
  • ~:launch~ When an application is launched
  • ~:close~ When an application is terminated

#+begin_src fennel (local emacs-config {:key "Emacs" :activate "vim:disable" :deactivate "vim:enable" :launch "emacs:maximize" :items [] :keys []})

(local config {:apps [emacs-config]}) #+end_src

*** Replacing spacehammer behavior The =~/.spacehammer= directory is added to the module search paths. If you wish to change the behavior of a feature, such as vim mode, you can create =~/.spacehammer/vim.fnl= to override the default implementation.

** Using it with a window manager

It is possible to use Spacehammer with a WM. Here's [[https://github.com/agzam/.spacehammer/blob/master/config.fnl#L120-L151][an example]] of using it with [[https://github.com/koekeishiya/yabai/][Yabai]]

View on GitHub
GitHub Stars629
CategoryDevelopment
Updated22h ago
Forks73

Languages

Fennel

Security Score

100/100

Audited on Mar 27, 2026

No findings