org-noter-nov.el 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. ;;; org-noter-nov.el --- Integration with Nov.el -*- lexical-binding: t; -*-
  2. ;; Copyright (C) 2022 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)
  19. (defun org-noter-get-buffer-file-name-nov ()
  20. (bound-and-true-p nov-file-name))
  21. (defun org-noter-nov-approx-location-cons (major-mode &optional precise-info _force-new-ref)
  22. (org-noter--with-valid-session
  23. (when (eq (org-noter--session-doc-mode session) 'nov-mode)
  24. (cons nov-documents-index (if (or (numberp precise-info)
  25. (and (consp precise-info)
  26. (numberp (car precise-info))
  27. (numberp (cdr precise-info))))
  28. precise-info
  29. (max 1 (/ (+ (window-start) (window-end nil t)) 2)))))))
  30. (add-to-list 'org-noter--doc-approx-location-hook #'org-noter-nov-approx-location-cons)
  31. (defun org-noter-nov-setup-handler (major-mode)
  32. (when (eq major-mode 'nov-mode)
  33. (advice-add 'nov-render-document :after 'org-noter--nov-scroll-handler)
  34. (add-hook 'window-scroll-functions 'org-noter--nov-scroll-handler nil t)
  35. t))
  36. (add-to-list 'org-noter-set-up-document-hook #'org-noter-nov-setup-handler)
  37. (defun org-noter-nov--pretty-print-location (location)
  38. (org-noter--with-valid-session
  39. (when (eq (org-noter--session-doc-mode session) 'nov-mode)
  40. (format "%s" (if (or (not (org-noter--get-location-top location)) (<= (org-noter--get-location-top location) 1))
  41. (org-noter--get-location-page location)
  42. location)))))
  43. (add-to-list 'org-noter--pretty-print-location-hook #'org-noter-nov--pretty-print-location)
  44. (defun org-noter-nov--get-precise-info (major-mode)
  45. (when (eq major-mode 'nov-mode)
  46. (if (region-active-p)
  47. (cons (mark) (point))
  48. (while (not (and (eq 'mouse-1 (car event))
  49. (eq window (posn-window (event-start event)))))
  50. (setq event (read-event "Click where you want the start of the note to be!")))
  51. (posn-point (event-start event)))))
  52. (add-to-list 'org-noter--get-precise-info-hook #'org-noter-nov--get-precise-info)
  53. (defun org-noter-nov-goto-location (mode location)
  54. (when (eq mode 'nov-mode)
  55. (setq nov-documents-index (org-noter--get-location-page location))
  56. (nov-render-document)
  57. (goto-char (org-noter--get-location-top location))
  58. ;; NOTE(nox): This needs to be here, because it would be issued anyway after
  59. ;; everything and would run org-noter--nov-scroll-handler.
  60. (recenter)))
  61. (add-to-list 'org-noter--doc-goto-location-hook #'org-noter-nov-goto-location)
  62. (defun org-noter-nov--get-current-view (mode)
  63. (when (eq mode 'nov-mode)
  64. (vector 'nov
  65. (org-noter-nov-approx-location-cons mode (window-start))
  66. (org-noter-nov-approx-location-cons mode (window-end nil t)))))
  67. (add-to-list 'org-noter--get-current-view-hook #'org-noter-nov--get-current-view)
  68. (defun org-noter-nov--get-selected-text (mode)
  69. (when (and (eq mode 'nov-mode) (region-active-p))
  70. (buffer-substring-no-properties (mark) (point))))
  71. (add-to-list 'org-noter-get-selected-text-hook #'org-noter-nov--get-selected-text)
  72. ;; Shamelessly stolen code from Yuchen Li.
  73. ;; This code is originally from org-noter-plus package.
  74. ;; At https://github.com/yuchen-lea/org-noter-plus
  75. (defun org-noter--handle-nov-toc-item (ol depth)
  76. (mapcar (lambda (li)
  77. (mapcar (lambda (a-or-ol)
  78. (pcase-exhaustive (dom-tag a-or-ol)
  79. ('a
  80. (vector :depth depth
  81. :title (dom-text a-or-ol)
  82. :href (esxml-node-attribute 'href a-or-ol)))
  83. ('ol
  84. (org-noter--handle-nov-toc-item a-or-ol
  85. (1+ depth)))))
  86. (dom-children li)))
  87. (dom-children ol)))
  88. (defun org-noter-create-skeleton-epub (mode)
  89. "Epub outline with nov link."
  90. (when (eq mode 'nov-mode)
  91. (require 'esxml)
  92. (require 'nov)
  93. (require 'dom)
  94. (org-noter--with-valid-session
  95. (let* ((ast (org-noter--parse-root))
  96. (top-level (or (org-element-property :level ast) 0))
  97. output-data)
  98. (with-current-buffer (org-noter--session-doc-buffer session)
  99. (let* ((toc-path (cdr (aref nov-documents 0)))
  100. (toc-tree (with-temp-buffer
  101. (insert (nov-ncx-to-html toc-path))
  102. (replace-regexp "\n"
  103. ""
  104. nil
  105. (point-min)
  106. (point-max))
  107. (libxml-parse-html-region (point-min)
  108. (point-max))))
  109. (origin-index nov-documents-index)
  110. (origin-point (point)))
  111. (dolist (item
  112. (nreverse (flatten-tree (org-noter--handle-nov-toc-item toc-tree 1))))
  113. (let ((relative-level (aref item 1))
  114. (title (aref item 3))
  115. (url (aref item 5)))
  116. (apply 'nov-visit-relative-file
  117. (nov-url-filename-and-target url))
  118. (when (not (integerp nov-documents-index))
  119. (setq nov-documents-index 0))
  120. (push (vector title (list nov-documents-index (point)) relative-level) output-data)))
  121. (push (vector "Skeleton" (list 0) 1) output-data)
  122. (nov-goto-document origin-index)
  123. (goto-char origin-point)))
  124. (save-excursion
  125. (goto-char (org-element-property :end ast))
  126. (with-current-buffer (org-noter--session-notes-buffer session)
  127. (dolist (data output-data)
  128. (setq title (aref data 0)
  129. location (aref data 1)
  130. relative-level (aref data 2))
  131. (setq last-absolute-level (+ top-level relative-level)
  132. level last-absolute-level)
  133. (org-noter--insert-heading level title)
  134. (when location
  135. (org-entry-put nil org-noter-property-note-location (org-noter--pretty-print-location location)))
  136. (when org-noter-doc-property-in-notes
  137. (org-entry-put nil org-noter-property-doc-file (org-noter--session-property-text session))
  138. (org-entry-put nil org-noter--property-auto-save-last-location "nil")))
  139. (setq ast (org-noter--parse-root))
  140. (org-noter--narrow-to-root ast)
  141. (goto-char (org-element-property :begin ast))
  142. (outline-hide-subtree)
  143. (org-show-children 2)))
  144. output-data))))
  145. (add-to-list 'org-noter-create-skeleton-functions #'org-noter-create-skeleton-epub)
  146. (provide 'org-noter-nov)
  147. ;;; org-noter-nov.el ends here