Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

https://github.com/AdamNiederer/metamorph

Transform your code in turing-complete ways
https://github.com/AdamNiederer/metamorph

emacs emacs-lisp metaprogramming transforming-files

Last synced: 3 months ago
JSON representation

Transform your code in turing-complete ways

Lists

README

        

* metamorph
Higher-order buffer transformations for Emacs.

** Usage
Say you're writing some lovely code for your new libc implementation:

#+BEGIN_SRC c
void free(void* ptr) {
void* prev_freelist_ptr = (void*)*(size_t**)(ptr - 24);
void* next_freelist_ptr = (void*)*(size_t**)(ptr - 16);
size_t this_size = *(size_t*)(ptr - 8);

// Set prev->next to this->next and next->prev to this->prev
*(size_t*)(prev_freelist_ptr - 24) = next_freelist_ptr;
*(size_t*)(next_freelist_ptr - 16) = prev_freelist_ptr;
}
#+END_SRC

But all of a sudden, you want to add a new feature, and change the pointer
offsets above:

#+BEGIN_SRC c
void free(void* ptr) {
void* prev_freelist_ptr = (void*)*(size_t**)(ptr - 32);
void* next_freelist_ptr = (void*)*(size_t**)(ptr - 24);
size_t this_size = *(size_t*)(ptr - 16);
size_t magic_number = *(size_t*)(ptr - 8);

// Check for freelist corruption
assert(magic_number == 0xdeadbeefcafefade);

// Set prev->next to this->next and next->prev to this->prev
*(size_t*)(prev_freelist_ptr - 32) = next_freelist_ptr;
*(size_t*)(next_freelist_ptr - 24) = prev_freelist_ptr;
}
#+END_SRC

You could use ~replace-string~ three times for each number literal in your code
Or, you could use ~(metamorph-map-region "[0-9]+" "(- %i 8)")~.

Metamorph provides a powerful way to transform your buffer contents - perform
base conversions, increment numbers, transform every nth match, and more. Use
any Emacs Lisp function to transform your data - the sky is the limit.

Metamorph's principal function, ~metamorph-map-region~ will prompt you for a
regular expression, and a lisp expression. It will then replace everything
matching the regular expression in your region with the result of the lisp
expression. You can use the following variables in the lisp expression:

- ~%~ is the matched string without any additional processing
- ~%i~ is the matched string's value as an integer
- ~%0~ is an index which starts at zero, and increments for each match
- ~%n~ is the total number of matches

Additionally, if a prefix argument is specified, the following
values may be used in TRANSFORM:

- ~%!~ is the matched string's value as a lisp expression
** Security
When a prefix argument is provided to ~metamorph-map-region~, metamorph reads
all strings matching the regular expression, and will gladly evaluate them as
Lisp if ~%!~ is included in the transformation expression. Because of the
security implications of such behavior, it is recommended to not provide a
prefix argument or use ~%!~ on untrusted buffers.

Calling ~(read %)~ in your transformation expression will also nullify the
safeguards in ~metammorph-map-region~ and carries the same security implications
as providing a prefix argument and using ~%!~.
** Cleanup
Metamorph removes all preview overlays when either both the regular expression
and transformation are entered, or ~C-g~ is pressed. If you manage to leave the
minibuffer without doing either of those things, you can call
~metamorph-cleanup~ to remove the preview overlays.