求助:org-link-set-parameters 中设置的函数无法被调用?

看了这个回复帖 如何实现MediaWiki 的弹出提示和页面预览功能 - #19,来自 Voleking 中介绍的博客 https://kitchingroup.cheme.cmu.edu/blog/2016/11/04/New-link-features-in-org-9/。 对 其中 A better file link 的功能比较感兴趣。把该博主的代码拷贝到自己的配置中尝试,但是发现 org-link-set-parameters 中设置的函数无法被调用?

我使用的是 spacemacs,代码的配置如下:

(with-eval-after-load 'org
  (org-link-set-parameters "file" :follow #'hurricane//org-file-link-follow))

(defun hurricane//org-file-link-follow (path _)
  (message "%s" path)
	(funcall
	 (helm :sources
		     `((name . "Action")
		       (candidates . ,(append
				                   (loop for f in '(find-file
						                                org-open-file)
					                       collect (cons (symbol-name f) f))
				                   '(("dired" . (lambda (path)
						                              (dired (file-name-directory path))
						                              (re-search-forward (file-name-nondirectory path))))
				                     ("copy org link" . (lambda (path)
							                                    (kill-new (format "[[file:%s]]" path)))))))
		       (action . identity)))
	 path))

希望实现的功能是,在 org 文件中点击 file 类型的 link 时,不是直接打开 link,而是弹出 helm completion(我 spacemacs 默认是使用 ivy)让你选择相应的预设的 action。

2021-12-27 00.38.28

但是我使用了相应的代码, 手动激活 helm-mode 在无论是鼠标点击还是光标选中并回车 file link 后都是直接打开对应的文件。并没有出现我希望中的效果。

自己做了简单的排查。

  1. hurricane//org-file-link-follow 中简单的打印函数 (message "%s" path) 并没有打印出 path 参数,说明 hurricane//org-file-link-follow 没有被调用。
  2. 在 emacs 中查找到 org-link-parameters 中:
("file" :complete org-link-complete-file :follow hurricane//org-file-link-follow)

可以看到 file link 相关的 parameters 中有我预设的 hurricane//org-file-link-follow

  1. goole 中寻找了一番,没有找到答案。

坛友能否帮忙解答一下疑问?

(defun org-link-open (link &optional arg)
  "Open a link object LINK.

ARG is an optional prefix argument.  Some link types may handle
it.  For example, it determines what application to run when
opening a \"file\" link.

Functions responsible for opening the link are either hard-coded
for internal and \"file\" links, or stored as a parameter in
`org-link-parameters', which see."
  (let ((type (org-element-property :type link))
	(path (org-element-property :path link)))
    (pcase type
      ;; Opening a "file" link requires special treatment since we
      ;; first need to integrate search option, if any.
      ("file"
       (let* ((option (org-element-property :search-option link))
	      (path (if option (concat path "::" option) path)))
	 (org-link-open-as-file path
				(pcase (org-element-property :application link)
				  ((guard arg) arg)
				  ("emacs" 'emacs)
				  ("sys" 'system)))))
      ;; Internal links.
      ((or "coderef" "custom-id" "fuzzy" "radio")
       (unless (run-hook-with-args-until-success 'org-open-link-functions path)
	 (if (not arg) (org-mark-ring-push)
	   (switch-to-buffer-other-window (org-link--buffer-for-internals)))
	 (let ((destination
		(org-with-wide-buffer
		 (if (equal type "radio")
		     (org-link--search-radio-target path)
		   (org-link-search
		    (pcase type
		      ("custom-id" (concat "#" path))
		      ("coderef" (format "(%s)" path))
		      (_ path))
		    ;; Prevent fuzzy links from matching themselves.
		    (and (equal type "fuzzy")
			 (+ 2 (org-element-property :begin link)))))
		 (point))))
	   (unless (and (<= (point-min) destination)
			(>= (point-max) destination))
	     (widen))
	   (goto-char destination))))
      (_
       ;; Look for a dedicated "follow" function in custom links.
       (let ((f (org-link-get-parameter type :follow)))
	 (when (functionp f)
	   ;; Function defined in `:follow' parameter may use a single
	   ;; argument, as it was mandatory before Org 9.4.  This is
	   ;; deprecated, but support it for now.
	   (condition-case nil
	       (funcall (org-link-get-parameter type :follow) path arg)
	     (wrong-number-of-arguments
	      (funcall (org-link-get-parameter type :follow) path)))))))))

因为 file 是写死的,换个自己的 org-link type 吧。

设置 org-file-apps ?

谢谢帮忙解答疑惑,后面使用 advice 实现自己的功能了。

(defun hurricane//org-image-link-open (orgfn context &optional args)
  (when-let ((link (plist-get context 'link))
             (type (plist-get link ':type))
             (path (plist-get link ':path)))
    (if (string-match "\\(?:jpg\\|jpeg\\|png\\|gif\\|xpm\\)" path)
        (funcall
         (helm :sources
               `((name . "Action")
                 (candidates . ,(append
                                 (loop for f in '(find-file
                                                  org-open-file)
                                       collect (cons (symbol-name f) f))
                                 '(("dired" . (lambda (path)
                                                (dired (file-name-directory path))
                                                (re-search-forward (file-name-nondirectory path))))
                                   ("copy org link" . (lambda (path)
                                                        (kill-new (format "[[file:%s]]" path))))
                                   ("delete image file and link" . (lambda (path)
                                                                     (let* ((link-list (org-element-map (org-element-parse-buffer) 'link
                                                                                         (lambda (link)
                                                                                           (when (string= (org-element-property :type link) "file")
                                                                                             (list (org-element-property :path link)
                                                                                                   (org-element-property :begin link)
                                                                                                   (org-element-property :end link))))))
                                                                            (file-full-path (concat default-directory "/" path))
                                                                            (begin-end-list (hurricane//find-org-link-begin-and-end link-list path)))
                                                                       (progn
                                                                         (if (yes-or-no-p "Do you want to delete the image link?")
                                                                             (hurricane//do-delete-link-function begin-end-list))
                                                                         (if (yes-or-no-p
                                                                              "Do you really want to delete the image file? This can't be revert!")
                                                                             (progn
                                                                               (delete-file file-full-path)
                                                                               )))))))))
                 (action . identity)))
         path)
      (funcall orgfn context))
    ))

(advice-add 'org-link-open :around #'hurricane//org-image-link-open)

谢谢,这个函数不能解决我需要的。