Skip to content

AdamNiederer/metamorph

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 
 
 
 
 
 
 

Repository files navigation

metamorph

Higher-order buffer transformations for Emacs.

Usage

Say you’re writing some lovely code for your new libc implementation:

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;
}

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

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;
}

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.