mirror of
https://github.com/logseq/logseq.git
synced 2026-02-01 22:47:36 +00:00
remove diff-merge
This commit is contained in:
@@ -137,7 +137,6 @@
|
||||
"@js-joda/core": "3.2.0",
|
||||
"@js-joda/locale_en-us": "3.1.1",
|
||||
"@js-joda/timezone": "2.5.0",
|
||||
"@logseq/diff-merge": "^0.2.2",
|
||||
"@logseq/react-tweet-embed": "1.3.1-1",
|
||||
"@logseq/simple-wave-record": "^0.0.3",
|
||||
"@radix-ui/colors": "^0.1.8",
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
[logseq.common.util.page-ref :as page-ref]
|
||||
[logseq.db :as ldb]
|
||||
[logseq.db.frontend.class :as db-class]
|
||||
[logseq.graph-parser.property :as gp-property]
|
||||
[logseq.shui.hooks :as hooks]
|
||||
[logseq.shui.ui :as shui]
|
||||
[promesa.core :as p]
|
||||
@@ -426,41 +425,6 @@
|
||||
:item-render (fn [property] property)
|
||||
:class "black"})))))
|
||||
|
||||
(rum/defc property-value-search-aux
|
||||
[id property q]
|
||||
(let [[values set-values!] (rum/use-state nil)]
|
||||
(hooks/use-effect!
|
||||
(fn []
|
||||
(p/let [result (editor-handler/get-matched-property-values property q)]
|
||||
(set-values! result)))
|
||||
[property q])
|
||||
(ui/auto-complete
|
||||
values
|
||||
{:on-chosen (editor-handler/property-value-on-chosen-handler id q)
|
||||
:on-enter (fn [_state]
|
||||
((editor-handler/property-value-on-chosen-handler id q) nil))
|
||||
:empty-placeholder [:div.px-4.py-2.text-sm (str "Create a new property value: " q)]
|
||||
:header [:div.px-4.py-2.text-sm.font-medium "Matched property values: "]
|
||||
:item-render (fn [property-value] property-value)
|
||||
:class "black"})))
|
||||
|
||||
(rum/defc property-value-search < rum/reactive
|
||||
[id]
|
||||
(let [property (:property (state/get-editor-action-data))
|
||||
input (gdom/getElement id)]
|
||||
(when (and input
|
||||
(not (string/blank? property)))
|
||||
(let [current-pos (cursor/pos input)
|
||||
edit-content (state/sub-edit-content)
|
||||
start-idx (string/last-index-of (subs edit-content 0 current-pos)
|
||||
gp-property/colons)
|
||||
q (or
|
||||
(when (>= current-pos (+ start-idx 2))
|
||||
(subs edit-content (+ start-idx 2) current-pos))
|
||||
"")
|
||||
q (string/triml q)]
|
||||
(property-value-search-aux id property q)))))
|
||||
|
||||
(rum/defc code-block-mode-keyup-listener
|
||||
[_q _edit-content last-pos current-pos]
|
||||
(hooks/use-effect!
|
||||
@@ -723,10 +687,9 @@
|
||||
(open-editor-popup! :template-search
|
||||
(template-search id format) {})
|
||||
|
||||
(:property-search :property-value-search)
|
||||
:property-search
|
||||
(open-editor-popup! action
|
||||
(if (= :property-search action)
|
||||
(property-search id) (property-value-search id))
|
||||
(property-search id)
|
||||
{})
|
||||
|
||||
;; TODO: try remove local model state
|
||||
@@ -756,7 +719,7 @@
|
||||
|
||||
(or (contains?
|
||||
#{:commands :page-search :page-search-hashtag :block-search :template-search
|
||||
:property-search :property-value-search :datepicker}
|
||||
:property-search :datepicker}
|
||||
action)
|
||||
(and (keyword? action)
|
||||
(= (namespace action) "editor.action")))
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
[frontend.date :as date]
|
||||
[frontend.db :as db]
|
||||
[frontend.db.async :as db-async]
|
||||
[frontend.db.file-based.model :as file-model]
|
||||
[frontend.db.model :as db-model]
|
||||
[frontend.fs :as fs]
|
||||
[frontend.state :as state]
|
||||
[frontend.ui :as ui]
|
||||
@@ -103,7 +103,7 @@
|
||||
(let [repo-dir (config/get-repo-dir (state/get-current-repo))
|
||||
rel-path (when (string/starts-with? path repo-dir)
|
||||
(path/trim-dir-prefix repo-dir path))
|
||||
title (file-model/get-file-page (or path rel-path))
|
||||
title (db-model/get-file-page (or path rel-path))
|
||||
in-db? (when-not (path/absolute? path)
|
||||
(boolean (db/get-file (or path rel-path))))
|
||||
file-path (cond
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
[frontend.db :as db]
|
||||
[frontend.db-mixins :as db-mixins]
|
||||
[frontend.db.async :as db-async]
|
||||
[frontend.db.file-based.model :as file-model]
|
||||
[frontend.db.model :as db-model]
|
||||
[frontend.db.query-dsl :as query-dsl]
|
||||
[frontend.handler.editor :as editor-handler]
|
||||
@@ -21,27 +20,12 @@
|
||||
[logseq.common.util.page-ref :as page-ref]
|
||||
[logseq.db :as ldb]
|
||||
[logseq.db.frontend.property :as db-property]
|
||||
[logseq.db.sqlite.util :as sqlite-util]
|
||||
[logseq.graph-parser.db :as gp-db]
|
||||
[logseq.shui.hooks :as hooks]
|
||||
[logseq.shui.ui :as shui]
|
||||
[promesa.core :as p]
|
||||
[rum.core :as rum]))
|
||||
|
||||
(rum/defc page-block-selector
|
||||
[*find]
|
||||
[:div.filter-item {:on-pointer-down (fn [e] (util/stop-propagation e))}
|
||||
(ui/select [{:label "Blocks"
|
||||
:value "block"
|
||||
:selected (not= @*find :page)}
|
||||
{:label "Pages"
|
||||
:value "page"
|
||||
:selected (= @*find :page)}]
|
||||
(fn [e v]
|
||||
;; Prevent opening the current block's editor
|
||||
(util/stop e)
|
||||
(reset! *find (keyword v))))])
|
||||
|
||||
(defn- select
|
||||
([items on-chosen]
|
||||
(select items on-chosen {}))
|
||||
@@ -162,26 +146,20 @@
|
||||
properties)
|
||||
(fn [{value :value db-ident :db/ident}]
|
||||
(reset! *mode "property-value")
|
||||
(reset! *property (if (config/db-based-graph? (state/get-current-repo))
|
||||
db-ident
|
||||
(keyword value)))))]))
|
||||
(reset! *property db-ident)))]))
|
||||
|
||||
(rum/defc property-value-select-inner
|
||||
< rum/reactive db-mixins/query
|
||||
[*property *private-property? *find *tree opts loc values {:keys [db-graph?]}]
|
||||
[*property *private-property? *tree opts loc values]
|
||||
(let [values' (cons {:label "Select all"
|
||||
:value "Select all"}
|
||||
(map #(hash-map :value (str (:value %))
|
||||
;; Preserve original-value as non-string values like boolean do not display in select
|
||||
:original-value (:value %))
|
||||
values))
|
||||
find' (rum/react *find)]
|
||||
values))]
|
||||
(select values'
|
||||
(fn [{:keys [value original-value]}]
|
||||
(let [k (cond
|
||||
db-graph? (if @*private-property? :private-property :property)
|
||||
(= find' :page) :page-property
|
||||
:else :property)
|
||||
(let [k (if @*private-property? :private-property :property)
|
||||
x (if (= value "Select all")
|
||||
[k @*property]
|
||||
[k @*property original-value])]
|
||||
@@ -189,25 +167,18 @@
|
||||
(append-tree! *tree opts loc x))))))
|
||||
|
||||
(rum/defc property-value-select
|
||||
[repo *property *private-property? *find *tree opts loc]
|
||||
(let [db-graph? (sqlite-util/db-based-graph? repo)
|
||||
[values set-values!] (rum/use-state nil)]
|
||||
[*property *private-property? *tree opts loc]
|
||||
(let [[values set-values!] (rum/use-state nil)]
|
||||
(hooks/use-effect!
|
||||
(fn [_property]
|
||||
(p/let [result (if db-graph?
|
||||
(p/let [result (db-async/<get-property-values @*property)]
|
||||
(map (fn [{:keys [label]}]
|
||||
{:label label
|
||||
:value label})
|
||||
result))
|
||||
(p/let [result (db-async/<file-get-property-values repo @*property)]
|
||||
(map (fn [value]
|
||||
{:label (str value)
|
||||
:value value}) result)))]
|
||||
(p/let [result (p/let [result (db-async/<get-property-values @*property)]
|
||||
(map (fn [{:keys [label]}]
|
||||
{:label label
|
||||
:value label})
|
||||
result))]
|
||||
(set-values! result)))
|
||||
[@*property])
|
||||
(property-value-select-inner *property *private-property? *find *tree opts loc values
|
||||
{:db-graph? db-graph?})))
|
||||
(property-value-select-inner *property *private-property? *tree opts loc values)))
|
||||
|
||||
(rum/defc tags
|
||||
[repo *tree opts loc]
|
||||
@@ -253,7 +224,7 @@
|
||||
(property-select *mode *property *private-property?)
|
||||
|
||||
"property-value"
|
||||
(property-value-select repo *property *private-property? *find *tree opts loc)
|
||||
(property-value-select *property *private-property? *tree opts loc)
|
||||
|
||||
"sample"
|
||||
(select (range 1 101)
|
||||
@@ -315,85 +286,6 @@
|
||||
|
||||
nil)]))
|
||||
|
||||
(defn- file-based-query-filter-picker
|
||||
[state *find *tree loc clause opts]
|
||||
(let [*mode (::mode state)
|
||||
*property (::property state)
|
||||
*private-property? (::private-property? state)
|
||||
repo (state/get-current-repo)]
|
||||
[:div
|
||||
(case @*mode
|
||||
"namespace"
|
||||
(let [items (sort (map :block/title (file-model/get-all-namespace-parents repo)))]
|
||||
(select items
|
||||
(fn [{:keys [value]}]
|
||||
(append-tree! *tree opts loc [:namespace value]))))
|
||||
|
||||
"tags"
|
||||
(tags repo *tree opts loc)
|
||||
|
||||
"property"
|
||||
(property-select *mode *property *private-property?)
|
||||
|
||||
"property-value"
|
||||
(property-value-select repo *property *private-property? *find *tree opts loc)
|
||||
|
||||
"sample"
|
||||
(select (range 1 101)
|
||||
(fn [{:keys [value]}]
|
||||
(append-tree! *tree opts loc [:sample (util/safe-parse-int value)])))
|
||||
|
||||
"task"
|
||||
(select (if (config/db-based-graph? repo)
|
||||
(let [values (:property/closed-values (db/entity :logseq.property/status))]
|
||||
(mapv db-property/property-value-content values))
|
||||
gp-db/built-in-markers)
|
||||
(constantly nil)
|
||||
{:multiple-choices? true
|
||||
;; Need the existing choices later to improve the UX
|
||||
:selected-choices #{}
|
||||
:extract-chosen-fn :value
|
||||
:prompt-key :select/default-select-multiple
|
||||
:close-modal? false
|
||||
:on-apply (fn [choices]
|
||||
(when (seq choices)
|
||||
(append-tree! *tree opts loc (vec (cons :task choices)))))})
|
||||
|
||||
"priority"
|
||||
(select (if (config/db-based-graph? repo)
|
||||
(let [values (:property/closed-values (db/entity :logseq.property/priority))]
|
||||
(mapv db-property/property-value-content values))
|
||||
gp-db/built-in-priorities)
|
||||
(constantly nil)
|
||||
{:multiple-choices? true
|
||||
:selected-choices #{}
|
||||
:extract-chosen-fn :value
|
||||
:prompt-key :select/default-select-multiple
|
||||
:close-modal? false
|
||||
:on-apply (fn [choices]
|
||||
(when (seq choices)
|
||||
(append-tree! *tree opts loc (vec (cons :priority choices)))))})
|
||||
|
||||
"page"
|
||||
(page-search (fn [{:keys [value]}]
|
||||
(append-tree! *tree opts loc [:page value])))
|
||||
|
||||
"page reference"
|
||||
(page-search (fn [{:keys [value]}]
|
||||
(append-tree! *tree opts loc [:page-ref value])))
|
||||
|
||||
"full text search"
|
||||
(search (fn [v] (append-tree! *tree opts loc v))
|
||||
(:toggle-fn opts))
|
||||
|
||||
"between"
|
||||
(between (merge opts
|
||||
{:tree *tree
|
||||
:loc loc
|
||||
:clause clause}))
|
||||
|
||||
nil)]))
|
||||
|
||||
(rum/defcs picker < rum/reactive
|
||||
{:will-mount (fn [state]
|
||||
(state/clear-selection!)
|
||||
@@ -403,29 +295,14 @@
|
||||
(rum/local false ::private-property?)
|
||||
[state *find *tree loc clause opts]
|
||||
(let [*mode (::mode state)
|
||||
db-based? (config/db-based-graph? (state/get-current-repo))
|
||||
filters (if db-based?
|
||||
query-builder/db-based-block-filters
|
||||
(if (= :page (rum/react *find))
|
||||
query-builder/page-filters
|
||||
query-builder/block-filters))
|
||||
filters query-builder/db-based-block-filters
|
||||
filters-and-ops (concat filters query-builder/operators)
|
||||
operator? #(contains? query-builder/operators-set (keyword %))]
|
||||
[:div.query-builder-picker
|
||||
(if @*mode
|
||||
(when-not (operator? @*mode)
|
||||
(if db-based?
|
||||
(db-based-query-filter-picker state *find *tree loc clause opts)
|
||||
(file-based-query-filter-picker state *find *tree loc clause opts)))
|
||||
(db-based-query-filter-picker state *find *tree loc clause opts))
|
||||
[:div
|
||||
(when-not db-based?
|
||||
[:<>
|
||||
(when-not @*find
|
||||
[:div.flex.flex-row.items-center.p-2.justify-between
|
||||
[:div.ml-2 "Find: "]
|
||||
(page-block-selector *find)])
|
||||
(when-not @*find
|
||||
[:hr.m-0])])
|
||||
(select
|
||||
(map name filters-and-ops)
|
||||
(fn [{:keys [value]}]
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
[frontend.date :as date]
|
||||
[frontend.db :as db]
|
||||
[frontend.db.async.util :as db-async-util]
|
||||
[frontend.db.file-based.async :as file-async]
|
||||
[frontend.db.file-based.model :as file-model]
|
||||
[frontend.db.model :as db-model]
|
||||
[frontend.db.react :as react]
|
||||
[frontend.db.utils :as db-utils]
|
||||
@@ -62,12 +60,6 @@
|
||||
(when-let [graph (state/get-current-repo)]
|
||||
(db-model/get-all-properties graph opts)))
|
||||
|
||||
(defn <file-get-property-values
|
||||
"For file graphs, returns property value names for given property name"
|
||||
[graph property]
|
||||
(when-not (config/db-based-graph? graph)
|
||||
(file-async/<get-file-based-property-values graph property)))
|
||||
|
||||
(defn <get-property-values
|
||||
"For db graphs, returns a vec of property value maps for given property
|
||||
db-ident. The map contains a :label key which can be a string or number (for
|
||||
@@ -204,42 +196,21 @@
|
||||
start-time (date/journal-day->utc-ms date)
|
||||
future-time (tc/to-long future-date)]
|
||||
(when-let [repo (and future-day (state/get-current-repo))]
|
||||
(p/let [result
|
||||
(if (config/db-based-graph? repo)
|
||||
(<q repo {}
|
||||
'[:find [(pull ?block ?block-attrs) ...]
|
||||
:in $ ?start-time ?end-time ?block-attrs
|
||||
:where
|
||||
(or [?block :logseq.property/scheduled ?n]
|
||||
[?block :logseq.property/deadline ?n])
|
||||
[(>= ?n ?start-time)]
|
||||
[(<= ?n ?end-time)]
|
||||
[?block :logseq.property/status ?status]
|
||||
[?status :db/ident ?status-ident]
|
||||
[(not= ?status-ident :logseq.property/status.done)]
|
||||
[(not= ?status-ident :logseq.property/status.canceled)]]
|
||||
start-time
|
||||
future-time
|
||||
'[*])
|
||||
(<q repo {}
|
||||
'[:find [(pull ?block ?block-attrs) ...]
|
||||
:in $ ?day ?future ?block-attrs
|
||||
:where
|
||||
(or
|
||||
[?block :block/scheduled ?d]
|
||||
[?block :block/deadline ?d])
|
||||
[(get-else $ ?block :block/repeated? false) ?repeated]
|
||||
[(get-else $ ?block :block/marker "NIL") ?marker]
|
||||
[(not= ?marker "DONE")]
|
||||
[(not= ?marker "CANCELED")]
|
||||
[(not= ?marker "CANCELLED")]
|
||||
[(<= ?d ?future)]
|
||||
(or-join [?repeated ?d ?day]
|
||||
[(true? ?repeated)]
|
||||
[(>= ?d ?day)])]
|
||||
date
|
||||
future-day
|
||||
file-model/file-graph-block-attrs))]
|
||||
(p/let [result (<q repo {}
|
||||
'[:find [(pull ?block ?block-attrs) ...]
|
||||
:in $ ?start-time ?end-time ?block-attrs
|
||||
:where
|
||||
(or [?block :logseq.property/scheduled ?n]
|
||||
[?block :logseq.property/deadline ?n])
|
||||
[(>= ?n ?start-time)]
|
||||
[(<= ?n ?end-time)]
|
||||
[?block :logseq.property/status ?status]
|
||||
[?status :db/ident ?status-ident]
|
||||
[(not= ?status-ident :logseq.property/status.done)]
|
||||
[(not= ?status-ident :logseq.property/status.canceled)]]
|
||||
start-time
|
||||
future-time
|
||||
'[*])]
|
||||
(->> result
|
||||
db-model/sort-by-order-recursive
|
||||
db-utils/group-by-page))))))
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
(ns frontend.db.file-based.async
|
||||
"File based async queries"
|
||||
(:require [promesa.core :as p]
|
||||
[frontend.db.async.util :as db-async-util]
|
||||
[clojure.string :as string]
|
||||
[logseq.common.util.page-ref :as page-ref]))
|
||||
|
||||
(def <q db-async-util/<q)
|
||||
|
||||
(defn <file-based-get-all-properties
|
||||
[graph]
|
||||
(p/let [properties (<q graph {:transact-db? false}
|
||||
'[:find [?p ...]
|
||||
:where
|
||||
[_ :block/properties ?p]])
|
||||
properties (remove (fn [m] (empty? m)) properties)]
|
||||
(->> (map keys properties)
|
||||
(apply concat)
|
||||
distinct
|
||||
sort
|
||||
(map name)
|
||||
(map #(hash-map :block/title %)))))
|
||||
|
||||
(defn- property-value-for-refs-and-text
|
||||
"Given a property value's refs and full text, determines the value to
|
||||
autocomplete"
|
||||
[[refs text]]
|
||||
(if (or (not (coll? refs)) (= 1 (count refs)))
|
||||
text
|
||||
(map #(cond
|
||||
(string/includes? text (page-ref/->page-ref %))
|
||||
(page-ref/->page-ref %)
|
||||
(string/includes? text (str "#" %))
|
||||
(str "#" %)
|
||||
:else
|
||||
%)
|
||||
refs)))
|
||||
|
||||
(defn <get-file-based-property-values
|
||||
[graph property]
|
||||
(p/let [result (<q graph {:transact-db? false}
|
||||
'[:find ?property-val ?text-property-val
|
||||
:in $ ?property
|
||||
:where
|
||||
[?b :block/properties ?p]
|
||||
[?b :block/properties-text-values ?p2]
|
||||
[(get ?p ?property) ?property-val]
|
||||
[(get ?p2 ?property) ?text-property-val]]
|
||||
property)]
|
||||
(->>
|
||||
result
|
||||
(map property-value-for-refs-and-text)
|
||||
(map (fn [x] (if (coll? x) x [x])))
|
||||
(apply concat)
|
||||
(map str)
|
||||
(remove string/blank?)
|
||||
distinct
|
||||
sort)))
|
||||
@@ -553,6 +553,31 @@ independent of format as format specific heading characters are stripped"
|
||||
(:block/_tags class))
|
||||
(remove ldb/hidden?))))
|
||||
|
||||
(defn get-file-page
|
||||
([file-path]
|
||||
(get-file-page file-path true))
|
||||
([file-path title?]
|
||||
(when-let [repo (state/get-current-repo)]
|
||||
(when-let [db (conn/get-db repo)]
|
||||
(some->
|
||||
(d/q
|
||||
(if title?
|
||||
'[:find ?page-name
|
||||
:in $ ?path
|
||||
:where
|
||||
[?file :file/path ?path]
|
||||
[?page :block/file ?file]
|
||||
[?page :block/title ?page-name]]
|
||||
'[:find ?page-name
|
||||
:in $ ?path
|
||||
:where
|
||||
[?file :file/path ?path]
|
||||
[?page :block/file ?file]
|
||||
[?page :block/name ?page-name]])
|
||||
db file-path)
|
||||
db-utils/seq-flatten
|
||||
first)))))
|
||||
|
||||
(comment
|
||||
;; For debugging
|
||||
(defn get-all-blocks
|
||||
|
||||
@@ -1,194 +0,0 @@
|
||||
(ns frontend.fs.diff-merge
|
||||
"Implementation of text (file) based content diff & merge for conflict resolution"
|
||||
(:require ["@logseq/diff-merge" :refer [attach_uuids Differ Merger]]
|
||||
[cljs-bean.core :as bean]
|
||||
[clojure.string :as string]
|
||||
[frontend.db.file-based.model :as file-model]
|
||||
[frontend.db.utils :as db-utils]
|
||||
[logseq.graph-parser.block :as gp-block]
|
||||
[logseq.graph-parser.mldoc :as gp-mldoc]
|
||||
[logseq.graph-parser.property :as gp-property]
|
||||
[logseq.graph-parser.utf8 :as utf8]))
|
||||
|
||||
(defn diff
|
||||
"2-ways diff
|
||||
Accept: blocks in the struct with the required info
|
||||
Please refer to the `Block` struct in the link below
|
||||
https://github.com/logseq/diff-merge/blob/master/lib/mldoc.ts"
|
||||
[base incoming]
|
||||
(let [differ (Differ.)]
|
||||
(.diff_logseqMode differ (bean/->js base) (bean/->js incoming))))
|
||||
|
||||
;; (defonce getHTML visualizeAsHTML)
|
||||
|
||||
(defonce attachUUID attach_uuids)
|
||||
|
||||
(defn db->diff-blocks
|
||||
"db: datascript db
|
||||
page-name: string"
|
||||
[page-name]
|
||||
{:pre (string? page-name)}
|
||||
(let [walked (file-model/get-sorted-page-block-ids-and-levels page-name)
|
||||
blocks (db-utils/pull-many [:block/uuid :block/title :block/level] (map :id walked))
|
||||
levels (map :level walked)
|
||||
blocks (map (fn [block level]
|
||||
{:uuid (str (:block/uuid block)) ;; Force to be string
|
||||
:body (:block/title block)
|
||||
:level level})
|
||||
blocks levels)]
|
||||
blocks))
|
||||
|
||||
;; TODO: Switch to ast->diff-blocks-alt
|
||||
;; Diverged from gp-block/extract-blocks for decoupling
|
||||
;; The process of doing 2 way diff is like:
|
||||
;; 1. Given a base ver. of page (AST in DB), and a branch ver. of page (externally modified file content)
|
||||
;; 2. Transform both base ver (done by THIS fn). & branch ver. into the same format (diff-blocks)
|
||||
;; 3. Apply diff-merge/diff on them, which returns the resolved uuids of the branch ver
|
||||
;; 4. Attach these resolved uuids into the blocks newly parsed by graph-parser
|
||||
;; Keep all the diff-merge fns, including diff-merge/ast->diff-blocks out of the graph-parser,
|
||||
;; Only inject the step 4 into graph-parser as a hook
|
||||
(defn ast->diff-blocks
|
||||
"Prepare the blocks for diff-merge
|
||||
blocks: ast of blocks
|
||||
content: corresponding raw content"
|
||||
[blocks content format {:keys [user-config block-pattern]}]
|
||||
{:pre [(string? content) (contains? #{:markdown :org} format)]}
|
||||
(let [encoded-content (utf8/encode content)]
|
||||
(loop [headings []
|
||||
blocks (reverse blocks)
|
||||
properties {}
|
||||
end-pos (.-length encoded-content)]
|
||||
(if (seq blocks)
|
||||
(let [[block pos-meta] (first blocks)
|
||||
;; fix start_pos
|
||||
pos-meta (assoc pos-meta :end_pos end-pos)]
|
||||
(cond
|
||||
(gp-block/heading-block? block)
|
||||
(let [content (gp-block/get-block-content encoded-content (second block) format pos-meta block-pattern)]
|
||||
(recur (conj headings {:body content
|
||||
:level (:level (second block))
|
||||
:uuid (:id properties)})
|
||||
(rest blocks) {} (:start_pos pos-meta))) ;; The current block's start pos is the next block's end pos
|
||||
|
||||
(gp-property/properties-ast? block)
|
||||
(let [new-props (:properties (gp-block/extract-properties (second block) (assoc user-config :format format)))]
|
||||
;; sending the current end pos to next, as it's not finished yet
|
||||
;; supports multiple properties sub-block possible in future
|
||||
(recur headings (rest blocks) (merge properties new-props) (:end_pos pos-meta)))
|
||||
|
||||
:else
|
||||
(recur headings (rest blocks) properties (:end_pos pos-meta))))
|
||||
(if (empty? properties)
|
||||
(reverse headings)
|
||||
;; Add pre-blocks
|
||||
(let [[block _] (first blocks)
|
||||
pos-meta {:start_pos 0 :end_pos end-pos}
|
||||
content (gp-block/get-block-content encoded-content block format pos-meta block-pattern)
|
||||
uuid (:id properties)]
|
||||
(cons {:body content
|
||||
:level 1
|
||||
:uuid uuid}
|
||||
(reverse headings))))))))
|
||||
|
||||
(defn- get-sub-content-from-pos-meta
|
||||
"Replace gp-block/get-block-content, return bare content, without any trim"
|
||||
[raw-content pos-meta]
|
||||
(let [{:keys [start_pos end_pos]} pos-meta]
|
||||
(utf8/substring raw-content start_pos end_pos)))
|
||||
|
||||
;; Diverged from ast->diff-blocks
|
||||
;; Add :meta :raw-body to the block
|
||||
(defn- ast->diff-blocks-alt
|
||||
"Prepare the blocks for diff-merge
|
||||
blocks: ast of blocks
|
||||
content: corresponding raw content"
|
||||
[blocks content format {:keys [user-config block-pattern]}]
|
||||
{:pre [(string? content) (contains? #{:markdown :org} format)]}
|
||||
(let [utf8-encoded-content (utf8/encode content)]
|
||||
(loop [headings []
|
||||
blocks (reverse blocks)
|
||||
properties {}
|
||||
end-pos (.-length utf8-encoded-content)]
|
||||
(cond
|
||||
(seq blocks)
|
||||
(let [[block pos-meta] (first blocks)
|
||||
;; fix start_pos for properties
|
||||
fixed-pos-meta (assoc pos-meta :end_pos end-pos)]
|
||||
(cond
|
||||
(gp-block/heading-block? block)
|
||||
(let [content (gp-block/get-block-content utf8-encoded-content (second block) format fixed-pos-meta block-pattern)
|
||||
content-raw (get-sub-content-from-pos-meta utf8-encoded-content fixed-pos-meta)]
|
||||
(recur (conj headings {:body content
|
||||
:meta {:raw-body (string/trimr content-raw)}
|
||||
:level (:level (second block))
|
||||
:uuid (:id properties)})
|
||||
(rest blocks)
|
||||
{}
|
||||
(:start_pos fixed-pos-meta))) ;; The current block's start pos is the next block's end pos
|
||||
|
||||
(gp-property/properties-ast? block)
|
||||
(let [new-props (:properties (gp-block/extract-properties (second block) (assoc user-config :format format)))]
|
||||
;; sending the current end pos to next, as it's not finished yet
|
||||
;; supports multiple properties sub-block possible in future
|
||||
(recur headings (rest blocks) (merge properties new-props) (:end_pos fixed-pos-meta)))
|
||||
|
||||
:else
|
||||
(recur headings (rest blocks) properties (:end_pos fixed-pos-meta))))
|
||||
|
||||
(empty? properties)
|
||||
(reverse headings)
|
||||
|
||||
;; Add pre-blocks
|
||||
:else ;; ??? unreachable
|
||||
(let [[block _] (first blocks)
|
||||
pos-meta {:start_pos 0 :end_pos end-pos}
|
||||
content (gp-block/get-block-content utf8-encoded-content block format pos-meta block-pattern)
|
||||
content-raw (get-sub-content-from-pos-meta utf8-encoded-content pos-meta)
|
||||
uuid (:id properties)]
|
||||
(cons {:body content
|
||||
:meta {:raw-body (string/trimr content-raw)}
|
||||
:level 1
|
||||
:uuid uuid}
|
||||
(reverse headings)))))))
|
||||
|
||||
(defn- rebuild-content
|
||||
"translate [[[op block]]] to merged content"
|
||||
[_base-diffblocks diffs _format]
|
||||
;; [[[0 {:body "attrib:: xxx", :level 1, :uuid nil}] ...] ...]
|
||||
(let [ops-fn (fn [ops]
|
||||
(map (fn [[op {:keys [meta]}]]
|
||||
(when (or (= op 0) (= op 1)) ;; equal or insert
|
||||
(:raw-body meta)))
|
||||
ops))]
|
||||
(->> diffs
|
||||
(mapcat ops-fn)
|
||||
(filter seq)
|
||||
(string/join "\n"))))
|
||||
|
||||
(defn three-way-merge
|
||||
[base income current format]
|
||||
(let [->ast (fn [text] (if (= format :org)
|
||||
(gp-mldoc/->edn text (gp-mldoc/default-config :org))
|
||||
(gp-mldoc/->edn text (gp-mldoc/default-config :markdown))))
|
||||
options (if (= format :org)
|
||||
{:block-pattern "*"}
|
||||
{:block-pattern "-"})
|
||||
merger (Merger.)
|
||||
base-ast (->ast base)
|
||||
base-diffblocks (ast->diff-blocks-alt base-ast base format options)
|
||||
income-ast (->ast income)
|
||||
income-diffblocks (ast->diff-blocks-alt income-ast income format options)
|
||||
current-ast (->ast current)
|
||||
current-diffblocks (ast->diff-blocks-alt current-ast current format options)
|
||||
branch-diffblocks [current-diffblocks income-diffblocks]
|
||||
merged (.mergeBlocks merger (bean/->js base-diffblocks) (bean/->js branch-diffblocks))
|
||||
;; For extracting diff-merge test cases
|
||||
;; _ (prn "input:")
|
||||
;; _ (prn (js/JSON.stringify (bean/->js base-diffblocks)))
|
||||
;; _ (prn (js/JSON.stringify (bean/->js branch-diffblocks)))
|
||||
;; _ (prn "logseq diff merge version: " version)
|
||||
;; _ (prn "output:")
|
||||
;; _ (prn (js/JSON.stringify merged))
|
||||
merged-diff (bean/->clj merged)
|
||||
merged-content (rebuild-content base-diffblocks merged-diff format)]
|
||||
merged-content))
|
||||
@@ -10,7 +10,6 @@
|
||||
[frontend.date :as date]
|
||||
[frontend.db :as db]
|
||||
[frontend.db.async :as db-async]
|
||||
[frontend.db.file-based.model :as file-model]
|
||||
[frontend.db.model :as db-model]
|
||||
[frontend.db.utils :as db-utils]
|
||||
[frontend.diff :as diff]
|
||||
@@ -1393,7 +1392,7 @@
|
||||
(log/error :save-block-failed error)))))))
|
||||
|
||||
(defn delete-asset-of-block!
|
||||
[{:keys [repo asset-block href full-text block-id local? delete-local?] :as _opts}]
|
||||
[{:keys [repo asset-block full-text block-id local? delete-local?] :as _opts}]
|
||||
(let [block (db-model/query-block-by-uuid block-id)
|
||||
_ (or block (throw (ex-info (str block-id " not exists")
|
||||
{:block-id block-id})))
|
||||
@@ -1403,17 +1402,8 @@
|
||||
(string/replace text full-text ""))]
|
||||
(save-block! repo block content)
|
||||
(when (and local? delete-local?)
|
||||
(if asset-block
|
||||
(delete-block-aux! asset-block)
|
||||
(when-let [href (if (util/electron?) href
|
||||
(second (re-find #"\((.+)\)$" full-text)))]
|
||||
(let [block-file-rpath (file-model/get-block-file-path block)
|
||||
asset-fpath (if (string/starts-with? href "assets://")
|
||||
(path/url-to-path href)
|
||||
(config/get-repo-fpath
|
||||
repo
|
||||
(path/resolve-relative-path block-file-rpath href)))]
|
||||
(fs/unlink! repo asset-fpath nil)))))))
|
||||
(when asset-block
|
||||
(delete-block-aux! asset-block)))))
|
||||
|
||||
(defn db-based-write-asset!
|
||||
[repo dir file file-rpath]
|
||||
@@ -1667,10 +1657,6 @@
|
||||
[q]
|
||||
(search/property-search q))
|
||||
|
||||
(defn get-matched-property-values
|
||||
[property q]
|
||||
(search/property-value-search property q))
|
||||
|
||||
(defn get-last-command
|
||||
[input]
|
||||
(try
|
||||
|
||||
@@ -73,21 +73,6 @@
|
||||
(let [result (fuzzy/fuzzy-search properties q :limit limit)]
|
||||
(vec result))))))))
|
||||
|
||||
;; file-based graph only
|
||||
(defn property-value-search
|
||||
([property q]
|
||||
(property-value-search property q 100))
|
||||
([property q limit]
|
||||
(when-let [repo (state/get-current-repo)]
|
||||
(when q
|
||||
(p/let [q (fuzzy/clean-str q)
|
||||
result (db-async/<file-get-property-values repo (keyword property))]
|
||||
(when (seq result)
|
||||
(if (string/blank? q)
|
||||
result
|
||||
(let [result (fuzzy/fuzzy-search result q :limit limit)]
|
||||
(vec result)))))))))
|
||||
|
||||
(defn rebuild-indices!
|
||||
([]
|
||||
(rebuild-indices! (state/get-current-repo)))
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
(ns frontend.db.file-based.model-test
|
||||
(:require [cljs.test :refer [use-fixtures deftest is]]
|
||||
[frontend.db.file-based.model :as file-model]
|
||||
[frontend.test.helper :as test-helper :refer [load-test-files]]))
|
||||
|
||||
(use-fixtures :each {:before test-helper/start-test-db!
|
||||
:after test-helper/destroy-test-db!})
|
||||
|
||||
(deftest get-namespace-pages
|
||||
(load-test-files [{:file/path "pages/a.b.c.md"
|
||||
:file/content "foo"}
|
||||
{:file/path "pages/b.c.md"
|
||||
:file/content "bar"}
|
||||
{:file/path "pages/b.d.md"
|
||||
:file/content "baz"}])
|
||||
|
||||
(is (= ["a/b" "a/b/c"]
|
||||
(map :block/name (file-model/get-namespace-pages test-helper/test-db "a"))))
|
||||
|
||||
(is (= ["b/c" "b/d"]
|
||||
(map :block/name (file-model/get-namespace-pages test-helper/test-db "b")))))
|
||||
|
||||
(deftest get-page-namespace-routes
|
||||
(load-test-files [{:file/path "pages/a.b.c.md"
|
||||
:file/content "foo"}
|
||||
{:file/path "pages/b.c.md"
|
||||
:file/content "bar"}
|
||||
{:file/path "pages/b.d.md"
|
||||
:file/content "baz"}])
|
||||
|
||||
(is (= '()
|
||||
(map :block/name (file-model/get-page-namespace-routes test-helper/test-db "b/c")))
|
||||
"Empty if page exists"))
|
||||
@@ -1,17 +1,36 @@
|
||||
(ns frontend.test.file
|
||||
"Provides util handler fns for file graph files"
|
||||
(:refer-clojure :exclude [load-file])
|
||||
(:require [frontend.db :as db]
|
||||
[frontend.db.file-based.model :as file-model]
|
||||
(:require [datascript.core :as d]
|
||||
[frontend.db :as db]
|
||||
[frontend.db.conn :as conn]
|
||||
[frontend.db.utils :as db-utils]
|
||||
[frontend.handler.common.config-edn :as config-edn-common-handler]
|
||||
[frontend.handler.global-config :as global-config-handler]
|
||||
[frontend.schema.handler.global-config :as global-config-schema]
|
||||
[frontend.schema.handler.repo-config :as repo-config-schema]
|
||||
[frontend.state :as state]
|
||||
[frontend.test.file.reset :as file-reset]
|
||||
[frontend.util :as util]
|
||||
[logseq.common.path :as path]
|
||||
[logseq.common.util :as common-util]))
|
||||
|
||||
(defn- get-file-page-id
|
||||
[file-path]
|
||||
(when-let [repo (state/get-current-repo)]
|
||||
(when-let [db (conn/get-db repo)]
|
||||
(some->
|
||||
(d/q
|
||||
'[:find ?page
|
||||
:in $ ?path
|
||||
:where
|
||||
[?file :file/path ?path]
|
||||
[?page :block/name]
|
||||
[?page :block/file ?file]]
|
||||
db file-path)
|
||||
db-utils/seq-flatten
|
||||
first))))
|
||||
|
||||
(defn reset-file!
|
||||
[repo file-path content opts]
|
||||
(when util/node-test?
|
||||
@@ -57,7 +76,7 @@
|
||||
:mtime mtime}
|
||||
result (if reset?
|
||||
(do
|
||||
(when-let [page-id (file-model/get-file-page-id path)]
|
||||
(when-let [page-id (get-file-page-id path)]
|
||||
(db/transact! repo
|
||||
[[:db/retract page-id :block/alias]
|
||||
[:db/retract page-id :block/tags]]
|
||||
|
||||
Reference in New Issue
Block a user