有什么办法让emacs的互链方式像obsidian那样吗?

我有大量用obsidian管理的mardown笔记,由于markdown的编辑功能比orgmode差太多,缺少类似org-subtree-copy或者org-subtree-speacial-cut 或者 org-subtree-archive 之类功能,我就转换成orgmode文件了,但是原来的markdown文件里面有大量的[[]]类链接,在orgmode里面是不能正常链接的,1500多文件也无法一一手工处理。 我现在的想法是找个插件或者设置,实现在orgmode里面点击[[]]查找同路径下的文件,而不是新建一个header,有这样的插件或者设置吗?

谢谢各位大佬。

我的大部分 Obsidian 笔记没有设置 ID,所以就测试了一些空文件,效果还凑合。

1 个赞

谢谢大佬指点,我上次安装org-roam没成功,不知道啥原因,我再去努力一下。

安装很简单,配置不容易,这是我的全部配置,有一部分还不能生效我也没搞懂。

你要用就修改下模板的设置,不理解的部分都删掉就行了:

;; org-roam: basic config
;; {{{
(use-package org-roam
  :ensure t
  :defer t ;; autoload
  :bind (("C-c n l" . org-roam-buffer-toggle)
         ("C-c n f" . org-roam-node-find)
         ("C-c n g" . org-roam-graph)
         ("C-c n i" . org-roam-node-insert)
         ("C-c n c" . org-roam-capture)
         ("C-c n j" . org-roam-dailies-capture-today) ;; Dailies
         (:map org-mode-map
               ("C-c n i" . org-roam-node-insert)
               ("C-c n o" . org-id-get-create)
               ("C-c n t" . org-roam-tag-add)
               ("C-c n a" . org-roam-alias-add)
               ("C-c n m". completion-at-point)
               ("C-c n l" . org-roam-buffer-toggle))
         )
  :config
  ;; If you're using a vertical completion framework,
  ;; you might want a more informative completion interface
  ;; file-truename is optional
  ;; it seems required when use symbolic links, which Org-roam does not resolve
  (setq org-roam-file-extensions '("org" "md")) ;; enable Org-roam for markdown
  (require 'org-roam-protocol)                  ;; org-roam-protocol
  )
;; }}}

;; org-roam: backlink count & node hierarchy
;; {{{
;; https://github.com/Jousimies/.emacs.d/blob/master/lisp/init-roam.el
(require 'org)
(require 'org-roam)
;;
(cl-defmethod org-roam-node-directories ((node org-roam-node))
  (if-let ((dirs (file-name-directory (file-relative-name (org-roam-node-file node) org-roam-directory))))
      (format "(%s)" (car (split-string dirs "/")))
    ""))
;;
(cl-defmethod org-roam-node-backlinkscount ((node org-roam-node))
  (let* ((count (caar (org-roam-db-query
                       [:select (funcall count source)
                                :from links
                                :where (= dest $s1)
                                :and (= type "id")]
                       (org-roam-node-id node)))))
    (format "[%d]" count)))
;;
(cl-defmethod org-roam-node-hierarchy ((node org-roam-node))
  (let ((level (org-roam-node-level node)))
    (concat
     (when (> level 0) (concat (org-roam-node-file-title node) " > "))
     (when (> level 1) (concat (string-join (org-roam-node-olp node) " > ") " > "))
     (org-roam-node-title node))))
;;
(setq org-roam-node-display-template
      "${title:50} ${hierarchy:*} ${backlinkscount:6} ${tags:50} ${directories:10}")
;;
;; (setq org-roam-node-display-template (concat
;;                                    "${type:8} ${backlinkscount:3} ${hierarchy:*}"
;;                                   (propertize "${tags:20}" 'face 'org-tag) " "))
;;
;; (setq org-roam-node-display-template "${hierarchy:*} ${tags:20}")
;;
;; (setq org-roam-node-display-template
;;       (concat "${title:*} "
;;               (propertize "${tags:10}" 'face 'org-tag)
;;               ))
;; }}}

;; org-roam: completion
;; {{{
(setq org-roam-completion-everywhere t)
;;roam links support auto-completion via completion-at-point
;; call M-x completion-at-point within a roam link.
;; Where the | character represents the cursor:
;; [[|]] : completes for a file title
;; [[roam:]] : completes for a file title
;; [[*|]] : completes for a headline within this file
;; [[foo*|]] : completes a headline within the file with title “foo”
;; [[roam:foo*|]] completes a headline within the file with title “foo”
;; }}}

;; org-roam: slug (called by org-roam-capture-templates)
;; {{{
;; (cl-defmethod org-roam-node-slug ((node org-roam-node))
;;   "Return the slug of NODE."
;;   (let ((title (org-roam-node-title node))
;;         (slug-trim-chars '(;; Combining Diacritical Marks https://www.unicode.org/charts/PDF/U0300.pdf
;;                            768 ; U+0300 COMBINING GRAVE ACCENT
;;                            769 ; U+0301 COMBINING ACUTE ACCENT
;;                            770 ; U+0302 COMBINING CIRCUMFLEX ACCENT
;;                            771 ; U+0303 COMBINING TILDE
;;                            772 ; U+0304 COMBINING MACRON
;;                            774 ; U+0306 COMBINING BREVE
;;                            775 ; U+0307 COMBINING DOT ABOVE
;;                            776 ; U+0308 COMBINING DIAERESIS
;;                            777 ; U+0309 COMBINING HOOK ABOVE
;;                            778 ; U+030A COMBINING RING ABOVE
;;                            780 ; U+030C COMBINING CARON
;;                            795 ; U+031B COMBINING HORN
;;                            803 ; U+0323 COMBINING DOT BELOW
;;                            804 ; U+0324 COMBINING DIAERESIS BELOW
;;                            805 ; U+0325 COMBINING RING BELOW
;;                            807 ; U+0327 COMBINING CEDILLA
;;                            813 ; U+032D COMBINING CIRCUMFLEX ACCENT BELOW
;;                            814 ; U+032E COMBINING BREVE BELOW
;;                            816 ; U+0330 COMBINING TILDE BELOW
;;                            817 ; U+0331 COMBINING MACRON BELOW
;;                            )))
;;     (cl-flet* ((nonspacing-mark-p (char)
;;                                   (memq char slug-trim-chars))
;;                (strip-nonspacing-marks (s)
;;                                        (ucs-normalize-NFC-string
;;                                         (apply #'string (seq-remove #'nonspacing-mark-p
;;                                                                     (ucs-normalize-NFD-string s)))))
;;                (cl-replace (title pair)
;;                            (replace-regexp-in-string (car pair) (cdr pair) title)))
;;       (let* ((pairs `(("[^[:alnum:][:digit:]]" . "-") ;; convert anything not alphanumeric
;;                       ("--*" . "-")                   ;; remove sequential underscores
;;                       ("^-" . "")                     ;; remove starting underscore
;;                       ("-$" . "")))                   ;; remove ending underscore
;;              (slug (-reduce-from #'cl-replace (strip-nonspacing-marks title) pairs)))
;;         (downcase slug)))))
;; }}}

;; org-roam: filter tags
;; {{{
(defun my/org-roam-filter-by-tag (tag-name)
  (lambda (node)
    (member tag-name (org-roam-node-tags node))))

(defun my/org-roam-list-notes-by-tag (tag-name)
  (mapcar #'org-roam-node-file
          (seq-filter
           (my/org-roam-filter-by-tag tag-name)
           (org-roam-node-list))))
;; }}}

;; org-roam: search tag
;; {{{
(defun my/org-roam-node-find-by-tag ()
  (interactive)
  (let ((chosen-tag
         (completing-read "filter by tag: "
                          (seq-uniq
                           (org-roam-db-query
                            [:select [tag]
                                     :from tags ])))))
    (org-roam-node-find
     nil
     nil
     (lambda (node) (member chosen-tag (org-roam-node-tags node))))))
;; }}}

;; org-roam: template,  id (uuid) timestamps and so on
;; {{{
(setq org-roam-capture-templates
      '(
        ;; a: audio & music
        ;; b: book
        ("b" "图书" plain "%?"
         :target (file+head "图书/${title}.org"
                            "#+title: ${title}\n#+category:\n#+filetags: \n")
         :immediate-finish t
         :unnarrowed  t)
        ;; c:
        ("d" "default" plain "%?"
         :target (file+head "${slug}.org"
                            "#+title: ${title}\n#+category:\n#+filetags:\n")
         ;; #+date: %<%Y-%m-%d-%H:%M:%S %Z>\n
         :empty-lines 1
         :immediate-finish t
         :unnarrowed  t)
        ("e" "Emacs" plain "%?"
         :target (file+head "Emacs/${title}.org"
                            "#+title: ${title}\n#+category:\n#+filetags: \n")
         :immediate-finish t
         :unnarrowed  t)
        ;; f:
        ("f" "Emacs Function" plain "%?"
         :target (file+head "Emacs/function/${title}.org"
                            "#+title: ${title}\n#+category:\n#+filetags: \n")
         :immediate-finish t
         :unnarrowed  t)
        ;; g:
        ;; h: human
        ;; i:
        ;; j:
        ;; k:
        ;; l:
        ;; m:
        ;; n:
        ;; o:
        ;; p: project
        ("p" "project" plain "%?"
         :target (file+head "${title}.org"
                            "#+title: ${title}\n")
         :immediate-finish t
         :unnarrowed t)
        ("P" "Emacs 包/插件" plain "%?"
         :target (file+head "Emacs/package/${title}.org"
                            "#+title: ${title}\n#+filetags: :Emacs:\n")
         :immediate-finish t
         :unnarrowed t)
        ;; q:
        ("r" "reference" plain "%? \n %(v-i-or-nothing) \n\n%(v-a-or-nothing)"
         :target
         (file+head "references/%<%Y%m%d%H%M%S>-${title}.org"
                    "#+title: ${title}\n")
         :unnarrowed t)
        ;; s:
        ("s" "软件" plain "%?"
         :target (file+head "software/${title}.org"
                            "#+title: ${title}\n")
         :immediate-finish t
         :unnarrowed t)
        ;; t: topic todo
        ("t" "主题" plain "%?"
         :target (file+head "topics/${title}.org"
                            "#+title: ${title}\n")
         :immediate-finish t
         :unnarrowed t)
        ;; u:
        ;; v:
        ("v" "Emacs 变量" plain "%?"
         :target (file+head "Emacs/variable/${title}.org"
                            "#+title: ${title}\n")
         :immediate-finish t
         :unnarrowed t)
        ;; w:
        ;; x:
        ;; y:
        ;; z:
        ))
;; }}}

;; org-roam: UI
;; {{{
;; (custom-set-faces
;;   '((org-roam-link org-roam-link-current)
;;     :foreground "#e24888" :underline t))
;;
;; (defface my-org-id-link '((t :inherit org-link :slant italic))
;;   "Face for org-id links."
;;   :group 'org-faces)
;; }}}

;; little hack
;; {{{
;; brew install --cask db-browser-for-sqlite
(defun my/org-roam-view-db ()
  (interactive)
  (cond
   ((eq system-type 'darwin)
    (shell-command
     ;; net.sourceforge.sqlitebrowser
     (format "open \"/Applications/DB Browser for SQLite.app\" --args --table nodes %s" org-roam-db-location)))
   (t
    (message "my/org-roam-view-db not yet working on this system-type"))))
;; }}}

;; org-roam-ui
;; {{{
(use-package org-roam-ui
  :after org-roam
  ;; normally we'd recommend hooking orui after org-roam, but since org-roam does not have
  ;; a hookable mode anymore, you're advised to pick something yourself
  ;; if you don't care about startup time, use
  ;; :hook (after-init . org-roam-ui-mode)
  :bind (("C-c G" . org-roam-ui-open)
         )
  :config
  (setq org-roam-ui-sync-theme t
        org-roam-ui-follow t
        org-roam-ui-update-on-save t
        org-roam-ui-open-on-start t)
  )
;; }}}

收到,谢谢大佬!

:laughing: 我也是菜鸟,刚从 Obsidian 转 Org-roam 还没一个月。

试一下这个包 看看能不能把 ob 的 [[]] style 的 link 给转换过来。

收到,谢谢!我试试