fix(search): query highlight performace

Close #11027
Close #11026
pull/10934/head
Andelf 2024-02-22 15:57:33 +08:00
parent d4dca4feb0
commit 27433ed6f8
1 changed files with 16 additions and 57 deletions

View File

@ -3,6 +3,7 @@
["remove-accents" :as remove-accents]
[rum.core :as rum]
[clojure.string :as string]
[goog.string :as gstring]
[logseq.shui.icon.v2 :as icon]
[logseq.shui.shortcut.v1 :as shortcut]))
@ -14,66 +15,24 @@
:normalize (.normalize "NFKC")
(:feature/enable-search-remove-accents? app-config) (remove-accents)))
(defn split-text-on-highlight [text query normal-text normal-query]
(let [start-index (string/index-of normal-text normal-query)
end-index (+ start-index (count query))
text-string (to-string text)]
(if start-index
[(to-string (subs text-string 0 start-index))
(to-string (subs text-string start-index end-index))
(to-string (subs text-string end-index))]
[text-string "" ""])))
(defn span-with-single-highlight-token [text query normal-text normal-query]
(let [[before-text highlighted-text after-text] (split-text-on-highlight text query normal-text normal-query)]
[:span
(when-not (string/blank? before-text) [:span before-text])
(when-not (string/blank? highlighted-text) [:span {:class "ui__list-item-highlighted-span bg-accent-06 dark:bg-accent-08-alpha"} highlighted-text])
(when-not (string/blank? after-text) [:span after-text])]))
(defn span-with-multiple-highlight-tokens [app-config text normal-query]
(let [normalized-text (normalize-text app-config text)]
(loop [[query-token & more] (string/split normal-query #" ")
result [[:text (to-string text)]]]
(if-not query-token
(->> result
(map (fn [[type value]]
(if (= type :text)
[:span value]
[:span {:class "ui__list-item-highlighted-span"} value])))
(into [:span]))
(->> result
(mapcat (fn [[type value]]
(let [include-token? (and (= type :text) (string? value)
(string/includes? normalized-text query-token))]
(if include-token?
(let [normal-value (normalize-text app-config value)
normal-query-token (normalize-text app-config query-token)
[before-text highlighted-text after-text] (split-text-on-highlight value query-token normal-value normal-query-token)]
[[:text before-text]
[:match highlighted-text]
[:text after-text]])
[[type value]]))))
(recur more))))))
(defn highlight-query* [app-config query text]
(if (vector? text) ; hiccup
text
(let [text-string (to-string text)]
(if-not (seq text-string)
[:span text-string]
(when-let [text-string (not-empty (to-string text))]
(let [normal-text (normalize-text app-config text-string)
normal-query (normalize-text app-config query)]
(cond
(and (string? query) (re-find #" " query))
(span-with-multiple-highlight-tokens app-config text-string normal-query)
;; When the match is present and only a single token, highlight that token
(string/includes? normal-text normal-query)
(span-with-single-highlight-token text-string query normal-text normal-query)
;; Otherwise, just return the text
:else
[:span text-string]))))))
normal-query (normalize-text app-config query)
query-terms (string/replace (gstring/regExpEscape normal-query) #"\s+" "|")
query-re (re-pattern (str "(" query-terms ")"))
highlighted-text (string/replace normal-text query-re "<:hlmarker>$1<:hlmarker>")
segs (string/split highlighted-text #"<:hlmarker>")]
(if (seq segs)
(into [:span]
(map-indexed (fn [i seg]
(if (even? i)
[:span seg]
[:span {:class "ui__list-item-highlighted-span"} seg]))
segs))
[:span text-string])))))
(rum/defc root [{:keys [icon icon-theme query text info shortcut value-label value
title highlighted on-highlight on-highlight-dep header on-click