Merge branch 'feat/db' into enhance/plugin-web

This commit is contained in:
Tienson Qin
2025-01-03 20:15:46 +08:00
committed by GitHub
20 changed files with 586 additions and 448 deletions

View File

@@ -48,69 +48,70 @@
frontend.pubsub]}
:consistent-alias
{:aliases {cljs.reader reader
cljs-time.core t
{:aliases {"/electron/utils" js-utils
"path" node-path
cljs-time.coerce tc
cljs-time.core t
cljs.reader reader
clojure.string string
datascript.core d
datascript.transit dt
datascript.db ddb
datascript.transit dt
electron.ipc ipc
electron.utils utils
"/electron/utils" js-utils
frontend.commands commands
frontend.components.block.macros block-macros
frontend.components.query query
frontend.components.query.result query-result
frontend.components.class class-component
frontend.components.property property-component
frontend.components.title title
frontend.common.date common-date
frontend.common.file.core common-file
frontend.common.file.util wfu
frontend.common.missionary-util c.m
frontend.common.schema-register sr
frontend.common.search-fuzzy fuzzy
frontend.components.block.macros block-macros
frontend.components.class class-component
frontend.components.property property-component
frontend.components.query query
frontend.components.query.result query-result
frontend.components.title title
frontend.config config
frontend.date date
frontend.db db
frontend.db-mixins db-mixins
frontend.db.query-dsl query-dsl
frontend.db.react react
frontend.db.query-custom query-custom
frontend.db.query-dsl query-dsl
frontend.db.query-react query-react
frontend.db.react react
frontend.db.util db-utils
frontend.diff diff
frontend.encrypt encrypt
frontend.extensions.sci sci
frontend.format.mldoc mldoc
frontend.format.block block
frontend.format.mldoc mldoc
frontend.fs fs
frontend.fs.memory-fs memory-fs
frontend.fs.capacitor-fs capacitor-fs
frontend.fs.memory-fs memory-fs
frontend.fs.nfs nfs
frontend.handler.extract extract
frontend.handler.common common-handler
frontend.handler.common.file file-common-handler
frontend.handler.common.plugin plugin-common-handler
frontend.handler.common.developer dev-common-handler
frontend.handler.common.file file-common-handler
frontend.handler.common.page page-common-handler
frontend.handler.common.plugin plugin-common-handler
frontend.handler.config config-handler
frontend.handler.editor.property editor-property
frontend.handler.events events
frontend.handler.global-config global-config-handler
frontend.handler.ui ui-handler
frontend.handler.notification notification
frontend.handler.page page-handler
frontend.handler.db-based.editor db-editor-handler
frontend.handler.db-based.page db-page-handler
frontend.handler.db-based.property db-property-handler
frontend.handler.db-based.property.util db-pu
frontend.handler.editor.property editor-property
frontend.handler.events events
frontend.handler.extract extract
frontend.handler.file-based.page file-page-handler
frontend.handler.file-based.property file-property-handler
frontend.handler.file-based.page-property file-page-property
frontend.handler.file-based.property file-property-handler
frontend.handler.file-based.property.util property-util
frontend.handler.file-based.recent file-recent-handler
frontend.handler.file-based.repo file-repo-handler
frontend.handler.global-config global-config-handler
frontend.handler.notification notification
frontend.handler.page page-handler
frontend.handler.plugin plugin-handler
frontend.handler.plugin-config plugin-config-handler
frontend.handler.property.file property-file
@@ -120,11 +121,12 @@
frontend.handler.repo-config repo-config-handler
frontend.handler.route route-handler
frontend.handler.search search-handler
frontend.handler.ui ui-handler
frontend.idb idb
frontend.loader loader
frontend.mixins mixins
frontend.modules.outliner.ui ui-outliner-tx
frontend.mobile.util mobile-util
frontend.modules.outliner.ui ui-outliner-tx
frontend.page page
frontend.persist-db persist-db
frontend.schema.handler.common-config common-config-schema
@@ -137,37 +139,37 @@
frontend.util.file-based.clock clock
frontend.util.file-based.drawer drawer
frontend.util.page page-util
frontend.util.property property
frontend.util.persist-var persist-var
frontend.util.property property
frontend.util.text text-util
frontend.util.url url-util
frontend.util.thingatpt thingatpt
frontend.worker.pipeline worker-pipeline
frontend.worker.util worker-util
frontend.worker.state worker-state
frontend.util.url url-util
frontend.worker.handler.page worker-page
frontend.worker.pipeline worker-pipeline
frontend.worker.state worker-state
frontend.worker.util worker-util
lambdaisland.glogi log
logseq.common.config common-config
logseq.common.graph common-graph
logseq.common.date-time-util date-time-util
logseq.common.graph common-graph
logseq.common.path path
logseq.common.util common-util
logseq.common.util.page-ref page-ref
logseq.common.util.block-ref block-ref
logseq.common.util.macro macro-util
logseq.common.util.namespace ns-util
logseq.common.util.page-ref page-ref
logseq.db ldb
logseq.db.frontend.content db-content
logseq.db.frontend.class db-class
logseq.db.frontend.content db-content
logseq.db.frontend.db-ident db-ident
logseq.db.frontend.entity-plus entity-plus
logseq.db.frontend.entity-util entity-util
logseq.db.frontend.inputs db-inputs
logseq.db.frontend.order db-order
logseq.db.frontend.property db-property
logseq.db.frontend.property.build db-property-build
logseq.db.frontend.property.type db-property-type
logseq.db.frontend.property.util db-property-util
logseq.db.frontend.entity-plus entity-plus
logseq.db.frontend.entity-util entity-util
logseq.db.frontend.rules rules
logseq.db.frontend.schema db-schema
logseq.db.frontend.validate db-validate
@@ -175,21 +177,20 @@
logseq.db.sqlite.util sqlite-util
logseq.db.test.helper db-test
logseq.graph-parser graph-parser
logseq.graph-parser.text text
logseq.graph-parser.db gp-db
logseq.graph-parser.block gp-block
logseq.graph-parser.db gp-db
logseq.graph-parser.mldoc gp-mldoc
logseq.graph-parser.property gp-property
logseq.graph-parser.text text
logseq.outliner.batch-tx batch-tx
logseq.outliner.core outliner-core
logseq.outliner.datascript-report ds-report
logseq.outliner.op outliner-op
logseq.outliner.pipeline outliner-pipeline
logseq.outliner.validate outliner-validate
logseq.outliner.datascript-report ds-report
logseq.shui.ui shui
logseq.shui.popup.core shui-popup
logseq.shui.ui shui
medley.core medley
"path" node-path
promesa.core p}}
:namespace-name-mismatch {:level :warning}

View File

@@ -0,0 +1,60 @@
(ns frontend.components.profiler
"Profiler UI"
(:require [fipp.edn :as fipp]
[frontend.handler.profiler :as profiler-handler]
[frontend.util :as util]
[logseq.shui.ui :as shui]
[rum.core :as rum]))
(rum/defcs profiler < rum/reactive
(rum/local nil ::reports)
(rum/local nil ::register-fn-name)
[state]
(let [profiling-fns (keys (rum/react profiler-handler/*fn-symbol->origin-fn))
*reports (get state ::reports)
*register-fn-name (get state ::register-fn-name)]
[:div
[:b "Profiling fns:"]
[:div.pb-4
(for [f-name profiling-fns]
[:div.flex.flex-row.items-center.gap-2
[:pre.select-text (str f-name)]
[:a.inline.close.flex.transition-opacity.duration-300.ease-in
{:title "Unregister"
:on-pointer-down
(fn [e]
(util/stop e)
(profiler-handler/unregister-fn! f-name))}
(shui/tabler-icon "x")]])]
[:div.flex.flex-row.items-center.gap-2
(shui/button
{:on-click (fn []
(when-let [fn-sym (some-> @*register-fn-name symbol)]
(profiler-handler/register-fn! fn-sym)))}
"Register fn")
[:input.form-input.my-2.py-1
{:on-change (fn [e] (reset! *register-fn-name (util/evalue e)))
:on-focus (fn [e] (let [v (.-value (.-target e))]
(when (= v "input fn name here")
(set! (.-value (.-target e)) ""))))
:placeholder "input fn name here"}]]
[:hr]
[:div.flex.gap-2.flex-wrap.items-center.pb-3
(shui/button
{:size :sm
:on-click (fn [_] (reset! *reports (profiler-handler/profile-report)))}
(shui/tabler-icon "refresh") "Refresh reports")
(shui/button
{:size :sm
:on-click (fn [_] (profiler-handler/reset-report!)
(reset! *reports (profiler-handler/profile-report)))}
(shui/tabler-icon "x") "Reset reports")]
(let [update-time-sum
(fn [m] (update-vals m (fn [m2] (update-vals m2 #(.toFixed % 6)))))]
[:div.pb-4
[:pre.select-text
(when @*reports
(-> @*reports
(update :time-sum update-time-sum)
(fipp/pprint {:width 20})
with-out-str))]])]))

View File

@@ -22,7 +22,8 @@
[frontend.db.rtc.debug-ui :as rtc-debug-ui]
[frontend.handler.route :as route-handler]
[logseq.db :as ldb]
[frontend.components.icon :as icon]))
[frontend.components.icon :as icon]
[frontend.components.profiler :as profiler]))
(rum/defc toggle
[]
@@ -133,6 +134,10 @@
[[:.flex.items-center (ui/icon "cloud" {:class "text-md mr-2"}) "(Dev) RTC"]
(rtc-debug-ui/rtc-debug-ui)]
:profiler
[[:.flex.items-center (ui/icon "cloud" {:class "text-md mr-2"}) "(Dev) Profiler"]
(profiler/profiler)]
["" [:span]]))
(defonce *drag-to
@@ -407,7 +412,12 @@
[:div.text-sm
[:button.button.cp__right-sidebar-settings-btn {:on-click (fn [_e]
(state/sidebar-add-block! repo "rtc" :rtc))}
"(Dev) RTC"]])]]
"(Dev) RTC"]])
(when (state/sub [:ui/developer-mode?])
[:div.text-sm
[:button.button.cp__right-sidebar-settings-btn {:on-click (fn [_e]
(state/sidebar-add-block! repo "profiler" :profiler))}
"(Dev) Profiler"]])]]
[:.sidebar-item-list.flex-1.scrollbar-spacing.px-2
(if @*anim-finished?

View File

@@ -1,15 +1,15 @@
(ns frontend.extensions.calc
(:refer-clojure :exclude [eval numerator denominator])
(:require [clojure.string :as str]
[frontend.util :as util]
[bignumber.js :as bn]
#?(:clj [clojure.java.io :as io])
#?(:cljs [shadow.resource :as rc])
#?(:cljs [rum.core :as rum])
(:require #?(:clj [clojure.java.io :as io])
#?(:clj [instaparse.core :as insta]
:cljs [instaparse.core :as insta :refer-macros [defparser]])))
:cljs [instaparse.core :as insta :refer-macros [defparser]])
#?(:cljs [rum.core :as rum])
#?(:cljs [shadow.resource :as rc])
[bignumber.js :as bn]
[clojure.string :as string]
[frontend.util :as util]))
;; ======================================================================
;; Interpreter
@@ -17,9 +17,8 @@
#?(:clj (def parse (insta/parser (io/resource "grammar/calc.bnf")))
:cljs (defparser parse (rc/inline "grammar/calc.bnf")))
(def constants {
"PI" (bn/BigNumber "3.14159265358979323846")
"E" (bn/BigNumber "2.71828182845904523536")})
(def constants {"PI" (bn/BigNumber "3.14159265358979323846")
"E" (bn/BigNumber "2.71828182845904523536")})
(defn exception? [e]
#?(:clj (instance? Exception e)
@@ -34,13 +33,13 @@
(defn factorial [n]
(reduce
(fn [a b] (.multipliedBy a b))
(bn/BigNumber 1)
(range 2 (inc n))))
(fn [a b] (.multipliedBy a b))
(bn/BigNumber 1)
(range 2 (inc n))))
(defn eval* [env ast]
(insta/transform
{:number (comp bn/BigNumber #(str/replace % "," ""))
{:number (comp bn/BigNumber #(string/replace % "," ""))
:percent (fn percent [a] (-> a (.dividedBy 100.00)))
:scientific bn/BigNumber
:mixed-number (fn [whole numerator denominator]
@@ -53,12 +52,12 @@
:div (fn div [a b] (-> a (.dividedBy b)))
:mod (fn mod [a b] (-> a (.modulo b)))
:pow (fn pow [a b] (if (.isInteger b)
(.exponentiatedBy a b)
#?(:clj (java.lang.Math/pow a b)
:cljs (bn/BigNumber (js/Math.pow a b)))))
(.exponentiatedBy a b)
#?(:clj (java.lang.Math/pow a b)
:cljs (bn/BigNumber (js/Math.pow a b)))))
:factorial (fn fact [a] (if (and (.isInteger a) (.isPositive a) (.isLessThan a 254))
(factorial (.toNumber a))
(bn/BigNumber 'NaN')))
(factorial (.toNumber a))
(bn/BigNumber 'NaN')))
:abs (fn abs [a] (.abs a))
:sqrt (fn sqrt [a] (.sqrt a))
:log (fn log [a]
@@ -68,24 +67,24 @@
:exp (fn exp [a]
#?(:clj (java.lang.Math/exp a) :cljs (bn/BigNumber (js/Math.exp a))))
:sin (fn sin [a]
#?(:clj (java.lang.Math/sin a) :cljs (bn/BigNumber(js/Math.sin a))))
#?(:clj (java.lang.Math/sin a) :cljs (bn/BigNumber (js/Math.sin a))))
:cos (fn cos [a]
#?(:clj (java.lang.Math/cos a) :cljs (bn/BigNumber(js/Math.cos a))))
#?(:clj (java.lang.Math/cos a) :cljs (bn/BigNumber (js/Math.cos a))))
:tan (fn tan [a]
#?(:clj (java.lang.Math/tan a) :cljs (bn/BigNumber(js/Math.tan a))))
#?(:clj (java.lang.Math/tan a) :cljs (bn/BigNumber (js/Math.tan a))))
:atan (fn atan [a]
#?(:clj (java.lang.Math/atan a) :cljs (bn/BigNumber(js/Math.atan a))))
#?(:clj (java.lang.Math/atan a) :cljs (bn/BigNumber (js/Math.atan a))))
:asin (fn asin [a]
#?(:clj (java.lang.Math/asin a) :cljs (bn/BigNumber(js/Math.asin a))))
#?(:clj (java.lang.Math/asin a) :cljs (bn/BigNumber (js/Math.asin a))))
:acos (fn acos [a]
#?(:clj (java.lang.Math/acos a) :cljs (bn/BigNumber(js/Math.acos a))))
#?(:clj (java.lang.Math/acos a) :cljs (bn/BigNumber (js/Math.acos a))))
:assignment (fn assign! [var val]
(if (contains? constants var)
(throw
(ex-info (util/format "Can't redefine constant %s" var) {:var var}))
(ex-info (util/format "Can't redefine constant %s" var) {:var var}))
(swap! env assoc var val))
val)
:toassign str/trim
:toassign string/trim
:comment (constantly nil)
:digits int
:format-fix (fn format [places]
@@ -95,21 +94,21 @@
(swap! env assoc :mode "sci" :places places)
(get @env "last"))
:format-frac (fn format [max-denominator]
(swap! env dissoc :mode :improper)
(swap! env assoc :mode "frac" :max-denominator max-denominator)
(get @env "last"))
(swap! env dissoc :mode :improper)
(swap! env assoc :mode "frac" :max-denominator max-denominator)
(get @env "last"))
:format-impf (fn format [max-denominator]
(swap! env assoc :mode "frac" :max-denominator max-denominator :improper true)
(get @env "last"))
(swap! env assoc :mode "frac" :max-denominator max-denominator :improper true)
(get @env "last"))
:format-norm (fn format [precision]
(swap! env dissoc :mode :places)
(swap! env assoc :precision precision)
(get @env "last"))
(swap! env dissoc :mode :places)
(swap! env assoc :precision precision)
(get @env "last"))
:base (fn base [b]
(swap! env assoc :base (str/lower-case b))
(swap! env assoc :base (string/lower-case b))
(get @env "last"))
:variable (fn resolve [var]
(let [var (str/trim var)]
(let [var (string/trim var)]
(or (get constants var)
(get @env var)
(throw
@@ -136,12 +135,12 @@
"Check that number can render without loss of all significant digits,
and that the absolute value is less than 1e21."
[num' places]
(or (.isZero num' )
(let [mag (.abs num')
lower-bound (-> (bn/BigNumber 0.5) (.shiftedBy (- places)))
upper-bound (bn/BigNumber 1e21)]
(and (-> mag (.isGreaterThanOrEqualTo lower-bound))
(-> mag (.isLessThan upper-bound))))))
(or (.isZero num')
(let [mag (.abs num')
lower-bound (-> (bn/BigNumber 0.5) (.shiftedBy (- places)))
upper-bound (bn/BigNumber 1e21)]
(and (-> mag (.isGreaterThanOrEqualTo lower-bound))
(-> mag (.isLessThan upper-bound))))))
(defn can-fit?
"Check that number can render normally within the given number of digits.
@@ -152,16 +151,16 @@
(defn format-base [val base]
(let [sign (.-s val)
display-val (if (neg-int? sign) (.abs val) val)]
display-val (if (neg-int? sign) (.abs val) val)]
(str
(when (neg-int? sign) "-")
(case base 2 "0b" 8 "0o" 16 "0x")
(.toString display-val base))))
(when (neg-int? sign) "-")
(case base 2 "0b" 8 "0o" 16 "0x")
(.toString display-val base))))
(defn format-fraction [numerator denominator improper]
(let [whole (.dividedToIntegerBy numerator denominator)]
(if (or improper (.isZero whole))
(str numerator "/" denominator )
(str numerator "/" denominator)
(str whole " "
(.abs (.modulo numerator denominator)) "/" denominator))))
@@ -179,40 +178,40 @@
places (get @env :places)]
(cond
(= base "hex")
(format-base val 16)
(format-base val 16)
(= base "oct")
(format-base val 8)
(format-base val 8)
(= base "bin")
(format-base val 2)
(format-base val 2)
(= mode "fix")
(if (can-fix? val places)
(.toFixed val places)
(.toExponential val places))
(if (can-fix? val places)
(.toFixed val places)
(.toExponential val places))
(= mode "sci")
(.toExponential val places)
(.toExponential val places)
(= mode "frac")
(let [max-denominator (or (get @env :max-denominator) 4095)
improper (get @env :improper)
[numerator denominator] (.toFraction val max-denominator)
delta (.minus (.dividedBy numerator denominator) val)]
(if (or (.isZero delta) (< (.-e delta) -16))
(if (> denominator 1)
(format-fraction numerator denominator improper)
(format-normal env numerator))
(format-normal env val)))
(let [max-denominator (or (get @env :max-denominator) 4095)
improper (get @env :improper)
[numerator denominator] (.toFraction val max-denominator)
delta (.minus (.dividedBy numerator denominator) val)]
(if (or (.isZero delta) (< (.-e delta) -16))
(if (> denominator 1)
(format-fraction numerator denominator improper)
(format-normal env numerator))
(format-normal env val)))
:else
(format-normal env val)))
(format-normal env val)))
val))
(defn eval-lines [s]
{:pre [(string? s)]}
(let [env (new-env)]
(mapv (fn [line]
(when-not (str/blank? line)
(when-not (string/blank? line)
(format-val env (assign-last-value env (eval env (parse line))))))
(str/split-lines s))))
(string/split-lines s))))
;; ======================================================================
;; UI
@@ -225,7 +224,7 @@
;; if we stop click propagation on this element, we allow the user to
;; copy and paste the calc results
[:div.extensions__code-calc.pr-2 {:on-pointer-down (fn [e]
(.stopPropagation e))}
(.stopPropagation e))}
;; TODO: add react keys
(for [[i line] (map-indexed vector output-lines)]
[:div.extensions__code-calc-output-line.CodeMirror-line {:key i}

View File

@@ -1,13 +1,13 @@
(ns frontend.extensions.video.youtube
(:require [rum.core :as rum]
[cljs.core.async :refer [<! chan go] :as a]
(:require [cljs.core.async :refer [<! chan go] :as a]
[clojure.string :as string]
[frontend.components.svg :as svg]
[frontend.handler.notification :as notification]
[frontend.mobile.util :as mobile-util]
[frontend.state :as state]
[frontend.util :as util]
[goog.object :as gobj]
[clojure.string :as str]
[frontend.mobile.util :as mobile-util]
[frontend.handler.notification :as notification]))
[rum.core :as rum]))
(defn- load-yt-script []
(js/console.log "load yt script")
@@ -79,7 +79,7 @@
(when (or (> idx 0)
(not= v "00"))
v)))
(str/join ":"))))
(string/join ":"))))
(defn dom-after-video-node? [video-node target]
(not (zero?
@@ -92,11 +92,11 @@
(filter
(fn [node]
(let [src (gobj/get node "src" "")]
(str/includes? src "youtube.com"))))
(string/includes? src "youtube.com"))))
(filter #(dom-after-video-node? % target))
last)]
(let [id (gobj/get iframe "id" "")
id (str/replace-first id #"youtube-player-" "")]
id (string/replace-first id #"youtube-player-" "")]
(get (get @state/state :youtube/players) id))))
(rum/defc timestamp

View File

@@ -1,7 +1,7 @@
(ns frontend.extensions.zotero
(:require [cljs.core.async :refer [<! >! chan go go-loop] :as a]
[clojure.edn :refer [read-string]]
[clojure.string :as str]
[clojure.string :as string]
[frontend.components.svg :as svg]
[frontend.extensions.pdf.assets :as pdf-assets]
[frontend.extensions.zotero.api :as api]
@@ -29,7 +29,7 @@
{:on-click (fn [] (go
(set-is-creating-page! true)
(<!
(zotero-handler/create-zotero-page item {:block-dom-id id}))
(zotero-handler/create-zotero-page item {:block-dom-id id}))
(set-is-creating-page! false)))}
[[:div [[:span.font-medium.mb-1.mr-1.text-sm title]
[:span.zotero-search-item-type.text-xs.p-1.rounded type]]]
@@ -51,7 +51,7 @@
search-fn (fn [s-term start]
(go
(when-not (str/blank? s-term)
(when-not (string/blank? s-term)
(set-is-searching! true)
(let [{:keys [success next prev result] :as response}
@@ -68,16 +68,16 @@
(set-is-searching! false))))]
(rum/use-effect!
(fn []
(let [d-chan (chan)]
(a/tap debounce-chan-mult d-chan)
(go-loop []
(let [d-term (<! d-chan)]
(<! (search-fn d-term "0")))
(recur))
(fn []
(let [d-chan (chan)]
(a/tap debounce-chan-mult d-chan)
(go-loop []
(let [d-term (<! d-chan)]
(<! (search-fn d-term "0")))
(recur))
(fn [] (a/untap debounce-chan-mult d-chan))))
[])
(fn [] (a/untap debounce-chan-mult d-chan))))
[])
(when-not (setting/valid?)
(route-handler/redirect! {:to :zotero-setting})
@@ -103,24 +103,24 @@
(when (seq search-result)
[:div.p-2
(map
(fn [item] (rum/with-key (zotero-search-item item id) (:key item)))
search-result)
(fn [item] (rum/with-key (zotero-search-item item id) (:key item)))
search-result)
;; pagination
(when-not (str/blank? prev-page)
(when-not (string/blank? prev-page)
(ui/button
"prev"
:on-click
(fn []
(set! (.-scrollTop (.-parentNode (gdom/getElement "zotero-search"))) 0)
(search-fn prev-search-term prev-page))))
(when-not (str/blank? next-page)
"prev"
:on-click
(fn []
(set! (.-scrollTop (.-parentNode (gdom/getElement "zotero-search"))) 0)
(search-fn prev-search-term prev-page))))
(when-not (string/blank? next-page)
(ui/button
"next"
:on-click
(fn []
(set! (.-scrollTop (.-parentNode (gdom/getElement "zotero-search"))) 0)
(search-fn prev-search-term next-page))))])]))
"next"
:on-click
(fn []
(set! (.-scrollTop (.-parentNode (gdom/getElement "zotero-search"))) 0)
(search-fn prev-search-term next-page))))])]))
(rum/defcs user-or-group-setting <
(rum/local (setting/setting :type-id) ::type-id)
@@ -137,11 +137,11 @@
{:value (-> (setting/setting :type) name)
:on-change (fn [e]
(let [type (-> (util/evalue e)
(str/lower-case)
(string/lower-case)
keyword)]
(setting/set-setting! :type type)))}
(for [type (map name [:user :group])]
[:option {:key type :value type} (str/capitalize type)])]]]]
[:option {:key type :value type} (string/capitalize type)])]]]]
[:div.row
[:label.title.w-72
@@ -156,15 +156,15 @@
:on-change (fn [e] (reset! (::type-id state) (util/evalue e)))}]]]]
(when
(and (not (str/blank? (str @(::type-id state))))
(not (re-matches #"^\d+$" (str @(::type-id state)))))
(and (not (string/blank? (str @(::type-id state))))
(not (re-matches #"^\d+$" (str @(::type-id state)))))
(ui/admonition
:warning
[:p.text-error
"User ID is different from username and can be found on the "
[:a {:href "https://www.zotero.org/settings/keys" :target "_blank"}
"https://www.zotero.org/settings/keys"]
" page, it's a number of digits"]))])
:warning
[:p.text-error
"User ID is different from username and can be found on the "
[:a {:href "https://www.zotero.org/settings/keys" :target "_blank"}
"https://www.zotero.org/settings/keys"]
" page, it's a number of digits"]))])
(rum/defc overwrite-mode-setting <
rum/reactive
@@ -181,9 +181,9 @@
true)]]]
(when (setting/setting :overwrite-mode?)
(ui/admonition
:warning
[:p.text-error
"Dangerous! This will delete and recreate Zotero existing page! Make sure to backup your notes first in case something goes wrong. Make sure you don't put any personal item in previous Zotero page and it's OK to overwrite the page!"]))])
:warning
[:p.text-error
"Dangerous! This will delete and recreate Zotero existing page! Make sure to backup your notes first in case something goes wrong. Make sure you don't put any personal item in previous Zotero page and it's OK to overwrite the page!"]))])
(rum/defc attachment-setting <
rum/reactive
@@ -335,15 +335,15 @@
[:div.mt-5.sm:mt-4.sm:flex.sm:flex-row-reverse
[:span.flex.w-full.rounded-md.shadow-sm.sm:ml-3.sm:w-auto
(ui/button
"Submit"
:class "ui__modal-enter"
:on-click (fn []
(let [profile-name (str/trim @input)]
(when-not (str/blank? profile-name)
(p/let [_ (setting/add-profile profile-name)
_ (setting/set-profile profile-name)]
(reset! profile* profile-name)))
(shui/dialog-close!))))]
"Submit"
:class "ui__modal-enter"
:on-click (fn []
(let [profile-name (string/trim @input)]
(when-not (string/blank? profile-name)
(p/let [_ (setting/add-profile profile-name)
_ (setting/set-profile profile-name)]
(reset! profile* profile-name)))
(shui/dialog-close!))))]
[:span.mt-3.flex.w-full.rounded-md.sm:mt-0.sm:w-auto
(ui/button "Cancel" {:variant :ghost :on-click close-fn :class "opacity-70 hover:opacity-100"})]]]))
@@ -366,25 +366,25 @@
:value x}
x]) (setting/all-profiles))]
(ui/button
"New profile"
:small? true
:class "ml-4"
:on-click
(fn []
(shui/dialog-open!
(fn [{:keys [close]}]
(profile-name-dialog-inner profile* close))
{:align :center
:auto-width? true})))
"New profile"
:small? true
:class "ml-4"
:on-click
(fn []
(shui/dialog-open!
(fn [{:keys [close]}]
(profile-name-dialog-inner profile* close))
{:align :center
:auto-width? true})))
(ui/button
"Delete profile!"
:small? true
:background "red"
:class "ml-4"
:on-click
(fn []
(p/let [_ (setting/remove-profile @profile*)]
(reset! profile* (setting/get-profile)))))]])
"Delete profile!"
:small? true
:background "red"
:class "ml-4"
:on-click
(fn []
(p/let [_ (setting/remove-profile @profile*)]
(reset! profile* (setting/get-profile)))))]])
(rum/defcs add-all-items <
(rum/local nil ::progress)
@@ -399,24 +399,24 @@
"Add all zotero items"]
[:div.mt-1.sm:mt-0.sm:col-span-2
(ui/button
@(::fetching-button state)
:on-click
(fn []
(go
(let [_ (reset! (::fetching-button state) "Fetching..")
total (<! (api/all-top-items-count))
_ (reset! (::fetching-button state) "Add all")]
(when (.confirm
js/window
(str "This will import all your zotero items and add total number of " total " pages. Do you wish to continue?"))
@(::fetching-button state)
:on-click
(fn []
(go
(let [_ (reset! (::fetching-button state) "Fetching..")
total (<! (api/all-top-items-count))
_ (reset! (::fetching-button state) "Add all")]
(when (.confirm
js/window
(str "This will import all your zotero items and add total number of " total " pages. Do you wish to continue?"))
(reset! (::total state) total)
(<! (zotero-handler/add-all (::progress state)))
(reset! (::total state) false)
(notification/show! "Successfully added all items!" :success))))))]]
(reset! (::total state) total)
(<! (zotero-handler/add-all (::progress state)))
(reset! (::total state) false)
(notification/show! "Successfully added all items!" :success))))))]]
(ui/admonition
:warning
"If you have a lot of items in Zotero, adding them all can slow down Logseq. You can type /zotero to import specific item on demand instead.")
:warning
"If you have a lot of items in Zotero, adding them all can slow down Logseq. You can type /zotero to import specific item on demand instead.")
(when @(::total state)
[:div.row
@@ -464,43 +464,43 @@
(add-all-items)])
(defn open-button [full-path]
(if (str/ends-with? (str/lower-case full-path) "pdf")
(if (string/ends-with? (string/lower-case full-path) "pdf")
(ui/button
"open"
:small? true
:on-click
(fn [e]
(when-let [current (pdf-assets/inflate-asset full-path)]
(util/stop e)
(state/set-state! :pdf/current current))))
"open"
:small? true
:on-click
(fn [e]
(when-let [current (pdf-assets/inflate-asset full-path)]
(util/stop e)
(state/set-state! :pdf/current current))))
(ui/button
"open"
:small? true
:target "_blank"
:href full-path)))
"open"
:small? true
:target "_blank"
:href full-path)))
(rum/defc zotero-imported-file
[item-key filename]
(if (str/blank? (setting/setting :zotero-data-directory))
(if (string/blank? (setting/setting :zotero-data-directory))
[:p.warning "This is a zotero imported file, setting Zotero data directory would allow you to open the file in Logseq"]
(let [filename (read-string filename)
full-path
(str "file://"
(util/node-path.join
(setting/setting :zotero-data-directory)
"storage"
item-key
filename))]
(setting/setting :zotero-data-directory)
"storage"
item-key
filename))]
(open-button full-path))))
(rum/defc zotero-linked-file
[path]
(if (str/blank? (setting/setting :zotero-linked-attachment-base-directory))
(if (string/blank? (setting/setting :zotero-linked-attachment-base-directory))
[:p.warning "This is a zotero linked file, setting Zotero linked attachment base directory would allow you to open the file in Logseq"]
(let [path (read-string path)
full-path
(str "file://"
(util/node-path.join
(setting/setting :zotero-linked-attachment-base-directory)
(str/replace-first path "attachments:" "")))]
(setting/setting :zotero-linked-attachment-base-directory)
(string/replace-first path "attachments:" "")))]
(open-button full-path))))

View File

@@ -4,9 +4,9 @@
[cljs-http.client :as http]
[cljs.core.async :as async
:refer [<! >! alt! chan close! go go-loop]]
[clojure.string :as str]
[frontend.util :as util]
[frontend.extensions.zotero.setting :as setting]))
[clojure.string :as string]
[frontend.extensions.zotero.setting :as setting]
[frontend.util :as util]))
(defn config []
{:api-version 3
@@ -39,14 +39,14 @@
:next "rel=\"next\""
:prev "rel=\"prev\"")
links
(str/split
(string/split
(:link (cske/transform-keys csk/->kebab-case-keyword headers)) ",")
next-link (->> links
(filter (fn [l] (str/includes? l include-text)))
(filter (fn [l] (string/includes? l include-text)))
first)]
(when next-link
(let [start (str/index-of next-link "<")
end (str/last-index-of next-link ">;")
(let [start (string/index-of next-link "<")
end (string/last-index-of next-link ">;")
next-url (subs next-link (inc start) end)]
(or
(->

View File

@@ -1,15 +1,15 @@
(ns frontend.extensions.zotero.handler
(:require [cljs.core.async :refer [<! go]]
[cljs.core.async.interop :refer [p->c]]
[clojure.string :as str]
[clojure.string :as string]
[frontend.db :as db]
[frontend.extensions.zotero.api :as zotero-api]
[frontend.extensions.zotero.extractor :as extractor]
[frontend.extensions.zotero.setting :as setting]
[frontend.handler.notification :as notification]
[frontend.state :as state]
[frontend.handler.editor :as editor-handler]
[frontend.handler.notification :as notification]
[frontend.handler.page :as page-handler]
[frontend.db :as db]
[frontend.state :as state]
[logseq.common.util.page-ref :as page-ref]
[promesa.core :as p]))
@@ -31,7 +31,7 @@
(let [items (<! (api-fn key))
md-items (->> items
(map extractor/extract)
(remove str/blank?))]
(remove string/blank?))]
(when (not-empty md-items)
(p->c
(p/let [result (editor-handler/api-insert-new-block! first-block {:page page-name})]
@@ -52,7 +52,7 @@
(defn- create-abstract-note!
[page-name abstract-note]
(when-not (str/blank? abstract-note)
(when-not (string/blank? abstract-note)
(p/let [block (editor-handler/api-insert-new-block!
"[[Abstract]]" {:page page-name})]
(editor-handler/api-insert-new-block!
@@ -76,8 +76,8 @@
(let [{:keys [page-name properties abstract-note]} (extractor/extract item)]
(p->c
(p/do!
(when-not (str/blank? page-name)
(if (db/page-exists? (str/lower-case page-name) "page")
(when-not (string/blank? page-name)
(if (db/page-exists? (string/lower-case page-name) "page")
;; FIXME: Overwrite if it has a zotero tag (which means created by Zotero)
(if (setting/setting :overwrite-mode?)
(page-handler/<delete!

View File

@@ -1,9 +1,9 @@
(ns frontend.extensions.zotero.setting
(:require [clojure.string :as str]
[promesa.core :as p]
(:require [clojure.string :as string]
[frontend.handler.config :as config-handler]
[frontend.state :as state]
[frontend.storage :as storage]))
[frontend.storage :as storage]
[promesa.core :as p]))
(def default-settings
{:type :user
@@ -71,5 +71,5 @@
(defn valid? []
(and
(not (str/blank? (api-key)))
(not (str/blank? (setting :type-id)))))
(not (string/blank? (api-key)))
(not (string/blank? (setting :type-id)))))

View File

@@ -1,6 +1,6 @@
(ns ^:no-doc frontend.external.roam-export
(:require [clojure.set :as s]
[clojure.string :as str]
[clojure.string :as string]
[clojure.walk :as walk]
[frontend.db.async :as db-async]
[frontend.state :as state]
@@ -18,7 +18,7 @@
(defn nano-id []
(->> (repeatedly 9 nano-id-char)
(str/join)))
(string/join)))
(defn <uuid->uid-map []
(let [repo (state/get-current-repo)]
@@ -36,13 +36,13 @@
(defn update-content [content uuid->uid-map]
(when content ; page block doesn't have content
(let [uuids (keys uuid->uid-map)]
(reduce
(fn [acc uuid]
(if (str/includes? acc (str uuid))
(str/replace acc (str uuid) (get uuid->uid-map uuid))
acc))
content
uuids))))
(reduce
(fn [acc uuid]
(if (string/includes? acc (str uuid))
(string/replace acc (str uuid) (get uuid->uid-map uuid))
acc))
content
uuids))))
(defn update-uid [{:block/keys [uuid title] :as b}
uuid->uid-map]
@@ -50,7 +50,7 @@
(contains? uuid->uid-map uuid)
(assoc :block/uid (get uuid->uid-map uuid))
(some (fn [id] (str/includes? (str title) (str id))) (keys uuid->uid-map))
(some (fn [id] (string/includes? (str title) (str id))) (keys uuid->uid-map))
(update :block/title #(update-content % uuid->uid-map))))
(defn update-todo [{:block/keys [title] :as block}]
@@ -58,10 +58,10 @@
(update block :block/title
(fn [c]
(-> c
(str/replace todo-marker-regex "{{[[TODO]]}}")
(str/replace done-marker-regex "{{[[DONE]]}}")
(str/replace "{{embed " "{{embed: ")
(str/trim))))
(string/replace todo-marker-regex "{{[[TODO]]}}")
(string/replace done-marker-regex "{{[[DONE]]}}")
(string/replace "{{embed " "{{embed: ")
(string/trim))))
block))
(defn traverse

View File

@@ -0,0 +1,62 @@
(ns frontend.handler.profiler
"Provides fns for profiling.
TODO: support both main thread and worker thread."
(:require [goog.object :as g]))
(def ^:private *fn-symbol->key->call-count (volatile! {}))
(def ^:private *fn-symbol->key->time-sum (volatile! {}))
(def *fn-symbol->origin-fn (atom {}))
(defn- get-profile-fn
[fn-sym original-fn custom-key-fn]
(fn profile-fn-inner [& args]
(let [start (system-time)
r (apply original-fn args)
elapsed-time (- (system-time) start)
k (when custom-key-fn (custom-key-fn r))]
(vswap! *fn-symbol->key->call-count update-in [fn-sym :total] inc)
(vswap! *fn-symbol->key->time-sum update-in [fn-sym :total] #(+ % elapsed-time))
(when k
(vswap! *fn-symbol->key->call-count update-in [fn-sym k] inc)
(vswap! *fn-symbol->key->time-sum update-in [fn-sym k] #(+ % elapsed-time)))
r)))
(defn register-fn!
[fn-sym & {:keys [custom-key-fn] :as _opts}]
(assert (qualified-symbol? fn-sym))
(let [ns (namespace fn-sym)
s (munge (name fn-sym))]
(if-let [original-fn (find-ns-obj (str ns "." s))]
(let [profiled-fn (get-profile-fn fn-sym original-fn custom-key-fn)]
(swap! *fn-symbol->origin-fn assoc fn-sym original-fn)
(g/set (find-ns-obj ns) s profiled-fn))
(throw (ex-info (str "fn-sym not found: " fn-sym) {})))))
(defn unregister-fn!
[fn-sym]
(let [ns (namespace fn-sym)
s (munge (name fn-sym))]
(vswap! *fn-symbol->key->call-count dissoc fn-sym)
(vswap! *fn-symbol->key->time-sum dissoc fn-sym)
(when-let [origin-fn (get @*fn-symbol->origin-fn fn-sym)]
(some-> (find-ns-obj ns) (g/set s origin-fn))
(swap! *fn-symbol->origin-fn dissoc fn-sym))))
(defn reset-report!
[]
(vreset! *fn-symbol->key->call-count {})
(vreset! *fn-symbol->key->time-sum {}))
(defn profile-report
[]
{:call-count @*fn-symbol->key->call-count
:time-sum @*fn-symbol->key->time-sum})
(comment
(register-fn! 'datascript.core/entity)
(prn :profiling (keys @*fn-symbol->origin-fn))
(prn :report)
(pprint/pprint (profile-report))
(reset-report!)
(unregister-fn! 'datascript.core/entity))

View File

@@ -1,6 +1,6 @@
(ns frontend.modules.shortcut.config
(:require [clojure.data :as data]
[clojure.string :as str]
[clojure.string :as string]
[electron.ipc :as ipc]
[frontend.commands :as commands]
[frontend.components.commit :as commit]
@@ -1026,7 +1026,7 @@
(swap! *config assoc-in [handler-id id] shortcut-map)
(when-not config-only?
(swap! *shortcut-cmds assoc id (:cmd shortcut-map))
(let [plugin? (str/starts-with? (str id) ":plugin.")
(let [plugin? (string/starts-with? (str id) ":plugin.")
category (or (:category shortcut-map)
(if plugin?
:shortcut.category/plugins

View File

@@ -1,11 +1,11 @@
(ns frontend.modules.shortcut.core
(:require [clojure.string :as str]
(:require [clojure.string :as string]
[frontend.handler.config :as config-handler]
[frontend.handler.global-config :as global-config-handler]
[frontend.handler.plugin :as plugin-handler]
[frontend.handler.notification :as notification]
[frontend.modules.shortcut.data-helper :as dh]
[frontend.handler.plugin :as plugin-handler]
[frontend.modules.shortcut.config :as shortcut-config]
[frontend.modules.shortcut.data-helper :as dh]
[frontend.modules.shortcut.utils :as shortcut-utils]
[frontend.state :as state]
[frontend.util :as util]
@@ -20,10 +20,10 @@
(defonce *pending-shortcuts (atom []))
(def global-keys #js
[KeyCodes/TAB
KeyCodes/ENTER
KeyCodes/BACKSPACE KeyCodes/DELETE
KeyCodes/UP KeyCodes/LEFT KeyCodes/DOWN KeyCodes/RIGHT])
[KeyCodes/TAB
KeyCodes/ENTER
KeyCodes/BACKSPACE KeyCodes/DELETE
KeyCodes/UP KeyCodes/LEFT KeyCodes/DOWN KeyCodes/RIGHT])
(def key-names (js->clj KeyNames))
@@ -82,7 +82,7 @@
(log/error :shortcut/register-shortcut {:id id
:binding k
:error e})
(notification/show! (str/join " " [id k (.-message e)]) :error false)))))))))
(notification/show! (string/join " " [id k (.-message e)]) :error false)))))))))
(defn unregister-shortcut!
"Unregister a shortcut.
@@ -114,9 +114,9 @@
;; force uninstall existed handler
(some->>
(get-installed-ids-by-handler-id handler-id)
(map #(uninstall-shortcut-handler! % true))
(doall))
(get-installed-ids-by-handler-id handler-id)
(map #(uninstall-shortcut-handler! % true))
(doall))
(let [shortcut-map (dh/shortcuts-map-by-handler-id handler-id state)
handler (new KeyboardShortcutHandler js/window)]
@@ -167,25 +167,25 @@
([handler-id] (mixin handler-id true))
([handler-id remount-reinstall?]
(cond->
{:did-mount
(fn [state]
(let [install-id (install-shortcut-handler! handler-id {:state state})]
(assoc state ::install-id install-id)))
{:did-mount
(fn [state]
(let [install-id (install-shortcut-handler! handler-id {:state state})]
(assoc state ::install-id install-id)))
:will-unmount
(fn [state]
(when-let [install-id (::install-id state)]
(uninstall-shortcut-handler! install-id))
state)}
:will-unmount
(fn [state]
(when-let [install-id (::install-id state)]
(uninstall-shortcut-handler! install-id))
state)}
remount-reinstall?
(assoc
:will-remount
(fn [old-state new-state]
(util/profile "[shortcuts] reinstalled:"
(uninstall-shortcut-handler! (::install-id old-state))
(when-let [install-id (install-shortcut-handler! handler-id {:state new-state})]
(assoc new-state ::install-id install-id))))))))
:will-remount
(fn [old-state new-state]
(util/profile "[shortcuts] reinstalled:"
(uninstall-shortcut-handler! (::install-id old-state))
(when-let [install-id (install-shortcut-handler! handler-id {:state new-state})]
(assoc new-state ::install-id install-id))))))))
(defn mixin*
"This is an optimized version compared to (mixin).
@@ -197,7 +197,7 @@
(let [*state (volatile! state)
install-id (install-shortcut-handler! handler-id {:state *state})]
(assoc state ::install-id install-id
::*state *state)))
::*state *state)))
:will-remount
(fn [old-state new-state]
@@ -260,10 +260,10 @@
shift (.-shiftKey e)
keyname (get key-names (str (.-keyCode e)))]
(cond->> keyname
ctrl (str "ctrl+")
alt (str "alt+")
meta (str "meta+")
shift (str "shift+"))))
ctrl (str "ctrl+")
alt (str "alt+")
meta (str "meta+")
shift (str "shift+"))))
(defn keyname [e]
(let [name (get key-names (str (.-keyCode e)))]
@@ -283,9 +283,9 @@
(dissoc id)
(and global?
(or (string? binding)
(vector? binding)
(boolean? binding)))
(or (string? binding)
(vector? binding)
(boolean? binding)))
(assoc id binding)))]
;; TODO: exclude current graph config shortcuts
(config-handler/set-config! :shortcuts (into-shortcuts graph-shortcuts))

View File

@@ -1,7 +1,7 @@
(ns frontend.modules.shortcut.data-helper
(:require [clojure.set :refer [rename-keys] :as set]
[clojure.string :as str]
[cljs-bean.core :as bean]
(:require [cljs-bean.core :as bean]
[clojure.set :refer [rename-keys] :as set]
[clojure.string :as string]
[frontend.context.i18n :refer [t]]
[frontend.modules.shortcut.config :as shortcut-config]
[frontend.modules.shortcut.utils :as shortcut-utils]
@@ -20,27 +20,27 @@
{id (if binding-only?
(get user-shortcuts id binding)
(assoc opts :user-binding (get user-shortcuts id)
:handler-id (get-group id)
:id id))}))
:handler-id (get-group id)
:id id))}))
(into {})))
(defn- flatten-bindings-by-key
[config user-shortcuts]
(reduce-kv
(fn [r handler-id vs]
(reduce-kv
(fn [r id {:keys [binding]}]
(if-let [ks (get user-shortcuts id binding)]
(let [ks (if (sequential? ks) ks [ks])]
(reduce (fn [a k]
(let [k (shortcut-utils/undecorate-binding k)
k' (shortcut-utils/safe-parse-string-binding k)
k' (bean/->clj k')]
(-> a
(assoc-in [k' :key] k)
(assoc-in [k' :refs id] handler-id)))) r ks))
r)) r vs))
{} config))
(fn [r handler-id vs]
(reduce-kv
(fn [r id {:keys [binding]}]
(if-let [ks (get user-shortcuts id binding)]
(let [ks (if (sequential? ks) ks [ks])]
(reduce (fn [a k]
(let [k (shortcut-utils/undecorate-binding k)
k' (shortcut-utils/safe-parse-string-binding k)
k' (bean/->clj k')]
(-> a
(assoc-in [k' :key] k)
(assoc-in [k' :refs id] handler-id)))) r ks))
r)) r vs))
{} config))
(def m-flatten-bindings-by-id
(util/memoize-last flatten-bindings-by-id))
@@ -65,13 +65,13 @@
(let [{:keys [id desc cmd]} binding-map
desc (or desc (:desc cmd) (some-> id (shortcut-utils/decorate-namespace) (t)))]
(if (or (nil? desc)
(and (string? desc) (str/starts-with? desc "{Missing")))
(and (string? desc) (string/starts-with? desc "{Missing")))
(str id) desc)))
(defn mod-key [shortcut]
(when (string? shortcut)
(str/replace shortcut #"(?i)mod"
(if util/mac? "meta" "ctrl"))))
(string/replace shortcut #"(?i)mod"
(if util/mac? "meta" "ctrl"))))
(defn shortcut-binding
"override by user custom binding"
@@ -88,10 +88,10 @@
:else
(->>
(if (string? shortcut)
[shortcut]
shortcut)
(mapv mod-key)))))
(if (string? shortcut)
[shortcut]
shortcut)
(mapv mod-key)))))
(defn shortcut-item
[id]
@@ -102,14 +102,14 @@
(let [dict (get-bindings-ids-map)
plugin? (= name :shortcut.category/plugins)]
(->> (if plugin?
(->> (keys dict) (filter #(str/starts-with? (str %) ":plugin.")))
(->> (keys dict) (filter #(string/starts-with? (str %) ":plugin.")))
(shortcut-config/get-category-shortcuts name))
(mapv (fn [k] [k (assoc (get dict k) :category name)])))))
(defn shortcuts-map-full
[]
(->> (vals @shortcut-config/*config)
(into {})))
(into {})))
(defn shortcuts-map-by-handler-id
([handler-id]
@@ -123,15 +123,15 @@
(into {}))
before (-> raw meta :before)]
(cond->> handler-m
state (reduce-kv (fn [r k handle-fn]
(let [handle-fn' (if (volatile? state)
(fn [*state & args] (apply handle-fn (cons @*state args)))
handle-fn)]
(assoc r k (partial handle-fn' state))))
{})
before (reduce-kv (fn [r k f]
(assoc r k (before f (get raw' k))))
{})))))
state (reduce-kv (fn [r k handle-fn]
(let [handle-fn' (if (volatile? state)
(fn [*state & args] (apply handle-fn (cons @*state args)))
handle-fn)]
(assoc r k (partial handle-fn' state))))
{})
before (reduce-kv (fn [r k f]
(assoc r k (before f (get raw' k))))
{})))))
;; if multiple bindings, gen seq for first binding only for now
(defn gen-shortcut-seq [id]
@@ -139,8 +139,8 @@
(if (false? bindings)
[]
(-> bindings
last
(str/split #" |\+")))))
last
(string/split #" |\+")))))
(defn binding-for-display [k binding]
(let [tmp (cond
@@ -158,11 +158,11 @@
:else
(->> binding
(map shortcut-utils/decorate-binding)
(str/join " | ")))]
(string/join " | ")))]
;; Display "cmd" rather than "meta" to the user to describe the Mac
;; mod key, because that's what the Mac keyboards actually say.
(str/replace tmp "meta" "cmd")))
(string/replace tmp "meta" "cmd")))
(defn get-group
"Given shortcut key, return handler group
@@ -208,10 +208,10 @@
(when-let [{:keys [key refs]} o]
[k [key (reduce-kv (fn [r id handler-id']
(if (and
(not (contains? exclude-ids id))
(or (= handler-ids #{handler-id'})
(and (set? handler-ids) (contains? handler-ids handler-id'))
(and global? (contains? global-handlers handler-id'))))
(not (contains? exclude-ids id))
(or (= handler-ids #{handler-id'})
(and (set? handler-ids) (contains? handler-ids handler-id'))
(and global? (contains? global-handlers handler-id'))))
(assoc r id handler-id')
r))
{} refs)]]))]
@@ -233,19 +233,19 @@
(when-let [target (some-> target (mod-key) (shortcut-utils/safe-parse-string-binding) (bean/->clj))]
(->> from-binding
(filterv
#(when-let [from (some-> % (mod-key) (shortcut-utils/safe-parse-string-binding) (bean/->clj))]
(or (= from target)
(and (or (= (count from) 1)
(= (count target) 1))
(= (first target) (first from))))))))))
#(when-let [from (some-> % (mod-key) (shortcut-utils/safe-parse-string-binding) (bean/->clj))]
(or (= from target)
(and (or (= (count from) 1)
(= (count target) 1))
(= (first target) (first from))))))))))
(defn shortcut-data-by-id [id]
(let [binding (shortcut-binding id)
data (-> (shortcuts-map-full) id)]
(assoc
data
:binding
(binding-for-display id binding))))
data
:binding
(binding-for-display id binding))))
(defn shortcuts->commands [handler-id]
(let [m (get @shortcut-config/*config handler-id)]

View File

@@ -1,5 +1,5 @@
(ns frontend.modules.shortcut.utils
(:require [clojure.string :as str]
(:require [clojure.string :as string]
[frontend.util :as util])
(:import [goog.ui KeyboardShortcutHandler]))
@@ -11,8 +11,8 @@
(js/console.warn "[shortcuts] parse key error: " e) binding)))
(defn mod-key [binding]
(str/replace binding #"(?i)mod"
(if util/mac? "meta" "ctrl")))
(string/replace binding #"(?i)mod"
(if util/mac? "meta" "ctrl")))
(defn undecorate-binding
[binding]
@@ -32,10 +32,10 @@
"↑" "up"
"↓" "down"}]
(-> binding
(str/replace #"[;=-\[\]'\(\)\~\→\←\⇧]" #(get keynames %))
(str/replace #"\s+" " ")
(string/replace #"[;=-\[\]'\(\)\~\→\←\⇧]" #(get keynames %))
(string/replace #"\s+" " ")
(mod-key)
(str/lower-case)))))
(string/lower-case)))))
(defn decorate-namespace [k]
(let [n (name k)
@@ -45,18 +45,18 @@
(defn decorate-binding [binding]
(when (or (string? binding)
(sequential? binding))
(-> (if (string? binding) binding (str/join "+" binding))
(str/replace "mod" (if util/mac? "⌘" "ctrl"))
(str/replace "meta" (if util/mac? "⌘" "⊞ win"))
(str/replace "alt" (if util/mac? "opt" "alt"))
(str/replace "shift+/" "?")
(str/replace "left" "←")
(str/replace "right" "→")
(str/replace "up" "↑")
(str/replace "down" "↓")
(str/replace "shift" "⇧")
(str/replace "open-square-bracket" "[")
(str/replace "close-square-bracket" "]")
(str/replace "equals" "=")
(str/replace "semicolon" ";")
(str/lower-case))))
(-> (if (string? binding) binding (string/join "+" binding))
(string/replace "mod" (if util/mac? "⌘" "ctrl"))
(string/replace "meta" (if util/mac? "⌘" "⊞ win"))
(string/replace "alt" (if util/mac? "opt" "alt"))
(string/replace "shift+/" "?")
(string/replace "left" "←")
(string/replace "right" "→")
(string/replace "up" "↑")
(string/replace "down" "↓")
(string/replace "shift" "⇧")
(string/replace "open-square-bracket" "[")
(string/replace "close-square-bracket" "]")
(string/replace "equals" "=")
(string/replace "semicolon" ";")
(string/lower-case))))

View File

@@ -1,18 +1,18 @@
(ns frontend.rum
"Utility fns for rum"
(:require [clojure.string :as s]
(:require [cljs-bean.core :as bean]
[clojure.set :as set]
[clojure.string :as string]
[clojure.walk :as w]
[rum.core :refer [use-state use-effect!] :as rum]
[daiquiri.interpreter :as interpreter]
[cljs-bean.core :as bean]))
[rum.core :refer [use-state use-effect!] :as rum]))
;; copy from https://github.com/priornix/antizer/blob/35ba264cf48b84e6597743e28b3570d8aa473e74/src/antizer/core.cljs
(defn kebab-case->camel-case
"Converts from kebab case to camel case, eg: on-click to onClick"
[input]
(s/replace input #"-([a-z])" (fn [[_ c]] (s/upper-case c))))
(string/replace input #"-([a-z])" (fn [[_ c]] (string/upper-case c))))
(defn map-keys->camel-case
"Stringifys all the keys of a cljs hashmap and converts them
@@ -38,46 +38,46 @@
(adapt-class react-class false))
([react-class skip-opts-transform?]
(fn [& args]
(let [[opts children] (if (map? (first args))
[(first args) (rest args)]
[{} args])
type# (first children)
(let [[opts children] (if (map? (first args))
[(first args) (rest args)]
[{} args])
type# (first children)
;; we have to make sure to check if the children is sequential
;; as a list can be returned, eg: from a (for)
new-children (if (sequential? type#)
(let [result (interpreter/interpret children)]
(if (sequential? result)
result
[result]))
children)
new-children (if (sequential? type#)
(let [result (interpreter/interpret children)]
(if (sequential? result)
result
[result]))
children)
;; convert any options key value to a react element, if
;; a valid html element tag is used, using sablono
vector->react-elems (fn [[key val]]
(if (sequential? val)
[key (interpreter/interpret val)]
[key val]))
new-options (into {}
(if skip-opts-transform?
opts
(map vector->react-elems opts)))]
(apply js/React.createElement react-class
vector->react-elems (fn [[key val]]
(if (sequential? val)
[key (interpreter/interpret val)]
[key val]))
new-options (into {}
(if skip-opts-transform?
opts
(map vector->react-elems opts)))]
(apply js/React.createElement react-class
;; sablono html-to-dom-attrs does not work for nested hashmaps
(bean/->js (map-keys->camel-case new-options :html-props true))
new-children)))))
(bean/->js (map-keys->camel-case new-options :html-props true))
new-children)))))
(defn use-atom-fn
[a getter-fn setter-fn]
(let [[val set-val] (use-state (getter-fn @a))]
(use-effect!
(fn []
(let [id (str (random-uuid))]
(add-watch a id (fn [_ _ prev-state next-state]
(let [prev-value (getter-fn prev-state)
next-value (getter-fn next-state)]
(when-not (= prev-value next-value)
(set-val next-value)))))
#(remove-watch a id)))
[])
(fn []
(let [id (str (random-uuid))]
(add-watch a id (fn [_ _ prev-state next-state]
(let [prev-value (getter-fn prev-state)
next-value (getter-fn next-state)]
(when-not (= prev-value next-value)
(set-val next-value)))))
#(remove-watch a id)))
[])
[val #(swap! a setter-fn %)]))
(defn use-atom
@@ -94,10 +94,10 @@
[]
(let [*mounted (rum/use-ref false)]
(use-effect!
(fn []
(rum/set-ref! *mounted true)
#(rum/set-ref! *mounted false))
[])
(fn []
(rum/set-ref! *mounted true)
#(rum/set-ref! *mounted false))
[])
#(rum/deref *mounted)))
(defn use-bounding-client-rect

View File

@@ -596,6 +596,12 @@
(= (:db/ident data) :logseq.kv/schema-version)
nil
(:file/path data)
(if-let [block (d/entity @conn [:file/path (:file/path data)])]
(let [existing-data (assoc (into {} block) :db/id (:db/id block))]
(merge data existing-data))
data)
(:block/uuid data)
(if-let [block (d/entity @conn [:block/uuid (:block/uuid data)])]
(do

View File

@@ -1,11 +1,11 @@
(ns frontend.db.query-dsl-test
(:require [cljs.test :refer [are deftest testing use-fixtures is]]
[clojure.string :as str]
[logseq.common.util.page-ref :as page-ref]
[clojure.string :as string]
[frontend.db :as db]
[frontend.util :as util]
[frontend.db.query-dsl :as query-dsl]
[frontend.test.helper :as test-helper :include-macros true :refer [load-test-files load-test-files-for-db-graph]]))
[frontend.test.helper :as test-helper :include-macros true :refer [load-test-files load-test-files-for-db-graph]]
[frontend.util :as util]
[logseq.common.util.page-ref :as page-ref]))
;; TODO: quickcheck
;; 1. generate query filters
@@ -58,7 +58,7 @@
[query]
(if js/process.env.DB_GRAPH
(some-> query
(str/replace "(page-tags" "(tags"))
(string/replace "(page-tags" "(tags"))
query))
(defn- dsl-query
@@ -105,7 +105,7 @@
[{:block/keys [title]}]
(some->> title
(re-find #"[^\[]+")
str/trim))
string/trim))
(defn- block-property-queries-test
[]
@@ -126,51 +126,51 @@ prop-d:: [[nada]]"}])
(testing "Blocks have given property value"
(is (= #{"b1" "b2"}
(set (map (comp first str/split-lines :block/title)
(set (map (comp first string/split-lines :block/title)
(dsl-query "(property prop-a val-a)")))))
(is (= ["b2"]
(map (comp first str/split-lines :block/title)
(map (comp first string/split-lines :block/title)
(dsl-query "(property prop-b val-b)")))))
(is (= ["b2"]
(map (comp first str/split-lines :block/title)
(map (comp first string/split-lines :block/title)
(dsl-query "(and (property prop-b val-b))")))
"Blocks have property value with empty AND")
(is (= ["b3"]
(map (comp first str/split-lines :block/title)
(map (comp first string/split-lines :block/title)
(dsl-query "(and (property prop-c \"page c\"))")))
"Blocks have property value from a set of values")
(is (= ["b3"]
(map (comp first str/split-lines :block/title)
(map (comp first string/split-lines :block/title)
(dsl-query "(and (property prop-c \"page c\") (property prop-c \"page b\"))")))
"Blocks have ANDed property values")
(is (= #{"b2" "b3"}
(set
(map (comp first str/split-lines :block/title)
(map (comp first string/split-lines :block/title)
(dsl-query "(or (property prop-c \"page c\") (property prop-b val-b))"))))
"Blocks have ORed property values")
(is (= ["b1"]
(map (comp first str/split-lines :block/title)
(map (comp first string/split-lines :block/title)
(dsl-query "(property prop-num 2000)")))
"Blocks have integer property value")
(is (= ["b3"]
(map (comp first str/split-lines :block/title)
(map (comp first string/split-lines :block/title)
(dsl-query "(property prop-linked-num 3000)")))
"Blocks have property with integer page value")
(is (= ["b3"]
(map (comp first str/split-lines :block/title)
(map (comp first string/split-lines :block/title)
(dsl-query "(property prop-d no-space-link)")))
"Blocks have property value with no space")
(is (= #{"b3" "b4"}
(set (map (comp first str/split-lines :block/title)
(set (map (comp first string/split-lines :block/title)
(dsl-query "(property prop-d)"))))
"Blocks that have a property"))
@@ -296,7 +296,7 @@ prop-d:: [[nada]]"}])
{:file/path (str "pages/page" idx ".md")
:file/content (if (seq tags)
(str "page-prop:: b\n- block for page" idx
"\ntagz:: " (str/join ", " (map page-ref/->page-ref tags)))
"\ntagz:: " (string/join ", " (map page-ref/->page-ref tags)))
"")})))
_ (load-test-files pages)
{:keys [result time]}

View File

@@ -1,7 +1,7 @@
(ns frontend.extensions.calc-test
(:require [clojure.test :as test :refer [are deftest testing]]
[clojure.string :as str]
[clojure.edn :as edn]
(:require [clojure.edn :as edn]
[clojure.string :as string]
[clojure.test :as test :refer [are deftest testing]]
[frontend.extensions.calc :as calc]))
(defn convert-bigNum [b]
@@ -173,7 +173,7 @@
(are [final-env exprs] (let [env (calc/new-env)]
(doseq [expr exprs]
(calc/eval env (calc/parse expr)))
(= final-env (into {} (for [[k v] @env] [k (convert-bigNum v)]))))
(= final-env (into {} (for [[k v] @env] [k (convert-bigNum v)]))))
{"a" 1 "b" 2} ["a = 1" "b = a + 1"]
{"a" 1 "b" 0} ["a = 1" "b = -a + 1"]
{"a" 1 "b" 3} ["a = 1" "b=a*2+1"]
@@ -184,22 +184,22 @@
(are [final-env exprs] (let [env (calc/new-env)]
(doseq [expr exprs]
(calc/eval env (calc/parse expr)))
(= final-env (into {} (for [[k v] @env] [k (convert-bigNum v)]))))
(= final-env (into {} (for [[k v] @env] [k (convert-bigNum v)]))))
{"a" 2} ["a = 1" "a = 2"]
{"a" 2 "b" 2} ["a = 1" "b = a + 1" "a = b"]
{"variable" 1 "x" 0} ["variable = 1 + 0 * 2" "x = log(variable)" "x = variable - 1"])))
(deftest last-value
(testing "last value is set"
(are [values exprs] (= values (calc/eval-lines (str/join "\n" exprs)))
(are [values exprs] (= values (calc/eval-lines (string/join "\n" exprs)))
["42" "126"] ["6*7" "last*3"]
["25" "5"] ["3^2+4^2" "sqrt(last)"]
["6" nil nil nil "12"] ["2*3" "# a comment" "" " " "last*2"])))
(deftest formatting
(testing "display normal"
(are [values exprs] (= values (calc/eval-lines (str/join "\n" exprs)))
[nil "1000000"] [":format norm" "1e6" ]
(are [values exprs] (= values (calc/eval-lines (string/join "\n" exprs)))
[nil "1000000"] [":format norm" "1e6"]
[nil "1000000"] [":format norm 7" "1e6"]
[nil "1e+6"] [":format norm 6" "1e6"]
[nil "3.14"] [":format norm 3" "PI"]
@@ -209,7 +209,7 @@
[nil "123400000"] [":format normal 9" "1.234e8"]
[nil "1.234e+8"] [":format normal 8" "1.234e8"]))
(testing "display fixed"
(are [values exprs] (= values (calc/eval-lines (str/join "\n" exprs)))
(are [values exprs] (= values (calc/eval-lines (string/join "\n" exprs)))
[nil "0.123450"] [":format fix 6" "0.12345"]
[nil "0.1235"] [":format fix 4" "0.12345"]
[nil "2.7183"] [":format fixed 4" "E"]
@@ -217,7 +217,7 @@
[nil "4.000e-4"] [":format fix 3" "0.0004"]
[nil "1.00e+21"] [":format fixed 2" "1e21+0.1"]))
(testing "display scientific"
(are [values exprs] (= values (calc/eval-lines (str/join "\n" exprs)))
(are [values exprs] (= values (calc/eval-lines (string/join "\n" exprs)))
[nil "1e+6"] [":format sci" "1e6"]
[nil "3.142e+0"] [":format sci 3" "PI"]
[nil "3.14e+2"] [":format scientific" "3.14*10^2"])))
@@ -234,7 +234,7 @@
2.00101 "2 101/100000"
-99.2 "-99 8/40"))
(testing "display fractions"
(are [values exprs] (= values (calc/eval-lines (str/join "\n" exprs)))
(are [values exprs] (= values (calc/eval-lines (string/join "\n" exprs)))
[nil "4 3/8"] [":format frac" "4.375"]
[nil "-7 1/4"] [":format fraction" "-7.25"]
[nil "2"] [":format fractions" "19/20 + 1 1/20"]
@@ -242,10 +242,10 @@
[nil "3.14157"] [":format frac" "3.14157"]
[nil "3 14157/100000"] [":format frac 100000" "3.14157"]))
(testing "display improper fractions"
(are [values exprs] (= values (calc/eval-lines (str/join "\n" exprs)))
(are [values exprs] (= values (calc/eval-lines (string/join "\n" exprs)))
[nil "35/8"] [":format improper" "4.375"]
[nil "-29/4"] [":format imp" "-7.25"]
[nil "3.14157"] [":format improper" "3.14157" ]
[nil "3.14157"] [":format improper" "3.14157"]
[nil "314157/100000"] [":format imp 100000" "3.14157"])))
(deftest base-conversion
@@ -257,10 +257,10 @@
324.0 "0x100 + 0o100 + 0b100"
32.0 "0b100 * 0b1000"))
(testing "mixed base output"
(are [values exprs] (= values (calc/eval-lines (str/join "\n" exprs)))
(are [values exprs] (= values (calc/eval-lines (string/join "\n" exprs)))
["12345" "0x3039"] ["12345" ":hex"]
["12345" "0o30071"] ["12345" ":oct"]
["12345" "0b11000000111001"]["12345" ":bin"]
["12345" "0b11000000111001"] ["12345" ":bin"]
[nil "0b100000000"] [":bin" "0b10000 * 0b10000"]
[nil "-0xff"] [":hex" "-255"])))

View File

@@ -6,13 +6,13 @@
to call from the commandline. Once this test runner is stable enough we should
contribute it upstream"
{:dev/always true} ;; necessary for test-data freshness
(:require [shadow.test.env :as env]
[clojure.tools.cli :as cli]
[clojure.string :as str]
(:require [cljs.test :as ct]
[clojure.set :as set]
[clojure.string :as string]
[clojure.tools.cli :as cli]
[goog.string :as gstring]
[shadow.test :as st]
[cljs.test :as ct]
[goog.string :as gstring]))
[shadow.test.env :as env]))
;; Cljs.test customization
;; Inherit behavior from default reporter
@@ -58,8 +58,8 @@
(let [{:keys [errors] :as parsed-input}
(apply cli/parse-opts args cli-opts parse-opts-options)]
(if (seq errors)
(do (println (str/join "\n" (into ["Options failed to parse:"] errors)))
(js/process.exit 1))
(do (println (string/join "\n" (into ["Options failed to parse:"] errors)))
(js/process.exit 1))
parsed-input)))
(defn- get-selected-tests
@@ -80,11 +80,11 @@ returns selected tests and namespaces to run"
#(seq (set/intersection exclude (set (keys (meta %)))))
test-vars)))
test-syms (cond (some? focused-tests)
focused-tests
namespace
[namespace]
namespace-regex
(filter #(re-find namespace-regex (str %)) test-namespaces))]
focused-tests
namespace
[namespace]
namespace-regex
(filter #(re-find namespace-regex (str %)) test-namespaces))]
test-syms))
;; This is a patched version of https://github.com/thheller/shadow-cljs/blob/f271b3c40d3ccd4e587b0ffeaa2713d2f642114a/src/main/shadow/test/node.cljs#L44-L56