hyperspace

Get there from here


Keywords
tools, convenience

Documentation

Hyperspace

Hyperspace is a way to get nearly anywhere from wherever you are, whether that’s within Emacs or on the web. It’s somewhere in between Quicksilver and keyword URLs, giving you a single, consistent interface to get directly where you want to go. It’s for things that you use often, but not often enough to justify a dedicated binding.

When you enter Hyperspace, it prompts you where to go:

HS:

This expects a keyword and a query. The keyword picks where you want to go, and the remainder of the input is an optional argument which can be used to further search or direct you within that space.

Some concrete examples illustrate this. These all work with the bundled default configuration.

If you enter then Hyperspace
el opens info node (elisp)Top
el eval-region searches for “eval-region” in the elisp Info index
bb shows all BBDB entries
bb kenneth shows all BBDB entries with a name matching “kenneth”
ddg foo searches DuckDuckGo for “foo” using browse-url
wp foo searches Wikipedia for “foo” using browse-url

Regions and defaults

If there’s an active region when you enter Hyperspace, the query is prefilled with it, and point is positioned so you can easily enter the keyword.

If there’s an active region and you give a prefix argument to Hyperspace, it invokes hyperspace-default-action.

Installation

Hyperspace will be in MELPA soon. Until then, you can clone this repo, open hyperspace.el and run M-x package-install-from-buffer.

Minor mode, bindings

The bundled hyperspace-minor-mode binds H-SPC to Hyperspace. If you don’t have a hyper modifier available, you can bind it to C-s with:

(eval-after-load "hyperspace"
  (define-key hyperspace-minor-mode-map "\C-cs" #'hyperspace))

Custom actions

Hyperspace ships with an embarrassing array of things I use all the time, but you can make it do whatever you want. All actions are in hyperspace-actions, and take the form:

(KEYWORD . ACTION)

ACTION can be a function, a sexp, or a string.

When it’s a function, it’s called with the query part of the input as its argument.

If it’s a sexp, it must evaluate to a function. That function is called with the query part of the input as its argument.

If it’s a string, it must contain a %s, which is replaced with the query part of the input, then browse-url is called with that as its argument. This is convenience, you could get the same effect with a sexp of:

(apply-partially
 #‘hyperspace-action->browse-url-pattern
   "https://whatever.com?s=%s")

Examples

mu4e

If you enter then Hyperspace
m4 opens mu4e, loads the first bookmarked, updates mail
m4 foo opens mu4e and searches for “foo”
m4c work foo switches to mu4e context “work,” then searches for “foo”
;; Recommended customization for hyperspace-actions:
;;
;; ("m4" . hyperspace-action->mu4e)
;; ("m4c" . hyperspace-action->mu4e-context)
'
(defun hyperspace--mu4e-context (query)
  "Return a mu4e context for QUERY.

   If the first word of QUERY matches the beginning of a mu4e
   context, return its name.  Otherwise, return NIL."
  (cl-loop with parts = (s-split-up-to "\\s-+" query 1)
           with possible-context = (car parts)
           with possible-query = (cadr parts)
           for context in mu4e-contexts
           for context-name = (mu4e-context-name context)
           if (s-starts-with? possible-context context-name)
           return (cons context-name possible-query)))

(defun hyperspace-action->mu4e (&optional query)
  "Search mu4e with QUERY.

   If QUERY is unspecified, use the first bookmark in variable
   ‘mu4e-bookmarks’ and update mail and index."

  (mu4e-headers-search (or query (caar mu4e-bookmarks)))
  (unless query
    (mu4e-update-mail-and-index nil)))

(defun hyperspace-action->mu4e-context (&optional query)
  "Look for a mu4e context in the first word of QUERY.

   A valid context is one which matches a left-anchored substring of
   all defined mu4e contexts.

   If found, switch to it, then call `hyperspace-action->mu4e' with
   the remainder of QUERY.  Otherwise, call with the entire QUERY,
   without switching the context."

  (thread-first
      (pcase (hyperspace--mu4e-context query)
        (`(context . query)
         (mu4e-context-switch nil context)
         query))
    (or query)
    (hyperspace-action->mu4e)))

Elfeed

If you enter then Hyperspace
lf opens elfeed
lf blah opens elfeed, searches for “blah”
;; Recommended customization for hyperspace-actions:
;;
;; ("lf" . hyperspace-action->elfeed)

(defun hyperspace-action->elfeed (&optional query)
  "Load elfeed, optionally searching for QUERY."
  (elfeed)
  (if query
      (elfeed-search-set-filter query)
    (elfeed-search-fetch nil)))