(def logo ` ▓█████▄ ▒█████ ██▀███ ▒█████ ▒██▀ ██▌▒██▒ ██▒▓██ ▒ ██▒▒██▒ ██▒ ░██ █▌▒██░ ██▒▓██ ░▄█ ▒▒██░ ██▒ ░▓█▄ ▌▒██ ██░▒██▀▀█▄ ▒██ ██░ ░▒████▓ ░ ████▓▒░░██▓ ▒██▒░ ████▓▒░ ▒▒▓ ▒ ░ ▒░▒░▒░ ░ ▒▓ ░▒▓░░ ▒░▒░▒░ ░ ▒ ▒ ░ ▒ ▒░ ░▒ ░ ▒░ ░ ▒ ▒░ ░ ░ ░ ░ ░ ░ ▒ ░░ ░ ░ ░ ░ ▒ ░ ░ ░ ░ ░ ░ ░ `) (def bye ` ▄▄▄▄ ▓██ ██▓▓█████ ▓█████▄▒██ ██▒▓█ ▀ ▒██▒ ▄██▒██ ██░▒███ ▒██░█▀ ░ ▐██▓░▒▓█ ▄ ░▓█ ▀█▓░ ██▒▓░░▒████▒ ░▒▓███▀▒ ██▒▒▒ ░░ ▒░ ░ ▒░▒ ░▓██ ░▒░ ░ ░ ░ ░ ░▒ ▒ ░░ ░ ░ ░ ░ ░ ░ ░░ ░ `) (def dorodata "dorodata") (defn help [] (print "add, rm, mod, help, quit, [enter]")) (defn readline [] (let [line (file/read stdin :line)] (if (nil? line) nil (string/trimr line)))) (defn quit [] (print bye) (os/exit 0)) (defn lines->entries [lines] (var entries @[]) (loop [line :in lines :when (> (length line) 0)] (let [[key content] (string/split ":" line) kwkey (keyword key)] (when (or (= "id" key) (nil? (array/peek entries))) (array/push entries @{})) (set ((array/peek entries) kwkey) content))) entries) (defn ensure-dorodata [] (-> (file/open dorodata :w) (file/flush) (file/close))) (defn load-entries [] (let [f (file/open dorodata :r) content (file/read f :all)] (file/close f) (->> content (string/split "\n") lines->entries))) (defn entries->string [entries] (reduce (fn [acc entry] (string acc "id:" (entry :id) "\n" "title:" (entry :title) "\n")) "" entries)) (defn save-entries [entries] (let [f (file/open dorodata :w)] (file/write f (entries->string entries)) (file/flush f) (file/close f))) (defn request-val [label] (print label ":") (readline)) (defn new-id [] (inc (or (max ;(map (fn [e] (scan-number (get e :id "0"))) (load-entries))) 0))) (defn add [] (-> (load-entries) (array/push {:id (new-id) :title (request-val "Title")}) save-entries)) (defn col-length [entries col] (or (max ;(map (fn [entry] (length (entry col))) entries)) 0)) (def vt100-codes {:underlined "\e[4m" :lightgray "\e[100m" :bold "\e[1m" :clear "\e[0m"}) (defn overview [] (let [entries (load-entries) len-id (max (col-length entries :id) (length "Id")) len-title (max (col-length entries :title) (length "Title")) spaces (fn [l m] (string/repeat " " (max 0 (- m l))))] (print (vt100-codes :underlined) "Id" (spaces 2 len-id) " " "Title" (spaces 5 len-title) (vt100-codes :clear)) (var ix 0) (loop [entry :in entries :let [id (entry :id) title (entry :title)]] (print (if (odd? ix) (vt100-codes :lightgray) (vt100-codes :bold)) id (spaces (length id) len-id) " " title (spaces (length title) len-title) (vt100-codes :clear)) (set ix (inc ix)))) (print)) (defn rm [] (let [id (request-val "Id") to-delete (->> (load-entries) (filter (fn [e] (= id (e :id)))) first) confirm (fn [] (not= "n" (request-val (string "Confirm deletion of " (to-delete :title) " (Y/n)"))))] (when (and to-delete (confirm)) (->> (load-entries) (filter (fn [e] (not= id (e :id)))) (save-entries))))) (def structure {"add" add "rm" rm "mod" (fn [] (print "mod")) "help" help "" overview "quit" quit}) (defn main [& args] (ensure-dorodata) (print logo) (help) (while true ((get structure (readline) help))))