dotemacs

My Emacs configuration
git clone git://git.entf.net/dotemacs
Log | Files | Refs | LICENSE

README.org (9562B)


      1 * macrostep: interactive macro-expander
      2 
      3    =macrostep= is an Emacs minor mode for interactively stepping
      4    through the expansion of macros in Emacs Lisp source code.  It lets
      5    you see exactly what happens at each step of the expansion process
      6    by pretty-printing the expanded forms inline in the source buffer,
      7    which is temporarily read-only while macro expansions are visible.
      8    You can expand and collapse macro forms one step at a time, and
      9    evaluate or instrument the expansions for debugging with Edebug as
     10    normal (but see "Bugs and known limitations", below).
     11    Single-stepping through the expansion is particularly useful for
     12    debugging macros that expand into another macro form.  These can be
     13    difficult to debug with Emacs' built-in =macroexpand=, which
     14    continues expansion until the top-level form is no longer a macro
     15    call.
     16 
     17    Both globally-visible macros as defined by =defmacro= and local
     18    macros bound by =(cl-)macrolet= or another macro-defining form can
     19    be expanded.  Within macro expansions, calls to macros and compiler
     20    macros are fontified specially: macro forms using
     21    =macrostep-macro-face=, and functions with compiler macros using
     22    =macrostep-compiler-macro-face=.  Uninterned symbols (gensyms) are
     23    fontified based on which step in the expansion created them, to
     24    distinguish them both from normal symbols and from other gensyms
     25    with the same print name.
     26 
     27    As of version 0.9, it is also possible to extend =macrostep= to
     28    work with other languages with macro systems in addition to Emacs
     29    Lisp.  An extension for Common Lisp (via SLIME) is in the works;
     30    contributions for other languages are welcome.  See "Extending
     31    macrostep" below for details.
     32 
     33 ** Key-bindings and usage
     34    The standard keybindings in =macrostep-mode= are the following:
     35  
     36     - e, =, RET  :: expand the macro form following point one step
     37     - c, u, DEL  :: collapse the form following point
     38     - q, C-c C-c :: collapse all expanded forms and exit macrostep-mode
     39     - n, TAB     :: jump to the next macro form in the expansion
     40     - p, M-TAB   :: jump to the previous macro form in the expansion
     41 
     42     It's not very useful to enable and disable macrostep-mode
     43     directly.  Instead, bind =macrostep-expand= to a key in
     44     =emacs-lisp-mode-map=, for example C-c e:
     45 
     46 #+BEGIN_SRC emacs-lisp
     47   (define-key emacs-lisp-mode-map (kbd "C-c e") 'macrostep-expand)
     48 #+END_SRC
     49 
     50     You can then enter macrostep-mode and expand a macro form
     51     completely by typing =C-c e e e ...= as many times as necessary.
     52 
     53     Exit macrostep-mode by typing =q= or =C-c C-c=, or by successively
     54     typing =c= to collapse all surrounding expansions.
     55 
     56 ** Customization options
     57    Type =M-x customize-group RET macrostep RET= to customize options
     58    and faces.
     59 
     60    To display macro expansions in a separate window, instead of inline
     61    in the source buffer, customize
     62    =macrostep-expand-in-separate-buffer= to =t=.  The default is
     63    =nil=.  Whichever default behavior is selected, the alternative
     64    behavior can be obtained temporarily by giving a prefix argument to
     65    =macrostep-expand=.
     66 
     67    To have =macrostep= ignore compiler macros, customize
     68    =macrostep-expand-compiler-macros= to =nil=.  The default is =t=.
     69 
     70    Customize the faces =macrostep-macro-face=,
     71    =macrostep-compiler-macro-face=, and =macrostep-gensym-1= through
     72    =macrostep-gensym-5= to alter the appearance of macro expansions.
     73 
     74 ** Locally-bound macros
     75    As of version 0.9, =macrostep= can expand calls to a locally-bound
     76    macro, whether defined by a surrounding =(cl-)macrolet= form, or by
     77    another macro-defining macro.  In other words, it is possible to
     78    expand the inner =local-macro= forms in both the following
     79    examples, whether =local-macro= is defined by an enclosing
     80    =cl-macrolet= --
     81    
     82    #+BEGIN_SRC emacs-lisp
     83      (cl-macrolet ((local-macro (&rest args)
     84                      `(expansion of ,args)))
     85        (local-macro (do-something)))
     86    #+END_SRC
     87 
     88    -- or by a macro which expands into =cl-macrolet=, provided that
     89    its definition of macro is evaluated prior to calling
     90    =macrostep-expand=:
     91 
     92    #+BEGIN_SRC emacs-lisp
     93      (defmacro with-local-macro (&rest body)
     94        `(cl-macrolet ((local-macro (&rest args)
     95                         `(expansion of ,args)))
     96           ,@body))
     97 
     98      (with-local-macro
     99          (local-macro (do something (else)))
    100    #+END_SRC
    101 
    102    See the =with-js= macro in Emacs's =js.el= for a real example of
    103    the latter kind of macro.
    104 
    105    Expansion of locally-bound macros is implemented by instrumenting
    106    Emacs Lisp's macro-expander to capture the environment at point.  A
    107    similar trick is used to detect macro- and compiler-macro calls
    108    within expanded text so that they can be fontified accurately.
    109 
    110 ** Expanding sub-forms
    111    By moving point around in the macro expansion using
    112    =macrostep-next-macro= and =macrostep-prev-macro= (bound to the =n=
    113    and =p= keys), it is possible to expand other macro calls within
    114    the expansion before expanding the outermost form.  This can
    115    sometimes be useful, although it does not correspond to the real
    116    order of macro expansion in Emacs Lisp, which proceeds by fully
    117    expanding the outer form to a non-macro form before expanding
    118    sub-forms.
    119 
    120    The main reason to expand sub-forms out of order is to help with
    121    debugging macros which programmatically expand their arguments in
    122    order to rewrite them.  Expanding the arguments of such a macro
    123    lets you visualise what the macro definition would compute via
    124    =macroexpand-all=.
    125 
    126 ** Extending macrostep for other languages
    127    Since version 0.9, it is possible to extend macrostep to work with
    128    other languages besides Emacs Lisp.  In typical Emacs fashion, this
    129    is implemented by setting buffer-local variables to different
    130    function values.  Six buffer-local variables define the
    131    language-specific part of the implementation:
    132 
    133    - =macrostep-sexp-bounds-function=
    134    - =macrostep-sexp-at-point-function=
    135    - =macrostep-environment-at-point-function=
    136    - =macrostep-expand-1-function=
    137    - =macrostep-print-function=
    138    - =macrostep-macro-form-p-function=
    139 
    140    Typically, an implementation for another language would set these
    141    variables in a major-mode hook.  See the docstrings of each
    142    variable for details on how each one is called and what it should
    143    return.  At a minimum, another language implementation needs to
    144    provide =macrostep-sexp-at-point-function=,
    145    =macrostep-expand-1-function=, and =macrostep-print-function=.
    146    Lisp-like languages may be able to reuse the default
    147    =macrostep-sexp-bounds-function= if they provide another
    148    implementation of =macrostep-macro-form-p-function=.  Languages
    149    which do not implement locally-defined macros can set
    150    =macrostep-environment-at-point-function= to =ignore=.
    151    
    152    Note that the core =macrostep= machinery only interprets the return
    153    value of =macrostep-sexp-bounds-function=, so implementations for
    154    other languages can use any internal representations of code and
    155    environments which is convenient.  Although the terminology is
    156    Lisp-specific, there is no reason that implementations could not be
    157    provided for non-Lisp languages with macro systems, provided there
    158    is some way of identifying macro calls and calling the compiler /
    159    preprocessor to obtain their expansions.
    160 
    161 ** Bugs and known limitations
    162    You can evaluate and edebug macro-expanded forms and step through
    163    the macro-expanded version, but the form that =eval-defun= and
    164    friends read from the buffer won't have the uninterned symbols of
    165    the real macro expansion.  This will probably work OK with CL-style
    166    gensyms, but may cause problems with =make-symbol= symbols if they
    167    have the same print name as another symbol in the expansion. It's
    168    possible that using =print-circle= and =print-gensym= could get
    169    around this.
    170 
    171    Please send other bug reports and feature requests to the author.
    172 
    173 ** Acknowledgements
    174    Thanks to:
    175    - John Wiegley for fixing a bug with the face definitions under
    176      Emacs 24 & for plugging macrostep in his [[http://youtu.be/RvPFZL6NJNQ][EmacsConf presentation]]!
    177    - George Kettleborough for bug reports, and patches to highlight
    178      the expanded region and properly handle backquotes.
    179    - Nic Ferrier for suggesting support for local definitions within
    180      macrolet forms
    181    - Luís Oliveira for suggesting and implementing SLIME support
    182 
    183    =macrostep= was originally inspired by J. V. Toups's 'Deep Emacs
    184    Lisp' articles ([[http://dorophone.blogspot.co.uk/2011/04/deep-emacs-part-1.html][part 1]], [[http://dorophone.blogspot.co.uk/2011/04/deep-emacs-lisp-part-2.html][part 2]], [[http://dorophone.blogspot.co.uk/2011/05/monadic-parser-combinators-in-elisp.html][screencast]]).
    185 
    186 ** Changelog
    187    - v0.9, 2015-10-01:
    188      - separate into Elisp-specific and generic components
    189      - highlight and expand compiler macros
    190      - improve local macro expansion and macro form identification by
    191        instrumenting =macroexpand(-all)=
    192    - v0.8, 2014-05-29: fix a bug with printing the first element of
    193      lists
    194    - v0.7, 2014-05-11: expand locally-defined macros within
    195      =(cl-)macrolet= forms
    196    - v0.6, 2013-05-04: better handling of quote and backquote
    197    - v0.5, 2013-04-16: highlight region, maintain cleaner buffer state
    198    - v0.4, 2013-04-07: only enter macrostep-mode on successful
    199      macro-expansion
    200    - v0.3, 2012-10-30: print dotted lists correctly. autoload
    201      definitions.
    202 
    203 #+OPTIONS: author:nil email:nil toc:nil timestamp:nil