Pārlūkot izejas kodu

feat: simplified markdown properties wip

Tienson Qin 4 gadi atpakaļ
vecāks
revīzija
0c758fc268

+ 0 - 32
src/main/frontend/components/content.cljs

@@ -145,38 +145,6 @@
              :on-click (fn [_e]
                          (editor-handler/remove-block-property! block-id "background-color"))}
             "Clear"]]
-          (let [empty-properties? (empty? (:block/properties block))
-                all-hidden? (text/properties-hidden? (:block/properties block))]
-            (when (or empty-properties? all-hidden?)
-              (ui/menu-link
-               {:key "Add a property"
-                :on-click (fn [_e]
-                            (when-let [block-node (util/rec-get-block-node target)]
-                              (let [block-dom-id (gobj/get block-node "id")
-                                    edit-input-id (string/replace block-dom-id "ls-block" "edit-block")
-                                    content (:block/content block)
-                                    content (cond
-                                              empty-properties?
-                                              (text/rejoin-properties content {"" ""} {:remove-blank? false})
-                                              all-hidden?
-                                              (let [idx (string/index-of content "\n:END:")]
-                                                (str
-                                                 (subs content 0 idx)
-                                                 "\n:: "
-                                                 (subs content idx)))
-                                              :else
-                                              content)
-                                    content-without-level (text/remove-level-spaces content (:block/format block))
-                                    pos (string/index-of content-without-level ": \n:END:")]
-                                (editor-handler/edit-block! block
-                                                            pos
-                                                            (:block/format block)
-                                                            edit-input-id
-                                                            (cond-> {:custom-content content}
-                                                              all-hidden?
-                                                              (assoc :custom-properties
-                                                                     (assoc (:block/properties block) "" "")))))))}
-               "Add a property")))
 
           (ui/menu-link
            {:key "Open in sidebar"

+ 1 - 1
src/main/frontend/external/roam.cljc

@@ -85,7 +85,7 @@
         level-pattern (apply str (repeat level "#"))
         properties (when (contains? @all-refed-uids uid)
                      (str
-                      (util/format ":PROPERTIES:\n:ID:%s\n:END:"
+                      (util/format "id:: %s"
                                    (str (get @uid->uuid uid)))
                       "\n"))]
     (if string

+ 2 - 2
src/main/frontend/handler/common.cljs

@@ -55,8 +55,8 @@
                  (js/console.dir error)))))))
 
 (defn copy-to-clipboard-without-id-property!
-  [content]
-  (util/copy-to-clipboard! (text/remove-id-property content)))
+  [format content]
+  (util/copy-to-clipboard! (text/remove-id-property! format content)))
 
 (defn config-with-document-mode
   [config]

+ 12 - 13
src/main/frontend/handler/editor.cljs

@@ -716,14 +716,13 @@
       (when-let [block (db/entity [:block/uuid block-id])]
         (let [format (:block/format block)
               content (:block/content block)
-              markdown? (= format :markdown)
               properties (:block/properties block)
               properties (if value        ; add
                            (assoc properties key value)
                            (dissoc properties key))
               content (if value
-                        (text/insert-property content key value)
-                        (text/remove-property content key))
+                        (text/insert-property! format content key value)
+                        (text/remove-property! format key content))
               block (outliner-core/block {:block/uuid block-id
                                           :block/properties properties
                                           :block/content content})]
@@ -891,8 +890,9 @@
           ids (if (= :up (state/get-selection-direction))
                 (reverse ids)
                 ids)
-          [content tree] (compose-copied-blocks-contents-&-block-tree repo ids)]
-      (common-handler/copy-to-clipboard-without-id-property! content)
+          [content tree] (compose-copied-blocks-contents-&-block-tree repo ids)
+          block (db/pull [:block/uuid (first ids)])]
+      (common-handler/copy-to-clipboard-without-id-property! (:block/format block) content)
       (state/set-copied-blocks content tree))))
 
 (defn cut-selection-blocks
@@ -994,7 +994,7 @@
   [block-id]
   (when-let [block (db/pull [:block/uuid block-id])]
     (let [content (:block/content block)]
-      (common-handler/copy-to-clipboard-without-id-property! content)
+      (common-handler/copy-to-clipboard-without-id-property! (:block/format block) content)
       (delete-block-aux! block false))))
 
 (defn clear-last-selected-block!
@@ -1815,8 +1815,8 @@
                                                   [(:block/content %) (:block/title %)])
                                                 new-content
                                                 (-> new-content
-                                                    (text/remove-property "id")
-                                                    (text/remove-property "custom_id"))]
+                                                    (text/remove-property! format "id")
+                                                    (text/remove-property! format "custom_id"))]
                                             (conj {:block/uuid uuid
                                                    :block/page (select-keys page [:db/id])
                                                    :block/file (select-keys file [:db/id])
@@ -1844,9 +1844,8 @@
          (db/refresh! repo {:key :block/insert :data new-blocks}))))))
 
 (defn template-on-chosen-handler
-  [input id q format edit-block edit-content]
-  (fn [[template db-id] _click?]
-    (save-current-block!)
+  [_input id _q format _edit-block _edit-content]
+  (fn [[_template db-id] _click?]
     (let [repo (state/get-current-repo)
           block (db/entity db-id)
           block-uuid (:block/uuid block)
@@ -1857,8 +1856,8 @@
       (paste-block-tree-at-point tree [:template :including-parent]
                                  (fn [content]
                                    (-> content
-                                       (text/remove-property "template")
-                                       (text/remove-property "including-parent")
+                                       (text/remove-property! format "template")
+                                       (text/remove-property! format "including-parent")
                                        template/resolve-dynamic-template!)))
       (clear-when-saved!)
       (insert-command! id "" format {})

+ 1 - 1
src/main/frontend/handler/export.cljs

@@ -59,7 +59,7 @@
   [block-id]
   (when-let [block (db/pull [:block/uuid block-id])]
     (let [content (:block/content block)]
-      (common-handler/copy-to-clipboard-without-id-property! content))))
+      (common-handler/copy-to-clipboard-without-id-property! (:block/format block) content))))
 
 (defn copy-block-as-json!
   [block-id]

+ 3 - 3
src/main/frontend/search/db.cljs

@@ -16,7 +16,7 @@
 (defn block->index
   [{:block/keys [uuid content format] :as block}]
   (when-let [result (->> (text/remove-level-spaces content format)
-                         (text/remove-properties!))]
+                         (text/remove-id-property! format))]
     {:id (:db/id block)
      :uuid (str uuid)
      :content result}))
@@ -35,7 +35,7 @@
                       (clj->js {:keys ["uuid" "content"]
                                 :shouldSort true
                                 :tokenize true
-                                :minMatchCharLength 2
+                                :minMatchCharLength 1
                                 :distance 1000
                                 :threshold 0.35}))]
     (swap! indices assoc-in [repo :blocks] indice)
@@ -52,7 +52,7 @@
                         (clj->js {:keys ["name"]
                                   :shouldSort true
                                   :tokenize true
-                                  :minMatchCharLength 2
+                                  :minMatchCharLength 1
                                   :distance 1000
                                   :threshold 0.35
                                   }))]

+ 106 - 134
src/main/frontend/text.cljs

@@ -170,154 +170,116 @@
     (->> (concat title-lines body)
          (string/join "\n"))))
 
-(defn remove-id-property
-  [content]
-  (let [lines (->> (string/split-lines content)
-                   (remove #(let [s (string/lower-case (string/trim %))]
-                              (and
-                               (or (string/starts-with? s ":id:")
-                                   (string/starts-with? s ":custom_id:")
-                                   (string/starts-with? s "id:: ")
-                                   (string/starts-with? s "custom_id:: "))
-                               (let [id (and
-                                         (> (count s) 36)
-                                         (subs s (- (count s) 36)))]
-                                 (and id (util/uuid-string? id)))))))]
-    (string/join "\n" lines)))
-
 (defn build-properties-str
-  [properties]
+  [format properties]
   (when (seq properties)
-    (let [properties-content (->> (map (fn [[k v]] (util/format ":%s: %s" k v)) properties)
+    (let [org? (= format :org)
+          kv-format (if org? ":%s: %s" "%s:: %s")
+          full-format (if org? ":PROPERTIES:\n%s\n:END:\n" "%s\n")
+          properties-content (->> (map (fn [[k v]] (util/format kv-format k v)) properties)
                                   (string/join "\n"))]
-      (util/format ":PROPERTIES:\n%s\n:END:\n"
-                   properties-content))))
-
-(defn rejoin-properties
-  ([content properties]
-   (rejoin-properties content properties {}))
-  ([content properties {:keys [remove-blank? block-with-title?]
-                        :or {remove-blank? true
-                             block-with-title? true}}]
-   (let [content (string/triml content)
-         properties (if (false? (get properties :heading))
-                      (dissoc properties :heading)
-                      properties)
-         properties (if remove-blank?
-                      (remove (fn [[k _v]] (string/blank? k)) properties)
-                      properties)
-         [title body] (if block-with-title?
-                        (util/safe-split-first "\n" content)
-                        ["" content])
-         properties (build-properties-str properties)]
-     (if block-with-title?
-       (str title "\n" properties body)
-       (str properties body)))))
+      (util/format full-format properties-content))))
 
 (defn contains-properties?
-  [s]
-  (let [lines (set (map string/trim (string/split-lines s)))]
-    (when (seq lines)
-      (set/subset? #{":PROPERTIES:" ":END:"} lines))))
-
-;; FIXME:
-(defn get-properties-text
-  [text]
-  (let [start (or (string/index-of text ":PROPERTIES:")
-                  (string/index-of text ":properties:"))
-        end (or (string/index-of text ":END:")
-                (string/index-of text ":end:"))]
-    (when (and start end)
-      (subs text start (+ end 5)))))
-
-(defn extract-properties
-  [text]
-  (when-let [properties-text (get-properties-text text)]
-    (->> (string/split-lines properties-text)
-         (map (fn [line]
-                (when (= ":" (first line))
-                  (let [[k v] (util/split-first ":" (subs line 1))]
-                    (when (and k v)
-                      (let [k (string/trim (string/lower-case k))
-                            v (string/trim v)]
-                        (when-not (contains? #{"properties" "end"} k)
-                          [k v])))))))
-         (into {}))))
-
-(defn insert-property
-  [content key value]
+  [content]
+  (and (string/includes? content properties-start)
+       (string/includes? content properties-end)))
+
+(defn simplified-property?
+  [line]
+  (some? (first (util/split-first ":: " line))))
+
+(defn insert-property!
+  [format content key value]
   (when (and (not (string/blank? (name key)))
              (not (string/blank? (str value))))
-    (let [key (string/lower-case (name key))
-          value (str value)
-          [title body] (util/safe-split-first "\n" content)]
-      (if-not (contains-properties? content)
-        (let [properties (build-properties-str {key value})]
+    (let [org? (= :org format)
+          key (string/lower-case (name key))
+          value (string/trim (str value))
+          lines (string/split-lines content)
+          start-idx (.indexOf lines properties-start)
+          end-idx (.indexOf lines properties-end)]
+      (cond
+        (and org? (not (contains-properties? content)))
+        (let [properties (build-properties-str format {key value})
+              [title body] (util/safe-split-first "\n" content)]
           (str title "\n" properties body))
-        (let [lines (string/split-lines content)
-              [title-lines properties-and-body] (split-with (fn [l] (not (string/starts-with? (string/upper-case (string/triml l)) ":PROPERTIES:"))) lines)
-              properties? (fn [l]
-                            (or
-                             (string/starts-with? (string/triml l) ":") ; kv
-                             (string/starts-with? (string/upper-case (string/triml l)) ":end:")))
-              properties (take-while properties? properties-and-body)
-              exists? (atom false)
-              new-properties (doall
-                              (map (fn [l]
-                                     (if (string/starts-with? (string/triml l) (str ":" key ":"))
-                                       (do
-                                         (reset! exists? true)
-                                         (util/format ":%s: %s" key value))
-                                       l)) properties))
-              new-properties (if @exists?
-                               new-properties
-                               (concat
-                                (drop-last new-properties)
-                                [(util/format ":%s: %s" key value)
-                                 (last new-properties)]))
-              body (drop-while properties? properties-and-body)]
-          (->> (concat title-lines new-properties body)
-               (string/join "\n")))))))
-
-(defn remove-property
-  [content key]
-  (when (not (string/blank? (name key)))
-    (let [key (string/lower-case (name key))
-          [title body] (util/safe-split-first "\n" content)]
-      (if-not (contains-properties? content)
-        content
-        (let [lines (string/split-lines content)
-              [title-lines properties-and-body] (split-with (fn [l] (not (string/starts-with? (string/upper-case (string/triml l)) ":PROPERTIES:"))) lines)
-              properties? (fn [l]
-                            (or
-                             (string/starts-with? (string/triml l) ":") ; kv
-                             (string/starts-with? (string/upper-case (string/triml l)) ":end:")))
-              properties (take-while properties? properties-and-body)
-              exists? (atom false)
-              new-properties (->> (map (fn [l]
-                                     (if (string/starts-with? (string/triml l) (str ":" key ":"))
-                                       nil
-                                       l)) properties)
-                                  (remove nil?))
-              body (drop-while properties? properties-and-body)]
-          (->> (concat title-lines new-properties body)
-               (string/join "\n")))))))
 
-(defn build-data-value
-  [col]
-  (let [items (map (fn [item] (str "\"" item "\"")) col)]
-    (util/format "[%s]"
-                 (string/join ", " items))))
+        (and (>= start-idx 0) (> end-idx 0) (> end-idx start-idx))
+        (let [exists? (atom false)
+              before (subvec lines 0 start-idx)
+              middle (doall
+                      (->> (subvec lines (inc start-idx) end-idx)
+                           (mapv (fn [text]
+                                   (let [[k v] (util/split-first ":" (subs text 1))]
+                                     (if (and k v)
+                                       (let [key-exists? (= k key)
+                                             _ (when key-exists? (reset! exists? true))
+                                             v (if key-exists? value v)]
+                                         (str ":" k ": "  (string/trim v)))
+                                       text))))))
+              middle (if @exists? middle (conj middle (str ":" key ": "  value)))
+              after (subvec lines (inc end-idx))
+              lines (concat before middle after)]
+          (string/join "\n" lines))
 
-(defn image-link?
-  [img-formats s]
-  (some (fn [fmt] (re-find (re-pattern (str "(?i)\\." fmt "(?:\\?([^#]*))?(?:#(.*))?$")) s)) img-formats))
+        (not org?)
+        (let [exists? (atom false)
+              new-property-s (str key ":: "  value)
+              groups (partition-by simplified-property? lines)
+              no-properties? (and (= 1 (count groups))
+                                  (not (simplified-property? (ffirst groups))))
+              lines (mapcat (fn [lines]
+                              (if (simplified-property? (first lines))
+                                (let [lines (doall
+                                             (mapv (fn [text]
+                                                     (let [[k v] (util/split-first ":: " text)]
+                                                       (if (and k v)
+                                                         (let [key-exists? (= k key)
+                                                               _ (when key-exists? (reset! exists? true))
+                                                               v (if key-exists? value v)]
+                                                           (str k ":: "  (string/trim v)))
+                                                         text)))
+                                                   lines))
+                                      lines (if @exists? lines (conj lines new-property-s))]
+                                  lines)
+                                lines))
+                            groups)
+              lines (if no-properties?
+                      (if (string/blank? content)
+                        [new-property-s]
+                        (cons (first lines) (cons new-property-s (rest lines))))
+                      lines)]
+          (string/join "\n" lines))
+
+        :else
+        content))))
+
+(defn remove-property!
+  ([format key content]
+   (remove-property! format key content true))
+  ([format key content first?]
+   (when (not (string/blank? (name key)))
+     (let [format (or format :markdown)
+           key (string/lower-case (name key))
+           remove-f (if first? util/remove-first remove)]
+       (if-not (and (= format :org) (contains-properties? content))
+         content
+         (let [lines (->> (string/split-lines content)
+                          (remove-f (fn [line]
+                                      (let [s (string/triml (string/lower-case line))]
+                                        (or (string/starts-with? s (str ":" key ":"))
+                                            (string/starts-with? s (str key ":: ")))))))]
+           (string/join "\n" lines)))))))
+
+(defn remove-id-property!
+  [format content]
+  (remove-property! format "id" content false))
 
 (defn ->new-properties
   "New syntax: key:: value"
   [content]
-  (if (and (string/includes? content properties-start)
-           (string/includes? content properties-end))
+  (if (contains-properties? content)
     (let [lines (string/split-lines content)
           start-idx (.indexOf lines properties-start)
           end-idx (.indexOf lines properties-end)]
@@ -334,3 +296,13 @@
           (string/join "\n" lines))
         content))
     content))
+
+(defn build-data-value
+  [col]
+  (let [items (map (fn [item] (str "\"" item "\"")) col)]
+    (util/format "[%s]"
+                 (string/join ", " items))))
+
+(defn image-link?
+  [img-formats s]
+  (some (fn [fmt] (re-find (re-pattern (str "(?i)\\." fmt "(?:\\?([^#]*))?(?:#(.*))?$")) s)) img-formats))

+ 9 - 0
src/main/frontend/util.cljc

@@ -1245,3 +1245,12 @@
    (defn trace!
      []
      (js/console.trace)))
+
+(defn remove-first [pred coll]
+  ((fn inner [coll]
+     (lazy-seq
+      (when-let [[x & xs] (seq coll)]
+        (if (pred x)
+          xs
+          (cons x (inner xs))))))
+   coll))

+ 5 - 5
src/test/frontend/text_test.cljs

@@ -99,7 +99,7 @@
 
 (defn remove-id-property
   []
-  (are [x y] (= (text/remove-id-property x) y)
+  (are [x y] (= (text/remove-id-property! x) y)
     "hello\n:PROPERTIES:\n:id: f9873a81-07b9-4246-b910-53a6f5ec7e04\n:END:\n"
     "hello\n:PROPERTIES:\n:END:"
 
@@ -126,16 +126,16 @@
 (defn test-insert-property
   []
   (are [x y] (= x y)
-    (text/insert-property "hello" "a" "b")
+    (text/insert-property! :org "hello" "a" "b")
     "hello\n:PROPERTIES:\n:a: b\n:END:\n"
 
-    (text/insert-property "hello" "a" false)
+    (text/insert-property! :org "hello" "a" false)
     "hello\n:PROPERTIES:\n:a: false\n:END:\n"
 
-    (text/insert-property "hello\n:PROPERTIES:\n:a: b\n:END:\n" "c" "d")
+    (text/insert-property! :org "hello\n:PROPERTIES:\n:a: b\n:END:\n" "c" "d")
     "hello\n:PROPERTIES:\n:a: b\n:c: d\n:END:"
 
-    (text/insert-property "hello\n:PROPERTIES:\n:a: b\n:END: world\n" "c" "d")
+    (text/insert-property! :org "hello\n:PROPERTIES:\n:a: b\n:END: world\n" "c" "d")
     "hello\n:PROPERTIES:\n:c: d\n:END:\n:PROPERTIES:\n:a: b\n:END: world\n"))
 
 (defn test->new-properties