Does renaming title no longer renames the filename?

Earlier in v1 when titles were basically notes, vs title with ID is a note, one could rename the title and the filename used to change. After v2 implementation when I change title I see the filename is still the same.

Can someone suggest on how to achieve this?

Thanks!

2 Likes

I am also asking about this and like to know if anyone has achieved this.

I wrote this function to update backlinks and file names on a node-name change. It’s messy and I haven’t tested it much, but maybe it’s a start:

  (defun azr/org-roam-modify-title ()
    "Modify title of org-roam current node and update all backlinks in roam database."
    (interactive)
    (unless (org-roam-buffer-p) (error "Not in an org-roam buffer."))
    (save-some-buffers t)
    (let* ((old-title (org-roam-get-keyword "title"))
           (ID (org-entry-get (point) "ID"))
           (new-title (read-string "Enter new title: " old-title)))
      (org-roam-set-keyword "title" new-title)
      (save-buffer)
      (let* ((new-slug (org-roam-node-slug (org-roam-node-at-point)))
             (new-file-name (replace-regexp-in-string "-.*\\.org" (format "-%s.org" new-slug) (buffer-file-name)))
             (new-buffer-name (file-name-nondirectory new-file-name)))
	(rename-buffer new-buffer-name)
	(rename-file (buffer-file-name) new-file-name 1)
	(set-visited-file-name new-file-name)) ; I don't know why this last command is necessary. Getting it from here: https://stackoverflow.com/a/384346/2422698
      (save-buffer)
      ;; Rename backlinks in the rest of the Org-roam database.
      (let* ((search (format "[[id:%s][%s]]" ID old-title))
             (replace (format "[[id:%s][%s]]" ID new-title))
             (rg-command (format "rg -t org -lF %s ~/Org/roam/" search))
             (file-list (split-string (shell-command-to-string rg-command))))
	(dolist (file file-list)
          (let ((file-open (get-file-buffer file)))
	    (find-file file)
            (beginning-of-buffer)
            (while (search-forward search nil t)
              (replace-match replace))
            (save-buffer)
            (unless file-open
              (kill-buffer)))))))
1 Like

Thanks @arozbiz .
I just have a test and it works!
BTW, I adjust the rg-command a little bit, to make ‘org-roam-directory’ not hardcoded.

From:

(rg-command (format “rg -t org -lF %s ~/Org/roam/” search)

To:

(rg-command (format (concat "rg -t org -lF %s " org-roam-directory) search)

Thank you!

Awesome guys! thanks a lot

My solution to this is

(add-hook! 'after-save-hook
           (defun org-rename-to-new-title ()
             (when-let*
                 ((old-file (buffer-file-name))
                  (is-roam-file (org-roam-file-p old-file))
                  (file-node (save-excursion
                               (goto-char 1)
                               (org-roam-node-at-point)))
                  (slug (org-roam-node-slug file-node))
                  (new-file (expand-file-name (concat slug ".org")))
                  (different-name? (not (string-equal old-file new-file))))
               (rename-buffer new-file)
               (rename-file old-file new-file)
               (set-visited-file-name new-file)
               (set-buffer-modified-p nil))))

(note using Doom’s add-hook! rather than the standard add-hook which is slightly different)

This renames the file, but does not rename link references (I don’t like doing this)

@arozbiz, the set-visited-file-name assigns the buffer to the new file so that writing the buffer will write to the correct new file.

This work great for me. one little thing: from a UX perspective, I found it confusing that after renaming #+title and hitting C-x C-s the minibuffer prints a message saying that the buffer has been saved to /path/to/org-roam/old-title.org (even though it actually saves it to /path/to/org-roam/new-title.org as one would expect):

Saving file /path/to/org-roam/old-title.org...
Wrote /path/to/org-roam/old-title.org

I replaced the last line of code with the following two lines, which seems to fix the issue

(set-buffer-modified-p t)
(save-buffer))))

After hitting C-x C-s the minibuffer now prints

Saving file /path/to/org-roam/old-title.org...
Wrote /path/to/org-roam/old-title.org
Saving file /path/to/org-roam/new-title.org...
Wrote /path/to/org-roam/new-title.org

Disclaimer: I am new to elisp, so please correct me if I got anything wrong. Or if there is a better way to improve this.

I made a version that will keep date prefix of the file:

(add-hook! 'after-save-hook
  (defun org-rename-to-new-title ()
    (when-let*
        ((old-file (buffer-file-name))
         (is-roam-file (org-roam-file-p old-file))
         (file-node (save-excursion
                      (goto-char 1)
                      (org-roam-node-at-point)))
         (file-name  (file-name-base (org-roam-node-file file-node)))
         (file-time  (or (and (string-match "\\`\\([0-9]\\{14\\}\\)-" file-name)
                              (concat (match-string 1 file-name) "-"))
                         ""))
         (slug (org-roam-node-slug file-node))
         (new-file (expand-file-name (concat file-time slug ".org")))
         (different-name? (not (string-equal old-file new-file))))

      (rename-buffer new-file)
      (rename-file old-file new-file)
      (set-visited-file-name new-file)
      (set-buffer-modified-p nil))))

@quolpr thanks for sharing. BTW:

Would the regexp “^\\([0-9]\\{14\\}\\)-” be a better one?

Thanks for code sharing and for keeping the date prefix. After testing it I realized that it messes up the newly created nodes and prevents them from getting the date prefix when you hit C-c C-c to confirm the captured node. Is there a way to modify this code to make it distinguish newly created nodes from old ones?