Tienson Qin 1 рік тому
батько
коміт
c392a9c321

+ 9 - 6
src/main/frontend/common/search_fuzzy.cljs

@@ -8,7 +8,7 @@
 
 (defn clean-str
   [s]
-  (string/replace (string/lower-case s) #"[\[ \\/_\]\(\)]+" ""))
+  (string/lower-case (string/replace (string/lower-case s) #"[\[ \\/_\]\(\)]+" "")))
 
 (defn char-array
   [s]
@@ -31,9 +31,9 @@
 (defn score
   [oquery ostr]
   (let [query (clean-str oquery)
-        s (clean-str ostr)]
+        original-s (clean-str ostr)]
     (loop [q (seq (char-array query))
-           s (seq (char-array s))
+           s (seq (char-array original-s))
            mult 1
            idx MAX-STRING-LENGTH
            score' 0]
@@ -41,12 +41,15 @@
         ;; add str-len-distance to score, so strings with matches in same position get sorted by length
         ;; boost score if we have an exact match including punctuation
         (empty? q) (+ score'
-                      (str-len-distance query s)
+                      (str-len-distance query original-s)
                       (cond
-                        (<= 0 (.indexOf ostr oquery))
+                        (string/starts-with? original-s query)
+                        (+ MAX-STRING-LENGTH 10)
+
+                        (<= 0 (.indexOf original-s query))
                         MAX-STRING-LENGTH
 
-                        (<= 0 (.indexOf (string/lower-case ostr) (string/lower-case oquery)))
+                        (<= 0 (.indexOf original-s query))
                         (- MAX-STRING-LENGTH 0.1)
 
                         :else

+ 95 - 89
src/main/frontend/components/cmdk/core.cljs

@@ -106,7 +106,9 @@
                             (take 5 items))))
         node-exists? (let [blocks-result (keep :source-block (get-in results [:nodes :items]))]
                        (when-not (string/blank? input)
-                         (or (db/get-page (string/trim (last (string/split input "/"))))
+                         (or (some-> (last (string/split input "/"))
+                                     string/trim
+                                     db/get-page)
                              (some (fn [block]
                                      (and
                                       (:block/tags block)
@@ -223,7 +225,7 @@
                 new-result)))]))
 
 (defn- page-item
-  [repo page q]
+  [repo page]
   (let [entity (db/entity [:block/uuid (:block/uuid page)])
         source-page (model/get-alias-source-page repo (:db/id entity))
         icon (cond
@@ -235,7 +237,7 @@
                "whiteboard"
                :else
                "page")
-        title (highlight-content-query (title/block-unique-title page) q)
+        title (title/block-unique-title page)
         title' (if source-page (str title " -> alias: " (:block/title source-page)) title)]
     (hash-map :icon icon
               :icon-theme :gray
@@ -267,9 +269,11 @@
     (swap! !results assoc-in [:current-page :status] :loading)
     (p/let [blocks (search/block-search repo @!input opts)
             blocks (remove nil? blocks)
+            blocks (search/fuzzy-search blocks @!input {:limit 100
+                                                        :extract-fn :block/title})
             items (keep (fn [block]
                           (if (:page? block)
-                            (page-item repo block !input)
+                            (page-item repo block)
                             (block-item repo block current-page !input))) blocks)]
       (if (= group :current-page)
         (let [items-on-current-page (filter :current-page? items)]
@@ -656,8 +660,7 @@
          e-type (gobj/getValueByKeys e "type")
          composing-end? (= e-type "compositionend")
          !input (::input state)
-         input-ref @(::input-ref state)
-         !load-results-throttled (::load-results-throttled state)]
+         input-ref @(::input-ref state)]
 
      ;; update the input value in the UI
      (reset! !input input)
@@ -665,14 +668,9 @@
 
      (reset! (::input-changed? state) true)
 
-     ;; ensure that there is a throttled version of the load-results function
-     (when-not @!load-results-throttled
-       (reset! !load-results-throttled (gfun/throttle load-results 50)))
-
      ;; retrieve the load-results function and update all the results
      (when (or (not composing?) composing-end?)
-       (when-let [load-results-throttled @!load-results-throttled]
-         (load-results-throttled :default state))))))
+       (load-results :default state)))))
 
 (defn- open-current-item-link
   "Opens a link for the current item if a page or block. For pages, opens the
@@ -777,14 +775,23 @@
   [state all-items opts]
   (let [highlighted-item @(::highlighted-item state)
         input @(::input state)
-        input-ref (::input-ref state)]
+        input-ref (::input-ref state)
+        debounced-on-change (rum/use-callback
+                             (gfun/debounce
+                              (fn [e]
+                                (let [new-value (.-value (.-target e))]
+                                  (handle-input-change state e)
+                                  (when-let [on-change (:on-input-change opts)]
+                                    (on-change new-value))))
+                              150)
+                             [])]
     ;; use-effect [results-ordered input] to check whether the highlighted item is still in the results,
     ;; if not then clear that puppy out!
     ;; This was moved to a functional component
     (rum/use-effect! (fn []
                        (when (and highlighted-item (= -1 (.indexOf all-items (dissoc highlighted-item :mouse-enter-triggered-highlight))))
                          (reset! (::highlighted-item state) nil)))
-      [all-items])
+                     [all-items])
     (rum/use-effect! (fn [] (load-results :default state)) [])
     [:div {:class "bg-gray-02 border-b border-1 border-gray-07"}
      [:input.cp__cmdk-search-input
@@ -793,30 +800,29 @@
        :autoComplete "off"
        :placeholder (input-placeholder false)
        :ref #(when-not @input-ref (reset! input-ref %))
-       :on-change (fn [e]
-                    (let [new-value (.-value (.-target e))]
-                      (handle-input-change state e)
-                      (when-let [on-change (:on-input-change opts)]
-                        (on-change new-value))))
+       :on-change debounced-on-change
        :on-blur (fn [_e]
                   (when-let [on-blur (:on-input-blur opts)]
                     (on-blur input)))
-       :on-composition-end (fn [e] (handle-input-change state e))
-       :on-key-down (fn [e]
-                      (p/let [value (.-value @input-ref)
-                              last-char (last value)
-                              backspace? (= (util/ekey e) "Backspace")
-                              filter-group (:group @(::filter state))
-                              slash? (= (util/ekey e) "/")
-                              namespace-pages (when (and slash? (contains? #{:whiteboards} filter-group))
-                                                (search/block-search (state/get-current-repo) (str value "/") {}))
-                              namespace-page-matched? (some #(string/includes? % "/") namespace-pages)]
-                        (when (and filter-group
-                                (or (and slash? (not namespace-page-matched?))
-                                  (and backspace? (= last-char "/"))
-                                  (and backspace? (= input ""))))
-                          (reset! (::filter state) nil)
-                          (load-results :default state))))
+       :on-composition-end (gfun/debounce (fn [e] (handle-input-change state e)) 150)
+       :on-key-down (gfun/debounce
+                     (fn [e]
+                       (p/let [value (.-value @input-ref)
+                               last-char (last value)
+                               backspace? (= (util/ekey e) "Backspace")
+                               filter-group (:group @(::filter state))
+                               slash? (= (util/ekey e) "/")
+                               namespace-pages (when (and slash? (contains? #{:whiteboards} filter-group))
+                                                 (search/block-search (state/get-current-repo) (str value "/") {}))
+                               namespace-page-matched? (some #(string/includes? % "/") namespace-pages)]
+                         (when (and filter-group
+                                    (or (and slash? (not namespace-page-matched?))
+                                        (and backspace? (= last-char "/"))
+                                        (and backspace? (= input ""))))
+                           (reset! (::filter state) nil)
+                           ;; (load-results :default state)
+                           )))
+                     150)
        :default-value input}]]))
 
 (defn rand-tip
@@ -921,49 +927,48 @@
 
 (rum/defcs cmdk
   < rum/static
-    rum/reactive
-    {:will-mount
-     (fn [state]
-       (when-not (:sidebar? (last (:rum/args state)))
-         (shortcut/unlisten-all!))
-       state)
-
-     :will-unmount
-     (fn [state]
-       (when-not (:sidebar? (last (:rum/args state)))
-         (shortcut/listen-all!))
-       state)}
-    {:init (fn [state]
-             (let [search-mode (:search/mode @state/state)
-                   opts (last (:rum/args state))]
-               (assoc state
-                 ::ref (atom nil)
-                 ::filter (if (and search-mode
-                                (not (contains? #{:global :graph} search-mode))
-                                (not (:sidebar? opts)))
-                            (atom {:group search-mode})
-                            (atom nil))
-                 ::input (atom (or (:initial-input opts) "")))))
-     :will-unmount (fn [state]
-                     (state/set-state! :search/mode nil)
-                     state)}
-    (mixins/event-mixin
-      (fn [state]
-        (let [ref @(::ref state)]
-          (mixins/on-key-down state {}
-            {:target ref
-             :all-handler (fn [e _key] (keydown-handler state e))})
-          (mixins/on-key-up state {} (fn [e _key]
-                                       (keyup-handler state e))))))
-    (rum/local false ::shift?)
-    (rum/local false ::meta?)
-    (rum/local nil ::highlighted-group)
-    (rum/local nil ::highlighted-item)
-    (rum/local default-results ::results)
-    (rum/local nil ::load-results-throttled)
-    (rum/local nil ::scroll-container-ref)
-    (rum/local nil ::input-ref)
-    (rum/local false ::input-changed?)
+  rum/reactive
+  {:will-mount
+   (fn [state]
+     (when-not (:sidebar? (last (:rum/args state)))
+       (shortcut/unlisten-all!))
+     state)
+
+   :will-unmount
+   (fn [state]
+     (when-not (:sidebar? (last (:rum/args state)))
+       (shortcut/listen-all!))
+     state)}
+  {:init (fn [state]
+           (let [search-mode (:search/mode @state/state)
+                 opts (last (:rum/args state))]
+             (assoc state
+                    ::ref (atom nil)
+                    ::filter (if (and search-mode
+                                      (not (contains? #{:global :graph} search-mode))
+                                      (not (:sidebar? opts)))
+                               (atom {:group search-mode})
+                               (atom nil))
+                    ::input (atom (or (:initial-input opts) "")))))
+   :will-unmount (fn [state]
+                   (state/set-state! :search/mode nil)
+                   state)}
+  (mixins/event-mixin
+   (fn [state]
+     (let [ref @(::ref state)]
+       (mixins/on-key-down state {}
+                           {:target ref
+                            :all-handler (fn [e _key] (keydown-handler state e))})
+       (mixins/on-key-up state {} (fn [e _key]
+                                    (keyup-handler state e))))))
+  (rum/local false ::shift?)
+  (rum/local false ::meta?)
+  (rum/local nil ::highlighted-group)
+  (rum/local nil ::highlighted-item)
+  (rum/local default-results ::results)
+  (rum/local nil ::scroll-container-ref)
+  (rum/local nil ::input-ref)
+  (rum/local false ::input-changed?)
   [state {:keys [sidebar?] :as opts}]
   (let [*input (::input state)
         search-mode (:search/mode @state/state)
@@ -987,22 +992,23 @@
          (search-only state (string/capitalize (name group-filter)))])
 
       (let [items (filter
-                    (fn [[_group-name group-key group-count _group-items]]
-                      (and (not= 0 group-count)
-                        (if-not group-filter true
-                                             (or (= group-filter group-key)
-                                               (and (= group-filter :nodes)
-                                                 (= group-key :current-page))
-                                               (and (contains? #{:create} group-filter)
-                                                 (= group-key :create))))))
-                    results-ordered)]
-        (if (seq items)
+                   (fn [[_group-name group-key group-count _group-items]]
+                     (and (not= 0 group-count)
+                          (if-not group-filter true
+                                  (or (= group-filter group-key)
+                                      (and (= group-filter :nodes)
+                                           (= group-key :current-page))
+                                      (and (contains? #{:create} group-filter)
+                                           (= group-key :create))))))
+                   results-ordered)]
+        (when-not (= ["Filters"] (map first items))
+          (if (seq items)
           (for [[group-name group-key _group-count group-items] items]
             (let [title (string/capitalize group-name)]
               (result-group state title group-key group-items first-item sidebar?)))
           [:div.flex.flex-col.p-4.opacity-50
            (when-not (string/blank? @*input)
-             "No matched results")]))]
+             "No matched results")])))]
      (when-not sidebar? (hints state))]))
 
 (rum/defc cmdk-modal [props]

+ 8 - 8
src/main/frontend/components/editor.cljs

@@ -137,14 +137,14 @@
   [id format embed? db-tag? q current-pos input pos]
   (let [db? (config/db-based-graph? (state/get-current-repo))
         q (string/trim q)
-        [matched-pages set-matched-pages!] (rum/use-state nil)]
-    (rum/use-effect! (fn []
-                       (when-not (string/blank? q)
-                         (p/let [result (if db-tag?
-                                          (editor-handler/get-matched-classes q)
-                                          (editor-handler/<get-matched-blocks q {:nlp-pages? true}))]
-                           (set-matched-pages! result))))
-                     [q])
+        [matched-pages set-matched-pages!] (rum/use-state nil)
+        search-f (fn []
+                   (when-not (string/blank? q)
+                     (p/let [result (if db-tag?
+                                      (editor-handler/get-matched-classes q)
+                                      (editor-handler/<get-matched-blocks q {:nlp-pages? true}))]
+                       (set-matched-pages! result))))]
+    (rum/use-effect! search-f [(mixins/use-debounce 50 q)])
     (let [matched-pages (if (string/blank? q)
                           (->> (map (fn [title] {:block/title title
                                                  :nlp-date? true})

+ 10 - 1
src/main/frontend/mixins.cljs

@@ -3,7 +3,8 @@
   (:require [rum.core :as rum]
             [goog.dom :as dom]
             [frontend.util :refer [profile] :as util]
-            [frontend.state :as state])
+            [frontend.state :as state]
+            [goog.functions :as gfun])
   (:import [goog.events EventHandler]))
 
 (defn detach
@@ -156,3 +157,11 @@
        (profile
         (str "Render " desc)
         (render-fn state))))})
+
+(defn use-debounce
+  "A rumext custom hook that debounces the value changes"
+  [ms value]
+  (let [[state update-fn] (rum/use-state value)
+        update-fn (rum/use-callback (gfun/debounce update-fn ms) [])]
+    (rum/use-effect! #(update-fn value) #js [value])
+    state))