(def logo ` ______ _____ ______ _____ | \ | | |_____/ | | |_____/ |_____| | \_ |_____| `) (def bye ` ______ __ __ _______ |_____] \_/ |______ |_____] | |______ `) (def dorodata "dorodata") (defn help [] (print "add, rm, prio, 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 [] (let [f (file/open dorodata :r)] (if (nil? f) (-> (file/open dorodata :w) (file/flush) (file/close)) (file/close f)))) (defn load-entries [] (let [f (file/open dorodata :r) content (file/read f :all)] (file/close f) (->> content (string/split "\n") lines->entries))) (defn load-entries-sorted [] (sorted (load-entries) (fn [a b] (some true? (map (fn [int-a int-b] (> int-a int-b)) (string/bytes (a :prio)) (string/bytes (b :prio))))))) (defn entries->string [entries] (reduce (fn [acc entry] (string acc "id:" (entry :id) "\n" "title:" (entry :title) "\n" "prio:" (entry :prio) "\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 &opt if-nil] (print label ":") (or (readline) if-nil)) (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") :prio "5"}) save-entries)) (defn col-length [entries col] (or (max ;(map (fn [entry] (length (get 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-sorted) len-id (max (col-length entries :id) (length "Id")) len-title (max (col-length entries :title) (length "Title")) len-prio (max (col-length entries :prio) (length "Prio")) spaces (fn [l m] (string/repeat " " (max 0 (- m l))))] (print (vt100-codes :underlined) "Id" (spaces 2 len-id) " " "Prio" (spaces 4 len-prio) " " "Title" (spaces 5 len-title) (vt100-codes :clear)) (var ix 0) (loop [entry :in entries :let [id (string (entry :id)) title (string (entry :title)) prio (string (entry :prio))]] (print (if (odd? ix) (vt100-codes :lightgray) (vt100-codes :bold)) id (spaces (length id) len-id) " " prio (spaces (length prio) len-prio) " " title (spaces (length title) len-title) (vt100-codes :clear)) (set ix (inc ix)))) (print)) (defn id->entry [id] (->> (load-entries) (filter (fn [e] (= id (e :id)))) first)) (defn rm [] (let [id (request-val "Id") to-delete (id->entry id) 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))))) (defn prio [] (let [m-entry (put (id->entry (request-val "Id")) :prio (request-val "Prio" "5"))] (when m-entry (save-entries (map (fn [e] (if (= (e :id) (m-entry :id)) m-entry e)) (load-entries)))))) (def structure {"add" add "rm" rm "prio" prio "help" help "" overview "quit" quit}) (defn main [& args] (ensure-dorodata) (print logo) (help) (while true ((get structure (readline) help))))