[gist] [分享] 重命名org-link指向的文件并更新链接

分享一段简单的代码,它的作用是:

会把光标所在org-link的路径作为默认值显示在mini buffer,修改后回车就会重命名文件,并且更新org文件中所有指向这一文件的链接。

比较简单,有需要的同学可以自取,有bug可以在这里或者在gist下面留言。

好久不写elisp了,需要时不时热热身啊 :joy:

  (defun et/rename-org-link-file (path)
    (interactive
     (list
      (let* ((link (org-element-context))
             (old-path (org-element-property :path link)))
        (read-string "PATH: " old-path nil old-path))))
    (let ((old-path (org-element-property :path (org-element-context))))
      (mkdir (file-name-directory path) t)
      (rename-file old-path path)
      (save-excursion
        (goto-char (point-min))
        (while (search-forward old-path nil t)
          (replace-match path)))
      (message (format "Rename %s to %s" old-path path)))
    )

Edit 1: 当目标文件夹不存在时mkdir

2 个赞

这段代码比较令我不爽的是:org-element-context被重复调用了两次,一次是在interactive form里用于生成默认值,一次是在函数主体内。但是没有办法,因为好像不能把interactive放到let里?

这个好。经常是先改文件名,再去改链接名。但怎么用上呢

加到你的配置里(或者直接eval一下先试试再决定要不要加到配置里),然后M-x 找到这个命令就可以调用了,确保你的光标停留在org-link上

因为我的使用情形比较简单,遇到复杂情形可能不工作,如果有遇到可以在这里反馈。

哦。我改链接时是用默认的C-c C-l命令,我以为是搞成advice,链接修改后去改文件名

应该写一个:aroundadvice就行了,比较一下调用org-link(应该是C-c C-l的默认绑定?)前后的org-link路径值,然后如果两个值不一致就调用et/rename-org-link-file,应该是可行的

还要考虑是否是文件类链接,考虑是重新指向其他文件还是重命名文件。不知还有没有其他的,似乎有点麻烦

org-insert-link里面是用正则匹配把link和description提取出来 仔细看了下好像并不是,这个正则会把link type也匹配了。。

((org-in-regexp org-link-bracket-re 1)
      ;; We do have a link at point, and we are going to edit it.
      (setq remove (list (match-beginning 0) (match-end 0)))
      (setq desc (when (match-end 2) (match-string-no-properties 2)))
      (setq link (read-string "Link: "
			      (org-link-unescape
			       (match-string-no-properties 1)))))

基于楼主的版本增加了对原文件是否存在的检查和link type的检查

(defun et/rename-org-link-file (path)
  (interactive
   (list
    (let* ((link (org-element-context))
           (old-path (org-element-property :path link)))
	  (read-string "PATH: " old-path nil old-path))))
  (let* ((link (org-element-context))
		 (old-path (org-element-property :path link))
		 (ltype (org-element-property :type link)))
	(if (and (file-exists-p old-path)
			 (member ltype '("file" "docview" "attachment")))
		(progn (mkdir (file-name-directory path) t)
			   (rename-file old-path path)
			   (save-excursion
				 (goto-char (point-min))
				 (while (search-forward old-path nil t)
				   (replace-match path)))
			   (message (format "Rename %s to %s" old-path path)))
	  (message (format "!!!File type not valid or dose not exist!!! %s %s" ltype old-path)))))
3 个赞