`setup.el`
==========

The `setup` macro simplifies repetitive configuration patterns, by
providing context-sensitive local macros in `setup` bodies.

For example, these macros:

~~~elisp
(setup shell
  (let ((key (kbd "C-c s")))
    (:global key shell)
    (:bind key bury-buffer)))

(setup dired
  (:also-load dired-x)
  (:option (prepend dired-guess-shell-alist-user) '("" "xdg-open")
           dired-dwim-target t)
  (:hook auto-revert-mode))

(setup (:package paredit)
  (:hide-mode)
  (:hook-into scheme-mode lisp-mode))
~~~

will be replaced with the functional equivalent of

~~~elisp
(global-set-key (kbd "C-c s") #'shell)
(with-eval-after-load 'shell
  (define-key shell-mode-map (kbd "C-c s") #'bury-buffer))

(with-eval-after-load 'dired
  (require 'dired-x))
(customize-set-variable 'dired-guess-shell-alist-user
                        (cons '("" "xdg-open")
			      dired-guess-shell-alist-user))
(customize-set-variable 'dired-dwim-target t)
(add-hook 'dired-mode-hook #'auto-revert-mode)

(unless (package-install-p 'paredit)
  (package-install 'paredit))
(setq minor-mode-alist
      (delq (assq 'paredit-mode minor-mode-alist)
            minor-mode-alist))
(add-hook 'scheme-mode-hook #'paredit-mode)
(add-hook 'lisp-mode-hook #'paredit-mode)
~~~

Additional "keywords" can be defined using `setup-define`. All known
keywords are documented in the docstring for `setup`.

Installation
------------

`setup.el` is part of [GNU ELPA][elpa], and can be installed using
`package.el`.

Usage
-----

The `setup` macro is autoloaded, and can be used directly.  The code
generated by `setup` does not depend on `setup.el`, meaning that your
initialization file can be byte-compiled more efficiently.

Tips
----

1. The first element of a `setup` body can but does not have to be a
   name. That can be exploited to use `setup` in your own macros. I have
   this macro in my personal configuration, when I'm only interested in
   modifying user options:

   ~~~elisp
   (defmacro setc (&rest args)
     "Customize user options using ARGS like `setq'."
     (declare (debug setq))
     `(setup (:option ,@args)))
   ~~~

2. If you wish to define you own macros, use `setup-define`. In case the
   syntax is too cumbersome, you can use a macro like this:

   ~~~elisp
   (defmacro defsetup (name signature &rest body)
     "Shorthand for `setup-define'.
   NAME is the name of the local macro.  SIGNATURE is used as the
   argument list for FN.  If BODY starts with a string, use this as
   the value for :documentation.  Any following keywords are passed
   as OPTS to `setup-define'."
     (declare (debug defun))
     (let (opts)
       (when (stringp (car body))
         (setq opts (nconc (list :documentation (pop body))
                           opts)))
       (while (keywordp (car body))
         (let* ((prop (pop body))
                (val `',(pop body)))
           (setq opts (nconc (list prop val) opts))))
       `(setup-define ,name
          (cl-function (lambda ,signature ,@body))
          ,@opts)))
   ~~~

   To declare local macros more like `defun` or `defmacro`. Here is how
   the definition for `:package` could be rewritten:

   ~~~elisp
   (defsetup :package (package)
     "Install PACKAGE if it hasn't been installed yet."
     :repeatable t
     :shorthand #'cadr
     `(unless (package-installed-p ',package)
          (package-install ',package)))
   ~~~

Comparison to `use-package`
---------------------------

The most popular configuration macro for Emacs is
[`use-package`][use-package], by John Wiegley. The intention is
similar, but usage is noticeably different.  While `use-package` to
specifies information about package and it's usage, `setup` is less
declarative and just provides a set of context-sensitive local macros,
that are simply substituted.

The higher level of abstraction allows `use-package` to hide some of
the complexity, by transparently reordering everything into the right
order. The downside is that it is easy to get lost or forget what
use-package is doing. Each `setup` macro on the other hand intends to
encapsulate one common configuration action, and simplify the
syntax. Here a few examples:

~~~elisp
(setup flymake
  (:bind "M-n" #'flymake-goto-next-error
         "M-p" #'flymake-goto-prev-error)
  (:hook-into prog-mode))
~~~

is expanded to

~~~elisp
(progn
  (eval-after-load 'flymake
    (function
     (lambda nil
       (progn
         (define-key flymake-mode-map
           [134217838]
           (function flymake-goto-next-error))
         (define-key flymake-mode-map
           [134217840]
           (function flymake-goto-prev-error))))))
  (add-hook 'prog-mode-hook
            (function flymake-mode)))
~~~

The macro `:bind` wraps `define-key` calls in a `eval-after-load`
block, and automatically parses multiple arguments in a `setq`-like
fashion. Likewise, `:hook-into` knows to deuce that `flymake-mode`
should be added to `prog-mode`'s hook (`prog-mode-hook`).

Furthermore `use-package` might be said to be less flexible, because
the macro assumes a certain kind of usage. Each expression _should_
define one package. This is not assumed for `setup`: Each body can
just as easily configure no to as many packages as one wants.

~~~elisp
(setup (:package company company-math)
  (:bind "TAB" company-complete))
~~~

would install both `company` and `company-math`. The context is set to
`company`, because the `:package` call is the first element of the
list, and `company` is it's first argument. One might also write

~~~elisp
(setup
  (:with-feature company
    (:package company company-math)
    (:bind "TAB" company-complete)))
~~~

that explicit sets the context to the feature `company`.

Similarly, non-context sensitive macros might be used even if `setup`
cannot deduce what is being configured automatically.  The `setc`
macro above, is one simple example.

An attempt is also made by `setup.el` to ease extensibility. Each
macro is defined using the `setup-define` function. Combined with
further attributes, it allows for the simple definition of local and
context sensitive macros, that are debug-able, can be composed and
deferred. While `use-package` is [also extensible][extend-up] the
process is more difficult because of the more complex syntax and
higher level of abstraction (at least in the eyes of the `setup`
author).

Another alternative to `setup` is [`leaf.el`][leaf], that is also
available on ELPA. It shares the same idea as `use-package` and has a
richer set of keywords.

Bugs
----

Bugs or patches can be submitted to my [public inbox][mail] or via the
[GitHub mirror][github].  Note that non-trivial contributions require
a [copyright assignment][ca] to the FSF.

This package is still young, so wishes, impressions and criticism are
very appreciated. If you have anything to say, feel free to send an
email to the aforementioned [public inbox][mail].

Copying
-------

`setup.el` is distributed under the [GPL v3][gpl3] license.

[elpa]: http://elpa.gnu.org/packages/setup.html
[use-package]: https://github.com/jwiegley/use-package
[extend-up]: https://github.com/jwiegley/use-package#how-to-create-an-extension
[leaf]: https://github.com/conao3/leaf.el
[mail]: https://lists.sr.ht/~pkal/public-inbox
[github]: https://github.com/phikal/setup.el
[ca]: https://www.gnu.org/software/emacs/manual/html_node/emacs/Copyright-Assignment.html#Copyright-Assignment
[gpl3]: https://www.gnu.org/licenses/gpl-3.0.en.html
