From 1feb3becc3e304f838e004f6376517bad4f52aea Mon Sep 17 00:00:00 2001
From: louie
Date: Sun, 3 Nov 2019 17:24:00 +0800
Subject: [PATCH] Reduce duplication in latex functions
---
anki-editor.el | 152 ++++++++++++++++++++-----------------------------
1 file changed, 62 insertions(+), 90 deletions(-)
diff --git a/anki-editor.el b/anki-editor.el
index 8035c9b..a5546e2 100644
--- a/anki-editor.el
+++ b/anki-editor.el
@@ -64,19 +64,6 @@
(require 'ox)
(require 'ox-html)
-(defconst anki-editor-prop-note-type "ANKI_NOTE_TYPE")
-(defconst anki-editor-prop-note-id "ANKI_NOTE_ID")
-(defconst anki-editor-prop-exporter "ANKI_EXPORTER")
-(defconst anki-editor-prop-deck "ANKI_DECK")
-(defconst anki-editor-prop-tags "ANKI_TAGS")
-(defconst anki-editor-prop-tags-plus (concat anki-editor-prop-tags "+"))
-(defconst anki-editor-prop-failure-reason "ANKI_FAILURE_REASON")
-(defconst anki-editor-buffer-html-output "*AnkiEditor HTML Output*")
-(defconst anki-editor-org-tag-regexp "^\\([[:alnum:]_@#%]+\\)+$")
-(defconst anki-editor-exporter-raw "raw")
-(defconst anki-editor-exporter-default "default")
-(defconst anki-editor-api-version 5)
-
(defgroup anki-editor nil
"Customizations for anki-editor."
:group 'org)
@@ -117,6 +104,8 @@ form entries."
;;; AnkiConnect
+(defconst anki-editor-api-version 5)
+
(cl-defun anki-editor--fetch (url
&rest settings
&key type data success error parser
@@ -246,95 +235,68 @@ The result is the path to the newly stored media file."
media-file-name))
-;;; Org Export Backend
+;;; Org export backend
(defconst anki-editor--ox-anki-html-backend
- (if anki-editor-use-math-jax
- (org-export-create-backend
- :parent 'html
- :transcoders '((latex-fragment . anki-editor--ox-latex-for-mathjax)
- (latex-environment . anki-editor--ox-latex-for-mathjax)))
- (org-export-create-backend
- :parent 'html
- :transcoders '((latex-fragment . anki-editor--ox-latex)
- (latex-environment . anki-editor--ox-latex)))))
+ (org-export-create-backend
+ :parent 'html
+ :transcoders '((latex-fragment . anki-editor--ox-latex)
+ (latex-environment . anki-editor--ox-latex))))
(defconst anki-editor--ox-export-ext-plist
'(:with-toc nil :anki-editor-mode t))
-(defun anki-editor--translate-latex-delimiters (latex-code)
- (catch 'done
- (let ((delimiter-map (list (list (cons (format "^%s" (regexp-quote "$$")) "[$$]")
- (cons (format "%s$" (regexp-quote "$$")) "[/$$]"))
- (list (cons (format "^%s" (regexp-quote "$")) "[$]")
- (cons (format "%s$" (regexp-quote "$")) "[/$]"))
- (list (cons (format "^%s" (regexp-quote "\\(")) "[$]")
- (cons (format "%s$" (regexp-quote "\\)")) "[/$]"))
- (list (cons (format "^%s" (regexp-quote "\\[")) "[$$]")
- (cons (format "%s$" (regexp-quote "\\]")) "[/$$]"))))
- (matched nil))
- (save-match-data
- (dolist (pair delimiter-map)
- (dolist (delimiter pair)
- (when (setq matched (string-match (car delimiter) latex-code))
- (setq latex-code (replace-match (cdr delimiter) t t latex-code))))
- (when matched (throw 'done latex-code)))))
- latex-code))
+(cl-macrolet ((with-table (table)
+ `(cl-loop for delims in ,table
+ collect
+ (list (concat "^" (regexp-quote (cl-first delims)))
+ (cl-second delims)
+ (concat (regexp-quote (cl-third delims)) "$")
+ (cl-fourth delims)))))
-(defun anki-editor--translate-latex-delimiters-to-anki-mathjax-delimiters (latex-code)
- (catch 'done
- (let ((delimiter-map (list (list (cons (format "^%s" (regexp-quote "$$")) "\\[")
- (cons (format "%s$" (regexp-quote "$$")) "\\]"))
- (list (cons (format "^%s" (regexp-quote "$")) "\\(")
- (cons (format "%s$" (regexp-quote "$")) "\\)"))))
- (matched nil))
- (save-match-data
- (dolist (pair delimiter-map)
- (dolist (delimiter pair)
- (when (setq matched (string-match (car delimiter) latex-code))
- (setq latex-code (replace-match (cdr delimiter) t t latex-code))))
- (when matched (throw 'done latex-code)))))
- latex-code))
+ (defconst anki-editor--native-latex-delimiters
+ (with-table '(("$$" "[$$]"
+ "$$" "[/$$]")
+ ("$" "[$]"
+ "$" "[/$]")
+ ("\\(" "[$]"
+ "\\)" "[/$]")
+ ("\\[" "[$$]"
+ "\\]" "[/$$]"))))
-(defun anki-editor--wrap-latex (content)
- "Wrap CONTENT with Anki-style latex markers."
- (format "[latex]
%s[/latex]
" content))
+ (defconst anki-editor--mathjax-delimiters
+ (with-table '(("$$" "\\["
+ "$$" "\\]")
+ ("$" "\\("
+ "$" "\\)")))))
-(defun anki-editor--wrap-latex-for-mathjax (content)
- "Wrap CONTENT for Anki's native MathJax support."
- (format "%s
" content))
+(defun anki-editor--translate-latex-fragment (latex-code)
+ (let ((table (if anki-editor-use-math-jax
+ anki-editor--mathjax-delimiters
+ anki-editor--native-latex-delimiters)))
+ (cl-loop for delims in table
+ for matches = (string-match (cl-first delims) latex-code)
+ when matches
+ do
+ (setq latex-code (replace-match (cl-second delims) t t latex-code))
+ (string-match (cl-third delims) latex-code)
+ (setq latex-code (replace-match (cl-fourth delims) t t latex-code))
+ until matches
+ finally return latex-code)))
-(defun anki-editor--wrap-div (content)
- (format "%s
" content))
+(defun anki-editor--translate-latex-env (latex-code)
+ (setq latex-code (replace-regexp-in-string "\n" "
" (org-html-encode-plain-text latex-code)))
+ (if anki-editor-use-math-jax
+ (concat "\\[
" latex-code "\\]")
+ (concat "[latex]
" latex-code "[/latex]")))
(defun anki-editor--ox-latex (latex _contents _info)
"Transcode LATEX from Org to HTML.
CONTENTS is nil. INFO is a plist holding contextual information."
(let ((code (org-remove-indentation (org-element-property :value latex))))
- (setq code
- (pcase (org-element-type latex)
- ('latex-fragment (anki-editor--translate-latex-delimiters code))
- ('latex-environment (anki-editor--wrap-latex
- (mapconcat #'anki-editor--wrap-div
- (split-string (org-html-encode-plain-text code) "\n")
- "")))))
-
- (if anki-editor-break-consecutive-braces-in-latex
- (replace-regexp-in-string "}}" "} } " code)
- code)))
-
-(defun anki-editor--ox-latex-for-mathjax (latex _contents _info)
- "Transcode LATEX from Org to HTML.
-CONTENTS is nil. INFO is a plist holding contextual information."
- (let ((code (org-remove-indentation (org-element-property :value latex))))
- (setq code
- (pcase (org-element-type latex)
- ('latex-fragment (anki-editor--translate-latex-delimiters-to-anki-mathjax-delimiters code))
- ('latex-environment (anki-editor--wrap-latex-for-mathjax
- (mapconcat #'anki-editor--wrap-div
- (split-string (org-html-encode-plain-text code) "\n")
- "")))))
-
+ (setq code (cl-ecase (org-element-type latex)
+ (latex-fragment (anki-editor--translate-latex-fragment code))
+ (latex-environment (anki-editor--translate-latex-env code))))
(if anki-editor-break-consecutive-braces-in-latex
(replace-regexp-in-string "}}" "} } " code)
code)))
@@ -342,7 +304,6 @@ CONTENTS is nil. INFO is a plist holding contextual information."
(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
(unless (plist-get info :anki-editor-mode)
(throw 'giveup nil))
@@ -405,7 +366,18 @@ The implementation is borrowed and simplified from ox-html."
(funcall oldfun link desc info)))
-;;; Core Functions
+;;; Core primitives
+
+(defconst anki-editor-prop-note-type "ANKI_NOTE_TYPE")
+(defconst anki-editor-prop-note-id "ANKI_NOTE_ID")
+(defconst anki-editor-prop-exporter "ANKI_EXPORTER")
+(defconst anki-editor-prop-deck "ANKI_DECK")
+(defconst anki-editor-prop-tags "ANKI_TAGS")
+(defconst anki-editor-prop-tags-plus (concat anki-editor-prop-tags "+"))
+(defconst anki-editor-prop-failure-reason "ANKI_FAILURE_REASON")
+(defconst anki-editor-org-tag-regexp "^\\([[:alnum:]_@#%]+\\)+$")
+(defconst anki-editor-exporter-raw "raw")
+(defconst anki-editor-exporter-default "default")
(cl-defstruct anki-editor-note
id model deck fields tags)
@@ -812,7 +784,7 @@ same as how it is used by `M-RET'(org-insert-heading)."
(interactive)
(org-export-to-buffer
anki-editor--ox-anki-html-backend
- anki-editor-buffer-html-output nil t nil t anki-editor--ox-export-ext-plist #'html-mode))
+ "*AnkiEditor HTML Output*" nil t nil t anki-editor--ox-export-ext-plist #'html-mode))
(defun anki-editor-convert-region-to-html ()
"Convert and replace region to HTML."