mirror of https://github.com/logseq/logseq
feat: support org mode file links (#681)
* feat: support org-mode file links Add a `:org-mode/insert-file-links` option to configuration.pull/687/head
parent
85a1837004
commit
5d3b6322f5
|
@ -6,7 +6,10 @@
|
|||
[clojure.string :as string]
|
||||
[goog.dom :as gdom]
|
||||
[goog.object :as gobj]
|
||||
[frontend.format :as format]))
|
||||
[frontend.format :as format]
|
||||
[frontend.handler.common :as common-handler]))
|
||||
|
||||
;; TODO: move to frontend.handler.editor.commands
|
||||
|
||||
(defonce *show-commands (atom false))
|
||||
(defonce *slash-caret-pos (atom nil))
|
||||
|
@ -16,10 +19,6 @@
|
|||
(defonce *angle-bracket-caret-pos (atom nil))
|
||||
(defonce *current-command (atom nil))
|
||||
|
||||
(defn ->page-reference
|
||||
[page]
|
||||
(util/format "[[%s]]" page))
|
||||
|
||||
(def link-steps [[:editor/input (str slash "link")]
|
||||
[:editor/show-input [{:command :link
|
||||
:id :link
|
||||
|
@ -87,7 +86,7 @@
|
|||
|
||||
;; Credits to roamresearch.com
|
||||
(defn commands-map
|
||||
[]
|
||||
[get-page-ref-text]
|
||||
(->>
|
||||
(concat
|
||||
(get-preferred-workflow)
|
||||
|
@ -107,9 +106,9 @@
|
|||
:placeholder "Draw title"}]]]]
|
||||
["WAITING" (->marker "WAITING")]
|
||||
["CANCELED" (->marker "CANCELED")]
|
||||
["Tomorrow" (->page-reference (date/tomorrow))]
|
||||
["Yesterday" (->page-reference (date/yesterday))]
|
||||
["Today" (->page-reference (date/today))]
|
||||
["Tomorrow" #(get-page-ref-text (date/tomorrow))]
|
||||
["Yesterday" #(get-page-ref-text (date/yesterday))]
|
||||
["Today" #(get-page-ref-text (date/today))]
|
||||
["Current Time" (date/get-current-time)]
|
||||
["Date Picker" [[:editor/show-date-picker]]]
|
||||
["Page Reference" [[:editor/input "[[]]" {:backward-pos 2}]
|
||||
|
@ -137,7 +136,14 @@
|
|||
(remove nil?)
|
||||
(util/distinct-by-last-wins first)))
|
||||
|
||||
(defonce *matched-commands (atom (commands-map)))
|
||||
(defonce *matched-commands (atom nil))
|
||||
(defonce *initial-commands (atom nil))
|
||||
|
||||
(defn init-commands!
|
||||
[get-page-ref-text]
|
||||
(let [commands (commands-map get-page-ref-text)]
|
||||
(reset! *initial-commands commands)
|
||||
(reset! *matched-commands commands)))
|
||||
|
||||
(defn ->block
|
||||
([type]
|
||||
|
@ -199,7 +205,7 @@
|
|||
(when restore-slash-caret-pos?
|
||||
(reset! *slash-caret-pos nil))
|
||||
(reset! *show-commands false)
|
||||
(reset! *matched-commands (commands-map))
|
||||
(reset! *matched-commands @*initial-commands)
|
||||
(reset! *angle-bracket-caret-pos nil)
|
||||
(reset! *show-block-commands false)
|
||||
(reset! *matched-block-commands (block-commands-map)))
|
||||
|
@ -288,7 +294,7 @@
|
|||
|
||||
(defn get-matched-commands
|
||||
([text]
|
||||
(get-matched-commands text (commands-map)))
|
||||
(get-matched-commands text @*initial-commands))
|
||||
([text commands]
|
||||
(search/fuzzy-search commands text
|
||||
:extract-fn first
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
(reset! commands/*current-command chosen)
|
||||
(let [command-steps (get (into {} matched) chosen)
|
||||
restore-slash? (and
|
||||
(not (fn? command-steps))
|
||||
(not (contains? (set (map first command-steps)) :editor/input))
|
||||
(not (contains? #{"Date Picker" "Template" "Deadline" "Scheduled"} chosen)))]
|
||||
(editor-handler/insert-command! id command-steps
|
||||
|
@ -75,6 +76,7 @@
|
|||
(when input
|
||||
(let [current-pos (:pos (util/get-caret-pos input))
|
||||
edit-content (state/sub [:editor/content id])
|
||||
edit-block (state/sub :editor/block)
|
||||
q (or
|
||||
@editor-handler/*selected-text
|
||||
(when (state/sub :editor/show-page-search-hashtag?)
|
||||
|
@ -86,22 +88,35 @@
|
|||
chosen-handler (if (state/sub :editor/show-page-search-hashtag?)
|
||||
(fn [chosen _click?]
|
||||
(state/set-editor-show-page-search! false)
|
||||
(editor-handler/insert-command! id
|
||||
(util/format "#%s" (if (string/includes? chosen " ")
|
||||
(str "[[" chosen "]]")
|
||||
chosen))
|
||||
format
|
||||
{:last-pattern (str "#" (if @editor-handler/*selected-text "" q))}))
|
||||
(let [page-ref-text (page-handler/get-page-ref-text chosen)]
|
||||
(editor-handler/insert-command! id
|
||||
(util/format "#%s" page-ref-text)
|
||||
format
|
||||
{:last-pattern (str "#" (if @editor-handler/*selected-text "" q))})))
|
||||
(fn [chosen _click?]
|
||||
(state/set-editor-show-page-search! false)
|
||||
(editor-handler/insert-command! id
|
||||
(util/format "[[%s]]" chosen)
|
||||
format
|
||||
{:last-pattern (str "[[" (if @editor-handler/*selected-text "" q))
|
||||
:postfix-fn (fn [s] (util/replace-first "]]" s ""))})))
|
||||
(let [page-ref-text (page-handler/get-page-ref-text chosen)]
|
||||
(editor-handler/insert-command! id
|
||||
page-ref-text
|
||||
format
|
||||
{:last-pattern (str "[[" (if @editor-handler/*selected-text "" q))
|
||||
:postfix-fn (fn [s] (util/replace-first "]]" s ""))}))))
|
||||
non-exist-page-handler (fn [_state]
|
||||
(state/set-editor-show-page-search! false)
|
||||
(util/cursor-move-forward input 2))]
|
||||
(if (state/org-mode-file-link? (state/get-current-repo))
|
||||
(let [page-ref-text (page-handler/get-page-ref-text q)
|
||||
value (gobj/get input "value")
|
||||
old-page-ref (util/format "[[%s]]" q)
|
||||
new-value (string/replace value
|
||||
old-page-ref
|
||||
page-ref-text)]
|
||||
(state/set-edit-content! id new-value)
|
||||
(let [new-pos (+ current-pos
|
||||
(- (count page-ref-text)
|
||||
(count old-page-ref))
|
||||
2)]
|
||||
(util/move-cursor-to input new-pos)))
|
||||
(util/cursor-move-forward input 2)))]
|
||||
(ui/auto-complete
|
||||
matched-pages
|
||||
{:on-chosen chosen-handler
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
(let [page (cond
|
||||
(and (vector? block) (= "Link" (first block)))
|
||||
(let [typ (first (:url (second block)))]
|
||||
;; {:url ["File" "file:../pages/hello_world.org"], :label [["Plain" "hello world"]], :title nil}
|
||||
(or
|
||||
(and
|
||||
(= typ "Search")
|
||||
|
@ -40,7 +41,11 @@
|
|||
(and
|
||||
(= typ "Complex")
|
||||
(= (:protocol (second (:url (second block)))) "file")
|
||||
(:link (second (:url (second block)))))))
|
||||
(:link (second (:url (second block)))))
|
||||
|
||||
(and
|
||||
(= typ "File")
|
||||
(second (first (:label (second block)))))))
|
||||
|
||||
(and (vector? block) (= "Nested_link" (first block)))
|
||||
(let [content (:content (last block))]
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
[cljs-bean.core :as bean]
|
||||
[frontend.date :as date]
|
||||
[frontend.handler.notification :as notification]
|
||||
[frontend.handler.page :as page-handler]
|
||||
[frontend.handler.repo :as repo-handler]
|
||||
[frontend.handler.file :as file-handler]
|
||||
[frontend.handler.ui :as ui-handler]
|
||||
|
@ -130,6 +131,8 @@
|
|||
(notification/show! "Sorry, it seems that your browser doesn't support IndexedDB, we recommend to use latest Chrome(Chromium) or Firefox(Non-private mode)." :error false)
|
||||
(state/set-indexedb-support! false)))
|
||||
|
||||
(page-handler/init-commands!)
|
||||
|
||||
(restore-and-setup! me repos logged?)
|
||||
|
||||
(periodically-persist-repo-to-indexeddb!)
|
||||
|
|
|
@ -30,10 +30,8 @@
|
|||
[frontend.handler.image :as image-handler]
|
||||
[frontend.commands :as commands
|
||||
:refer [*show-commands
|
||||
*matched-commands
|
||||
*slash-caret-pos
|
||||
*angle-bracket-caret-pos
|
||||
*matched-block-commands
|
||||
*show-block-commands]]
|
||||
[frontend.extensions.html-parser :as html-parser]
|
||||
[medley.core :as medley]
|
||||
|
@ -1363,6 +1361,10 @@
|
|||
:or {restore? true}
|
||||
:as option}]
|
||||
(cond
|
||||
(fn? command-output)
|
||||
(let [s (command-output)]
|
||||
(commands/insert! id s option))
|
||||
|
||||
;; replace string
|
||||
(string? command-output)
|
||||
(commands/insert! id command-output option)
|
||||
|
@ -1527,7 +1529,7 @@
|
|||
(when (> pos 0)
|
||||
(or
|
||||
(and (= \/ (util/nth-safe edit-content (dec pos)))
|
||||
(commands/commands-map))
|
||||
@commands/*initial-commands)
|
||||
(and last-command
|
||||
(commands/get-matched-commands last-command)))))
|
||||
(catch js/Error e
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
[frontend.handler.project :as project-handler]
|
||||
[frontend.handler.notification :as notification]
|
||||
[frontend.handler.ui :as ui-handler]
|
||||
[frontend.commands :as commands]
|
||||
[frontend.date :as date]
|
||||
[clojure.walk :as walk]
|
||||
[frontend.git :as git]
|
||||
|
@ -23,45 +24,57 @@
|
|||
[goog.object :as gobj]
|
||||
[frontend.format.mldoc :as mldoc]))
|
||||
|
||||
(defn- get-directory
|
||||
[journal?]
|
||||
(if journal?
|
||||
config/default-journals-directory
|
||||
(config/get-pages-directory)))
|
||||
|
||||
(defn- get-file-name
|
||||
[journal? title]
|
||||
(if journal?
|
||||
(date/journal-title->default title)
|
||||
(util/page-name-sanity (string/lower-case title))))
|
||||
|
||||
(defn create!
|
||||
[title]
|
||||
(let [repo (state/get-current-repo)
|
||||
dir (util/get-repo-dir repo)
|
||||
journal-page? (date/valid-journal-title? title)
|
||||
directory (if journal-page?
|
||||
config/default-journals-directory
|
||||
(config/get-pages-directory))]
|
||||
(when dir
|
||||
(p/let [_ (-> (fs/mkdir (str dir "/" directory))
|
||||
(p/catch (fn [_e])))]
|
||||
(let [format (name (state/get-preferred-format))
|
||||
page (string/lower-case title)
|
||||
path (str (if journal-page?
|
||||
(date/journal-title->default title)
|
||||
(util/page-name-sanity page))
|
||||
"."
|
||||
(if (= format "markdown") "md" format))
|
||||
path (str directory "/" path)
|
||||
file-path (str "/" path)]
|
||||
(p/let [exists? (fs/file-exists? dir file-path)]
|
||||
(if exists?
|
||||
(notification/show!
|
||||
[:p.content
|
||||
(util/format "File %s already exists!" file-path)]
|
||||
:error)
|
||||
;; create the file
|
||||
(let [content (util/default-content-with-title format title)]
|
||||
(p/let [_ (fs/create-if-not-exists dir file-path content)]
|
||||
(db/reset-file! repo path content)
|
||||
(git-handler/git-add repo path)
|
||||
(route-handler/redirect! {:to :page
|
||||
:path-params {:name page}})
|
||||
(let [blocks (db/get-page-blocks page)
|
||||
last-block (last blocks)]
|
||||
(when last-block
|
||||
(js/setTimeout
|
||||
#(editor-handler/edit-last-block-for-new-page! last-block 0)
|
||||
100))))))))))))
|
||||
([title]
|
||||
(create! title {}))
|
||||
([title {:keys [redirect?]
|
||||
:or {redirect? true}}]
|
||||
(let [repo (state/get-current-repo)
|
||||
dir (util/get-repo-dir repo)
|
||||
journal-page? (date/valid-journal-title? title)
|
||||
directory (get-directory journal-page?)]
|
||||
(when dir
|
||||
(p/let [_ (-> (fs/mkdir (str dir "/" directory))
|
||||
(p/catch (fn [_e])))]
|
||||
(let [format (name (state/get-preferred-format))
|
||||
page (string/lower-case title)
|
||||
path (str (get-file-name journal-page? title)
|
||||
"."
|
||||
(if (= format "markdown") "md" format))
|
||||
path (str directory "/" path)
|
||||
file-path (str "/" path)]
|
||||
(p/let [exists? (fs/file-exists? dir file-path)]
|
||||
(if exists?
|
||||
(notification/show!
|
||||
[:p.content
|
||||
(util/format "File %s already exists!" file-path)]
|
||||
:error)
|
||||
;; create the file
|
||||
(let [content (util/default-content-with-title format title)]
|
||||
(p/let [_ (fs/create-if-not-exists dir file-path content)]
|
||||
(db/reset-file! repo path content)
|
||||
(git-handler/git-add repo path)
|
||||
(when redirect?
|
||||
(route-handler/redirect! {:to :page
|
||||
:path-params {:name page}})
|
||||
(let [blocks (db/get-page-blocks page)
|
||||
last-block (last blocks)]
|
||||
(when last-block
|
||||
(js/setTimeout
|
||||
#(editor-handler/edit-last-block-for-new-page! last-block 0)
|
||||
100))))))))))))))
|
||||
|
||||
(defn page-add-properties!
|
||||
[page-name properties]
|
||||
|
@ -381,3 +394,31 @@
|
|||
(defn update-public-attribute!
|
||||
[page-name value]
|
||||
(page-add-properties! page-name {:public value}))
|
||||
|
||||
(defn get-page-ref-text
|
||||
[page]
|
||||
(when-let [edit-block (state/get-edit-block)]
|
||||
(let [page-name (string/lower-case page)
|
||||
edit-block-file-path (-> (:db/id (:block/file edit-block))
|
||||
(db/entity)
|
||||
:file/path)]
|
||||
(if (and edit-block-file-path
|
||||
(state/org-mode-file-link? (state/get-current-repo)))
|
||||
(if-let [ref-file-path (:file/path (:page/file (db/entity [:page/name page-name])))]
|
||||
(util/format "[[file:%s][%s]]"
|
||||
(util/get-relative-path edit-block-file-path ref-file-path)
|
||||
page)
|
||||
(let [journal? (date/valid-journal-title? page)
|
||||
ref-file-path (str (get-directory journal?)
|
||||
"/"
|
||||
(get-file-name journal? page)
|
||||
".org")]
|
||||
(create! page {:redirect? false})
|
||||
(util/format "[[file:%s][%s]]"
|
||||
(util/get-relative-path edit-block-file-path ref-file-path)
|
||||
page)))
|
||||
(util/format "[[%s]]" page)))))
|
||||
|
||||
(defn init-commands!
|
||||
[]
|
||||
(commands/init-commands! get-page-ref-text))
|
||||
|
|
|
@ -186,6 +186,10 @@
|
|||
(when-let [repo (get-current-repo)]
|
||||
(:pages-directory (get-config repo))))
|
||||
|
||||
(defn org-mode-file-link?
|
||||
[repo]
|
||||
(:org-mode/insert-file-link? (get-config repo)))
|
||||
|
||||
(defn get-preferred-workflow
|
||||
[]
|
||||
(keyword
|
||||
|
|
|
@ -856,10 +856,6 @@
|
|||
(fn []
|
||||
(js/window.indexedDB.deleteDatabase test-db))))))
|
||||
|
||||
(defn get-file-ext
|
||||
[file]
|
||||
(last (string/split file #"\.")))
|
||||
|
||||
(defonce mac? goog.userAgent/MAC)
|
||||
|
||||
(defn ->system-modifier
|
||||
|
@ -936,3 +932,41 @@
|
|||
(string/replace "Ctrl" "Cmd")
|
||||
(string/replace "Alt" "Opt"))
|
||||
keyboard-shortcut))
|
||||
|
||||
(defn remove-common-preceding
|
||||
[col1 col2]
|
||||
(if (and (= (first col1) (first col2))
|
||||
(seq col1))
|
||||
(recur (rest col1) (rest col2))
|
||||
[col1 col2]))
|
||||
|
||||
;; fs
|
||||
(defn get-file-ext
|
||||
[file]
|
||||
(last (string/split file #"\.")))
|
||||
|
||||
(defn get-relative-path
|
||||
[current-file-path another-file-path]
|
||||
(let [directories-f #(butlast (string/split % "/"))
|
||||
parts-1 (directories-f current-file-path)
|
||||
parts-2 (directories-f another-file-path)
|
||||
[parts-1 parts-2] (remove-common-preceding parts-1 parts-2)
|
||||
another-file-name (last (string/split another-file-path "/"))]
|
||||
(->> (concat
|
||||
(if (seq parts-1)
|
||||
(repeat (count parts-1) "..")
|
||||
["."])
|
||||
parts-2
|
||||
[another-file-name])
|
||||
(string/join "/"))))
|
||||
|
||||
(comment
|
||||
(= (get-relative-path "journals/2020_11_18.org" "pages/grant_ideas.org")
|
||||
"../pages/grant_ideas.org")
|
||||
|
||||
(= (get-relative-path "journals/2020_11_18.org" "journals/2020_11_19.org")
|
||||
"./2020_11_19.org")
|
||||
|
||||
(= (get-relative-path "a/b/c/d/g.org" "a/b/c/e/f.org")
|
||||
"../e/f.org")
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue