From 652521d65e7ca6b4a5f352e0e0d08b315add5c2b Mon Sep 17 00:00:00 2001 From: Peter Mao Date: Mon, 12 Jun 2023 20:14:07 -0700 Subject: [PATCH 01/13] replace lambda in `define-key' calls with named functions also, invert CxCc to CcCx. --- modules/org-noter-pdf.el | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/modules/org-noter-pdf.el b/modules/org-noter-pdf.el index a15965e..6546a38 100644 --- a/modules/org-noter-pdf.el +++ b/modules/org-noter-pdf.el @@ -501,19 +501,20 @@ current heading inherit the COLUMN_EDGES property." ;;; override some deleterious keybindings in pdf-view-mode. (define-key org-noter-doc-mode-map (kbd "C-c C-c") - (lambda () + (defun org-noter-pdf--execute-CcCc-in-notes () + "Override C-c C-c in pdf document buffer." (interactive) (select-window (org-noter--get-notes-window)) (org-ctrl-c-ctrl-c))) -(defun org-noter-pdf--execute-CxCc-in-notes () - "Execute C-c C-x prefixed command in notes buffer." - (interactive) - (let ((this-CxCc-cmd (vector (read-event)))) - (select-window (org-noter--get-notes-window)) - (execute-kbd-macro - (vconcat (kbd "C-c C-x") this-CxCc-cmd)))) -(define-key org-noter-doc-mode-map (kbd "C-c C-x") 'org-noter-pdf--execute-CxCc-in-notes) +(define-key org-noter-doc-mode-map (kbd "C-c C-x") + (defun org-noter-pdf--execute-CcCx-in-notes () + "Override C-c C-x in pdf document buffer." + (interactive) + (let ((this-CxCc-cmd (vector (read-event)))) + (select-window (org-noter--get-notes-window)) + (execute-kbd-macro + (vconcat (kbd "C-c C-x") this-CxCc-cmd))))) (provide 'org-noter-pdf) ;;; org-noter-pdf.el ends here From e7af76c2d08d943a70ec3ef120100c2078ca8aba Mon Sep 17 00:00:00 2001 From: Peter Mao Date: Sat, 24 Jun 2023 07:43:32 -0700 Subject: [PATCH 02/13] use the less restrictive `string-equal` vs `file-equal-p` This change allows file-rename syncing to happen after the document is renamed (and the original filepath no longer points to a file). --- org-noter-core.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org-noter-core.el b/org-noter-core.el index da09e80..358498c 100644 --- a/org-noter-core.el +++ b/org-noter-core.el @@ -1657,7 +1657,7 @@ DOCUMENT-PATH is a path to a document file." (insert-file-contents notes-path) (catch 'break (while (re-search-forward (org-re-property org-noter-property-doc-file) nil t) - (when (file-equal-p (expand-file-name (match-string 3) (file-name-directory notes-path)) + (when (string-equal (expand-file-name (match-string 3) (file-name-directory notes-path)) document-path) ;; NOTE(nox): This notes file has the document we want! (throw 'break t))))))) From 7163b0a5cd5f23b5ae65b7ea1c289bf7e82aabae Mon Sep 17 00:00:00 2001 From: Peter Mao Date: Sat, 24 Jun 2023 07:49:57 -0700 Subject: [PATCH 03/13] prototype code for syncing notes files when docs are renamed --- phmdev.el | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 phmdev.el diff --git a/phmdev.el b/phmdev.el new file mode 100644 index 0000000..c45377b --- /dev/null +++ b/phmdev.el @@ -0,0 +1,99 @@ +;; add this to org-noter-core.el +(defvar org-noter--doc-extensions nil + "List of extensions handled by org-noter when documents are moved. +Used by `phm/org-noter--sync-doc-rename-in-notes'.") +;; add to modules/..pdf +(push "pdf" org-noter--doc-extensions) +;; add to modules/..nov +(push "epub" org-noter--doc-extensions) +;; add to modules/..dvju +(push "djvu" org-noter--doc-extensions) + +(defun phm/org-noter--sync-doc-rename-in-notes (document-path &optional new-document-path) + "Rename org-noter references to document file whose name has changed. + +DOCUMENT-PATH is the original filename. +NEW-DOCUMENT-PATH is the new filename. + +This advice runs after `dired-rename-file' completes successfully +on files with `file-name-extension' in `org-noter--doc-extensions'. + +For notes files that have the same `file-name-base' as the +document, the notes filename will be changed, but not its +`file-name-directory'. + +If the document is moved to a path above the notes file, a +warning will be issued, but the sync will proceed. The directory +of the notes file will not be changed, as there may be other +documents referenced in the notes file. An `org-noter' session +can still be initiated from the notes file, but not vice-versa, +nor will future renames of the document be synced in the notes +file. +" + (when (member-ignore-case (file-name-extension document-path) org-noter--doc-extensions) + (let* ((document-name (file-name-nondirectory document-path)) + (document-base (file-name-base document-name)) + (document-directory (file-name-directory document-path)) + + (search-names (remove nil (append org-noter-default-notes-file-names + (list (concat document-base ".org")) + (list (run-hook-with-args-until-success 'org-noter-find-additional-notes-functions document-path))))) + notes-files-annotating ; List of files annotating document + notes-files) ; List of found notes files (annotating or not) + + ;; seems like the next two blocks can be combined into a single block if + ;; the `locate-dominating-file' paths can be combined with + ;; `org-noter-notes-search-path' check `org-noter-notes-search-path' for + + ;; annotating notes files + (dolist (path org-noter-notes-search-path) + (dolist (name search-names) + (let ((notes-path (expand-file-name name path))) + (when (file-exists-p notes-path) + (push notes-path notes-files) + (when (org-noter--check-if-document-is-annotated-on-file document-path notes-path) + (push notes-path notes-files-annotating)))))) + + ;; check filenames in `search-names' from the doc path up for annotating notes files + (dolist (name search-names) + (let ((directory (locate-dominating-file document-directory name)) + notes-path) + (when directory + (setq notes-path (expand-file-name name directory)) + (unless (member notes-path notes-files) (push notes-path notes-files)) + (when (org-noter--check-if-document-is-annotated-on-file document-path notes-path) + (push notes-path notes-files-annotating))))) + + (setq notes-files-annotating (delete-dups notes-files-annotating)) + + ;; in each annotating notes file, find the entry for this file and update + ;; the document's relative path + (dolist (notes-path notes-files-annotating) + (with-temp-buffer + (insert-file-contents notes-path) + (org-with-point-at (point-min) + (catch 'break ;stop when we find a match + (while (re-search-forward (org-re-property org-noter-property-doc-file) nil) + (let ((property-value (match-string 3)) + (notes-directory (file-name-directory notes-path))) + (when (string-equal (expand-file-name property-value notes-directory) + document-path) + (let ((doc-relative-name (file-relative-name new-document-path notes-directory)) + msg) + (org-set-property org-noter-property-doc-file doc-relative-name) + (when (string-prefix-p "../" doc-relative-name) ;warn against docs that reside above notes in path + (setq msg + (format-message "Document file has moved above notes file (%s). `org-noter' will not be able to find the notes file from the new document path (%s)." notes-path doc-relative-name)) + (display-warning 'org-noter msg :warning))) + (write-file notes-path nil) + ;; change the notes filename if it was based on the document filename + (if (string-equal (file-name-base notes-path) document-base) + (let ((new-notes-path (concat (file-name-directory notes-path) + (file-name-base new-document-path) ".org"))) + (rename-file notes-path new-notes-path))) + (throw 'break t))))))))))) + +(advice-add 'dired-rename-file :after #'phm/org-noter--sync-doc-rename-in-notes) + + +;;(dired-rename-file FILE NEWNAME OK-IF-ALREADY-EXISTS) From e862b45401caf2764e13b59f89fb20ec70bf5584 Mon Sep 17 00:00:00 2001 From: Peter Mao Date: Sat, 24 Jun 2023 09:28:03 -0700 Subject: [PATCH 04/13] clean up finding for candidate notes files --- phmdev.el | 85 +++++++++++++++++++++++++------------------------------ 1 file changed, 39 insertions(+), 46 deletions(-) diff --git a/phmdev.el b/phmdev.el index c45377b..2905d7c 100644 --- a/phmdev.el +++ b/phmdev.el @@ -38,60 +38,53 @@ file. (search-names (remove nil (append org-noter-default-notes-file-names (list (concat document-base ".org")) (list (run-hook-with-args-until-success 'org-noter-find-additional-notes-functions document-path))))) - notes-files-annotating ; List of files annotating document - notes-files) ; List of found notes files (annotating or not) + notes-files ; list of notes files with promising names (Notes.org or .org) + notes-path) ; junk variable when iterating over notes-files - ;; seems like the next two blocks can be combined into a single block if - ;; the `locate-dominating-file' paths can be combined with - ;; `org-noter-notes-search-path' check `org-noter-notes-search-path' for - - ;; annotating notes files - (dolist (path org-noter-notes-search-path) - (dolist (name search-names) - (let ((notes-path (expand-file-name name path))) - (when (file-exists-p notes-path) - (push notes-path notes-files) - (when (org-noter--check-if-document-is-annotated-on-file document-path notes-path) - (push notes-path notes-files-annotating)))))) - - ;; check filenames in `search-names' from the doc path up for annotating notes files + ;; find promising notes files by name in a few places... (dolist (name search-names) - (let ((directory (locate-dominating-file document-directory name)) - notes-path) + ;; check the notes-search-paths + (dolist (path org-noter-notes-search-path) + (setq notes-path (expand-file-name name path)) + (when (file-exists-p notes-path) + (push notes-path notes-files))) + ;; check paths at or above document-directory + (let ((directory (locate-dominating-file document-directory name))) (when directory (setq notes-path (expand-file-name name directory)) - (unless (member notes-path notes-files) (push notes-path notes-files)) - (when (org-noter--check-if-document-is-annotated-on-file document-path notes-path) - (push notes-path notes-files-annotating))))) + (push notes-path notes-files)))) - (setq notes-files-annotating (delete-dups notes-files-annotating)) + (setq notes-files (delete-dups notes-files)) ;; in each annotating notes file, find the entry for this file and update ;; the document's relative path - (dolist (notes-path notes-files-annotating) - (with-temp-buffer - (insert-file-contents notes-path) - (org-with-point-at (point-min) - (catch 'break ;stop when we find a match - (while (re-search-forward (org-re-property org-noter-property-doc-file) nil) - (let ((property-value (match-string 3)) - (notes-directory (file-name-directory notes-path))) - (when (string-equal (expand-file-name property-value notes-directory) - document-path) - (let ((doc-relative-name (file-relative-name new-document-path notes-directory)) - msg) - (org-set-property org-noter-property-doc-file doc-relative-name) - (when (string-prefix-p "../" doc-relative-name) ;warn against docs that reside above notes in path - (setq msg - (format-message "Document file has moved above notes file (%s). `org-noter' will not be able to find the notes file from the new document path (%s)." notes-path doc-relative-name)) - (display-warning 'org-noter msg :warning))) - (write-file notes-path nil) - ;; change the notes filename if it was based on the document filename - (if (string-equal (file-name-base notes-path) document-base) - (let ((new-notes-path (concat (file-name-directory notes-path) - (file-name-base new-document-path) ".org"))) - (rename-file notes-path new-notes-path))) - (throw 'break t))))))))))) + (dolist (notes-path notes-files) + (when (org-noter--check-if-document-is-annotated-on-file document-path notes-path) + (with-temp-buffer + (insert-file-contents notes-path) + (org-with-point-at (point-min) + (catch 'break ;stop when we find a match + (while (re-search-forward (org-re-property org-noter-property-doc-file) nil) + (let ((property-value (match-string 3)) + (notes-directory (file-name-directory notes-path))) + (when (string-equal (expand-file-name property-value notes-directory) + document-path) + (let ((doc-relative-name (file-relative-name new-document-path notes-directory)) + msg) + ;; sync the new document path in this notes file + (org-set-property org-noter-property-doc-file doc-relative-name) + ;; warn against docs that reside above notes in path + (when (string-prefix-p "../" doc-relative-name) + (setq msg + (format-message "Document file has moved above notes file (%s). `org-noter' will not be able to find the notes file from the new document path (%s)." notes-path doc-relative-name)) + (display-warning 'org-noter msg :warning))) + (write-file notes-path nil) + ;; change the notes filename if it was based on the document filename + (if (string-equal (file-name-base notes-path) document-base) + (let ((new-notes-path (concat (file-name-directory notes-path) + (file-name-base new-document-path) ".org"))) + (rename-file notes-path new-notes-path))) + (throw 'break t)))))))))))) (advice-add 'dired-rename-file :after #'phm/org-noter--sync-doc-rename-in-notes) From 97185b1172a48fb9eb7a71274fdff65108ad1280 Mon Sep 17 00:00:00 2001 From: Peter Mao Date: Sat, 24 Jun 2023 13:08:43 -0700 Subject: [PATCH 05/13] advise dired-rename-file -- works! --- phmdev.el | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/phmdev.el b/phmdev.el index 2905d7c..dafdc05 100644 --- a/phmdev.el +++ b/phmdev.el @@ -9,7 +9,7 @@ Used by `phm/org-noter--sync-doc-rename-in-notes'.") ;; add to modules/..dvju (push "djvu" org-noter--doc-extensions) -(defun phm/org-noter--sync-doc-rename-in-notes (document-path &optional new-document-path) +(defun phm/org-noter--sync-doc-rename-in-notes (document-path new-document-path &optional _ok-if-already-exists) "Rename org-noter references to document file whose name has changed. DOCUMENT-PATH is the original filename. @@ -86,7 +86,18 @@ file. (rename-file notes-path new-notes-path))) (throw 'break t)))))))))))) -(advice-add 'dired-rename-file :after #'phm/org-noter--sync-doc-rename-in-notes) - +(advice-add 'dired-rename-file :after-until 'phm/org-noter--sync-doc-rename-in-notes) +(advice-remove 'dired-rename-file 'phm/org-noter--sync-doc-rename-in-notes) ;;(dired-rename-file FILE NEWNAME OK-IF-ALREADY-EXISTS) + +;; ‘:after-while’ +;; Call FUNCTION after the old function and only if the old function +;; returned non-‘nil’. Both functions receive the same arguments, and +;; the return value of the composition is the return value of +;; FUNCTION. More specifically, the composition of the two functions +;; behaves like: +;; (lambda (&rest r) (and (apply OLDFUN r) (apply FUNCTION r))) +;; ‘(add-function :after-while FUNVAR FUNCTION)’ is comparable for +;; single-function hooks to ‘(add-hook 'HOOKVAR FUNCTION 'append)’ +;; when HOOKVAR is run via ‘run-hook-with-args-until-failure’. From b1ece566cb3fe3bf091eed6d1316e02dc091e896 Mon Sep 17 00:00:00 2001 From: Peter Mao Date: Sat, 24 Jun 2023 22:00:42 -0700 Subject: [PATCH 06/13] check for successful rename in --sync-doc-rename-in-notes `dired-rename-file's output is not clear -- it can return nil on a successful rename, which means :after-until would be the correct conditional :after-x advice. Instead, run the check for a successful rename inside --sync-doc-rename-in-notes and use a straight :after advice. --- phmdev.el | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/phmdev.el b/phmdev.el index dafdc05..beb9ca4 100644 --- a/phmdev.el +++ b/phmdev.el @@ -1,7 +1,7 @@ ;; add this to org-noter-core.el (defvar org-noter--doc-extensions nil "List of extensions handled by org-noter when documents are moved. -Used by `phm/org-noter--sync-doc-rename-in-notes'.") +Used by `org-noter--sync-doc-rename-in-notes'.") ;; add to modules/..pdf (push "pdf" org-noter--doc-extensions) ;; add to modules/..nov @@ -9,8 +9,8 @@ Used by `phm/org-noter--sync-doc-rename-in-notes'.") ;; add to modules/..dvju (push "djvu" org-noter--doc-extensions) -(defun phm/org-noter--sync-doc-rename-in-notes (document-path new-document-path &optional _ok-if-already-exists) - "Rename org-noter references to document file whose name has changed. +(defun org-noter--sync-doc-rename-in-notes (document-path new-document-path &optional _ok-if-already-exists) + "Update org-noter references to document-file whose name has changed. DOCUMENT-PATH is the original filename. NEW-DOCUMENT-PATH is the new filename. @@ -30,7 +30,12 @@ can still be initiated from the notes file, but not vice-versa, nor will future renames of the document be synced in the notes file. " - (when (member-ignore-case (file-name-extension document-path) org-noter--doc-extensions) + (when (and (member-ignore-case (file-name-extension document-path) + org-noter--doc-extensions) + (not (file-exists-p document-path)) + (file-exists-p new-document-path)) + ;; continue if the file extension is that of a document + ;; and the rename was successful (let* ((document-name (file-name-nondirectory document-path)) (document-base (file-name-base document-name)) (document-directory (file-name-directory document-path)) @@ -86,18 +91,6 @@ file. (rename-file notes-path new-notes-path))) (throw 'break t)))))))))))) -(advice-add 'dired-rename-file :after-until 'phm/org-noter--sync-doc-rename-in-notes) -(advice-remove 'dired-rename-file 'phm/org-noter--sync-doc-rename-in-notes) +(advice-add 'dired-rename-file :after 'org-noter--sync-doc-rename-in-notes) -;;(dired-rename-file FILE NEWNAME OK-IF-ALREADY-EXISTS) - -;; ‘:after-while’ -;; Call FUNCTION after the old function and only if the old function -;; returned non-‘nil’. Both functions receive the same arguments, and -;; the return value of the composition is the return value of -;; FUNCTION. More specifically, the composition of the two functions -;; behaves like: -;; (lambda (&rest r) (and (apply OLDFUN r) (apply FUNCTION r))) -;; ‘(add-function :after-while FUNVAR FUNCTION)’ is comparable for -;; single-function hooks to ‘(add-hook 'HOOKVAR FUNCTION 'append)’ -;; when HOOKVAR is run via ‘run-hook-with-args-until-failure’. +;;(advice-remove 'dired-rename-file 'org-noter--sync-doc-rename-in-notes) From 8df9905391bc2609a8b372f5fd044942b88d9a3d Mon Sep 17 00:00:00 2001 From: Peter Mao Date: Sun, 25 Jun 2023 07:19:27 -0700 Subject: [PATCH 07/13] move code from phmdev.el into org-noter --- modules/org-noter-djvu.el | 2 + modules/org-noter-nov.el | 2 + modules/org-noter-pdf.el | 1 + org-noter-core.el | 90 ++++++++++++++++++++++++++++++++++++ phmdev.el | 96 --------------------------------------- 5 files changed, 95 insertions(+), 96 deletions(-) delete mode 100644 phmdev.el diff --git a/modules/org-noter-djvu.el b/modules/org-noter-djvu.el index eccaacb..ed208e0 100644 --- a/modules/org-noter-djvu.el +++ b/modules/org-noter-djvu.el @@ -33,6 +33,8 @@ (require 'djvu) (error (message "ATTENTION: org-noter-djvu needs the package `djvu'"))) +(push "djvu" org-noter--doc-extensions) + (defun org-noter-djvu--pretty-print-location (location) (org-noter--with-valid-session (when (eq (org-noter--session-doc-mode session) 'djvu-read-mode) diff --git a/modules/org-noter-nov.el b/modules/org-noter-nov.el index e8f6374..9786ffb 100644 --- a/modules/org-noter-nov.el +++ b/modules/org-noter-nov.el @@ -33,6 +33,8 @@ (require 'nov) (error (message "ATTENTION: org-noter-nov needs the package `nov'"))) +(push "epub" org-noter--doc-extensions) + (defvar nov-documents-index) (defvar nov-file-name) (defvar-local org-noter--nov-timer nil diff --git a/modules/org-noter-pdf.el b/modules/org-noter-pdf.el index ecf67bc..6da18e8 100644 --- a/modules/org-noter-pdf.el +++ b/modules/org-noter-pdf.el @@ -34,6 +34,7 @@ (require 'pdf-tools) (error (message "ATTENTION: org-noter-pdf has many featues that depend on the package `pdf-tools'"))) +(push "pdf" org-noter--doc-extensions) (cl-defstruct pdf-highlight page coords) (defun org-noter-pdf--get-highlight () diff --git a/org-noter-core.el b/org-noter-core.el index 358498c..1228524 100644 --- a/org-noter-core.el +++ b/org-noter-core.el @@ -60,6 +60,10 @@ :group 'org-noter :type '(repeat symbol)) +(defvar org-noter--doc-extensions nil + "List of extensions handled by org-noter when documents are moved. +Used by `org-noter--sync-doc-rename-in-notes'. This variable gets filled in by supported modes, so it is not a `defcustom' variable.") + (defcustom org-noter-property-doc-file "NOTER_DOCUMENT" "Name of the property that specifies the document." :group 'org-noter @@ -1729,6 +1733,92 @@ mode." This is delegated to each document mode (eg pdf)." (run-hook-with-args-until-success 'org-noter--pretty-print-highlight-location-hook highlight-location)) +(defun org-noter--sync-doc-rename-in-notes (document-path new-document-path &optional _ok-if-already-exists) + "Update org-noter references to document-file whose name has changed. + +DOCUMENT-PATH is the original filename. +NEW-DOCUMENT-PATH is the new filename. + +This advice runs after `dired-rename-file' completes successfully +on files with `file-name-extension' in `org-noter--doc-extensions'. + +For notes files that have the same `file-name-base' as the +document, the notes filename will be changed, but not its +`file-name-directory'. + +If the document is moved to a path above the notes file, a +warning will be issued, but the sync will proceed. The directory +of the notes file will not be changed, as there may be other +documents referenced in the notes file. An `org-noter' session +can still be initiated from the notes file, but not vice-versa, +nor will future renames of the document be synced in the notes +file. +" + (when (and (member-ignore-case (file-name-extension document-path) + org-noter--doc-extensions) + (not (file-exists-p document-path)) + (file-exists-p new-document-path)) + ;; continue if the file extension is that of a document + ;; and the rename was successful + (let* ((document-name (file-name-nondirectory document-path)) + (document-base (file-name-base document-name)) + (document-directory (file-name-directory document-path)) + + (search-names (remove nil (append org-noter-default-notes-file-names + (list (concat document-base ".org")) + (list (run-hook-with-args-until-success 'org-noter-find-additional-notes-functions document-path))))) + notes-files ; list of notes files with promising names (Notes.org or .org) + notes-path) ; junk variable when iterating over notes-files + + ;; find promising notes files by name in a few places... + (dolist (name search-names) + ;; check the notes-search-paths + (dolist (path org-noter-notes-search-path) + (setq notes-path (expand-file-name name path)) + (when (file-exists-p notes-path) + (push notes-path notes-files))) + ;; check paths at or above document-directory + (let ((directory (locate-dominating-file document-directory name))) + (when directory + (setq notes-path (expand-file-name name directory)) + (push notes-path notes-files)))) + + (setq notes-files (delete-dups notes-files)) + + ;; in each annotating notes file, find the entry for this file and update + ;; the document's relative path + (dolist (notes-path notes-files) + (when (org-noter--check-if-document-is-annotated-on-file document-path notes-path) + (with-temp-buffer + (insert-file-contents notes-path) + (org-with-point-at (point-min) + (catch 'break ;stop when we find a match + (while (re-search-forward (org-re-property org-noter-property-doc-file) nil) + (let ((property-value (match-string 3)) + (notes-directory (file-name-directory notes-path))) + (when (string-equal (expand-file-name property-value notes-directory) + document-path) + (let ((doc-relative-name (file-relative-name new-document-path notes-directory)) + msg) + ;; sync the new document path in this notes file + (org-set-property org-noter-property-doc-file doc-relative-name) + ;; warn against docs that reside above notes in path + (when (string-prefix-p "../" doc-relative-name) + (setq msg + (format-message "Document file has moved above notes file (%s). `org-noter' will not be able to find the notes file from the new document path (%s)." notes-path doc-relative-name)) + (display-warning 'org-noter msg :warning))) + (write-file notes-path nil) + ;; change the notes filename if it was based on the document filename + (if (string-equal (file-name-base notes-path) document-base) + (let ((new-notes-path (concat (file-name-directory notes-path) + (file-name-base new-document-path) ".org"))) + (rename-file notes-path new-notes-path))) + (throw 'break t)))))))))))) + +(advice-add 'dired-rename-file :after 'org-noter--sync-doc-rename-in-notes) +;;uncomment or eval next line to disable. +;;(advice-remove 'dired-rename-file 'org-noter--sync-doc-rename-in-notes) + ;; -------------------------------------------------------------------------------- ;;; User commands (defun org-noter-set-start-location (&optional arg) diff --git a/phmdev.el b/phmdev.el deleted file mode 100644 index beb9ca4..0000000 --- a/phmdev.el +++ /dev/null @@ -1,96 +0,0 @@ -;; add this to org-noter-core.el -(defvar org-noter--doc-extensions nil - "List of extensions handled by org-noter when documents are moved. -Used by `org-noter--sync-doc-rename-in-notes'.") -;; add to modules/..pdf -(push "pdf" org-noter--doc-extensions) -;; add to modules/..nov -(push "epub" org-noter--doc-extensions) -;; add to modules/..dvju -(push "djvu" org-noter--doc-extensions) - -(defun org-noter--sync-doc-rename-in-notes (document-path new-document-path &optional _ok-if-already-exists) - "Update org-noter references to document-file whose name has changed. - -DOCUMENT-PATH is the original filename. -NEW-DOCUMENT-PATH is the new filename. - -This advice runs after `dired-rename-file' completes successfully -on files with `file-name-extension' in `org-noter--doc-extensions'. - -For notes files that have the same `file-name-base' as the -document, the notes filename will be changed, but not its -`file-name-directory'. - -If the document is moved to a path above the notes file, a -warning will be issued, but the sync will proceed. The directory -of the notes file will not be changed, as there may be other -documents referenced in the notes file. An `org-noter' session -can still be initiated from the notes file, but not vice-versa, -nor will future renames of the document be synced in the notes -file. -" - (when (and (member-ignore-case (file-name-extension document-path) - org-noter--doc-extensions) - (not (file-exists-p document-path)) - (file-exists-p new-document-path)) - ;; continue if the file extension is that of a document - ;; and the rename was successful - (let* ((document-name (file-name-nondirectory document-path)) - (document-base (file-name-base document-name)) - (document-directory (file-name-directory document-path)) - - (search-names (remove nil (append org-noter-default-notes-file-names - (list (concat document-base ".org")) - (list (run-hook-with-args-until-success 'org-noter-find-additional-notes-functions document-path))))) - notes-files ; list of notes files with promising names (Notes.org or .org) - notes-path) ; junk variable when iterating over notes-files - - ;; find promising notes files by name in a few places... - (dolist (name search-names) - ;; check the notes-search-paths - (dolist (path org-noter-notes-search-path) - (setq notes-path (expand-file-name name path)) - (when (file-exists-p notes-path) - (push notes-path notes-files))) - ;; check paths at or above document-directory - (let ((directory (locate-dominating-file document-directory name))) - (when directory - (setq notes-path (expand-file-name name directory)) - (push notes-path notes-files)))) - - (setq notes-files (delete-dups notes-files)) - - ;; in each annotating notes file, find the entry for this file and update - ;; the document's relative path - (dolist (notes-path notes-files) - (when (org-noter--check-if-document-is-annotated-on-file document-path notes-path) - (with-temp-buffer - (insert-file-contents notes-path) - (org-with-point-at (point-min) - (catch 'break ;stop when we find a match - (while (re-search-forward (org-re-property org-noter-property-doc-file) nil) - (let ((property-value (match-string 3)) - (notes-directory (file-name-directory notes-path))) - (when (string-equal (expand-file-name property-value notes-directory) - document-path) - (let ((doc-relative-name (file-relative-name new-document-path notes-directory)) - msg) - ;; sync the new document path in this notes file - (org-set-property org-noter-property-doc-file doc-relative-name) - ;; warn against docs that reside above notes in path - (when (string-prefix-p "../" doc-relative-name) - (setq msg - (format-message "Document file has moved above notes file (%s). `org-noter' will not be able to find the notes file from the new document path (%s)." notes-path doc-relative-name)) - (display-warning 'org-noter msg :warning))) - (write-file notes-path nil) - ;; change the notes filename if it was based on the document filename - (if (string-equal (file-name-base notes-path) document-base) - (let ((new-notes-path (concat (file-name-directory notes-path) - (file-name-base new-document-path) ".org"))) - (rename-file notes-path new-notes-path))) - (throw 'break t)))))))))))) - -(advice-add 'dired-rename-file :after 'org-noter--sync-doc-rename-in-notes) - -;;(advice-remove 'dired-rename-file 'org-noter--sync-doc-rename-in-notes) From 0541dd9f5d154b8334bc1e71712d9e689db8d57e Mon Sep 17 00:00:00 2001 From: Peter Mao Date: Mon, 26 Jun 2023 18:20:05 -0700 Subject: [PATCH 08/13] org-noter--sync-notes-rename-in-notes and enable/disable functions `..--sync-notes..' updates org noter references to docs in notes files when they are moved to a different directory. added enable/disable functions for the --sync-..-rename-.. advising functions. --- org-noter-core.el | 87 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 82 insertions(+), 5 deletions(-) diff --git a/org-noter-core.el b/org-noter-core.el index 1228524..209ce33 100644 --- a/org-noter-core.el +++ b/org-noter-core.el @@ -1739,6 +1739,9 @@ This is delegated to each document mode (eg pdf)." DOCUMENT-PATH is the original filename. NEW-DOCUMENT-PATH is the new filename. +Call `org-noter-enable-sync-renames' to enable this feature and +`org-noter-disable-sync-renames' to disable it. + This advice runs after `dired-rename-file' completes successfully on files with `file-name-extension' in `org-noter--doc-extensions'. @@ -1752,8 +1755,8 @@ of the notes file will not be changed, as there may be other documents referenced in the notes file. An `org-noter' session can still be initiated from the notes file, but not vice-versa, nor will future renames of the document be synced in the notes -file. -" +file." + (when (and (member-ignore-case (file-name-extension document-path) org-noter--doc-extensions) (not (file-exists-p document-path)) @@ -1815,9 +1818,63 @@ file. (rename-file notes-path new-notes-path))) (throw 'break t)))))))))))) -(advice-add 'dired-rename-file :after 'org-noter--sync-doc-rename-in-notes) -;;uncomment or eval next line to disable. -;;(advice-remove 'dired-rename-file 'org-noter--sync-doc-rename-in-notes) +(defun org-noter--sync-notes-rename-in-notes (notes-path new-notes-path &optional _ok-if-already-exists) + "Update org-noter references to docs when notes file is moved. + +NOTES-PATH is the original filename. +NEW-NOTES-PATH is the new filename. + +Call `org-noter-enable-sync-renames' to enable this feature and +`org-noter-disable-sync-renames' to disable it. + +This advice runs after `dired-rename-file' moves an '.org' file to +a different directory. + +If the notes file is moved to a path below any of its linked +documents, a warning will be issued, but the sync will proceed. +An `org-noter' session can still be initiated from the notes +file, but not vice-versa, but future renames of the notes file +will continue to sync the document references." + + (when (and (string-equal (file-name-extension notes-path) "org") + (not (file-exists-p notes-path)) + (file-exists-p new-notes-path) + (not (string-equal (file-name-directory notes-path) + (file-name-directory new-notes-path)))) + ;; continue if it is an org file + ;; and the rename was successful + ;; and the directory changes + (let* (;;(document-name (file-name-nondirectory document-path)) + ;;(document-base (file-name-base document-name)) + ( notes-directory (file-name-directory notes-path)) + (new-notes-directory (file-name-directory new-notes-path)) + (problem-path-list nil) + (this-org-file-uses-noter nil)) + + ;; update each document's relative path + (with-temp-buffer + (insert-file-contents new-notes-path) + (org-with-point-at (point-min) + (while (re-search-forward (org-re-property org-noter-property-doc-file) nil t) + (let* (( doc-file-rel-path (match-string 3)) + ( doc-file-abs-path (expand-file-name doc-file-rel-path notes-directory)) + (new-doc-file-rel-path (file-relative-name doc-file-abs-path new-notes-directory))) + (setq this-org-file-uses-noter t) + ;; sync the document path to the new notes file + (org-set-property org-noter-property-doc-file new-doc-file-rel-path) + (next-line) + ;; add problematic paths to the list + (when (string-prefix-p "../" new-doc-file-rel-path) + (push new-doc-file-rel-path problem-path-list))))) + ;; warn against docs that reside above notes in path + (when problem-path-list + (let ((msg (format-message + "Notes file has moved below some documents. `org-noter' will not be able to find the notes file from the document path for these files:"))) + (dolist (doc-path problem-path-list) + (setq msg (concat msg (format-message "\n%s" doc-path)))) + (display-warning 'org-noter msg :warning))) + (when this-org-file-uses-noter + (write-file new-notes-path nil)))))) ;; -------------------------------------------------------------------------------- ;;; User commands @@ -2466,6 +2523,26 @@ As such, it will only work when the notes window exists." (user-error "There is no next note")))) (select-window (org-noter--get-doc-window))) +(defun org-noter-enable-sync-renames () + "Enable `dired-rename-file' advice for moving docs and notes. +Enables `org-noter--sync-doc-rename-in-notes' and +`org-noter--sync-notes-rename-in-notes' as advice :after +`dired-rename-file'. + +In dired, this affects the renaming of supported document files +and .org files." + (interactive) + (advice-add 'dired-rename-file :after 'org-noter--sync-doc-rename-in-notes) + (advice-add 'dired-rename-file :after 'org-noter--sync-notes-rename-in-notes)) + +(defun org-noter-disable-sync-renames () + "Disable `dired-rename-file' advice for moving docs and notes. +Run this if you change your mind about using the rename +synchronization features." + (interactive) + (advice-remove 'dired-rename-file 'org-noter--sync-doc-rename-in-notes) + (advice-remove 'dired-rename-file 'org-noter--sync-notes-rename-in-notes)) + (define-minor-mode org-noter-doc-mode "Minor mode for the document buffer. Keymap: From f2d5188d219a6b48e35ccd14d709410bf8fb61e7 Mon Sep 17 00:00:00 2001 From: Peter Mao Date: Mon, 26 Jun 2023 18:34:49 -0700 Subject: [PATCH 09/13] Add documentation of sync-rename functions. --- README.org | 6 ++++++ org-noter-core.el | 4 +++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/README.org b/README.org index 94e99a4..fbbf9ef 100644 --- a/README.org +++ b/README.org @@ -105,6 +105,12 @@ the document to annotate. *** new (all formats) + - ~org-noter-enable-sync-renames~ :: Optional feature to update document + paths when renaming or moving document files or notes files. This allows + you to change your mind later about the names and locations of your + document files and notes files without having to manually update all the + links. + - ~org-noter-toggle-notes-window-location~ (~M-T~) :: Toggle between horizontal and vertical document/notes layout. diff --git a/org-noter-core.el b/org-noter-core.el index 209ce33..293ad28 100644 --- a/org-noter-core.el +++ b/org-noter-core.el @@ -2530,7 +2530,9 @@ Enables `org-noter--sync-doc-rename-in-notes' and `dired-rename-file'. In dired, this affects the renaming of supported document files -and .org files." +and .org files. + +This feature can be turn off with `org-noter-disable-sync-renames'." (interactive) (advice-add 'dired-rename-file :after 'org-noter--sync-doc-rename-in-notes) (advice-add 'dired-rename-file :after 'org-noter--sync-notes-rename-in-notes)) From ec76c7a76c25238db7c812edc0ed629cc5d5b638 Mon Sep 17 00:00:00 2001 From: Peter Mao Date: Fri, 30 Jun 2023 21:52:41 -0700 Subject: [PATCH 10/13] add optional decoration to headline title With `entitiespretty`, underscores in titles look terrible, but org's emphasis decorations make them readable again with minimal disturbance. --- org-noter-core.el | 18 +++++++++++++++++- org-noter.el | 5 ++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/org-noter-core.el b/org-noter-core.el index da09e80..8e00ee0 100644 --- a/org-noter-core.el +++ b/org-noter-core.el @@ -334,7 +334,23 @@ If it exists, it will be listed as a candidate that `org-noter' will have the user select to use as the note file of the document." :group 'org-noter - :type 'hook) + :type 'hook + :version "28.2") + +(defcustom org-noter-headline-title-decoration "" + "Decoration (emphasis) for the headline title string. + +If you use the Org STARTUP option 'entitiespretty', filenames +with underscores will end up looking ugly. This string is +prepended and appended to the document title in the top-level +headline, making it look nicer. + +Reasonable choices are: /, *, =, ~, _ + +With '/', 'The_Title' would become '/The_Title/'." + :group 'org-noter + :type 'string + :version "28.2") (defface org-noter-no-notes-exist-face '((t diff --git a/org-noter.el b/org-noter.el index 2693098..6e15d4c 100644 --- a/org-noter.el +++ b/org-noter.el @@ -267,7 +267,10 @@ DOCUMENT-FILE-NAME is the document filename." (with-current-buffer (find-file-noselect (car notes-files)) (goto-char (point-max)) (insert (if (save-excursion (beginning-of-line) (looking-at "[[:space:]]*$")) "" "\n") - "* " document-base) + "* " + org-noter-headline-title-decoration + document-base + org-noter-headline-title-decoration) (org-entry-put nil org-noter-property-doc-file (file-relative-name document-used-path (file-name-directory (car notes-files))))) From 980a12416bbcadaf37f5aa3a652c478e9283a16d Mon Sep 17 00:00:00 2001 From: Peter Mao Date: Sat, 8 Jul 2023 22:40:34 -0700 Subject: [PATCH 11/13] bugfix - skip filenames w/o extensions --- org-noter-core.el | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/org-noter-core.el b/org-noter-core.el index 293ad28..8ac9408 100644 --- a/org-noter-core.el +++ b/org-noter-core.el @@ -1757,7 +1757,8 @@ can still be initiated from the notes file, but not vice-versa, nor will future renames of the document be synced in the notes file." - (when (and (member-ignore-case (file-name-extension document-path) + (when (and (file-name-extension document-path) + (member-ignore-case (file-name-extension document-path) org-noter--doc-extensions) (not (file-exists-p document-path)) (file-exists-p new-document-path)) From e84c622f0401c97c7d9ed5fa1a0eed229ec6454e Mon Sep 17 00:00:00 2001 From: Peter Mao Date: Mon, 10 Jul 2023 23:04:12 -0700 Subject: [PATCH 12/13] for cask, use melpa rather than melpa-stable tablist was failing to load. --- Cask | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cask b/Cask index c224206..e040aaa 100644 --- a/Cask +++ b/Cask @@ -1,5 +1,5 @@ (source gnu) -(source melpa-stable) +(source melpa) (depends-on "buttercup") (depends-on "pdf-tools") From 6ca079cbdc982fef050a7826547bdacad53535a9 Mon Sep 17 00:00:00 2001 From: Peter Mao Date: Fri, 28 Jul 2023 13:27:10 -0700 Subject: [PATCH 13/13] change the verb of this feature from "sync" to "update" --- README.org | 2 +- org-noter-core.el | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/README.org b/README.org index fbbf9ef..aba0060 100644 --- a/README.org +++ b/README.org @@ -105,7 +105,7 @@ the document to annotate. *** new (all formats) - - ~org-noter-enable-sync-renames~ :: Optional feature to update document + - ~org-noter-enable-update-renames~ :: Optional feature to update document paths when renaming or moving document files or notes files. This allows you to change your mind later about the names and locations of your document files and notes files without having to manually update all the diff --git a/org-noter-core.el b/org-noter-core.el index 8ac9408..d6f45b1 100644 --- a/org-noter-core.el +++ b/org-noter-core.el @@ -62,7 +62,7 @@ (defvar org-noter--doc-extensions nil "List of extensions handled by org-noter when documents are moved. -Used by `org-noter--sync-doc-rename-in-notes'. This variable gets filled in by supported modes, so it is not a `defcustom' variable.") +Used by `org-noter--update-doc-rename-in-notes'. This variable gets filled in by supported modes, so it is not a `defcustom' variable.") (defcustom org-noter-property-doc-file "NOTER_DOCUMENT" "Name of the property that specifies the document." @@ -1733,7 +1733,7 @@ mode." This is delegated to each document mode (eg pdf)." (run-hook-with-args-until-success 'org-noter--pretty-print-highlight-location-hook highlight-location)) -(defun org-noter--sync-doc-rename-in-notes (document-path new-document-path &optional _ok-if-already-exists) +(defun org-noter--update-doc-rename-in-notes (document-path new-document-path &optional _ok-if-already-exists) "Update org-noter references to document-file whose name has changed. DOCUMENT-PATH is the original filename. @@ -1819,7 +1819,7 @@ file." (rename-file notes-path new-notes-path))) (throw 'break t)))))))))))) -(defun org-noter--sync-notes-rename-in-notes (notes-path new-notes-path &optional _ok-if-already-exists) +(defun org-noter--update-notes-rename-in-notes (notes-path new-notes-path &optional _ok-if-already-exists) "Update org-noter references to docs when notes file is moved. NOTES-PATH is the original filename. @@ -2524,10 +2524,10 @@ As such, it will only work when the notes window exists." (user-error "There is no next note")))) (select-window (org-noter--get-doc-window))) -(defun org-noter-enable-sync-renames () +(defun org-noter-enable-update-renames () "Enable `dired-rename-file' advice for moving docs and notes. -Enables `org-noter--sync-doc-rename-in-notes' and -`org-noter--sync-notes-rename-in-notes' as advice :after +Enables `org-noter--update-doc-rename-in-notes' and +`org-noter--update-notes-rename-in-notes' as advice :after `dired-rename-file'. In dired, this affects the renaming of supported document files @@ -2535,16 +2535,16 @@ and .org files. This feature can be turn off with `org-noter-disable-sync-renames'." (interactive) - (advice-add 'dired-rename-file :after 'org-noter--sync-doc-rename-in-notes) - (advice-add 'dired-rename-file :after 'org-noter--sync-notes-rename-in-notes)) + (advice-add 'dired-rename-file :after 'org-noter--update-doc-rename-in-notes) + (advice-add 'dired-rename-file :after 'org-noter--update-notes-rename-in-notes)) -(defun org-noter-disable-sync-renames () +(defun org-noter-disable-update-renames () "Disable `dired-rename-file' advice for moving docs and notes. Run this if you change your mind about using the rename synchronization features." (interactive) - (advice-remove 'dired-rename-file 'org-noter--sync-doc-rename-in-notes) - (advice-remove 'dired-rename-file 'org-noter--sync-notes-rename-in-notes)) + (advice-remove 'dired-rename-file 'org-noter--update-doc-rename-in-notes) + (advice-remove 'dired-rename-file 'org-noter--update-notes-rename-in-notes)) (define-minor-mode org-noter-doc-mode "Minor mode for the document buffer.