diff --git a/src/portal/ui/app.cljs b/src/portal/ui/app.cljs index aa6b336d..64509f66 100644 --- a/src/portal/ui/app.cljs +++ b/src/portal/ui/app.cljs @@ -25,6 +25,7 @@ [portal.ui.viewer.date-time :as date-time] [portal.ui.viewer.deref :as deref] [portal.ui.viewer.diff :as diff] + [portal.ui.viewer.diff-text :as diff-text] [portal.ui.viewer.duration :as duration] [portal.ui.viewer.edn :as edn] [portal.ui.viewer.exception :as ex] @@ -489,6 +490,7 @@ csv/viewer html/viewer diff/viewer + diff-text/viewer md/viewer hiccup/viewer date-time/viewer diff --git a/src/portal/ui/viewer/diff_text.cljs b/src/portal/ui/viewer/diff_text.cljs new file mode 100644 index 00000000..73031103 --- /dev/null +++ b/src/portal/ui/viewer/diff_text.cljs @@ -0,0 +1,124 @@ +(ns portal.ui.viewer.diff-text + (:require ["diff" :as df] + [clojure.string :as str] + [portal.colors :as c] + [portal.ui.icons :as icons] + [portal.ui.inspector :as ins] + [portal.ui.lazy :as l] + [portal.ui.styled :as d] + [portal.ui.theme :as theme])) + +(defn- changed? [^js item] + (or (some-> item .-added) + (some-> item .-removed))) + +(defn- inspect-text-diff [value] + (let [theme (theme/use-theme) + add (::c/diff-add theme) + remove (::c/diff-remove theme) + diff (df/diffLines (or (:- value) (first value)) + (or (:+ value) (second value))) + opts (ins/use-options) + bg (ins/get-background)] + [:pre + {:style {:margin 0 :white-space :pre-wrap :background bg}} + [d/div + {:style {:height (:padding theme) + :padding-left (:padding theme) + :border-top [1 :solid (::c/border theme)] + :border-left [5 :solid (::c/border theme)] + :border-right [1 :solid (::c/border theme)] + :border-top-left-radius (:border-radius theme) + :border-top-right-radius (:border-radius theme)}}] + [l/lazy-seq + (map-indexed + (fn [index [before item after]] + (let [added (.-added item) + removed (.-removed item) + text (.-value item) + border-color (cond + added add + removed remove + :else (::c/border theme))] + ^{:key index} + [d/div + {:style + {:position :relative + :border-left [5 :solid border-color] + :border-right [1 :solid border-color] + :padding [0 (:padding theme)]}} + (when (or removed added) + [d/div {:style {:position :absolute + :top 0 + :left 0 + :right 0 + :bottom 0 + :opacity 0.20 + :background (cond added add + removed remove)}}]) + (if-not (or removed added) + (if (:expanded? opts) + [ins/highlight-words text] + (let [lines (str/split-lines text)] + (if (< (count lines) 6) + [ins/highlight-words text] + [:<> + (when before + [:<> + [ins/highlight-words (str/join "\n" (take 3 lines))] + [d/div {:style {:background (::c/border theme) + :padding (:padding theme) + :text-align :center}} + [icons/ellipsis-h]]]) + (when after + [:<> + [d/div {:style {:background (::c/border theme) + :padding (:padding theme) + :text-align :center}} + [icons/ellipsis-h]] + [ins/highlight-words (str/join "\n" (take-last 3 lines))]])]))) + (cond (changed? before) + (keep-indexed + (fn [idx ^js item] + (when (or (.-added item) (not (.-removed item))) + ^{:key idx} + [d/span {:style {:background (when (.-added item) + (if added + (str add "66") + (str remove "66")))}} + [ins/highlight-words (.-value item)]])) + (df/diffChars (.-value before) text)) + (changed? after) + (keep-indexed + (fn [idx ^js item] + (when (or (.-added item) (not (.-removed item))) + ^{:key idx} + [d/span {:style {:background (when (.-added item) + (if added + (str add "66") + (str remove "66")))}} + [ins/highlight-words (.-value item)]])) + (df/diffChars (.-value after) text)) + :else text)) + + (when (or removed added) "\n")])) + (partition 3 1 (concat [nil] diff [nil])))] + [d/div + {:style {:height (:padding theme) + :padding-left (:padding theme) + :border-bottom [1 :solid (::c/border theme)] + :border-left [5 :solid (::c/border theme)] + :border-right [1 :solid (::c/border theme)] + :border-bottom-left-radius (:border-radius theme) + :border-bottom-right-radius (:border-radius theme)}}]])) + +(defn- text-diff? [value] + (and (coll? value) + (string? (first value)) + (string? (second value)))) + +(def viewer + {:predicate text-diff? + :component inspect-text-diff + :name :portal.viewer/diff-text + :doc "Diff two strings."}) \ No newline at end of file