diff --git a/android/app/build.gradle b/android/app/build.gradle index 4694be9e9..3595f3ede 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -7,8 +7,8 @@ android { applicationId "com.logseq.app" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 80 - versionName "0.10.6" + versionCode 81 + versionName "0.10.7" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" aaptOptions { // Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps. diff --git a/deps/shui/src/logseq/shui/list_item/v1.cljs b/deps/shui/src/logseq/shui/list_item/v1.cljs index 63628044e..e59dc9d56 100644 --- a/deps/shui/src/logseq/shui/list_item/v1.cljs +++ b/deps/shui/src/logseq/shui/list_item/v1.cljs @@ -3,77 +3,42 @@ ["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])) (def to-string shortcut/to-string) -(defn normalize-text [app-config text] +(defn- normalize-text [app-config text] (cond-> (to-string text) - :lower-case (string/lower-case) + ;; :lower-case (string/lower-case) :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 (or (vector? text) (object? text)) ; hiccup + (cond + (or (vector? text) (object? text)) ; hiccup text - (let [text-string (to-string text)] - (if-not (seq text-string) - [:span text-string] - (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])))))) + + (string/blank? query) + [:span (to-string text)] + + :else + (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) + query-terms (string/replace (gstring/regExpEscape normal-query) #"\s+" "|") + query-re (js/RegExp. (str "(" query-terms ")") "i") + 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 normal-text]))))) (rum/defc root [{:keys [icon icon-theme query text info shortcut value-label value title highlighted on-highlight on-highlight-dep header on-click diff --git a/e2e-tests/page-search.spec.ts b/e2e-tests/page-search.spec.ts index c2a5f299a..92fbf3223 100644 --- a/e2e-tests/page-search.spec.ts +++ b/e2e-tests/page-search.spec.ts @@ -157,7 +157,7 @@ async function alias_test(block: Block, page: Page, page_name: string, search_kw const results = await searchPage(page, kw_name) // test search results - expect(await results[0].innerText()).toContain(alias_name) + expect(await results[0].innerText()).toContain(alias_name.normalize('NFKC')) // test search entering (page) page.keyboard.press("Enter") diff --git a/resources/forge.config.js b/resources/forge.config.js index 96f42a6e4..fe609701e 100644 --- a/resources/forge.config.js +++ b/resources/forge.config.js @@ -4,7 +4,7 @@ module.exports = { packagerConfig: { name: 'Logseq', icon: './icons/logseq_big_sur.icns', - buildVersion: 80, + buildVersion: 81, protocols: [ { "protocol": "logseq", diff --git a/resources/package.json b/resources/package.json index 21bf27568..715ca9c90 100644 --- a/resources/package.json +++ b/resources/package.json @@ -1,7 +1,7 @@ { "name": "Logseq", "productName": "Logseq", - "version": "0.10.6", + "version": "0.10.7", "main": "electron.js", "author": "Logseq", "license": "AGPL-3.0", diff --git a/src/electron/electron/git.cljs b/src/electron/electron/git.cljs index 0d6822e28..f39716cd7 100644 --- a/src/electron/electron/git.cljs +++ b/src/electron/electron/git.cljs @@ -13,8 +13,8 @@ (def log-error (partial logger/error "[Git]")) (defn get-graph-git-dir - [] - (when-let [graph-path (some-> (state/get-graph-path) + [graph-path] + (when-let [graph-path (some-> graph-path (string/replace "/" "_") (string/replace ":" "comma"))] (let [dir (.join node-path (.homedir os) ".logseq" "git" graph-path ".git")] @@ -22,38 +22,35 @@ dir))) (defn run-git! - [commands] - (when-let [path (state/get-graph-path)] - (when (fs/existsSync path) - (p/let [result (.exec GitProcess commands path)] - (if (zero? (gobj/get result "exitCode")) - (let [result (gobj/get result "stdout")] - (p/resolved result)) - (let [error (gobj/get result "stderr")] - (when-not (string/blank? error) - (log-error error)) - (p/rejected error))))))) + [graph-path commands] + (when (and graph-path (fs/existsSync graph-path)) + (p/let [result (.exec GitProcess commands graph-path)] + (if (zero? (gobj/get result "exitCode")) + (let [result (gobj/get result "stdout")] + (p/resolved result)) + (let [error (gobj/get result "stderr")] + (when-not (string/blank? error) + (log-error error)) + (p/rejected error)))))) (defn run-git2! - [commands] - (when-let [path (state/get-graph-path)] - (when (fs/existsSync path) - (p/let [^js result (.exec GitProcess commands path)] - result)))) + [graph-path commands] + (when (and graph-path (fs/existsSync graph-path)) + (p/let [^js result (.exec GitProcess commands graph-path)] + result))) (defn git-dir-exists? - [] + [graph-path] (try - (let [p (.join node-path (state/get-graph-path) ".git")] + (let [p (.join node-path graph-path ".git")] (.isDirectory (fs/statSync p))) (catch :default _e nil))) (defn remove-dot-git-file! - [] + [graph-path] (try - (let [graph-path (state/get-graph-path) - _ (when (string/blank? graph-path) + (let [_ (when (string/blank? graph-path) (utils/send-to-renderer :setCurrentGraph {}) (throw (js/Error. "Empty graph path"))) p (.join node-path graph-path ".git")] @@ -70,23 +67,23 @@ (log-error e)))) (defn init! - [] - (let [_ (remove-dot-git-file!) - separate-git-dir (get-graph-git-dir) + [graph-path] + (let [_ (remove-dot-git-file! graph-path) + separate-git-dir (get-graph-git-dir graph-path) args (cond - (git-dir-exists?) + (git-dir-exists? graph-path) ["init"] separate-git-dir ["init" (str "--separate-git-dir=" separate-git-dir)] :else ["init"])] - (p/let [_ (run-git! (clj->js args))] + (p/let [_ (run-git! graph-path (clj->js args))] (when utils/win32? - (run-git! #js ["config" "core.safecrlf" "false"]))))) + (run-git! graph-path #js ["config" "core.safecrlf" "false"]))))) (defn add-all! - [] - (-> (run-git! #js ["add" "--ignore-errors" "./*"]) + [graph-path] + (-> (run-git! graph-path #js ["add" "--ignore-errors" "./*"]) (p/catch (fn [error] (let [error (string/lower-case (str error))] (if (or (string/includes? error "permission denied") @@ -97,33 +94,38 @@ ;; git log -100 --oneline -p ~/Desktop/org/pages/contents.org (defn commit! - [message] - (p/let [_ (run-git! #js ["config" "core.quotepath" "false"])] - (run-git! #js ["commit" "-m" message]))) + [graph-path message] + (p/do! + (run-git! graph-path #js ["config" "core.quotepath" "false"]) + (run-git! graph-path #js ["commit" "-m" message]))) + +(defn add-all-and-commit-single-graph! + [graph-path message] + (let [message (if (string/blank? message) + "Auto saved by Logseq" + message)] + (-> + (p/let [_ (init! graph-path) + _ (add-all! graph-path)] + (commit! graph-path message)) + (p/catch (fn [error] + (when (and + (string? error) + (not (string/blank? error))) + (if (string/starts-with? error "Author identity unknown") + (utils/send-to-renderer "setGitUsernameAndEmail" {:type "git"}) + (utils/send-to-renderer "notification" {:type "error" + :payload (str error "\nIf you don't want to see those errors or don't need git, you can disable the \"Git auto commit\" feature on Settings > Version control.")})))))))) (defn add-all-and-commit! ([] (add-all-and-commit! nil)) ([message] - (let [message (if (string/blank? message) - "Auto saved by Logseq" - message)] - (-> - (p/let [_ (init!) - _ (add-all!)] - (commit! message)) - (p/catch (fn [error] - (when (and - (string? error) - (not (string/blank? error))) - (if (string/starts-with? error "Author identity unknown") - (utils/send-to-renderer "setGitUsernameAndEmail" {:type "git"}) - (utils/send-to-renderer "notification" {:type "error" - :payload (str error "\nIf you don't want to see those errors or don't need git, you can disable the \"Git auto commit\" feature on Settings > Version control.")}))))))))) + (doseq [path (state/get-all-graph-paths)] (add-all-and-commit-single-graph! path message)))) (defn short-status! - [] - (run-git! #js ["status" "--porcelain"])) + [graph-path] + (run-git! graph-path #js ["status" "--porcelain"])) (defonce quotes-regex #"\"[^\"]+\"") (defn wrapped-by-quotes? @@ -151,8 +153,8 @@ (remove string/blank?)))) (defn raw! - [args] - (init!) + [graph-path args] + (init! graph-path) (let [args (if (string? args) (split-args args) args) @@ -165,8 +167,8 @@ (p/rejected error)))] (-> (p/let [_ (when (= (first args) "commit") - (add-all!)) - result (run-git! (clj->js args))] + (add-all! graph-path)) + result (run-git! graph-path (clj->js args))] (p/resolved result)) (p/catch error-handler)))) diff --git a/src/electron/electron/handler.cljs b/src/electron/electron/handler.cljs index 471f3c766..ae6f94f4a 100644 --- a/src/electron/electron/handler.cljs +++ b/src/electron/electron/handler.cljs @@ -434,7 +434,6 @@ (let [old-path (state/get-window-graph-path window)] (when (and old-path graph-path (not= old-path graph-path)) (close-watcher-when-orphaned! window old-path)) - (swap! state/state assoc :graph/current graph-path) (swap! state/state assoc-in [:window/graph window] graph-path) nil)) @@ -442,14 +441,14 @@ (when graph-name (set-current-graph! window (utils/get-graph-dir graph-name)))) -(defmethod handle :runGit [_ [_ args]] - (when (seq args) - (git/raw! args))) +(defmethod handle :runGit [_ [_ {:keys [repo command]}]] + (when (seq command) + (git/raw! (utils/get-graph-dir repo) command))) -(defmethod handle :runGitWithinCurrentGraph [_ [_ args]] - (when (seq args) - (git/init!) - (git/run-git2! (clj->js args)))) +(defmethod handle :runGitWithinCurrentGraph [_ [_ {:keys [repo command]}]] + (when (seq command) + (git/init! (utils/get-graph-dir repo)) + (git/run-git2! (utils/get-graph-dir repo) (clj->js command)))) (defmethod handle :runCli [window [_ {:keys [command args returnResult]}]] (try @@ -472,8 +471,8 @@ (defmethod handle :gitCommitAll [_ [_ message]] (git/add-all-and-commit! message)) -(defmethod handle :gitStatus [_ [_]] - (git/short-status!)) +(defmethod handle :gitStatus [_ [_ repo]] + (git/short-status! (utils/get-graph-dir repo))) (def debounced-configure-auto-commit! (debounce git/configure-auto-commit! 5000)) (defmethod handle :setGitAutoCommit [] diff --git a/src/electron/electron/state.cljs b/src/electron/electron/state.cljs index ac4c1c23b..90a9f35b7 100644 --- a/src/electron/electron/state.cljs +++ b/src/electron/electron/state.cljs @@ -5,9 +5,6 @@ (defonce state (atom {:config (config/get-config) - ;; FIXME: replace with :window/graph - :graph/current nil - ;; window -> current graph :window/graph {} @@ -33,15 +30,26 @@ [] (get-in @state [:config :git/commit-on-close?] false)) -(defn get-graph-path - [] - (:graph/current @state)) - (defn get-window-graph-path "Get the path of the graph of a window (might be `nil`)" [window] (get (:window/graph @state) window)) +(defn get-all-graph-paths + "Get the paths of all graphs currently open in all windows." + [] + (set (vals (:window/graph @state)))) + +(defn get-active-window-graph-path + "Get the path of the graph of the currently focused window (might be `nil`)" + [] + (let [windows (:window/graph @state) + active-windows-pairs (filter #(.isFocused (first %)) windows) + active-window-pair (first active-windows-pairs) + path (second active-window-pair)] + path) + ) + (defn close-window! [window] (swap! state medley/dissoc-in [:window/graph window])) diff --git a/src/main/frontend/components/commit.cljs b/src/main/frontend/components/commit.cljs index 84c18a29d..7adffddc5 100644 --- a/src/main/frontend/components/commit.cljs +++ b/src/main/frontend/components/commit.cljs @@ -39,7 +39,7 @@ (rum/defcs add-commit-message < rum/reactive (rum/local nil ::git-status) {:will-mount (fn [state] - (-> (ipc/ipc "gitStatus") + (-> (ipc/ipc "gitStatus" (state/get-current-repo)) (p/then (fn [status] (reset! (get state ::git-status) status)))) state) diff --git a/src/main/frontend/components/theme.cljs b/src/main/frontend/components/theme.cljs index 44acfe96b..322c64666 100644 --- a/src/main/frontend/components/theme.cljs +++ b/src/main/frontend/components/theme.cljs @@ -15,6 +15,22 @@ [rum.core :as rum] [frontend.context.i18n :refer [t]])) +(rum/defc scrollbar-measure + [] + (let [*el (rum/use-ref nil)] + (rum/use-effect! + (fn [] + (when-let [el (rum/deref *el)] + (let [w (- (.-offsetWidth el) (.-clientWidth el)) + c "custom-scrollbar" + l (.-classList js/document.documentElement)] + (if (or (not util/mac?) (> w 2)) + (.add l c) (.remove l c))))) + []) + [:div.fixed.w-16.h-16.overflow-scroll.opacity-0 + {:ref *el + :class "top-1/2 -left-1/2 z-[-999]"}])) + (rum/defc ^:large-vars/cleanup-todo container [{:keys [route theme accent-color on-click current-repo nfs-granted? db-restoring? settings-open? sidebar-open? system-theme? sidebar-blocks-len onboarding-state preferred-language]} child] @@ -117,4 +133,5 @@ {:on-click on-click} child - (pdf/default-embed-playground)])) + (pdf/default-embed-playground) + (scrollbar-measure)])) diff --git a/src/main/frontend/components/theme.css b/src/main/frontend/components/theme.css index 340ff4386..41ed36caa 100644 --- a/src/main/frontend/components/theme.css +++ b/src/main/frontend/components/theme.css @@ -16,7 +16,7 @@ } } -.visible-scrollbar, html:not(.is-mac) { +.visible-scrollbar , html.custom-scrollbar { ::-webkit-scrollbar-thumb { background-color: var(--lx-gray-05, var(--ls-scrollbar-foreground-color, var(--rx-gray-05))); } diff --git a/src/main/frontend/handler/export/text.cljs b/src/main/frontend/handler/export/text.cljs index 8a09a6d0c..83c5626ed 100644 --- a/src/main/frontend/handler/export/text.cljs +++ b/src/main/frontend/handler/export/text.cljs @@ -360,6 +360,10 @@ (when (and origin-ast newline-after-block? (not current-block-is-first-heading-block?)) [(newline* 2)]) (mapcatv inline-ast->simple-ast ast-content) + (let [last-element (last ast-content) + [last-element-type] last-element] + (when (and newline-after-block? (= "Break_Line" last-element-type)) + (inline-break-line))) [(newline* 1)])) "Paragraph_line" (assert false "Paragraph_line is mldoc internal ast") diff --git a/src/main/frontend/handler/shell.cljs b/src/main/frontend/handler/shell.cljs index b5a3af6d0..59d41ab70 100644 --- a/src/main/frontend/handler/shell.cljs +++ b/src/main/frontend/handler/shell.cljs @@ -11,11 +11,13 @@ (defn run-git-command! [command] - (ipc/ipc :runGit command)) + (ipc/ipc :runGit {:repo (state/get-current-repo) + :command command})) (defn run-git-command2! [command] - (ipc/ipc :runGitWithinCurrentGraph command)) + (ipc/ipc :runGitWithinCurrentGraph {:repo (state/get-current-repo) + :command command})) (defn run-cli-command! [command args] diff --git a/src/main/frontend/ui.cljs b/src/main/frontend/ui.cljs index 8914d64d6..38c60feba 100644 --- a/src/main/frontend/ui.cljs +++ b/src/main/frontend/ui.cljs @@ -1051,7 +1051,12 @@ :muted disabled?} button-props) - icon (when icon (shui/tabler-icon icon icon-props)) + icon (when icon (shui-ui/tabler-icon icon icon-props)) + href? (not (string/blank? href)) + text (cond + href? [:a {:href href :target "_blank" + :style {:color "inherit"}} text] + :else text) children [icon text]] (shui/button props children))) diff --git a/src/main/frontend/version.cljs b/src/main/frontend/version.cljs index 22176e32f..53b53dafd 100644 --- a/src/main/frontend/version.cljs +++ b/src/main/frontend/version.cljs @@ -1,3 +1,3 @@ (ns ^:no-doc frontend.version) -(defonce version "0.10.6") +(defonce version "0.10.7")