143 lines
4.9 KiB
EmacsLisp
143 lines
4.9 KiB
EmacsLisp
;;; init-org-refile.el --- org-refile config -*- lexical-binding: t -*-
|
||
|
||
;;; Commentary:
|
||
|
||
;;; Code:
|
||
|
||
(defun my-org-refile-to-new-file ()
|
||
"org-refile as a separate org file with custom template."
|
||
(interactive)
|
||
(require 'org-element)
|
||
(org-back-to-heading t)
|
||
|
||
(let* ((heading-components (org-heading-components))
|
||
;; (todo (nth 2 heading-components)) ; 保留todo状态
|
||
(raw-title (nth 4 heading-components)) ; 纯标题文本
|
||
(tags (org-get-tags nil t))
|
||
(begin (point))
|
||
(end (save-excursion (org-end-of-subtree t t) (point)))
|
||
(original-content (buffer-substring begin end))
|
||
|
||
;; 检测原条目是否有属性,不包括logbook
|
||
(has-properties-p
|
||
(with-temp-buffer
|
||
(insert original-content)
|
||
(goto-char (point-min))
|
||
(forward-line 1) ; 跳过headline
|
||
(looking-at org-property-drawer-re)))
|
||
|
||
;; 如果有属性则提取内容
|
||
(original-props
|
||
(when has-properties-p
|
||
(with-temp-buffer
|
||
(insert original-content)
|
||
(goto-char (point-min))
|
||
(forward-line 1)
|
||
(let ((start (point)))
|
||
(when (re-search-forward ":END:" nil t)
|
||
(forward-line 1)
|
||
(buffer-substring start (point)))))))
|
||
|
||
;; 询问文件名,保留中文,只替换空格和特殊字符
|
||
(default-name (replace-regexp-in-string "[ \\/:*?\"<>|]" "_" raw-title))
|
||
(user-filename (read-string "Filename (without .org): " default-name))
|
||
|
||
(filename (format "%s-%s.org"
|
||
(format-time-string "%Y%m%d")
|
||
user-filename))
|
||
(target-dir (if *is-windows*
|
||
"h:/emacs/my-org-note/"
|
||
"~/org/my-org-note/"))
|
||
(filepath (expand-file-name filename target-dir))
|
||
|
||
;; 询问category
|
||
(category (completing-read "Category: "
|
||
'("none" "note" "project")
|
||
nil t "project"))
|
||
|
||
;; 询问 Tags(原有标签作为默认值)
|
||
(tag-input (read-string "Tags (space separated): "
|
||
(mapconcat #'identity tags " ")))
|
||
|
||
(formatted-tags
|
||
(if (and tag-input (not (string= tag-input "")))
|
||
(concat ":" (replace-regexp-in-string " " ":" tag-input) ":")
|
||
""))
|
||
|
||
;; 提取body
|
||
(body
|
||
(with-temp-buffer
|
||
(insert original-content)
|
||
(goto-char (point-min))
|
||
(forward-line 1)
|
||
|
||
;; 如果有属性抽屉则跳过
|
||
(when (looking-at org-property-drawer-re)
|
||
(while (not (looking-at org-property-end-re))
|
||
(forward-line 1))
|
||
(forward-line 1))
|
||
|
||
;; 跳过schedule和deadline
|
||
;; (when (looking-at org-planning-line-re)
|
||
;; (forward-line 1))
|
||
|
||
;; 清理开头的空行
|
||
(skip-chars-forward "\n")
|
||
(buffer-substring (point) (point-max)))))
|
||
|
||
;; 检查文件是否存在
|
||
(when (and (file-exists-p filepath)
|
||
(not (y-or-n-p (format "File %s exists. Overwrite? " filename))))
|
||
(error "Refile canceled"))
|
||
|
||
(unless (file-exists-p target-dir)
|
||
(make-directory target-dir t))
|
||
|
||
;; 将原条目的TODO关键字改为COMMENT(如果有)
|
||
(let ((todo (nth 2 heading-components)))
|
||
(when todo
|
||
(save-excursion
|
||
(goto-char begin)
|
||
(when (re-search-forward (concat "^\\(\\*+ \\s-*\\)" (regexp-quote todo)) (save-excursion (forward-line 1) (point)) t)
|
||
(replace-match "\\1COMMENT" t nil)))))
|
||
|
||
;; 创建新文件
|
||
(condition-case err
|
||
(with-temp-file filepath
|
||
;; 文件头
|
||
(insert (format "#+title: %s\n" user-filename))
|
||
(insert (format "#+date: %s\n" (format-time-string "[%Y-%m-%d %a %H:%M]")))
|
||
(insert (format "#+category: %s\n\n" category))
|
||
|
||
;; 插入标题和tag
|
||
(insert (format "* STARTED %s %s\n"
|
||
;; (if todo (concat todo " ") "")
|
||
user-filename
|
||
formatted-tags))
|
||
|
||
;; 只有原条目有属性时才插入
|
||
(when original-props
|
||
(insert original-props))
|
||
|
||
;; 插入body
|
||
(insert body)
|
||
|
||
;; 确保格式正确,添加文件尾局部变量
|
||
(unless (bolp) (insert "\n"))
|
||
(insert "\n# Local Variables:\n# org-use-tag-inheritance: nil\n# End:\n"))
|
||
|
||
(error
|
||
(goto-char begin)
|
||
(insert original-content)
|
||
(error "Failed to create file: %s" err)))
|
||
|
||
(find-file-other-window filepath)
|
||
(message "Successfully refiled to %s" filepath)))
|
||
|
||
(with-eval-after-load 'org
|
||
(define-key org-mode-map (kbd "C-c o w") #'my-org-refile-to-new-file))
|
||
|
||
(provide 'init-org-refile)
|
||
|
||
;;; init-org-refile.el ends here
|