-
-
Save apg/1167939 to your computer and use it in GitHub Desktop.
Command-line structural data editing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns ded | |
"Structural Data EDitor for Clojure with zippers. Inspired by Interlisp: http://larry.masinter.net/interlisp-ieee.pdf" | |
(:require [clojure.zip :as z]) | |
(:use [clojure.pprint :only (with-pprint-dispatch code-dispatch pprint)] | |
[clojure.repl :only (source-fn)])) | |
(defn print-hr | |
"Prints 30 dashes and a newline." | |
[c] | |
(println (apply str (repeat 30 c)))) | |
(defn print-loc | |
"pprints form using code-dispatch, wrapping in HRs." | |
[root loc] | |
(with-pprint-dispatch code-dispatch | |
(print-hr \_) | |
(pprint root) | |
(print-hr \-) | |
(pprint loc) | |
(print-hr \_) | |
(flush))) | |
(defn code-zip | |
[root] | |
(z/zipper (some-fn seq? vector?) | |
identity | |
(fn [node children] (with-meta children (meta node))) | |
root)) | |
(def ^{:doc "Map of command characters to functions. Command functions take the current node as their argument."} | |
commands {;; basic movement | |
\u z/up | |
\d z/down | |
\< z/left | |
\> z/right | |
\b z/leftmost | |
\e z/rightmost | |
;; nav to top level | |
\t #(code-zip (z/root %)) | |
;; evaluate node at loc | |
\. #(do (print "= ") (pprint (eval (z/node %))) %) | |
;; evaluate root | |
\! #(do (print "= ") (pprint (eval (z/root %))) %) | |
;; insert to the left | |
\L #(z/left (z/insert-left % (read))) | |
;; insert to the right | |
\R #(z/right (z/insert-right % (read))) | |
;; remove | |
\D z/remove | |
;; overwrite | |
\O #(z/replace % (read)) | |
;; wrap with fn call. Prompts for fn name. | |
\W #(z/replace % `(~(read) ~(z/node %))) | |
;; raise | |
\w #(z/replace (z/up %) (z/node %))}) | |
(defn edit | |
"Opens form for editing. Commands are one character each, and are | |
executed in sequence. After successful command execution, prints root | |
followed by node at loc." | |
([] (edit ())) | |
([form] | |
(loop [loc (code-zip form)] | |
(print-loc (z/node (code-zip (z/root loc))) | |
(z/node loc)) | |
(print "> ") | |
(flush) | |
(let [input (str (read))] | |
(condp = input | |
"q" (z/root loc) | |
"Q" (do (eval (z/root loc)) (z/root loc)) | |
(recur (try (reduce #(%2 %1) loc (map commands input)) | |
(catch Exception _ (do (println "Error.") | |
loc))))))))) | |
(defn edit-fn | |
"Attempts to read fn's source code using clojure.repl/source-fn and | |
present it for editing." | |
[fn] | |
(edit (read-string (source-fn fn)))) | |
;; ded=> (edit '(+ (* 12 13) 2 (- 10 5))) | |
;; ------------------------------ | |
;; (+ (* 12 13) 2 (- 10 5)) <- root | |
;; ------------------------------ | |
;; (+ (* 12 13) 2 (- 10 5)) <- current location | |
;; ------------------------------ | |
;; > ! <- eval root | |
;; 163 | |
;; ------------------------------ | |
;; (+ (* 12 13) 2 (- 10 5)) | |
;; ------------------------------ | |
;; (+ (* 12 13) 2 (- 10 5)) | |
;; ------------------------------ | |
;; > dedbO! <- down, end, down, beginning, overwrite, eval | |
;; + | |
;; 173 | |
;; ------------------------------ | |
;; (+ (* 12 13) 2 (+ 10 5)) | |
;; ------------------------------ | |
;; + | |
;; ------------------------------ | |
;; > ub>D! <- up, beginning, right, delete, eval | |
;; 17 | |
;; ------------------------------ | |
;; (+ 2 (+ 10 5)) | |
;; ------------------------------ | |
;; + | |
;; ------------------------------ | |
;; > >>. <- right, right, eval at loc | |
;; 15 | |
;; ------------------------------ | |
;; (+ 2 (+ 10 5)) | |
;; ------------------------------ | |
;; (+ 10 5) | |
;; ------------------------------ | |
;; > |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment