org-noter-dynamic-block.el 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. ;;; org-noter-dynamic-block.el --- Use special blocks as notes -*- lexical-binding: t; -*-
  2. ;; Copyright (C) 2021 c1-g
  3. ;; Author: c1-g <char1iegordon@protonmail.com>
  4. ;; Keywords: multimedia
  5. ;; This program is free software; you can redistribute it and/or modify
  6. ;; it under the terms of the GNU General Public License as published by
  7. ;; the Free Software Foundation, either version 3 of the License, or
  8. ;; (at your option) any later version.
  9. ;; This program is distributed in the hope that it will be useful,
  10. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. ;; GNU General Public License for more details.
  13. ;; You should have received a copy of the GNU General Public License
  14. ;; along with this program. If not, see <https://www.gnu.org/licenses/>.
  15. ;;; Commentary:
  16. ;;
  17. ;;; Code:
  18. (require 'org-noter-core)
  19. (defun org-noter-insert-precise-dynamic-block (&optional toggle-no-questions)
  20. "Insert note associated with a specific location.
  21. This will ask you to click where you want to scroll to when you
  22. sync the document to this note. You should click on the top of
  23. that part. Will always create a new note.
  24. When text is selected, it will automatically choose the top of
  25. the selected text as the location and the text itself as the
  26. title of the note (you may change it anyway!).
  27. See `org-noter-insert-note' docstring for more."
  28. (interactive "P")
  29. (org-noter--with-valid-session
  30. (let ((org-noter-insert-note-no-questions (if toggle-no-questions
  31. (not org-noter-insert-note-no-questions)
  32. org-noter-insert-note-no-questions)))
  33. (org-noter-insert-dynamic-block (org-noter--get-precise-info)))))
  34. (defun org-noter-insert-dynamic-block (&optional precise-info)
  35. "Insert note associated with the current location.
  36. This command will prompt for a title of the note and then insert
  37. it in the notes buffer. When the input is empty, a title based on
  38. `org-noter-default-heading-title' will be generated.
  39. If there are other notes related to the current location, the
  40. prompt will also suggest them. Depending on the value of the
  41. variable `org-noter-closest-tipping-point', it may also
  42. suggest the closest previous note.
  43. PRECISE-INFO makes the new note associated with a more
  44. specific location (see `org-noter-insert-precise-note' for more
  45. info).
  46. When you insert into an existing note and have text selected on
  47. the document buffer, the variable `org-noter-insert-selected-text-inside-note'
  48. defines if the text should be inserted inside the note."
  49. (interactive)
  50. (org-noter--with-valid-session
  51. (let* ((ast (org-noter--parse-root))
  52. (contents (org-element-contents ast))
  53. (window (org-noter--get-notes-window 'force))
  54. (selected-text
  55. (pcase (org-noter--session-doc-mode session)
  56. ('pdf-view-mode
  57. (when (pdf-view-active-region-p)
  58. (mapconcat 'identity (pdf-view-active-region-text) ? )))
  59. ((or 'nov-mode 'djvu-read-mode)
  60. (when (region-active-p)
  61. (buffer-substring-no-properties (mark) (point))))))
  62. force-new
  63. (location (org-noter--doc-approx-location (or precise-info 'interactive) (gv-ref force-new)))
  64. (view-info (org-noter--get-view-info (org-noter--get-current-view) location)))
  65. (let ((inhibit-quit t))
  66. (with-local-quit
  67. (select-frame-set-input-focus (window-frame window))
  68. (select-window window)
  69. ;; IMPORTANT(nox): Need to be careful changing the next part, it is a bit
  70. ;; complicated to get it right...
  71. (let ((point (point))
  72. (minibuffer-local-completion-map org-noter--completing-read-keymap)
  73. collection default default-begin title
  74. (empty-lines-number (if org-noter-separate-notes-from-heading 2 1)))
  75. (cond
  76. ;; NOTE(nox): Both precise and without questions will create new notes
  77. ((or precise-info force-new)
  78. (setq default (and selected-text (replace-regexp-in-string "\n" " " selected-text))))
  79. (org-noter-insert-note-no-questions)
  80. (t
  81. (dolist (note-cons (org-noter--view-info-notes view-info))
  82. (let ((display (org-element-property :raw-value (car note-cons)))
  83. (begin (org-element-property :begin (car note-cons))))
  84. (push (cons display note-cons) collection)
  85. (when (and (>= point begin) (> begin (or default-begin 0)))
  86. (setq default display
  87. default-begin begin))))))
  88. ;; NOTE(nox): Inserting a new note
  89. (let ((reference-element-cons (org-noter--view-info-reference-for-insertion view-info))
  90. level)
  91. (if reference-element-cons
  92. (progn
  93. (cond
  94. ((eq (car reference-element-cons) 'before)
  95. (goto-char (org-element-property :begin (cdr reference-element-cons))))
  96. ((eq (car reference-element-cons) 'after)
  97. (goto-char (org-element-property :end (cdr reference-element-cons)))))
  98. ;; NOTE(nox): This is here to make the automatic "should insert blank" work better.
  99. (when (org-at-heading-p) (backward-char))
  100. (setq level (org-element-property :level (cdr reference-element-cons))))
  101. (goto-char (or (org-element-map contents 'section
  102. (lambda (section) (org-element-property :end section))
  103. nil t org-element-all-elements)
  104. (org-element-map ast 'section
  105. (lambda (section) (org-element-property :end section))
  106. nil t org-element-all-elements))))
  107. ;; (setq level (1+ (or (org-element-property :level ast) 0))))
  108. ;; NOTE(nox): This is needed to insert in the right place
  109. (unless (org-noter--no-heading-p) (outline-show-entry))
  110. ;; (org-noter--insert-heading level title empty-lines-number location)
  111. (insert
  112. "\n"
  113. (string-join (list (format "#+BEGIN: note %s"
  114. (if location
  115. (concat ":" org-noter-property-note-location
  116. (format " %S" location))
  117. ""))
  118. (or selected-text "")
  119. "#+END:")
  120. "\n")
  121. "\n")
  122. (when (org-noter--session-hide-other session) (org-overview))
  123. (setf (org-noter--session-num-notes-in-view session)
  124. (1+ (org-noter--session-num-notes-in-view session)))))
  125. (org-show-set-visibility t)
  126. (org-cycle-hide-drawers 'all)
  127. (org-cycle-show-empty-lines t)))
  128. (when quit-flag
  129. ;; NOTE(nox): If this runs, it means the user quitted while creating a note, so
  130. ;; revert to the previous window.
  131. (select-frame-set-input-focus (org-noter--session-frame session))
  132. (select-window (get-buffer-window (org-noter--session-doc-buffer session)))))))
  133. (defun org-dblock-write:note (params)
  134. (let ((location (plist-get params
  135. (intern (concat ":" org-noter-property-note-location))))
  136. (content (plist-get params :content))
  137. (session org-noter--session)
  138. (origin-window (selected-window))
  139. (origin-location))
  140. (org-noter--with-valid-session
  141. (setq origin-location (org-noter--doc-approx-location))
  142. (when (and location
  143. (org-noter--get-location-top location)
  144. (org-noter--get-location-left location))
  145. (org-noter--doc-goto-location location)
  146. (with-current-buffer (org-noter--session-doc-buffer session)
  147. (setq content
  148. (pcase major-mode
  149. ('pdf-view-mode (pdf-info-gettext (car location) (cdr location)))
  150. ((or 'nov-mode 'djvu-read-mode)
  151. (buffer-substring (org-noter--get-location-top location)
  152. (org-noter--get-location-left location))))))
  153. (org-noter--doc-goto-location origin-location)
  154. (select-window origin-window)))
  155. (insert content)))
  156. (defun org-noter--get-location-dynamic-block (dblock)
  157. (let ((params (read (concat "(" (org-element-property :arguments dblock) ")"))))
  158. (format "%S" (plist-get params (intern (concat ":" org-noter-property-note-location))))))
  159. (defun org-noter-get-containing-dynamic-block (&optional _include-root)
  160. (org-noter--with-valid-session
  161. (org-with-wide-buffer
  162. (let ((elt (org-element-at-point)))
  163. (catch 'break
  164. (while (org-element-property :parent elt)
  165. (cond
  166. ((eq (org-element-type elt) 'dynamic-block)
  167. (throw 'break elt))
  168. (t
  169. (setq elt (org-element-property :parent elt))))))))))
  170. (add-hook 'org-noter--get-containing-element-hook #'org-noter-get-containing-dynamic-block)
  171. (add-hook 'org-noter--get-location-property-hook #'org-noter--get-location-dynamic-block)
  172. (provide 'org-noter-dynamic-block)
  173. ;;; org-noter-dynamic-block.el ends here