Last active
June 30, 2024 16:13
-
-
Save mrrodriguez/055fa3e5ab08d4c2e135a8ac14d11b3d to your computer and use it in GitHub Desktop.
Simple Text Editor - Clojure
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 metasimple.simple-editor.core | |
(:require | |
[clojure.string :as str])) | |
(defn- process-op-append | |
[{:keys [text] :as ed-state} | |
{:keys [op-type arg]}] | |
(-> ed-state | |
(update :text str arg) | |
(update :undo-history conj {:op-type op-type :text text}))) | |
(defn undo-op-append | |
[ed-state | |
{:keys [text]}] | |
(assoc ed-state :text text)) | |
(defn- process-op-delete | |
[{:keys [text] :as ed-state} | |
{:keys [op-type arg]}] | |
(-> ed-state | |
(update :text subs 0 arg) | |
(update :undo-history conj {:op-type op-type :text text}))) | |
(defn undo-op-delete | |
[ed-state | |
{:keys [text]}] | |
(assoc ed-state :text text)) | |
(defn- process-op-print | |
[ed-state {:keys [arg]}] | |
(println (get-in ed-state [:text (dec arg)])) | |
ed-state) | |
(declare op-type->exec-fns) | |
(defn- process-op-undo | |
[{:keys [undo-history] :as ed-state} _op] | |
(if-let [{:keys [op-type] :as undo-item} (peek undo-history)] | |
(let [{:keys [undo-fn]} (op-type->exec-fns op-type)] | |
(when-not undo-fn | |
(throw (ex-info (format "No `:undo-fn` found for undo item op: %s" undo-item) | |
{:undo-item undo-item}))) | |
(-> ed-state | |
(update :undo-history pop) | |
(undo-fn undo-item))) | |
;; Nothing to undo. | |
ed-state)) | |
(defn- parse-int | |
[^String s] | |
(Long/parseLong s)) | |
(defn- create-op | |
[op-str] | |
(let [[op arg] (str/split op-str #" ")] | |
(case op | |
"1" {:op-type :append :arg arg} | |
"2" {:op-type :delete :arg (parse-int arg)} | |
"3" {:op-type :print :arg (parse-int arg)} | |
"4" {:op-type :undo} | |
(throw (ex-info (format "Unsupported op given: %s" | |
[op arg]) | |
{:op op :arg arg :op-str op-str}))))) | |
(def op-type->exec-fns | |
{:append {:process-fn process-op-append | |
:undo-fn undo-op-append} | |
:delete {:process-fn process-op-delete | |
:undo-fn undo-op-delete} | |
:print {:process-fn process-op-print} | |
:undo {:process-fn process-op-undo}}) | |
(def ^:dynamic *with-tracing* false) | |
(defn- print-ed-state | |
[{:keys [text undo-history]}] | |
(println (format "History: %s text: '%s'" undo-history text))) | |
(defn- exec-op | |
[ed-state {:keys [op-type] :as op}] | |
(when *with-tracing* | |
(println "*********************************************") | |
(println (format "Processing op: %s" op)) | |
(println "-- Before state:") | |
(print-ed-state ed-state) | |
(println "---------------")) | |
(let [{:keys [process-fn]} (op-type->exec-fns op-type) | |
new-ed-state (if process-fn | |
(process-fn ed-state op) | |
(throw (ex-info (format "No `:process-fn` found for op: %s" op) | |
{:op op})))] | |
(when *with-tracing* | |
(println "---------------") | |
(println "--- After state:") | |
(print-ed-state new-ed-state)) | |
new-ed-state)) | |
(defn process-input | |
[raw-ops] | |
(let [ops (mapv create-op raw-ops) | |
init-state {:text "" :undo-history []}] | |
(reduce exec-op | |
init-state | |
ops))) | |
(def input1 | |
["1 abc" | |
"1 xyz" | |
"2 3" | |
"4" | |
"3 6"]) | |
(comment | |
(do | |
(println "*********************************************") | |
(binding [*with-tracing* true] (process-input input1))) | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment