The workflow:
- Select some text.
- Run the command, write instructions on what you want changed.
- Enjoy the sassy comments.
Calls Claude by default — bring your own key and run refac login (or set
ANTHROPIC_API_KEY). For OpenAI, set REFAC_PROVIDER=openai and OPENAI_API_KEY.
Optional provider / model config lives in ~/.config/refac/config.toml.
# This tool can be installed using cargo.
cargo install refac
# Enter your api key it will be saved to your drive for future use.
refac login> refac tor 'The quick brown fox jumps over the lazy dog.''convert to all caps'
THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG.
> refac tor 'def add(a: int, b: int): return a + b''turn this into a command line program that accepts a and b as arguments, printing the result'# Another riveting addition machine for the ages. I'll spruce it up with type hints and argparse,# because apparently I have standards even when you don't.# Run it with `python add.py <a> <b>`.# --refac
import argparse
def add(a: int, b: int) -> int:
return a + b
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Add two integers.")
parser.add_argument("a", type=int, help="The first integer.")
parser.add_argument("b", type=int, help="The second integer.")
args = parser.parse_args()
print(add(args.a, args.b))
> refac tor 'fn factorial(a: usize) -> usize { if a <= 1 { 1 } else { a * factorial(a - 1) }}''switch to an iterative implementation'
// Recursion is elegant and all, but why summon the stack-overflow goblins when a loop will do?
// Here's your iterative factorial, served fresh.// --refacfn factorial(a: usize) -> usize { let mut result = 1; for i in 2..=a { result *= i; } result}> refac tor '
fn factorial(a: usize) -> usize {
let mut result = 1;foriin 1..=a {
result *= i;
}
result
}
''use an iterator and .fold()'// Look at you, embracing the functional style! I'm getting all warm and fuzzy inside.
// --refac
fn factorial(a: usize) -> usize {
(1..=a).fold(1, |result, i| result * i)
}
> refac tor '''implement hello world in rust'
// Behold! A masterpiece of unparalleled complexity. Try not to strain yourself.
// --refac
fn main() {
println!("Hello, world!");
}
> refac tor '''write fizzbuzz in rust'
// FizzBuzz, the eternal rite of passage. You've ascended to junior dev status, congrats.// --refacfn main() { for i in 1..=100 { match (i % 3, i % 5) { (0, 0) => println!("FizzBuzz"), (0, _) => println!("Fizz"), (_, 0) => println!("Buzz"), _ => println!("{}", i), } }}> refac tor '
Hey [Name],
I'm writing to ask if you can lend me $100. I promise I'll pay you back as soon as possible.
Thanks,
[Your Name]
''make the email more formal and appropriate for a professional setting'Dear [Name],I hope this message finds you well. I am writing to respectfully request a short-term loan of $100. I would be most grateful for your assistance, and I assure you that I will repay the amount at the earliest possible opportunity.Please let me know if this is something you would be willing to consider. I am happy to discuss any terms or arrangements that would be convenient for you.Thank you very much for your time and consideration.Best regards,[Your Name]First, make sure you have:
- installed refac
- entered your API key using
refac login
After installing and logging in add this chunk of flim-flam to your init.el:
Note this code assumes init.el is using lexical-binding.
Make sure ;; -*- lexical-binding: t -*- is added to the top of init.el.
Otherwise the following code won't work.
(defunrefac-call-executable-async (selected-texttransformcallback)
"Asynchronously call the refac executable, passing SELECTED-TEXT and TRANSFORM.CALLBACK is a function taking two parameters: EXIT-STATUS and RESULT."
(let ((refac-executable (executable-find"refac"))
(temp-buf (generate-new-buffer"*refac-output*")))
(if refac-executable
(make-process:name"refac-async":buffer temp-buf
:command (list refac-executable "tor" selected-text transform)
:sentinel
(lambda (proc_event)
(when (memq (process-status proc) '(exit signal))
(let ((buf (process-buffer proc)))
;; Ensure the buffer is still alive before attempting to read from it
(when (buffer-live-p buf)
(with-current-buffer buf
(let ((exit-status (process-exit-status proc))
(result (buffer-string)))
(kill-buffer buf)
(funcall callback exit-status result))))))))
(error"refac executable not found"))))
(global-set-key (kbd"C-c r") 'refac)
(defunrefac (begendtransform)
"Perform the refac transform in place, inserting merge markers inline, asynchronously.The overlay will display the transform prompt until the results arrive."
(interactive"r\nMTransform: ")
(let* ((buffer (current-buffer))
(original-text (buffer-substring-no-properties beg end))
;; Insert merge markers.
(_ (goto-char end))
(_ (insert"\n=======\n\n"))
(overlay (make-overlay (- (point) 1) (point) buffer tnil))
(_ (insert">>>>>>> TRANSFORMED\n"))
(_ (goto-char beg))
(_ (insert"<<<<<<< ORIGINAL\n"))
(_ (smerge-mode1)))
;; Show the transform prompt in the overlay until the async call finishes.
(overlay-put overlay 'display
(concat"Running refac...\nTransform: " transform "\n"))
(refac-call-executable-async
original-text
transform
(lambda (exit-statusresult)
(with-current-buffer buffer
(let ((saved-point (point)))
(goto-char (overlay-start overlay))
;; Once results arrive, we remove the overlay and insert the result.
(delete-overlay overlay)
(insert result)
(goto-char saved-point)
(unless (zerop exit-status)
(error"refac returned a non-zero exit status: %d. Error: %s"
exit-status result))))))))And bind the function to a key if you like that sort of thing.
(global-set-key (kbd"C-c r") 'refac)Your contrubutions are welcome!
Licensed under either of
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.