;;; 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" category)) (insert "#+STARTUP: content\n\n") ;; 插入标题和tag (insert (format "* STARTED %s :root%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