Skip to content

Commit

Permalink
Merge remote-tracking branch 'org-noter/master' into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
petermao committed Jul 28, 2023
2 parents b157534 + 4d47516 commit 0a9b03d
Show file tree
Hide file tree
Showing 7 changed files with 214 additions and 13 deletions.
2 changes: 1 addition & 1 deletion Cask
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
(source gnu)
(source melpa-stable)
(source melpa)

(depends-on "buttercup")
(depends-on "pdf-tools")
Expand Down
6 changes: 6 additions & 0 deletions README.org
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,12 @@
the document to annotate.

*** new (all formats)
- ~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
links.

- ~org-noter-toggle-notes-window-location~ (~M-T~) :: Toggle between
horizontal and vertical document/notes layout.

Expand Down
2 changes: 2 additions & 0 deletions modules/org-noter-djvu.el
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 2 additions & 0 deletions modules/org-noter-nov.el
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
20 changes: 11 additions & 9 deletions modules/org-noter-pdf.el
Original file line number Diff line number Diff line change
Expand Up @@ -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 ()
Expand Down Expand Up @@ -501,19 +502,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 <event> 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
190 changes: 188 additions & 2 deletions org-noter-core.el
Original file line number Diff line number Diff line change
Expand Up @@ -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--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."
:group 'org-noter
Expand Down Expand Up @@ -339,7 +343,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
Expand Down Expand Up @@ -1662,7 +1682,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)))))))
Expand Down Expand Up @@ -1734,6 +1754,150 @@ 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--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.
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'.
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 (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))
;; 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 <docname>.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))))))))))))

(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.
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
(defun org-noter-set-start-location (&optional arg)
Expand Down Expand Up @@ -2384,6 +2548,28 @@ 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-update-renames ()
"Enable `dired-rename-file' advice for moving docs and notes.
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
and .org files.
This feature can be turn off with `org-noter-disable-sync-renames'."
(interactive)
(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-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--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.
Keymap:
Expand Down
5 changes: 4 additions & 1 deletion org-noter.el
Original file line number Diff line number Diff line change
Expand Up @@ -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)))))
Expand Down

0 comments on commit 0a9b03d

Please sign in to comment.