From f0b967bc7dcf4f89fa1c29e1d3430b7a9b63ca75 Mon Sep 17 00:00:00 2001 From: Daneel Date: Mon, 23 Feb 2026 22:20:34 +0100 Subject: [PATCH] fix(org-noter): definitive fix -- repair wrong NOTER_DOCUMENT + cl-letf prompt bypass --- config.el | 94 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 51 insertions(+), 43 deletions(-) diff --git a/config.el b/config.el index d0af3a2..85f15e1 100644 --- a/config.el +++ b/config.el @@ -1249,58 +1249,66 @@ Otherwise: runs interactive ement-connect, then opens rooms after sync." org-noter-insert-note-no-questions nil org-noter-use-indirect-buffer nil)) -;; Smart org-noter launcher: always works from a PDF buffer. -;; Pre-creates the notes file with correct NOTER_DOCUMENT (relative path), -;; then starts org-noter from the notes file (org-mode context) to avoid -;; org-noter's file-search which requires parent-directory relationship. +;; Smart org-noter launcher: finds the PDF window, repairs broken notes files, +;; and auto-answers org-noter's prompts so sessions start without user interaction. +;; Uses absolute NOTER_DOCUMENT paths (avoids symlink issues with file-relative-name). (defun my/org-noter-start () "Start org-noter for the PDF visible in the current frame. -Creates the notes file with a correct NOTER_DOCUMENT property (relative path) -if it does not already exist, then starts the session from the notes buffer." +Repairs any existing notes file with a wrong NOTER_DOCUMENT property, +then starts the session — no interactive prompts required." (interactive) - ;; Ensure org-noter is loaded so its variables are available (require 'org-noter) (let* ((pdf-win (if (derived-mode-p 'pdf-view-mode) (selected-window) - (cl-find-if - (lambda (w) - (with-current-buffer (window-buffer w) - (derived-mode-p 'pdf-view-mode))) - (window-list (selected-frame))))) + (cl-find-if (lambda (w) + (with-current-buffer (window-buffer w) + (derived-mode-p 'pdf-view-mode))) + (window-list (selected-frame))))) (pdf-path (when pdf-win (with-current-buffer (window-buffer pdf-win) (buffer-file-name))))) - (if (not pdf-path) - ;; No PDF buffer found — fall back to standard org-noter - (org-noter) - (let* ((base (file-name-base pdf-path)) - (notes-dir (expand-file-name "notes/" org-directory)) - (notes-file (expand-file-name (concat base ".org") notes-dir)) - ;; Relative path from notes file dir to PDF (what org-noter stores) - (rel-path (file-relative-name pdf-path notes-dir))) - (make-directory notes-dir t) - ;; Create or update notes file — insert NOTER_DOCUMENT as relative path - (with-current-buffer (find-file-noselect notes-file) - (when (= (buffer-size) 0) - ;; New file: create a proper org-noter heading - (insert (format "* Notes: %s\n:PROPERTIES:\n:NOTER_DOCUMENT: %s\n:END:\n\n" - base rel-path)) - (save-buffer)) - (unless (save-excursion - (goto-char (point-min)) - (re-search-forward ":NOTER_DOCUMENT:" nil t)) - ;; Existing file without property: prepend heading - (goto-char (point-min)) - (insert (format "* Notes: %s\n:PROPERTIES:\n:NOTER_DOCUMENT: %s\n:END:\n\n" - base rel-path)) - (save-buffer))) - ;; Open notes file and start org-noter from there (org-mode context) - ;; This uses the simpler code path that reads NOTER_DOCUMENT directly - (find-file notes-file) - (goto-char (point-min)) - (re-search-forward ":NOTER_DOCUMENT:" nil t) - (org-back-to-heading t) - (org-noter))))) + (unless pdf-path + (user-error "No PDF buffer visible — open a PDF first")) + (let* ((base (file-name-base pdf-path)) + (notes-name (concat base ".org")) + (notes-dir (car org-noter-notes-search-path)) + (target (expand-file-name notes-name notes-dir))) + (make-directory notes-dir t) + ;; Repair existing notes file if NOTER_DOCUMENT is wrong (doesn't point to pdf-path). + ;; Uses absolute path for NOTER_DOCUMENT to avoid symlink resolution issues. + (when (file-exists-p target) + (with-current-buffer (find-file-noselect target) + (let ((modified nil)) + (save-excursion + (goto-char (point-min)) + (while (re-search-forward + (concat "^[ \t]*:" org-noter-property-doc-file ":[ \t]*\\(.*\\)$") + nil t) + (let* ((stored (string-trim (match-string 1))) + (expanded (if (file-name-absolute-p stored) + stored + (expand-file-name stored (file-name-directory target))))) + (unless (and (file-exists-p expanded) + (file-equal-p expanded pdf-path)) + ;; Wrong or missing target — replace with absolute path to PDF + (replace-match (concat ":" org-noter-property-doc-file + ": " pdf-path) + t t) + (setq modified t))))) + (when modified (save-buffer))))) + ;; Auto-answer org-noter's two interactive prompts: + ;; "What name do you want the notes to have?" -> notes-name (basename.org) + ;; "Where do you want to save it?" -> target (notes-dir/basename.org) + ;; org-noter will then create the heading with the correct NOTER_DOCUMENT itself. + (cl-letf* ((orig-cr (symbol-function 'completing-read)) + ((symbol-function 'completing-read) + (lambda (prompt collection &rest args) + (cond + ((string-match-p "name" prompt) notes-name) + ((string-match-p "save\\|where\\|Which" prompt) target) + (t (apply orig-cr prompt collection args)))))) + (with-selected-window pdf-win + (org-noter)))))) (map! :leader (:prefix ("o" . "open")