如何动态设置org-download-image-dir,其中包含buffer文件名?

比如我的org文件路径是 ~/.../bar/foo.org,我想存储图片到 bar/source/image/foo

求教一个org-download的问题 - Org-mode - Emacs China

这里是一个相关问题,但是解决方法是在每一个 org 文件头部放置 # -*- eval: (setq org-download-image-dir (file-name-sans-extension (buffer-name))); -*-

这个方法有点麻烦,如何一次性设置呢?

(setq-default
 org-download-image-dir (concat "./source/img/" (file-name-nondirectory (buffer-file-name)))
)

如果能设置变量为一个表达式,实时进行 eval 解释 (file-name-nondirectory (buffer-file-name)) 就好了,但似乎无法实现。。

下面是我的配置,问题是所有的 buffer org-download-image-dir 值都是一样的,在初始化的时候就变成固定值了。

  (setq-default org-download-heading-lvl nil
                org-download-image-dir (concat "./source/img/" (file-name-nondirectory (buffer-file-name)))
                org-download-screenshot-method "pngpaste %s"
                org-download-screenshot-file (expand-file-name "screenshot.jpg" temporary-file-directory))

想到一个比较Hack的方法,给 org-download--dir 方法写advice。

感谢帮助。看来没有办法给变量赋一个表达式了:joy:。

贴上最终我的解决方案,可以实现需求。

  (defun my-org-download--dir-1 ()
    (or org-download-image-dir (concat "./source/img/" (file-name-nondirectory (file-name-sans-extension (buffer-file-name))) )))

  (advice-add #'org-download--dir-1 :override #'my-org-download--dir-1)

但有一点烦人:图片上会有一个 header:

#+DOWNLOADED: /var/folders/mh/mphsxstx16v6wcfdlv7fymf40000gn/T/screenshot.png @ 2019-09-22 14:53:54

每次进入org buffer时更新这个变量

(add-hook 'org-mode-hook
          (lambda ()
            (setq-local (concat "./source/img/" (file-name-nondirectory
                                           (buffer-file-name))))))

显然,变量只是个存放值的地方,并不能每次给你重新算出值来

1 个赞

谢谢,又学到一招:smile:

理论上还是建议你用file local variable。这样比较portable。另外file local variable除了elisp的lexical-binding其实是可以用下面的格式写在结尾的

Local Variables:
mode: emacs-lisp
eval: (message "Hello!")
End:

另外还有对目录和子目录生效的directory local variable

1 个赞

按这样设置的话,除了会建立 /source/img/ 文件夹外,还会再建一层文件夹,就是所在列表的一级标题,这一层是否可以去掉?

请问有办法把这里 (求教一个org-download的问题 - #8,来自 lujun9972) 提到的动态 eval 方法用在 directory local variable 里么?

directory local eval 的格式像这样:

;;; Directory Local Variables
;;; For more information see (info "(emacs) Directory Variables")

((org-mode . ((org-download-image-dir . "../images")
              (eval . (org-hugo-auto-export-mode)))))

1 个赞

谢谢!

不过这种设置 local variable 的方式我还是我搞成功,用的 org-download 作者写的这一段代码成功设置了一个 org-mode 文件一个子文件夹 (How to use buffer-file-name as org-download-image-dir ? · Issue #46 · abo-abo/org-download · GitHub)

可以重新定义 org-download-method:

  (setq org-download-method 'my/org-download-method)
  (defun my/org-download-method (link)
    "store image to <currentBufferFileName>.assets/ directory and with timestamp
as its filename"
    (setq filename (concat "img_" (format-time-string "%Y%m%d_%H%M%S") ".png"))
    (setq dirname (concat (buffer-name) ".assets"))
    ;; if directory not exist, create it
    (unless (file-exists-p dirname)
      (make-directory dirname))
    (concat dirname "/" filename)
    )