diff --git a/anki-editor.el b/anki-editor.el index 608d2ba..97837c4 100644 --- a/anki-editor.el +++ b/anki-editor.el @@ -64,6 +64,7 @@ (require 'json) (require 'org-element) (require 'ox) +(require 'ox-html) (require 'request) (defconst anki-editor-prop-note-type "ANKI_NOTE_TYPE") @@ -196,14 +197,16 @@ The result is the path to the newly stored media file." (defun anki-editor-setup-minor-mode () "Set up this minor mode." (add-hook 'org-property-allowed-value-functions #'anki-editor--get-allowed-values-for-property) - (advice-add 'org-set-tags :before #'anki-editor--before-set-tags)) + (advice-add 'org-set-tags :before #'anki-editor--before-set-tags) + (advice-add 'org-html-link :around #'anki-editor--ox-html-link)) (defun anki-editor-teardown-minor-mode () "Tear down this minor mode." (remove-hook 'org-property-allowed-value-functions #'anki-editor--get-allowed-values-for-property) (advice-remove 'org-set-tags #'anki-editor--before-set-tags) (when (advice-member-p 'anki-editor--get-buffer-tags #'org-get-buffer-tags) - (advice-remove 'org-get-buffer-tags #'anki-editor--get-buffer-tags))) + (advice-remove 'org-get-buffer-tags #'anki-editor--get-buffer-tags)) + (advice-remove 'org-html-link #'anki-editor--ox-html-link)) ;;; Commands @@ -527,8 +530,7 @@ Do nothing when JUST-ALIGN is non-nil." (org-export-create-backend :parent 'html :transcoders '((latex-fragment . anki-editor--ox-latex) - (latex-environment . anki-editor--ox-latex) - (link . anki-editor--ox-link)))) + (latex-environment . anki-editor--ox-latex)))) (defconst anki-editor--anki-latex-syntax-map `((,(format "^%s" (regexp-quote "$$")) . "[$$]") @@ -564,145 +566,63 @@ CONTENTS is nil. INFO is a plist holding contextual information." (replace-regexp-in-string "}}" "} } " code) code))) -;; FIXME: since some functions get added and some get removed in -;; differenct versions of Org, this is going to break -(defun anki-editor--ox-link (link desc info) - "Transcode a LINK object from Org to HTML. -DESC is the description part of the link, or the empty string. -INFO is a plist holding contextual information. THE -IMPLEMENTATION IS BASICALLY COPIED AND SIMPLIFIED FROM -ox-html.el :)" - (let* ((type (org-element-property :type link)) - (raw-path (org-element-property :path link)) - ;; Ensure DESC really exists, or set it to nil. - (desc (org-string-nw-p desc)) - (path +(defun anki-editor--ox-html-link (oldfun link desc info) + "When LINK is a link to local file, transcodes it to html and stores the target file to Anki, otherwise calls OLDFUN for help. +The implementation is borrowed and simplified from ox-html." + (or (catch 'giveup + (let* ((type (org-element-property :type link)) + (raw-path (org-element-property :path link)) + (desc (org-string-nw-p desc)) + (path + (cond + ((string= type "file") + ;; Possibly append `:html-link-home' to relative file + ;; name. + (let ((inhibit-message nil) + (home (and (plist-get info :html-link-home) + (org-trim (plist-get info :html-link-home))))) + (when (and home + (plist-get info :html-link-use-abs-url) + (file-name-absolute-p raw-path)) + (setq raw-path (concat (file-name-as-directory home) raw-path))) + (message "Storing media file to Anki for %s..." raw-path) + ;; storing file to Anki and return the modified path + (anki-editor--anki-connect-store-media-file (expand-file-name (url-unhex-string raw-path))))) + (t (throw 'giveup nil)))) + (attributes-plist + (let* ((parent (org-export-get-parent-element link)) + (link (let ((container (org-export-get-parent link))) + (if (and (eq (org-element-type container) 'link) + (org-html-inline-image-p link info)) + container + link)))) + (and (eq (org-element-map parent 'link 'identity info t) link) + (org-export-read-attribute :attr_html parent)))) + (attributes + (let ((attr (org-html--make-attribute-string attributes-plist))) + (if (org-string-nw-p attr) (concat " " attr) "")))) (cond - ((member type '("http" "https" "ftp" "mailto" "news")) - (url-encode-url (org-link-unescape (concat type ":" raw-path)))) - ((string= type "file") - ;; Possibly append `:html-link-home' to relative file - ;; name. - (let ((home (and (plist-get info :html-link-home) - (org-trim (plist-get info :html-link-home))))) - (when (and home - (plist-get info :html-link-use-abs-url) - (file-name-absolute-p raw-path)) - (setq raw-path (concat (file-name-as-directory home) raw-path))) - (message "Storing media file to Anki for %s..." raw-path) - (anki-editor--anki-connect-store-media-file (expand-file-name (url-unhex-string raw-path))))) - (t raw-path))) - ;; Extract attributes from parent's paragraph. HACK: Only do - ;; this for the first link in parent (inner image link for - ;; inline images). This is needed as long as attributes - ;; cannot be set on a per link basis. - (attributes-plist - (let* ((parent (org-export-get-parent-element link)) - (link (let ((container (org-export-get-parent link))) - (if (and (eq (org-element-type container) 'link) - (org-html-inline-image-p link info)) - container - link)))) - (and (eq (org-element-map parent 'link 'identity info t) link) - (org-export-read-attribute :attr_html parent)))) - (attributes - (let ((attr (org-html--make-attribute-string attributes-plist))) - (if (org-string-nw-p attr) (concat " " attr) "")))) - (cond - ;; Image file. - ((and (plist-get info :html-inline-images) - (org-export-inline-image-p - link (plist-get info :html-inline-image-rules))) - (org-html--format-image path attributes-plist info)) - ;; Radio target: Transcode target's contents and use them as - ;; link's description. - ((string= type "radio") - (let ((destination (org-export-resolve-radio-link link info))) - (if (not destination) desc - (format "%s" - (org-export-get-reference destination info) - attributes - desc)))) - ;; Links pointing to a headline: Find destination and build - ;; appropriate referencing command. - ((member type '("custom-id" "fuzzy" "id")) - (let ((destination (if (string= type "fuzzy") - (org-export-resolve-fuzzy-link link info) - (org-export-resolve-id-link link info)))) - (pcase (org-element-type destination) - ;; ID link points to an external file. - (`plain-text - (let ((fragment (concat "ID-" path))) - (format "%s" - destination fragment attributes (or desc destination)))) - ;; Fuzzy link points nowhere. - (`nil - (format "%s" - (or desc - (org-export-data - (org-element-property :raw-link link) info)))) - ;; Link points to a headline. - (`headline - (let ((href (or (org-element-property :CUSTOM_ID destination) - (org-export-get-reference destination info))) - ;; What description to use? - (desc - ;; Case 1: Headline is numbered and LINK has no - ;; description. Display section number. - (if (and (org-export-numbered-headline-p destination info) - (not desc)) - (mapconcat #'number-to-string - (org-export-get-headline-number - destination info) ".") - ;; Case 2: Either the headline is un-numbered or - ;; LINK has a custom description. Display LINK's - ;; description or headline's title. - (or desc - (org-export-data - (org-element-property :title destination) info))))) - (format "%s" href attributes desc))) - ;; Fuzzy link points to a target or an element. - (_ - (let* ((ref (org-export-get-reference destination info)) - (number (cond - (desc nil) - ((org-html-standalone-image-p destination info) - (org-export-get-ordinal - (org-element-map destination 'link - #'identity info t) - info 'link 'org-html-standalone-image-p)) - (t (org-export-get-ordinal - destination info nil 'org-html--has-caption-p)))) - (desc (cond (desc) - ((not number) "No description for this link") - ((numberp number) (number-to-string number)) - (t (mapconcat #'number-to-string number "."))))) - (format "%s" ref attributes desc)))))) - ;; Coderef: replace link with the reference name or the - ;; equivalent line number. - ((string= type "coderef") - (let ((fragment (concat "coderef-" (org-html-encode-plain-text path)))) - (format "%s" - fragment - (format "class=\"coderef\" onmouseover=\"CodeHighlightOn(this, \ -'%s');\" onmouseout=\"CodeHighlightOff(this, '%s');\"" - fragment fragment) - attributes - (format (org-export-get-coderef-format path desc) - (org-export-resolve-coderef path info))))) - ;; External link with a description part. - ((and path desc) (format "%s" - (org-html-encode-plain-text path) - attributes - desc)) - ;; External link without a description part. - (path (let ((path (org-html-encode-plain-text path))) - (format "%s" - path - attributes - (org-link-unescape path)))) - ;; No path, only description. Try to do something useful. - (t (format "%s" desc))))) + ;; Image file. + ((and (plist-get info :html-inline-images) + (org-export-inline-image-p + link (plist-get info :html-inline-image-rules))) + (org-html--format-image path attributes-plist info)) + + ;; External link with a description part. + ((and path desc) (format "%s" + (org-html-encode-plain-text path) + attributes + desc)) + + ;; External link without a description part. + (path (let ((path (org-html-encode-plain-text path))) + (format "%s" + path + attributes + (org-link-unescape path)))) + + (t (throw 'giveup nil))))) + (funcall oldfun link desc info))) ;;; Utilities