mic

Homepage: https://github.com/ROCKTAKEY/mic

Author: ROCKTAKEY

Updated:

Summary

Minimal and combinable configuration manager

Commentary

Table of Contents
_________________

1. mic: Minimal and combinable configuration manager for Emacs
2. How to Use?
3. Use `mic-core', minimum one
.. 1. `:eval', `:eval-after-others', `:eval-before-all'
.. 2. `:eval-after-load', `:eval-after-others-after-load'
.. 3. `:eval-installation'
4. Use default `mic'
.. 1. `:autoload-interactive', `:autoload-noninteractive'
.. 2. `:auto-mode'
.. 3. `:custom', `:custom-after-load'
.. 4. `declare-function', `defvar-noninitial'
.. 5. `:define-key', `:define-key-after-load', `:define-key-with-feature'
.. 6. `:face'
.. 7. `:hook'
.. 8. `:package'
.. 9. `:require'
.. 10. `:require-after'
5. Define your own `mic'
.. 1. Define your own `mic' with `mic-defmic'
..... 1. What is a filter?
..... 2. Pre-defined filters
..... 3. Helper for defining a filter
..... 4. Define `mic' with `mic-defmic'
.. 2. Define your own `mic' with `defmacro'
6. Alternative
7. Contribute
8. License


[https://img.shields.io/github/tag/ROCKTAKEY/mic.svg?style=flat-square]
[https://img.shields.io/github/license/ROCKTAKEY/mic.svg?style=flat-square]
[https://img.shields.io/codecov/c/github/ROCKTAKEY/mic.svg?style=flat-square]
[https://img.shields.io/github/actions/workflow/status/ROCKTAKEY/mic/test.yml.svg?branch=master&style=flat-square]


[https://img.shields.io/github/tag/ROCKTAKEY/mic.svg?style=flat-square]


[https://img.shields.io/github/license/ROCKTAKEY/mic.svg?style=flat-square]


[https://img.shields.io/codecov/c/github/ROCKTAKEY/mic.svg?style=flat-square]


[https://img.shields.io/github/actions/workflow/status/ROCKTAKEY/mic/test.yml.svg?branch=master&style=flat-square]



1 mic: Minimal and combinable configuration manager for Emacs
=============================================================

        `mic' is uncustomizable.  Define your own `mic'.

  `mic' is minimal and combinable configuration manager for Emacs.  This
  package is yet another `use-package' and `leaf', but is also used with
  them (See [Alternative]).  `mic' is minimal, so if you would like to
  write complex configuration, `mic' is a little redundant.  However,
  there is no problem.  `mic' is combinable, in the other words, thought
  to be used as core to define your own, and more convenient `mic'.
  There are some functions to define your own `mic'.  See [Define your
  own mic].


[Alternative] See section 6

[Define your own mic] See section 5


2 How to Use?
=============

  For Emacs Lisp beginners, original `mic' macro is useful to configure
  your `init.el'.
  ,----
  | (mic lsp-mode
  |   ;; These are transformed to `define-key' sexp.
  |   ;; Each argument is `(KEYMAP (KEYS . COMMAND)...)'.
  |   ;; KEYS is passed to `kbd'.
  |   :define-key
  |   ((global-map
  |     ("M-l" . #'lsp)))
  |
  |   ;; These are same as `:define-key' argument,
  |   ;; but evaluated after loading the feature (`lsp-mode' for this example).
  |   ;; This is needed because `lsp-mode-map' is unavailable before `lsp'
  |   ;; loading.
  |   :define-key-after-load
  |   ((lsp-mode-map
  |     ("M-r" . #'lsp-rename)
  |     ("M-c" . #'lsp-execute-code-action)))
  |
  |   ;; These are transformed to `with-eval-after-load' and `define-key' sexp.
  |   ;; Each argument is `(FEATURE (KEYMAP (KEYS . COMMAND)...))'.
  |   ;; `cdr' is same as `:define-key' arguments.  Each `define-key' sexp is
  |   ;; evaluated after FEATURE is loaded.
  |   ;; This is needed because `dired-mode-map' is unavailable before `dired'
  |   ;; loading.
  |   :define-key-with-feature
  |   ((`dired'
  |     (dired-mode-map
  |      ("M-q" . #'lsp-dired-mode))))
  |
  |   ;; These are transformed to `customize-set-variable' sexp.
  |   ;; Each argument is `(VARIABLE . VALUE)'.
  |   :custom
  |   ((lsp-sesstion-file . (expand-file-name "etc/.lsp-session-v1" user-emacs-directory))
  |    (lsp-log-io . t))
  |
  |   ;; These are transformed to `add-hook' sexp.
  |   ;; Each argument is `(HOOK . FUNCTION)'.
  |   :hook
  |   ((c-mode-hook . #'lsp)
  |    (c++-mode-hook . #'lsp)
  |    (tex-mode-hook . #'lsp)
  |    (latex-mode-hook . #'lsp)
  |    (bibtex-mode-hook . #'lsp)
  |    (rust-mode-hook . #'lsp))
  |
  |   ;; Each element is evaluated immediately when this `mic' sexp is evaluated.
  |   :eval
  |   ((message "This is evaluated when this `mic' sexp is evaluated.")
  |    (message "This is also evaluated."))
  |
  |   ;; Each element will be evaluated after the package (`lsp-mode' for this example) is loaded.
  |   :eval-after-load
  |   ((message "This is evaluated when `lsp-mode' is loaded."))
  |
  |   ;; Each element is evaluated immediately when this `mic' sexp is evaluated.
  |   ;; These are evaluated before `:eval' and `:eval-after-load' elements.
  |   ;; This is for such use as defining function to use `:custom' argument.
  |   :eval-before-all
  |   ((message "This is evaluated when this `mic' sexp is evaluated.")
  |    (message "These are evaluated before `:eval' and `:eval-after-load' sexp.")))
  |
  |
  | ;; `mic' sexp above is expanded to:
  | (prog1 'lsp-mode
  |   ;; `:eval-before-all'
  |   (message "This is evaluated when this `mic' sexp is evaluated.")
  |   (message "These are evaluated before `:eval' and `:eval-after-load' sexp.")
  |
  |   ;; `:eval-after-load'
  |   (with-eval-after-load 'lsp-mode
  |     (message "This is evaluated when `lsp-mode' is loaded.")
  |     ;; `:define-key-after-load'
  |     (define-key lsp-mode-map
  |       (kbd "M-r")
  |       (function lsp-rename))
  |     (define-key lsp-mode-map
  |       (kbd "M-c")
  |       (function lsp-execute-code-action)))
  |
  |   ;; `:eval'
  |   (message "This is evaluated when this `mic' sexp is evaluated.")
  |   (message "This is also evaluated.")
  |
  |   ;; `:custom'
  |   (customize-set-variable 'lsp-sesstion-file
  |                            (expand-file-name "etc/.lsp-session-v1" user-emacs-directory))
  |   (customize-set-variable 'lsp-log-io t)
  |
  |   ;; `:define-key'
  |   (define-key global-map (kbd "M-l") #'lsp)
  |
  |   ;; `:define-key-with-feature'
  |   (with-eval-after-load '`dired'
  |     (define-key dired-mode-map (kbd "M-q") #'lsp-dired-mode))
  |
  |   ;; `:hook'
  |   (add-hook 'c-mode-hook #'lsp)
  |   (add-hook 'c++-mode-hook #'lsp)
  |   (add-hook 'tex-mode-hook #'lsp)
  |   (add-hook 'latex-mode-hook #'lsp)
  |   (add-hook 'bibtex-mode-hook #'lsp)
  |   (add-hook 'rust-mode-hook #'lsp))
  `----

  For Emacs Lisp expert, original `mic' is a little unsatisfactory or
  redundant.  `mic' is not customizable, but you can define your own
  `mic' easily.
  1. Determine parent.  You can use as parent `mic', `mic-core', which is
     simpler `mic'.  `mic-core' recieves only keywords start from
     `:eval', such as `:eval', `eval-after-load'.
  2. Define filter functions.  Each one recieves plist (property list)
     and returns plist.  returned plist is passed to parent (such as
     `mic', `mic-core') or next filter.  Note that filter function can
     get feature name as value of property `:name'.  Of course, you can
     use pre-defined filters.  `mic' is defined by some filters from the
     parent `mic-core'.
  3. Define your own mic by `mic-defmic'.  It recieves `NAME', optional
     `DOCSTRING', and keyword argument `FILTERS'.  `NAME' is name of your
     own `mic'.  `DOCSTRING' is the document string of yours.  `FILTERS'
     are list of filter.  As explained, filter recieves plist and
     returns plist.  It filter plist to get desired behavior.

  ,----
  | (defun my-filter-global-set-key-without-quote (plist)
  |   (let ((alist
  |          ;; Get value from your own keyword
  |          (plist-get plist :bind))
  |         sexps)
  |     (setq sexps
  |           ;; Transform each element
  |           (mapcar
  |            (lambda (arg)
  |              (let ((keys (car arg))
  |                    (command (cdr arg)))
  |                `(global-set-key (kbd ,keys) #',command)))
  |            alist))
  |     ;; Put sexps to `:eval' arguments
  |     (mic-plist-put-append plist :eval sexps)
  |     ;; Don't forget to delete your own keyword!
  |     ;; When forget it, parent recieves it and may cause unexpected result.
  |     (mic-plist-delete plist :bind)
  |     plist))
  |
  | (mic-defmic mymic
  |   ;; Parent is here.  You can also use `mic-core'.
  |   mic
  |   :filters
  |   '(my-filter-global-set-key-without-quote
  |     ;; You can add other filters below
  |     ))
  |
  | ;; Then you can use `mymic' like:
  | (mymic simple
  |   :bind
  |   (("C-d" . delete-forward-char)
  |    ("C-x l" . toggle-truncate-lines))
  |   ;; Of course parent keywords are accepted.
  |   :custom
  |   ((kill-whole-line . t)
  |    (set-mark-command-repeat-pop . t)
  |    (mark-ring-max . 50)))
  |
  | ;; `mymic' sexp is expanded to:
  | (mic simple
  |   :custom
  |   ((kill-whole-line . t)
  |    (set-mark-command-repeat-pop . t)
  |    (mark-ring-max . 50))
  |   :eval
  |   ((global-set-key (kbd "C-d") #'delete-forward-char)
  |    (global-set-key (kbd "C-x l") #'toggle-truncate-lines)))
  |
  | ;; Expanded to:
  | (mic-core simple
  |   :eval
  |   ((global-set-key (kbd "C-d") #'delete-forward-char)
  |    (global-set-key (kbd "C-x l") #'toggle-truncate-lines)
  |    (customize-set-variable 'kill-whole-line t)
  |    (customize-set-variable 'set-mark-command-repeat-pop t)
  |    (customize-set-variable 'mark-ring-max 50))
  |   :eval-after-load nil)
  |
  | ;; Expanded to:
  | (prog1 'simple
  |   (global-set-key  (kbd "C-d") #'delete-forward-char)
  |   (global-set-key (kbd "C-x l") #'toggle-truncate-lines)
  |   (customize-set-variable 'kill-whole-line t)
  |   (customize-set-variable 'set-mark-command-repeat-pop t)
  |   (customize-set-variable 'mark-ring-max 50))
  `----


3 Use `mic-core', minimum one
=============================

  `mic-core' is minimum.  It can recieves only several keywords:
  - `:eval'
  - `:eval-after-load'
  - `:eval-after-others'
  - `:eval-after-others-after-load'
  - `:eval-before-all'
  - `:eval-installation'

  Each element of `:eval' arguments are evaluated.  Time to evaluate is
  different.


3.1 `:eval', `:eval-after-others', `:eval-before-all'
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  Each element of these arguments are evaluated when the `mic' sexp is
  evaluated.  The order is:
  - `:eval-before-all'
  - (`with-eval-after-load' sexp, explained on [`eval-after-load'
    keyword section], is evaluated)
  - `:eval'
  - `:eval-after-others'

  ,----
  | (mic-core feature-name
  |   :eval
  |   ((message "eval1")
  |    (message "eval2"))
  |   :eval-after-others
  |   ((message "eval-after-others1")
  |    (message "eval-after-others2"))
  |   :eval-before-all
  |   ((message "eval-before-all1")
  |    (message "eval-before-all2"))
  |   :eval-after-load
  |   ((message "eval-after-load1")
  |    (message "eval-after-load2")))
  |
  | ;; Expanded to:
  | (prog1 'feature-name
  |   (message "eval-before-all1")
  |   (message "eval-before-all2")
  |   (with-eval-after-load 'feature-name
  |     (message "eval-after-load1")
  |     (message "eval-after-load2"))
  |   (message "eval1")
  |   (message "eval2")
  |   (message "eval-after-others1")
  |   (message "eval-after-others2"))
  `----

  `:eval-before-all' exists because a filter function appends sexp to
  `:eval' argument.  When some action should be evaluated before all
  action added by other filters, you can put it to `:eval-before-all'
  argument.  *Note that it should NOT be used by filters.* Any filter
  should not use this.  If it is used by filters, users cannot make their
  sexp to be evaluate before filter sexps.

  `:eval-after-others' exists because similar reason to
  `:eval-before-all'.  Some action should be evaluated after all action
  added by other filters.  Because of same reasons as
  `:eval-before-all', *it should NOT be used by filters*.


[`eval-after-load' keyword section] See section 3.2


3.2 `:eval-after-load', `:eval-after-others-after-load'
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  Each element of these arguments are evaluated after the package is
  loaded.  The evaluated order is:
  - `:eval-after-load'
  - `:eval-after-others-after-load'

  ,----
  | (mic-core feature-name
  |   :eval-after-load
  |   ((message "eval-after-load1")
  |    (message "eval-after-load2"))
  |   :eval-after-others-after-load
  |   ((message "eval-after-others-after-load1")
  |    (message "eval-after-others-after-load2")))
  |
  | ;; Expanded to:
  | (prog1 'feature-name
  |   (with-eval-after-load 'feature-name
  |     (message "eval-after-load1")
  |     (message "eval-after-load2")
  |     (message "eval-aftepr-others-after-load1")
  |     (message "eval-after-others-after-load2")))
  `----

  `:eval-after-others-after-load' exists because similar reason to
  `:eval-after-others'.  Some action should be evaluated after all
  action added by other filters.  Because of same reasons as
  `:eval-before-all', *it should NOT be used by filters*.


3.3 `:eval-installation'
~~~~~~~~~~~~~~~~~~~~~~~~

  Each element of this argument is evaluated before evaluation of other
  `:eval*' argument except `:eval-before-all'.  This exists because sexp
  to install the package is evaluated before sexp which uses package
  features.

  ,----
  | (mic-core feature-name
  |   :eval-before-all
  |   ((message "before all2")
  |    (message "before all1"))
  |   :eval-installation
  |   ((message "install1")
  |    (message "install2"))
  |   :eval-after-load
  |   ((message "eval-after-load1")
  |    (message "eval-after-load2"))
  |   :eval-after-others-after-load
  |   ((message "eval-after-others-after-load1")
  |    (message "eval-after-others-after-load2"))
  |   :eval
  |   ((message "eval1")
  |    (message "eval2")))
  |
  | ;; Expanded to:
  | (prog1 'feature-name
  |   (message "before all2")
  |   (message "before all1")
  |   (message "install1")
  |   (message "install2")
  |   (with-eval-after-load 'feature-name
  |     (message "eval-after-load1")
  |     (message "eval-after-load2")
  |     (message "eval-after-others-after-load1")
  |     (message "eval-after-others-after-load2"))
  |   (message "eval1")
  |   (message "eval2"))
  `----

  `:eval-after-others-after-load' exists because similar reason to
  `:eval-after-others'.  Some action should be evaluated after all
  action added by other filters.  Because of same reasons as
  `:eval-before-all', *it should NOT be used by filters*.


4 Use default `mic'
===================

  `mic' is minimal for use.  `mic-core' is minimum core, but it is not
  enough to use as it is.  In addition to keywords allowed by
  [`mic-core'], it allows some keyword arguments:
  - `:autoload-interactive'
  - `:autoload-noninteractive'
  - `:auto-mode'
  - `:custom'
  - `:custom-after-load'
  - `:declare-function'
  - `:define-key'
  - `:define-key-after-load'
  - `:define-key-with-feature'
  - `:defvar-noninitial'
  - `:face'
  - `:hook'
  - `:package'
  - `:require'
  - `:require-after'


[`mic-core'] See section 3

4.1 `:autoload-interactive', `:autoload-noninteractive'
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  These are transformed to `autoload' sexps.  Each element is function to
  autoload.  Since `autoload' should be informed whether the function is
  `interactive' or not, both `:autoload-interactive' and
  `:autoload-noninteractive' exist.

  ,----
  | (mic feature-name
  |   :autoload-interactive
  |   (interactive-func1
  |    interactive-func2)
  |   :autoload-noninteractive
  |   (noninteractive-func3
  |    noninteractive-func4))
  |
  | ;; Expanded to:
  | (mic-core feature-name :eval
  |   ((autoload #'interactive-func1 "feature-name" nil t)
  |    (autoload #'interactive-func2 "feature-name" nil t)
  |    (autoload #'noninteractive-func3 "feature-name")
  |    (autoload #'noninteractive-func4 "feature-name"))
  |   :eval-after-load nil)
  |
  | ;; Expanded to:
  | (prog1 'feature-name
  |   (autoload #'interactive-func1 "feature-name" nil t)
  |   (autoload #'interactive-func2 "feature-name" nil t)
  |   (autoload #'noninteractive-func3 "feature-name")
  |   (autoload #'noninteractive-func4 "feature-name"))
  `----


4.2 `:auto-mode'
~~~~~~~~~~~~~~~~

  It is transformed to sexp like `(add-to-list 'auto-mode-alist ...)'.
  Each element of the value should be valid as an element of
  `auto-mode-alist'.

  ,----
  | (mic feature-name
  |   :auto-mode
  |   (("\\.html?\\'" . web-mode)
  |    ("\\.css\\'" . web-mode)))
  |
  | ;; Expanded to:
  | (mic-core feature-name :eval-installation
  |   ((add-to-list 'auto-mode-alist '("\\.html?\\'" . web-mode))
  |    (add-to-list 'auto-mode-alist '("\\.css\\'" . web-mode)))
  |   :eval nil :eval-after-load nil)
  |
  | ;; Expanded to:
  | (prog1 'feature-name
  |   (add-to-list 'auto-mode-alist '("\\.html?\\'" . web-mode))
  |   (add-to-list 'auto-mode-alist '("\\.css\\'" . web-mode)))
  |

  `----


4.3 `:custom', `:custom-after-load'
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  These are transformed to `customize-set-variable' sexps.  Each element
  is `(VARIABLE . VALUE)'.  Each `VARIABLE' is set to `VALUE'.  Sexp
  from `:custom' argument are evaluated when the `mic' sexp is
  evaluated, while sexp from `:custom-after-load' argument are evaluated
  after the feature is loaded.  `:custom-after-load' is used when you
  want to use initial value of customized variable or function defined
  in the feature.

  ,----
  | (mic feature-name
  |   :custom
  |   ((variable1 . 1)
  |    ;; VALUE is evaluated
  |    (variable2 . (+ 1 1)))
  |   :custom-after-load
  |   ;; You can use the initial value of `variable3'
  |   ((variable3 . (+ variable3 1))
  |    ;; You can use function defined in the feature (for this example `feature-name')
  |    (variable2 . (function-defined-in-feature-name))))
  |
  | ;; Expanded to:
  | (mic-core feature-name
  |   :eval
  |   ((customize-set-variable 'variable1 1)
  |    (customize-set-variable 'variable2
  |                            (+ 1 1)))
  |   :eval-after-load
  |   ((customize-set-variable 'variable3
  |                            (+ variable3 1))
  |    (customize-set-variable 'variable2
  |                            (function-defined-in-feature-name))))
  |
  | ;; Expanded to:
  | (prog1 'feature-name
  |   (with-eval-after-load 'feature-name
  |     ;; `variable3' is already defined.
  |     (customize-set-variable 'variable3
  |                              (+ variable3 1))
  |     ;; `function-defined-in-feature-name' is already defined.
  |     (customize-set-variable 'variable2
  |                             (function-defined-in-feature-name)))
  |   (customize-set-variable 'variable1 1)
  |   (customize-set-variable 'variable2
  |                           (+ 1 1)))
  `----


4.4 `declare-function', `defvar-noninitial'
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  These arguments declare functions and variables.  Each element of
  `declare-function' / `defvar-noninitial' is symbol as
  function/variable.  They exist in order to suppress warning of
  undefined functions/variables.

  ,----
  | (mic feature-name
  |   :declare-function
  |   (function1
  |    function2)
  |   :defvar-noninitial
  |   (variable1
  |    variable2))
  |
  | ;; Expanded to:
  | (mic-core feature-name
  |   :eval
  |   ((declare-function function1 "ext:feature-name")
  |    (declare-function function2 "ext:feature-name")
  |    (defvar variable1)
  |    (defvar variable2))
  |   :eval-after-load nil)
  |
  | ;; Expanded to:
  | (prog1 'feature-name
  |   ;; They declare that the functions `function1' and `function2' is defined in
  |   ;; the feature `feature-name'.
  |   (declare-function function1 "ext:feature-name")
  |   (declare-function function2 "ext:feature-name")
  |   ;; They declare that the variables `variable1' and `variable2' will be defined.
  |   ;; `defvar' without initial value declares symbol as variable.
  |   (defvar variable1)
  |   (defvar variable2))
  `----


4.5 `:define-key', `:define-key-after-load', `:define-key-with-feature'
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  These arguments is transformed to `define-key' sexps.  On
  `:define-key' or `:define-key-after-load', each element of the
  argument is `(KEYMAP (KEYS . COMMAND)...)'.  `KEYMAP' is keymap.  `KEYS'
  is passed to `kbd'.  `COMMAND' is interactive function.

  On `:define-key-with-feature', each element is `(FEATURE (KEYMAP (KEYS
  . COMMAND)...))'.  `FEATURE' is feature, and the `define-key' sexp is
  evaluated after loading the `FEATURE'.  This exists in order to define
  `COMMAND' in the feature with `KEYS' to `KEYMAP' defined in `FEATURE'.
  Use it to make sure that `KEYMAP' is defined.

  ,----
  | (mic feature-name
  |   :define-key
  |   ;; (KEYMAP (KEYS . COMMAND)...)
  |   ((global-map
  |     ;; #' is needed
  |     ("M-l" . #'feature-name-command1))
  |    (prog-mode-map
  |     ;; #' is needed
  |     ("M-a" . #'feature-name-comman2)))
  |
  |   :define-key-after-load
  |   ;; When `feature-name-mode-map' is defined in `feature-name',
  |   ;; use `:define-key-after-load'.
  |   ((feature-name-mode-map
  |     ("M-r" . #'feature-name-command3)
  |     ("M-c" . #'feature-name-command4)))
  |
  |
  |   ;; When `other-feature-mode-map' is defined in `other-feature', which is not `feature-name',
  |   ;; use `:define-key-with-feature'.
  |   :define-key-with-feature
  |   ((other-feature
  |     (other-feature-mode-map
  |      ("M-q" . #'feature-name-command5)))))
  |
  | ;; Expanded to:
  | (mic-core feature-name
  |   :eval
  |   ((define-key global-map (kbd "M-l") #'feature-name-command1)
  |    (define-key prog-mode-map (kbd "M-a") #'feature-name-comman2)
  |    (with-eval-after-load 'other-feature
  |      (define-key other-feature-mode-map (kbd "M-q") #'feature-name-command5)))
  |   :eval-after-load
  |   ((define-key feature-name-mode-map (kbd "M-r") #'feature-name-command3)
  |    (define-key feature-name-mode-map (kbd "M-c") #'feature-name-command4)))
  |
  | ;; Expanded to:
  | (prog1 'feature-name
  |   (with-eval-after-load 'feature-name
  |     ;; `:define-key-after-load'
  |     (define-key feature-name-mode-map (kbd "M-r") #'feature-name-command3)
  |     (define-key feature-name-mode-map (kbd "M-c") #'feature-name-command4))
  |   ;; `:define-key'
  |   (define-key global-map (kbd "M-l") #'feature-name-command1)
  |   (define-key prog-mode-map (kbd "M-a") #'feature-name-comman2)
  |   ;; `:define-key-with-feature'
  |   (with-eval-after-load 'other-feature
  |     (define-key other-feature-mode-map (kbd "M-q") #'feature-name-command5)))
  `----


4.6 `:face'
~~~~~~~~~~~

  This is transformed to `custom-set-faces' sexp.  Each element is
  `(FACE-SYMBOL . FACE-DEFINITION)'.

  ,----
  | (mic feature-name
  |   :face
  |   ((face-1
  |     . ((t (:foreground "red" :height 10.0))))
  |    (face-2
  |     . ((t (:background "#006000" :foreground "white" :bold t))))))
  |
  | ;; Expanded to:
  | (mic-core feature-name
  |   :eval
  |   ((custom-set-faces
  |     '(face-1
  |       ((t (:foreground "red" :height 10.0))))
  |     '(face-2
  |       ((t (:background "#006000" :foreground "white" :bold t))))))
  |   :eval-after-load nil)
  |
  | ;; Expanded to:
  | (prog1 'feature-name
  |   (custom-set-faces
  |    '(face-1
  |      ((t (:foreground "red" :height 10.0))))
  |    '(face-2
  |      ((t (:background "#006000" :foreground "white" :bold t))))))
  `----


4.7 `:hook'
~~~~~~~~~~~

  This is transformed to `add-hook' sexp.  Each element is `(HOOK
  . FUNCTION)'.

  ,----
  | (mic feature-name
  |   :hook
  |   ;; #' is needed
  |   ((hook1 . #'function1)
  |    (hook2 . #'function2)
  |    ;; `lambda' is allowed (but not recommended)
  |    (hook3 . (lambda (arg) 1))))
  |
  | ;; Expanded to:
  | (mic-core feature-name
  |   :eval
  |   ((add-hook 'hook1 #'function1)
  |    (add-hook 'hook2 #'function2)
  |    (add-hook 'hook3 (lambda (arg) 1)))
  |   :eval-after-load nil)
  |
  | ;; Expanded to:
  | (prog1 'feature-name
  |   (add-hook 'hook1 #'function1)
  |   (add-hook 'hook2 #'function2)
  |   (add-hook 'hook3 (lambda (arg) 1)))
  `----


4.8 `:package'
~~~~~~~~~~~~~~

  This is transformed to `package-install' sexps.  Each arguments are
  `PKG' used by `package-install'.

  The expandation result is complicated, because it is annoying to fetch
  package archives many times.


  ,----
  | (mic feature-name
  |   :package
  |   (package-name1
  |    package-name2))
  |
  | ;; Expanded to:
  | (mic-core feature-name
  |   :eval
  |   ;; When package is not installed
  |   ((unless (package-installed-p 'package-name1)
  |      ;; Ensure package is exists in archive
  |      (when (assq 'package-name1 package-archive-contents)
  |        (ignore-errors
  |          (package-install 'package-name1)))
  |      (unless (package-installed-p 'package-name1)
  |        ;; Refresh (fetch) new archive
  |        (package-refresh-contents)
  |        (condition-case _
  |            (package-install 'package-name1)
  |          (error
  |           (warn "Package %s is not found" 'package-name1)))))
  |
  |    (unless (package-installed-p 'package-name2)
  |      (when (assq 'package-name2 package-archive-contents)
  |        (ignore-errors
  |          (package-install 'package-name2)))
  |      (unless (package-installed-p 'package-name2)
  |        (package-refresh-contents)
  |        (condition-case _
  |            (package-install 'package-name2)
  |          (error
  |           (warn "Package %s is not found" 'package-name2))))))
  |   :eval-after-load nil)
  |
  | ;; Expand to:
  | (prog1 'feature-name
  |   (unless (package-installed-p 'package-name1)
  |     (when (assq 'package-name1 package-archive-contents)
  |       (ignore-errors
  |         (package-install 'package-name1)))
  |     (unless (package-installed-p 'package-name1)
  |       (package-refresh-contents)
  |       (condition-case _
  |           (package-install 'package-name1)
  |         (error
  |          (warn "Package %s is not found" 'package-name1)))))
  |   (unless (package-installed-p 'package-name2)
  |     (when (assq 'package-name2 package-archive-contents)
  |       (ignore-errors
  |         (package-install 'package-name2)))
  |     (unless (package-installed-p 'package-name2)
  |       (package-refresh-contents)
  |       (condition-case _
  |           (package-install 'package-name2)
  |         (error
  |          (warn "Package %s is not found" 'package-name2))))))
  `----


4.9 `:require'
~~~~~~~~~~~~~~

  This is transformed to `require' sexps.  Each element is feature
  symbol and required on `:eval'.

  ,----
  | (mic feature-name
  |   :require
  |   (feat1
  |    feat2))
  |
  | ;; Expand to:
  | (mic-core feature-name
  |   :eval-installation nil
  |   :eval
  |   ((require 'feat1)
  |    (require 'feat2))
  |   :eval-after-load nil)
  |
  | ;; Expand to:
  | (prog1 'feature-name
  |   (require 'feat1)
  |   (require 'feat2))
  `----


4.10 `:require-after'
~~~~~~~~~~~~~~~~~~~~~

  This is transformed to `require' sexps in `with-eval-after-load'
  section.  Each element is alist.  `car' of each element is feature
  symbol which is used as first argument of `with-eval-after-load'.
  `cdr' of each element is list of features required after the `car'.

  This is used when you should require package after another one but
  there is no functions to call so `autoload' cannot be used.

  ,----
  | (mic feature-name
  |   :require-after
  |   ((feat-after1
  |     . (feat1  feat2))
  |    (feat-after2
  |     feat3
  |     feat4)))
  |
  | ;; Expand to:
  | (mic-core feature-name
  |   :eval-installation nil
  |   :eval
  |   ((with-eval-after-load 'feat-after1
  |      (require 'feat1)
  |      (require 'feat2))
  |    (with-eval-after-load 'feat-after2
  |      (require 'feat3)
  |      (require 'feat4)))
  |   :eval-after-load nil)
  |
  | ;; Expand to:
  | (prog1 'feature-name
  |   (with-eval-after-load 'feat-after1
  |     (require 'feat1)
  |     (require 'feat2))
  |   (with-eval-after-load 'feat-after2
  |     (require 'feat3)
  |     (require 'feat4)))
  `----


5 Define your own `mic'
=======================

  You do not like `mic' behavior? It is OK.  You can define your own
  `mic'!  There are some ways to define it:
  - Use `mic-defmic'
  - Use `defmacro'


5.1 Define your own `mic' with `mic-defmic'
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  If you would like to add keywords, or to make some keywords more
  simple, you can define `filter' and apply it to `mic' (or `mic-core',
  and another `mic', any parent is allowed).


5.1.1 What is a filter?
-----------------------

  The filter recieves one argument, `PLIST' (plist, property list), and
  returns `RETURNED-PLIST'.  It filters or transforms it into returned
  plist.  It is better to divide filters by every keyword, because of
  reusability.

  1. Each filter recieves 1 argument `PLIST', which is plist (property
     list).
  2. Each filter returns `RETURNED-PLIST', which is plist.
  3. `PLIST' is given by user or filter before.
  4. `PLIST' have feature name `:name' property.
  5. `RETURNED-PLIST' is passed to next filter or parent `mic' (`mic',
     `mic-core', or another).
  6. `RETURNED-PLIST' should have same value of `:name' property.
  7. The property only used by your filter should be removed in
     `RETURNED-PLIST'.

  Here is example:
  ,----
  | (defun my-filter-global-set-key-without-quote (plist)
  |   (let ((alist
  |          ;; Get value from your own keyword
  |          (plist-get plist :bind))
  |         sexps)
  |     (setq sexps
  |           ;; Transform each element
  |           (mapcar
  |            (lambda (arg)
  |              (let ((keys (car arg))
  |                    (command (cdr arg)))
  |                `(global-set-key (kbd ,keys) #',command)))
  |            alist))
  |     ;; Put sexps to `:eval' arguments
  |     (mic-plist-put-append plist :eval sexps)
  |     ;; Don't forget to delete your own keyword!
  |     ;; When forget it, parent recieves it and may cause unexpected result.
  |     (mic-plist-delete plist :bind)
  |     plist))
  |
  | ;; `defmic' defines new `mic' (see "Define mic with mic-defmic" section for more infomation)
  | (mic-defmic yourmic
  |   mic                                   ; Derived from `mic'
  |   :filters '(my-filter-global-set-key-without-quote))
  |
  | ;; Here is `yourmic' expression
  | (yourmic package-name
  |   ;; New keyword you added by `my-filter-global-set-key-without-quote'
  |   :bind
  |   (("M-a" . beginning-of-defun)
  |    ("M-e" . end-of-defun))
  |   ;; Of course keywords for `mic', which is original of `yourmic', is allowed.
  |   :hook ((after-init-hook . #'ignore)))
  |
  | ;; Then first `PLIST' is:
  | '( :name package-name
  |    :bind (("M-a" . beginning-of-defun)
  |           ("M-e" . end-of-defun))
  |    :hook ((after-init-hook . #'ignore)))
  |
  | ;; When you expand the sexp before, the filter you defined is called like:
  | (my-filter-global-set-key-without-quote
  |  '( :name package-name
  |     :bind (("M-a" . beginning-of-defun)
  |            ("M-e" . end-of-defun))
  |     :hook ((after-init-hook . #'ignore))))
  |
  | ;; It returns `RETURNED-PLIST':
  | '( :name package-name
  |    :hook ((after-init-hook function ignore))
  |    :eval
  |    ((global-set-key (kbd "M-a") #'beginning-of-defun)
  |     (global-set-key (kbd "M-e") #'end-of-defun)))
  |
  | ;; The `RETURNED-PLIST' is passed to a next filter if exists.
  | ;; You use only one filter in definition,
  | ;; so it is expanded to:
  | (mic package-name
  |   :hook ((after-init-hook . #'ignore))
  |   :eval
  |   ((global-set-key (kbd "M-a") #'beginning-of-defun)
  |    (global-set-key (kbd "M-e") #'end-of-defun)))
  `----


5.1.2 Pre-defined filters
-------------------------

  Some pre-defined filter, unused by `mic' definition, are available in
  `mic-filter.el'.


* 5.1.2.1 Filters for package manager

  - `mic-filter-ell-get'
  - `mic-filter-straight'
  - `mic-filter-quelpa'
  For more infomation, see docstring of each filter.

  ,----
  | ;;;  el-get
  | (mic-defmic mic-with-el-get mic
  |   :filters '(mic-filter-el-get))
  |
  | (mic-with-el-get hydra
  |   :el-get ((hydra :repo "abo-abo/hydra" :fetcher github)))
  |
  | ;; Expanded to:
  | (mic hydra
  |   :eval-installation
  |   ((el-get-bundle hydra :repo "abo-abo/hydra" :fetcher github)))
  `----

  ,----
  | ;;;  quelpa
  | (mic-defmic mic-with-quelpa mic
  |   :filters '(mic-filter-quelpa))
  |
  | (mic-with-quelpa hydra
  |   :quelpa ((hydra :repo "abo-abo/hydra" :fetcher github)))
  |
  | ;; Expanded to:
  | (mic hydra
  |   :eval-installation
  |   ((quelpa
  |     '(hydra :repo "abo-abo/hydra" :fetcher github))))
  `----

  ,----
  | ;;;  straight
  | (mic-defmic mic-with-straight mic
  |   :filters '(mic-filter-straight))
  |
  | (mic-with-straight hydra
  |   :straight ((hydra :repo "abo-abo/hydra" :host github)))
  |
  | ;; Expanded to:
  | (mic hydra
  |   :eval-installation
  |   ((straight-use-package
  |     '(hydra :repo "abo-abo/hydra" :host github))))
  `----


* 5.1.2.2 Key definition

  - `mic-filter-define-key-general', `mic-filter-general-define-key'
  - `mic-filter-mykie'
  - `mic-filter-hydra'
  - `mic-filter-pretty-hydra', `mic-filter-pretty-hydra+'
  - `mic-filter-mode-hydra'

  Here is summaries and examples for these filters.  See a docstring and
  definition of each filter for more information.


  + 5.1.2.2.1 general.el

    [general.el] makes key definition more convenient.  There are some
    filters for integration with it:
    - `mic-filter-define-key-general'
    - `mic-filter-general-define-key'
    The both are expanded to `general-define-key' call.

    `mic-filter-define-key-general', which uses a `:define-key-general'
    keyword, is compatible with `:define-key' keyword.  In the other
    words, the syntax like `((keymap (key . function)...)...)' is
    allowed but `general-define-key' is used as backend.

    On the other hand, `mic-filter-general-define-key', which uses
    `:general-define-key' keyword, uses `general-define-key' syntax.  So
    you can use `:keymap' or `:prefix' keyword.  Each element of the
    value of `:general-define-key' is directly passed to
    `general-define-key'.

    ,----
    | (mic-defmic mic-with-define-key-general mic
    |   :filters
    |   '(mic-filter-define-key-general))
    |
    | (mic-with-define-key-general package-name
    |   :define-key-general
    |   ((keymap1
    |     ("C-d" . #'func1)
    |     ("C-q" . #'func2))
    |    (override
    |     ("C-a" . #'func3)
    |     ("C-e" . #'func4))))
    |
    | ;; Expanded to:
    | (mic package-name
    |   :eval
    |   ((general-define-key :keymaps 'keymap1
    |                        "C-d" (function func1)
    |                        "C-q" (function func2))
    |    (general-define-key :keymaps 'override
    |                        "C-a" (function func3)
    |                        "C-e" (function func4))))
    `----


    [general.el] 


  + 5.1.2.2.2 Mykie.el

    [Mykie.el] is is multiplexer of key definition.  There is filter for
    mykie:
    - `mic-filter-mykie'

    `mic-filter-mykie', which uses a `:mykie' keyword, creates
    `mykie:define-key' sexp.  Each element of the value on `:mykie'
    keyword is a cons cell like `((keymap (key [:keyword function1]
    ...)...)...)'.  `car' of each element, which is keymap, and each
    element of `cdr' of each element of the value is passed to
    `mykie:define-key'.

    ,----

    `----

    ,----
    | (mic-defmic mic-with-filter-mykie mic
    |   :filters
    |   '(mic-filter-mykie))
    |
    | (mic-with-filter-mykie package-name
    |   :mykie
    |   ((global-map
    |     ("C-w" :default hydra-window-resizer/body :region kill-region))))
    |
    | ;; Expanded to:
    | (mic package-name
    |   :eval
    |   ((mykie:define-key global-map "C-w" :default hydra-window-resizer/body :region kill-region)))
    `----


    [Mykie.el] 


  + 5.1.2.2.3 Hydra

    [Hydra] makes Emacs bindings stick around.  There is a filter for
    integration of Hydra:
    - `mic-filter-hydra'

    `mic-filter-hydra', which uses a `:hydra' keyword, creates
    `defhydra' sexp.  Each element of the value on the `:hydra' keyword
    is passed to `defhydra' directly.

    ,----
    | (mic-defmic mic-with-hydra mic
    |   :filters '(mic-filter-hydra))
    |
    | (mic-with-hydra package-name
    |   :hydra
    |   ;; Spacing induces good indent
    |   (( hydra-window-resizer ()
    |      ("p" shrink-window "shrink")
    |      ("n" enlarge-window "enlarge")
    |      ("f" enlarge-window-horizontally "enlarge-horizontally")
    |      ("b" shrink-window-horizontally "shrink-horizontally")
    |      ("" shrink-window)
    |      ("" enlarge-window)
    |      ("" enlarge-window-horizontally)
    |      ("" shrink-window-horizontally)
    |      ("q" nil "quit"))))
    |
    | ;; Expanded to:
    | (mic package-name
    |   :eval
    |   ((defhydra hydra-window-resizer nil
    |      ("p" shrink-window "shrink" :exit nil :cmd-name hydra-window-resizer/shrink-window :column nil)
    |      ("n" enlarge-window "enlarge")
    |      ("f" enlarge-window-horizontally "enlarge-horizontally")
    |      ("b" shrink-window-horizontally "shrink-horizontally")
    |      ("" shrink-window)
    |      ("" enlarge-window)
    |      ("" enlarge-window-horizontally)
    |      ("" shrink-window-horizontally)
    |      ("q" nil "quit"))))
    `----


    [Hydra] 


  + 5.1.2.2.4 pretty-hydra

    [Pretty Hydra] defines prettier hydra.  There is some filters for
    integration of it:
    - `mic-filter-pretty-hydra'
    - `mic-filter-pretty-hydra+'

    `mic-filter-pretty-hydra' uses `:pretty-hydra', whereas
    `mic-filter-pretty-hydra+' uses `:pretty-hydra+'.  Each element is
    passed to `pretty-hydra-define', which defines new hydra, or
    `pretty-hydra-define+', which appends to existing hydra if exist.
    The both have absolutely same syntax.  Each element is passed to each
    defining macros directly.

    ,----
    | (mic-defmic mic-with-pretty-hydra mic
    |   :filters '(mic-filter-pretty-hydra
    |              mic-filter-pretty-hydra+))
    |
    | ;;; `:pretty-hydra'
    | (mic-with-pretty-hydra package-name
    |   :pretty-hydra
    |   (( hydra-window-resizer ()
    |      ("Alphabet"
    |       (("p" shrink-window "shrink")
    |        ("n" enlarge-window "enlarge")
    |        ("f" enlarge-window-horizontally "enlarge-horizontally")
    |        ("b" shrink-window-horizontally "shrink-horizontally"))
    |       "Arrow"
    |       (("" shrink-window)
    |        ("" enlarge-window)
    |        ("" enlarge-window-horizontally)
    |        ("" shrink-window-horizontally))
    |       "Quit"
    |       ("q" nil "quit")))))
    |
    | ;; Expanded to:
    | (mic package-name
    |   :eval
    |   ((pretty-hydra-define hydra-window-resizer nil
    |      ("Alphabet"
    |       (("p" shrink-window "shrink")
    |        ("n" enlarge-window "enlarge")
    |        ("f" enlarge-window-horizontally "enlarge-horizontally")
    |        ("b" shrink-window-horizontally "shrink-horizontally"))
    |       "Arrow"
    |       (("" shrink-window "shrink-window")
    |        ("" enlarge-window "enlarge-window")
    |        ("" enlarge-window-horizontally "enlarge-window-horizontally")
    |        ("" shrink-window-horizontally "shrink-window-horizontally"))
    |       "Quit"
    |       ("q" nil "quit")))))
    |
    |
    | ;;; `:pretty-hydra+'
    | (mic-with-pretty-hydra package-name
    |   :pretty-hydra+
    |   (( hydra-window-resizer ()
    |      ("Vim-like"
    |       (("h" enlarge-window-horizontally "enlarge-horizontally")
    |        ("j" shrink-window "shrink")
    |        ("k" enlarge-window "enlarge")
    |        ("l" shrink-window-horizontally "shrink-horizontally"))))))
    |
    | ;; Expanded to:
    | (mic package-name
    |   :eval
    |   ((pretty-hydra-define+ hydra-window-resizer nil
    |      ("Vim-like"
    |       (("h" enlarge-window-horizontally "enlarge-horizontally")
    |        ("j" shrink-window "shrink")
    |        ("k" enlarge-window "enlarge")
    |        ("l" shrink-window-horizontally "shrink-horizontally"))))))
    `----


    [Pretty Hydra]
    


  + 5.1.2.2.5 major-mode-hydra

    [Major Mode Hydra] defines major-mode specific hydra function,
    `major-mode-hydra'.  There is a filter for integration of it:
    - `mic-filter-mode-hydra'

    `mic-filter-mode-hydra' uses a `:mode-hydra' keyword.  Each element
    of the value of the keyword is passed to `major-mode-hydra-define'
    directly.

    ,----
    | (mic-defmic mic-with-mode-hydra mic
    |   :filters '(mic-filter-mode-hydra
    |              mic-filter-mode-hydra+))
    |
    | ;;; `:mode-hydra'
    | (mic-with-mode-hydra package-name
    |   :mode-hydra
    |   (( c-mode (:title "C Mode" :quit-key "q")
    |      ("Alphabet"
    |       (("p" shrink-window "shrink")
    |        ("n" enlarge-window "enlarge")
    |        ("f" enlarge-window-horizontally "enlarge-horizontally")
    |        ("b" shrink-window-horizontally "shrink-horizontally"))
    |       "Arrow"
    |       (("" shrink-window)
    |        ("" enlarge-window)
    |        ("" enlarge-window-horizontally)
    |        ("" shrink-window-horizontally))))))
    |
    | ;; Expanded to:
    | (mic package-name
    |   :eval
    |   ((major-mode-hydra-define c-mode
    |      (:title "C Mode" :quit-key "q")
    |      ("Alphabet"
    |       (("p" shrink-window "shrink")
    |        ("n" enlarge-window "enlarge")
    |        ("f" enlarge-window-horizontally "enlarge-horizontally")
    |        ("b" shrink-window-horizontally "shrink-horizontally"))
    |       "Arrow"
    |       (("" shrink-window "shrink-window")
    |        ("" enlarge-window "enlarge-window")
    |        ("" enlarge-window-horizontally "enlarge-window-horizontally")
    |        ("" shrink-window-horizontally "shrink-window-horizontally"))))))
    |
    | ;;;  `:mode-hydra+'
    | (mic-with-mode-hydra package-name
    |   :mode-hydra+
    |   (( c-mode (:title "C Mode" :quit-key "q")
    |      ("Alphabet"
    |       (("p" shrink-window "shrink")
    |        ("n" enlarge-window "enlarge")
    |        ("f" enlarge-window-horizontally "enlarge-horizontally")
    |        ("b" shrink-window-horizontally "shrink-horizontally"))
    |       "Arrow"
    |       (("" shrink-window)
    |        ("" enlarge-window)
    |        ("" enlarge-window-horizontally)
    |        ("" shrink-window-horizontally))))))
    |
    | ;; Expanded to:
    | (mic package-name :eval
    |   ((major-mode-hydra-define+ c-mode
    |      (:title "C Mode" :quit-key "q" :hint nil :color teal :separator "═")
    |      ("Alphabet"
    |       (("p" shrink-window "shrink")
    |        ("n" enlarge-window "enlarge")
    |        ("f" enlarge-window-horizontally "enlarge-horizontally")
    |        ("b" shrink-window-horizontally "shrink-horizontally"))
    |       "Arrow"
    |       (("" shrink-window "shrink-window")
    |        ("" enlarge-window "enlarge-window")
    |        ("" enlarge-window-horizontally "enlarge-window-horizontally")
    |        ("" shrink-window-horizontally "shrink-window-horizontally"))))))
    `----


    [Major Mode Hydra]
    


* 5.1.2.3 Alternative of filters

  + 5.1.2.3.1 Hook

    `mic-filter-hook-list'
          This is almost same as `mic-filter-hook', but `car' of each
          element of the value should be list of hook, and the `cdr'
          should be list of function (should be quoted).  `:hook-list'
          is used as keyword.
    `mic-filter-hook-list-maybe'
          This is almost same as `mic-filter-hook', but `car' of each
          element of the value should be list of hook or just one hook,
          and the `cdr' should be list of function or just one function
          (should *NOT* be quoted).  `:hook-list-maybe' is used as
          keyword.
    `mic-filter-hook-quote'
          This is almost same as `mic-filter-hook', but `cdr' of each
          element of the value should not be quoted.  `:hook-quote' is
          used as keyword.


5.1.3 Helper for defining a filter
----------------------------------

  There are some helpers for defining a filter.


* 5.1.3.1 Utilities

  Usually, a filter proceeds filtering by 4 steps:
  1. Get data on a specific keyword in `PLIST'
  2. Convert data to sexp
  3. Append the sexp to value on `:eval' in `PLIST'
  4. Delete the specific keyword from `PLIST'

  There are some macros to help step 3. and 4. in `mic-utils.el'.
  - `mic-plist-put-append', which helps step 3., takes three arguments,
    `PLIST', `PROP', which means keyword, and `VAL'.  It get a value on
    `PROP' in `PLIST', and appends `VAL' to the value.
  - `mic-plist-delete', which helps step 4., takes one obligatory
    argument `PLIST', and extra arguments `PROPS'.  It removes `PROPS'
    keywords from `PLIST' and return it.


* 5.1.3.2 `deffilter'

  To define a simple filter or to modify an existing filter, you can use
  `mic-deffilter-*' macros in `mic-deffilter.el'.  See each macro
  definition and docstring for more information.

  `mic-deffilter-alias'
        Induce alias keyword.
        ,----
        | (mic-deffilter-alias example-filter-alias :alias :origin)
        |
        | (example-filter-alias '(:alias "Hello"))
        | ;; =>
        | (:origin "Hello")
        `----
  `mic-deffilter-const'
        Put constant value on keyword.
        ,----
        | (mic-deffilter-const example-filter-const
        |   "Optional docstring."
        |   :eval '((message "Hello")))
        |
        | ;; Add a :eval keyword when it does not exist.
        | (example-filter-const '(:other-keyword "Hi"))
        | ;; =>
        | (:other-keyword "Hi" :eval ((message "Hello")))
        |
        | ;; Overwrite when a :eval keyword exists.
        | (example-filter-const '(:eval ((message "Good bye")) :other-keyword "Hi"))
        | ;; =>
        | (:eval ((message "Hello")) :other-keyword "Hi")
        `----
  `mic-deffilter-const-append'
        Append constant value on keyword.
        ,----
        | (mic-deffilter-const-append example-filter-const-append
        |   :eval '((message "Hello")))
        |
        | ;; Same as `mic-deffilter-const' when any :eval keyword does not exist.
        | (example-filter-const-append '(:other-keyword "Hi"))
        | ;; =>
        | (:other-keyword "Hi" :eval ((message "Hello")))
        |
        | ;; Append the value when the a :eval keyword exists.
        | (example-filter-const-append '(:eval ((message "Good bye")) :other-keyword "Hi"))
        | ;; =>
        | (:eval ((message "Good bye") (message "Hello")) :other-keyword "Hi")
        `----
  `mic-deffilter-ignore'
        Just remove value on keyword.
        ,----
        | (mic-deffilter-ignore example-filter-ignore
        |   :ignore-me)
        |
        | (example-filter-ignore '(:ignore-me "Ignored" :remain-me "Remained"))
        | ;; =>
        | (:remain-me "Remained")
        `----
  `mic-deffilter-nonlist-to-list'
        If value is not list, wrap it into list.
        ,----
        | (mic-deffilter-nonlist-to-list example-filter-nonlist-to-list
        |   :package)
        |
        | (example-filter-nonlist-to-list '(:package t))
        | ;; =>
        | (:package (t))
        `----
  `mic-deffilter-replace-keyword-append'
        From an existing filter, define a new filter which uses another
        keywords as input and output.  Value is appended to the keyword
        for output.
        ,----
        | ;; Original filter: `mic-filter-mykie'
        | (mic-filter-mykie '(:mykie ((global-map ("C-a" :default beginning-of-line)))))
        | ;; =>
        | (:eval ((mykie:define-key global-map "C-a" :default beginning-of-line)))
        |
        |
        | (mic-deffilter-replace-keyword-append example-filter-replace-keyword-append
        |   mic-filter-mykie
        |   :mykie-after-load :mykie
        |   '((:eval . :eval-after-load)))
        |
        | ;; An input keyword and an output keyword is replaced
        | (example-filter-replace-keyword-append '(:mykie-after-load ((global-map ("C-a" :default beginning-of-line)))))
        | ;; =>
        | (:eval-after-load ((mykie:define-key global-map "C-a" :default beginning-of-line)))
        `----
  `mic-deffilter-convert-after-load'
        From an existing filter, define a new filter which outputs an
        `:eval-after-load' keyword instead of `:eval'.  It is same as
        `(mic-deffilter-replace-keyword-append name filter old-keyword
        new-keyword '((:eval . :eval-after-load)))'.
        ,----
        | ;; Original filter: `mic-filter-mykie'
        | (mic-filter-mykie '(:mykie ((global-map ("C-a" :default beginning-of-line)))))
        | ;; =>
        | (:eval ((mykie:define-key global-map "C-a" :default beginning-of-line)))
        |
        |
        | (mic-deffilter-convert-after-load example-filter-convert-after-load
        |   mic-filter-mykie
        |   :mykie-after-load :mykie)
        |
        | ;; An input keyword and an output keyword is replaced
        | (example-filter-convert-after-load '(:mykie-after-load ((global-map ("C-a" :default beginning-of-line)))))
        | ;; =>
        | (:eval-after-load ((mykie:define-key global-map "C-a" :default beginning-of-line)))
        `----
  `mic-deffilter-t-to-name'
        Replace `t' with feature name in a list keyword.
        ,----
        | (mic-deffilter-t-to-name example-filter-t-to-name
        |   :replace)
        |
        |  ;; :name keyword is needed in addition to :replace keyword
        | (example-filter-t-to-name '(:name feature-name :replace (1 2 3 t 5 6 t)))
        | ;; =>
        | (:name feature-name :replace (1 2 3 feature-name 5 6 feature-name))
        `----
  `mic-deffilter-validate'
        Return a recieved plist except that it validates and sieves
        keyword in the plist to confirm the returned plist has no
        invalid keywords.
        ,----
        | (mic-deffilter-validate example-filter-validate
        |   :name :key1 :key2)
        |
        | (example-filter-validate '(:name feature-name :key1 "Hello" :key2 "Hi" :key3 "Bad" :key4 "Sad"))
        | ;; =>
        | (:name feature-name :key1 "Hello" :key2 "Hi")
        | ;; In addition, warnings are displayed like:
        | ;; Warning (Emacs): 'mic' feature-name: The keyword :key3 is not allowed by filter 'example-filter-validate'
        | ;; Warning (Emacs): 'mic' feature-name: The keyword :key4 is not allowed by filter 'example-filter-validate'
        `----


5.1.4 Define `mic' with `mic-defmic'
------------------------------------

  `mic-defmic' recieves arguments: `NAME', `PANRENT', optional
  `DOCSTRING', keyword argument `FILTERS'.  `NAME' is your new `mic'
  macro name.  `PARENT' is parent `mic', which recieves `RETURNED-PLIST'
  at last.  `FILTERS' is list of your filters.  When your `mic' recieves
  plist, the plist is filtered by all of your `FILTERS' in order, then
  the plist is passed to `PARENT'.

  Here is example:
  ,----
  | ;; Define `mymic'
  | (mic-defmic mymic
  |   ;; Parent is here.  You can also use `mic-core'.
  |   mic
  |   :filters
  |   '(my-filter-global-set-key-without-quote
  |     ;; You can add other filters below
  |     )
  |   ;; You can comment out the line below to catch, warn and ignore errors.
  |   ;; :error-protection? t
  |   )
  |
  | ;; Then you can use `mymic' like:
  | (mymic simple
  |   :bind
  |   (("C-d" . delete-forward-char)
  |    ("C-x l" . toggle-truncate-lines))
  |   ;; Of course parent keywords are accepted.
  |   :custom
  |   ((kill-whole-line . t)
  |    (set-mark-command-repeat-pop . t)
  |    (mark-ring-max . 50)))
  |
  | ;; Expanded to:
  | (mic simple
  |   :custom
  |   ((kill-whole-line . t)
  |    (set-mark-command-repeat-pop . t)
  |    (mark-ring-max . 50))
  |   :eval
  |   ((global-set-key (kbd "C-d") #'delete-forward-char)
  |    (global-set-key (kbd "C-x l") #'toggle-truncate-lines)))
  `----

  When you would like to use `mic-core' as `PARENT',
  `mic-filter-core-validate' is useful to validate plist.  *Please put
  it tail of `FILTERS' if you use it.*


* 5.1.4.1 Error protection

  If you want your `mic' to catch, warn and dismiss errors and to
  continue evaluation, set `:error-protection?' `t'.
  ,----
  | (mic-defmic mymic-with-error-protection
  |   ;; Parent is here.  You can also use `mic-core'.
  |   mic
  |   :filters
  |   '(my-filter-global-set-key-without-quote)
  |   :error-protection? t)
  |
  | (mymic-with-error-protection simple
  |   :bind
  |   (("C-d" . delete-forward-char)
  |    ("C-x l" . toggle-truncate-lines))
  |   ;; Of course parent keywords are accepted.
  |   :custom
  |   ((kill-whole-line . t)
  |    (set-mark-command-repeat-pop . t)
  |    (mark-ring-max . 50)))
  |
  | ;; Expanded to:
  | (condition-case-unless-debug error      ; Catch error
  |     (mic simple
  |       :custom
  |       ((kill-whole-line . t)
  |        (set-mark-command-repeat-pop . t)
  |        (mark-ring-max . 50))
  |       :eval
  |       ((global-set-key (kbd "C-d") (function delete-forward-char))
  |        (global-set-key (kbd "C-x l") (function toggle-truncate-lines))))
  |   ;; Warn caught error but continue evaluation
  |   (error
  |    (warn "`%s' %s: evaluation error: %s" 'mymic-with-error-protection 'simple
  |          (error-message-string error))))
  `----


* 5.1.4.2 Accept non-plist input

  Like `use-package' and `leaf', you can define `mic' which accepts
  non-plist input.  If you want to do so, you should pass `:inputter'
  argument to `mic-defmic'.  `INPUTTER' is a function which takes one
  argument `INPUT', and transform it into `PLIST' as returned value.

  Simply, you can use `mic-definputter-pseudo-plist' defined in
   to define inputter like `use-package' or
  `leaf'.  it takes two arguments `NAME' and `LISTIZED-KEYWORDS'.  `NAME'
  is a name of the inputter function, and `LISTIZED-KEYWORDS' is list of
  keyword whose value can be passed multiple times.
  ,----
  | (mic-definputter-pseudo-plist my-inputter
  |   '(:eval :eval-after-load :define-key))
  |
  | (mic-defmic mymic-with-inputter mic
  |   :inputter #'my-inputter)
  |
  | (mymic-with-inputter feature-name
  |   :eval
  |   ;; Like `use-package', you can put multiple sexps after :eval, instead of list of sexp
  |   (message "Hello")
  |   (message "Good bye")
  |
  |   :eval-after-load
  |   (message "Hello, after load")
  |   (message "Good bye, after load")
  |
  |   ;; Instead, list of sexp is not allowed
  |   ;; :eval-after-load
  |   ;; ((message "Hello, after load")
  |   ;;  (message "Good bye, after load"))
  |
  |   :define-key
  |   (global-map
  |    ("M-a" . #'beginning-of-defun))
  |   (esc-map
  |    ("e" . #'end-of-defun))
  |
  |   ;; Other keyword is not affected by inputter
  |   :package
  |   (ivy hydra))
  `----


* 5.1.4.3 Adopt a parent other than `mic', `mic-core' and its derivation

  You can use other configuration managers, such as [use-package] and
  [leaf.el].  However, filters defined by `mic' output keyword for `mic'
  family, such as `:eval', `:eval-after-load'.  So you should tell
  `mic-defmic' how to adapt outputs to its parent by `:adapter' option.
  The adapter takes one argument `PLIST', and returns a list to pass to
  the parent.

  Two adapter are pre-defined:
  `mic-adapter-use-package'
        Adapter for `use-package'.
  `mic-adapter-leaf'
        Adapter for `leaf'.

  ,----
  | (mic-defmic mic-with-use-package use-package
  |   :filters '(mic-filter-define-key-with-feature)
  |   :adapter #'mic-adapter-use-package)
  |
  | (mic-with-use-package feature-name
  |   :define-key-with-feature
  |   ((org
  |     (org-mode-map
  |      ("M-a" . #'feature-name-command))))
  |   ;; You can use `use-package' feature
  |   :bind
  |   (("M-a" . beginning-of-defun)
  |    ("M-e" . end-of-defun)))
  |
  | ;; Expanded to:
  | (use-package feature-name
  |   :bind
  |   (("M-a" . beginning-of-defun)
  |    ("M-e" . end-of-defun))
  |   ;; :defer is needed to wrap :config section around `eval-after-load'
  |   :defer t
  |   :init
  |   (with-eval-after-load 'org
  |     (define-key org-mode-map (kbd "M-a") (function feature-name-command))))
  `----


  [use-package] 

  [leaf.el] 


5.2 Define your own `mic' with `defmacro'
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  When you read here, you should know `defmacro'.  You can do anything
  with `defmacro'.  `mic-defmic' is easy way to define your `mic', but
  may be not enough for you, because of restriction.  Then *I RECOMMEND
  to use `defmacro'*.  I am looking forward to seeing your `mic' defined
  by `defmacro'!


6 Alternative
=============

  There are some alternatives:
  - [`use-package']
  - [`leaf']

  They are more easy to use, but sometimes have less expressive ability.
  `mic' is more simple and has more expressive ability, but sometimes
  more redundant.  It is just your preference.

  In addition, they are customizable, while `mic' is not customizable,
  but re-definable.  You can define your own `mic' according to your
  preference, with `mic' help.  Of course you can define your own `mic'
  with `use-package' or `leaf' as backend.


[`use-package'] 

[`leaf'] 


7 Contribute
============

  When you think you would like to share your filter or your own `mic',
  use GitHub Discussion.  Of course your `mic' defined by
  `defmacro'.  Any issue is welcome.


8 License
=========

  This package is licensed by GPLv3. See [LICENSE].


[LICENSE] 

Dependencies