443 lines
21 KiB
EmacsLisp
443 lines
21 KiB
EmacsLisp
|
;;; ox-hugo-deprecated.el --- Deprecated stuff from ox-hugo -*- lexical-binding: t -*-
|
|||
|
|
|||
|
;; Authors: Kaushal Modi <kaushal.modi@gmail.com>
|
|||
|
;; URL: https://ox-hugo.scripter.co
|
|||
|
|
|||
|
;;; Commentary:
|
|||
|
|
|||
|
;; This file contains variables and functions deprecated from ox-hugo.
|
|||
|
;; Do not depend on this file as it may disappear any day.
|
|||
|
|
|||
|
|
|||
|
;;; Obsoletions
|
|||
|
|
|||
|
;; Blackfriday support is being removed from `ox-hugo' as Hugo has
|
|||
|
;; deprecated its support for a while.
|
|||
|
;; https://github.com/kaushalmodi/ox-hugo/discussions/485
|
|||
|
|
|||
|
;;; Code:
|
|||
|
|
|||
|
;; Silence byte-compiler
|
|||
|
(defvar org-hugo--date-time-regexp)
|
|||
|
(defvar org-hugo--subtree-coord)
|
|||
|
(declare-function org-string-nw-p "org-macs")
|
|||
|
(declare-function org-hugo--calc-weight "ox-hugo")
|
|||
|
(declare-function org-hugo-slug "ox-hugo")
|
|||
|
(declare-function org-hugo--front-matter-value-booleanize "ox-hugo")
|
|||
|
(declare-function org-hugo--delim-str-to-list "ox-hugo")
|
|||
|
(declare-function org-hugo--parse-property-arguments "ox-hugo")
|
|||
|
;;
|
|||
|
|
|||
|
(make-obsolete-variable 'org-hugo-blackfriday-options nil "Hugo has switched to use Goldmark as the default Markdown parser since v0.60." "Jan 15, 2022")
|
|||
|
(make-obsolete-variable 'org-hugo-blackfriday-extensions nil "Hugo has switched to use Goldmark as the default Markdown parser since v0.60." "Jan 15, 2022")
|
|||
|
|
|||
|
|
|||
|
;;; Variables
|
|||
|
|
|||
|
(defvar org-hugo-blackfriday-options
|
|||
|
'("taskLists"
|
|||
|
"smartypants"
|
|||
|
"smartypantsQuotesNBSP"
|
|||
|
"angledQuotes"
|
|||
|
"fractions"
|
|||
|
"smartDashes"
|
|||
|
"latexDashes"
|
|||
|
"hrefTargetBlank"
|
|||
|
"plainIDAnchors"
|
|||
|
"extensions"
|
|||
|
"extensionsmask")
|
|||
|
"Deprecated Blackfriday parser option names.")
|
|||
|
|
|||
|
(defvar org-hugo-blackfriday-extensions
|
|||
|
'("noIntraEmphasis"
|
|||
|
"tables"
|
|||
|
"fencedCode"
|
|||
|
"autolink"
|
|||
|
"strikethrough"
|
|||
|
"laxHtmlBlocks"
|
|||
|
"spaceHeaders"
|
|||
|
"hardLineBreak"
|
|||
|
"tabSizeEight"
|
|||
|
"footnotes"
|
|||
|
"noEmptyLineBeforeBlock"
|
|||
|
"headerIds"
|
|||
|
"titleblock"
|
|||
|
"autoHeaderIds"
|
|||
|
"backslashLineBreak"
|
|||
|
"definitionLists"
|
|||
|
"joinLines")
|
|||
|
"Deprecated Blackfriday extension names.")
|
|||
|
|
|||
|
|
|||
|
|
|||
|
;;; Functions
|
|||
|
|
|||
|
(defun org-hugo--parse-blackfriday-prop-to-alist (str)
|
|||
|
"Return an alist of valid Hugo blackfriday properties converted from STR.
|
|||
|
|
|||
|
For example, input STR:
|
|||
|
|
|||
|
\":fractions :smartdashes nil :angledquotes t\"
|
|||
|
|
|||
|
would convert to:
|
|||
|
|
|||
|
((fractions . \"false\") (smartDashes . \"false\") (angledQuotes . \"true\"))
|
|||
|
|
|||
|
The \"true\" and \"false\" strings in the return value are due to
|
|||
|
`org-hugo--front-matter-value-booleanize'."
|
|||
|
(let ((blackfriday-alist (org-hugo--parse-property-arguments str))
|
|||
|
valid-blackfriday-alist)
|
|||
|
(dolist (ref-prop org-hugo-blackfriday-options)
|
|||
|
(dolist (user-prop blackfriday-alist)
|
|||
|
(when (string= (downcase (symbol-name (car user-prop)))
|
|||
|
(downcase ref-prop))
|
|||
|
(let* ((key (intern ref-prop))
|
|||
|
(value (cdr user-prop))
|
|||
|
(value (if (or (equal key 'extensions)
|
|||
|
(equal key 'extensionsmask))
|
|||
|
(org-hugo--delim-str-to-list value)
|
|||
|
(org-hugo--front-matter-value-booleanize value))))
|
|||
|
(push (cons key value)
|
|||
|
valid-blackfriday-alist)))))
|
|||
|
valid-blackfriday-alist))
|
|||
|
|
|||
|
(defun org-hugo--return-valid-blackfriday-extension (ext)
|
|||
|
"Return valid case-sensitive string for Blackfriday extension EXT.
|
|||
|
|
|||
|
Example: If EXT is \"hardlinebreak\",
|
|||
|
\"\"hardLineBreak\"\" (quoted string) is returned."
|
|||
|
(let (ret)
|
|||
|
(dolist (ref-ext org-hugo-blackfriday-extensions)
|
|||
|
;; (message "ox-hugo bf valid ext DBG: ext=%s ref-ext=%s" ext ref-ext)
|
|||
|
(when (string= (downcase ext) (downcase ref-ext))
|
|||
|
(setq ret ref-ext)))
|
|||
|
(unless ret
|
|||
|
(user-error "Invalid Blackfriday extension name %S, see `org-hugo-blackfriday-extensions'"
|
|||
|
ext))
|
|||
|
(org-hugo--yaml-quote-string ret)))
|
|||
|
|
|||
|
;;; YAML Support
|
|||
|
(defun org-hugo--yaml-quote-string (val &optional prefer-no-quotes)
|
|||
|
"Wrap VAL with quotes as appropriate.
|
|||
|
|
|||
|
VAL can be a string, symbol, number or nil.
|
|||
|
|
|||
|
VAL is returned as-it-is under the following cases:
|
|||
|
- It is a number.
|
|||
|
- It is a string and is already wrapped with double quotes.
|
|||
|
- It is a string and it's value is \"true\" or \"false\".
|
|||
|
- It is a string representing a date.
|
|||
|
- It is a string representing an integer or float.
|
|||
|
|
|||
|
If VAL is nil or an empty string, a quoted empty string \"\" is
|
|||
|
returned.
|
|||
|
|
|||
|
If optional argument PREFER-NO-QUOTES is non-nil, return the VAL
|
|||
|
as-it-is if it's a string with just alphanumeric characters."
|
|||
|
(cond
|
|||
|
((null val) ;nil
|
|||
|
val)
|
|||
|
((numberp val)
|
|||
|
val)
|
|||
|
((symbolp val)
|
|||
|
(format "\"%s\"" (symbol-name val)))
|
|||
|
((stringp val)
|
|||
|
(cond
|
|||
|
((org-string-nw-p val) ;If `val' is a non-empty string
|
|||
|
(cond
|
|||
|
((or (and (string= (substring val 0 1) "\"") ;First char is literally a "
|
|||
|
(string= (substring val -1) "\"")) ;Last char is literally a "
|
|||
|
(and prefer-no-quotes ;If quotes are not preferred and `val' is only alpha-numeric
|
|||
|
(string-match-p "\\`[a-zA-Z0-9]+\\'" val))
|
|||
|
;; or if it an integer that can be stored in the system as
|
|||
|
;; a fixnum. For example, if `val' is
|
|||
|
;; "10040216507682529280" that needs more than 64 bits to
|
|||
|
;; be stored as a signed integer, it will be automatically
|
|||
|
;; stored as a float. So (integerp (string-to-number
|
|||
|
;; val)) will return nil [or `fixnump' instead of
|
|||
|
;; `integerp' in Emacs 27 or newer]
|
|||
|
;; https://github.com/toml-lang/toml#integer Integer
|
|||
|
;; examples: 7, +7, -7, 7_000
|
|||
|
(and (string-match-p "\\`[+-]?[[:digit:]_]+\\'" val)
|
|||
|
(if (functionp #'fixnump) ;`fixnump' and `bignump' get introduced in Emacs 27.x
|
|||
|
(fixnump (string-to-number val))
|
|||
|
(integerp (string-to-number val)))) ;On older Emacsen, `integerp' behaved the same as the new `fixnump'
|
|||
|
(string= "true" val)
|
|||
|
(string= "false" val)
|
|||
|
;; or if it is a date (date, publishDate, expiryDate, lastmod)
|
|||
|
(string-match-p org-hugo--date-time-regexp val)
|
|||
|
;; or if it is a float
|
|||
|
;; https://github.com/toml-lang/toml#float
|
|||
|
;; Float examples (decimals): 7.8, +7.8, -7.8
|
|||
|
(string-match-p "\\`[+-]?[[:digit:]_]+\\.[[:digit:]_]+\\'" val)
|
|||
|
;; Float examples (exponentials): 7e-8, -7E+8, 1.7e-05
|
|||
|
(string-match-p "\\`[+-]?[[:digit:]_]+\\(\\.[[:digit:]_]+\\)*[eE][+-]?[[:digit:]_]+\\'" val)
|
|||
|
;; Special float values (infinity/NaN)
|
|||
|
;; Looks like Hugo is not supporting these.. Tue Mar 20 18:05:40 EDT 2018 - kmodi
|
|||
|
;; (let ((case-fold-search nil))
|
|||
|
;; (string-match-p "\\`[+-]?\\(inf\\|nan\\)\\'" val))
|
|||
|
)
|
|||
|
val)
|
|||
|
((string-match-p "\n" val) ;Multi-line string
|
|||
|
;; The indentation of the multi-line string is needed only for the
|
|||
|
;; YAML format. But the same is done for TOML too just for better
|
|||
|
;; presentation.
|
|||
|
(setq val (replace-regexp-in-string "^" " " val))
|
|||
|
|
|||
|
;; https://yaml-multiline.info/
|
|||
|
;;
|
|||
|
;; | |foo : >
|
|||
|
;; |abc | abc
|
|||
|
;; | >>> |
|
|||
|
;; |def |
|
|||
|
;; | | def
|
|||
|
;;
|
|||
|
;; In Org, a single blank line is used to start a new
|
|||
|
;; paragraph. In the YAML multi-line string, that needs to
|
|||
|
;; be 2 blank lines.
|
|||
|
(setq val (replace-regexp-in-string "\n[[:blank:]]*\n" "\n\n\n" val))
|
|||
|
(format ">\n%s" val))
|
|||
|
(t ;Single-line string
|
|||
|
;; Below 2 replacements are order-dependent.. first escape the
|
|||
|
;; backslashes, then escape the quotes with backslashes.
|
|||
|
|
|||
|
;; Escape the backslashes (for both TOML and YAML).
|
|||
|
(setq val (replace-regexp-in-string "\\\\" "\\\\\\\\" val))
|
|||
|
;; Escape the double-quotes.
|
|||
|
(setq val (replace-regexp-in-string "\"" "\\\\\"" val))
|
|||
|
(concat "\"" val "\""))))
|
|||
|
(t ;If `val' is any empty string
|
|||
|
"\"\"")))
|
|||
|
(t ;Return empty string if anything else
|
|||
|
"\"\"")))
|
|||
|
|
|||
|
(defun org-hugo--get-yaml-list-string (key list)
|
|||
|
"Return KEY's LIST value as a YAML list, represented as a string.
|
|||
|
|
|||
|
KEY is a string and LIST is a list where an element can be a
|
|||
|
symbol, number or a non-empty string. Examples:
|
|||
|
|
|||
|
\(\"abc\" \"def\") -> \"[\\\"abc\\\", \\\"def\\\"]\"."
|
|||
|
(concat "["
|
|||
|
(mapconcat #'identity
|
|||
|
(mapcar (lambda (v)
|
|||
|
(org-hugo--yaml-quote-string
|
|||
|
(cond
|
|||
|
((symbolp v)
|
|||
|
(symbol-name v))
|
|||
|
((numberp v)
|
|||
|
(number-to-string v))
|
|||
|
((org-string-nw-p v)
|
|||
|
v)
|
|||
|
(t
|
|||
|
(user-error "Invalid element %S in `%s' value %S" v key list)))))
|
|||
|
list)
|
|||
|
", ")
|
|||
|
"]"))
|
|||
|
|
|||
|
(defun org-hugo--gen-yaml-front-matter (data)
|
|||
|
"Generate Hugo front-matter in YAML format, and return that string.
|
|||
|
|
|||
|
DATA is an alist of the form \((KEY1 . VAL1) (KEY2 . VAL2) .. \),
|
|||
|
where KEY is a symbol and VAL is a string."
|
|||
|
(let ((sep "---\n")
|
|||
|
(sign ":")
|
|||
|
(front-matter "")
|
|||
|
(indent (make-string 2 ? ))
|
|||
|
(nested-string "")
|
|||
|
(menu-string "")
|
|||
|
(res-string ""))
|
|||
|
(dolist (pair data)
|
|||
|
(let ((key (symbol-name (car pair)))
|
|||
|
(value (cdr pair)))
|
|||
|
;; (message "[hugo fm key value DBG] %S %S" key value)
|
|||
|
(unless (or (null value) ;Skip writing front-matter variables whose value is nil
|
|||
|
(and (stringp value) ;or an empty string.
|
|||
|
(string= "" value)))
|
|||
|
;; In TOML/YAML, the value portion needs to be wrapped in
|
|||
|
;; double quotes.
|
|||
|
;; TOML example:
|
|||
|
;; title = "My Post"
|
|||
|
;; YAML example:
|
|||
|
;; title: "My Post"
|
|||
|
(cond
|
|||
|
((string= key "menu")
|
|||
|
(unless (listp value)
|
|||
|
(user-error (concat "The `menu' front-matter did not get the expected "
|
|||
|
"list value; probably because HUGO_MENU was not "
|
|||
|
"used to set its value.\n"
|
|||
|
"Usage examples: \":EXPORT_HUGO_MENU: :menu main\" or "
|
|||
|
"\"#+hugo_menu: :menu main\"")))
|
|||
|
;; Menu name needs to be non-nil to insert menu info in front-matter.
|
|||
|
(when (assoc 'menu value)
|
|||
|
(let* ((menu-alist value)
|
|||
|
;; Menu entry string might need to be quoted if
|
|||
|
;; it contains spaces, for example.
|
|||
|
(menu-entry (org-hugo--yaml-quote-string (cdr (assoc 'menu menu-alist)) :prefer-no-quotes))
|
|||
|
(menu-entry-str "")
|
|||
|
(menu-value-str ""))
|
|||
|
;; Auto-set menu identifier if not already set by user.
|
|||
|
(unless (assoc 'identifier menu-alist)
|
|||
|
(let ((title (cdr (assoc 'title data))))
|
|||
|
(push `(identifier . ,(org-hugo-slug title)) menu-alist)))
|
|||
|
|
|||
|
;; Auto-set menu weight if not already set by user.
|
|||
|
(unless (assoc 'weight menu-alist)
|
|||
|
(when org-hugo--subtree-coord
|
|||
|
(push `(weight . ,(org-hugo--calc-weight)) menu-alist)))
|
|||
|
|
|||
|
;; (message "[menu alist DBG] = %S" menu-alist)
|
|||
|
(when menu-entry
|
|||
|
(setq menu-entry-str (prog1
|
|||
|
(format "menu%s\n%s%s%s\n"
|
|||
|
sign indent menu-entry sign)
|
|||
|
(setq indent (concat indent indent)))) ;Double the indent for next use
|
|||
|
(dolist (menu-pair menu-alist)
|
|||
|
(let ((menu-key (symbol-name (car menu-pair)))
|
|||
|
(menu-value (cdr menu-pair)))
|
|||
|
;; (message "menu DBG: %S %S %S" menu-entry menu-key menu-value)
|
|||
|
(unless (string= "menu" menu-key)
|
|||
|
(when menu-value
|
|||
|
;; Cannot skip quote wrapping for values of keys inside menu.
|
|||
|
;; Attempting to do:
|
|||
|
;; [menu.foo]
|
|||
|
;; parent = main
|
|||
|
;; # parent = "main" # But this works
|
|||
|
;; gives this error:
|
|||
|
;; ERROR 2017/07/21 10:56:07 failed to parse page metadata
|
|||
|
;; for "singles/post-draft.md": Near line 10 (last key parsed
|
|||
|
;; 'menu.foo.parent'): expected value but found "main" instead.
|
|||
|
(setq menu-value (org-hugo--yaml-quote-string menu-value))
|
|||
|
(setq menu-value-str
|
|||
|
(concat menu-value-str
|
|||
|
(format "%s%s%s %s\n"
|
|||
|
indent menu-key sign menu-value)))))))
|
|||
|
(setq menu-string (concat menu-entry-str menu-value-str))))))
|
|||
|
((string= key "resources")
|
|||
|
(unless (listp value)
|
|||
|
(user-error (concat "The `resources' front-matter did not get the expected "
|
|||
|
"list value; probably because HUGO_RESOURCES was not "
|
|||
|
"used to set its value.\n"
|
|||
|
"Usage examples: \":EXPORT_HUGO_RESOURCES: :src \"my-image.png\" :title \"My Image\" "
|
|||
|
"or \"#+hugo_resources: :src \"my-image.png\" :title \"My Image\"")))
|
|||
|
(when value
|
|||
|
(dolist (res-alist value)
|
|||
|
(let ((res-entry-str "")
|
|||
|
(res-value-str "")
|
|||
|
res-src-present
|
|||
|
res-param-str)
|
|||
|
(setq res-entry-str
|
|||
|
;; For YAML, this string
|
|||
|
;; needs to be inserted
|
|||
|
;; only once.
|
|||
|
(if (org-string-nw-p res-string)
|
|||
|
""
|
|||
|
(format "resources%s\n" sign)))
|
|||
|
(dolist (res-pair res-alist)
|
|||
|
;; (message "[resources DBG] res-pair: %S" res-pair)
|
|||
|
(let* ((res-key (symbol-name (car res-pair)))
|
|||
|
(res-value (cdr res-pair)))
|
|||
|
;; (message "[resources DBG]: %S %S" res-key res-value)
|
|||
|
(cond ((string= res-key "params")
|
|||
|
(setq indent (make-string 4 ? ))
|
|||
|
(setq res-param-str (format " %s%s\n" res-key sign))
|
|||
|
(dolist (param-pair res-value) ;res-value would be an alist of params
|
|||
|
(let ((param-key (symbol-name (car param-pair)))
|
|||
|
(param-value (cdr param-pair))
|
|||
|
param-value-str)
|
|||
|
;; (message "[resources DBG] param-key: %S" param-key)
|
|||
|
;; (message "[resources DBG] param-value: %S" param-value)
|
|||
|
(setq param-value-str (if (listp param-value)
|
|||
|
(org-hugo--get-yaml-list-string param-key param-value)
|
|||
|
(org-hugo--yaml-quote-string param-value)))
|
|||
|
(setq res-param-str
|
|||
|
(concat res-param-str
|
|||
|
(format "%s%s%s %s\n"
|
|||
|
indent param-key sign param-value-str)))))
|
|||
|
;; (message "[resources params DBG] %s" res-param-str)
|
|||
|
)
|
|||
|
(t
|
|||
|
(when (string= res-key "src")
|
|||
|
(setq res-src-present t))
|
|||
|
(if (string= res-key "src")
|
|||
|
(setq indent "- ")
|
|||
|
(setq indent " "))
|
|||
|
(setq res-value (org-hugo--yaml-quote-string res-value))
|
|||
|
(setq res-value-str
|
|||
|
(concat res-value-str
|
|||
|
(format "%s%s%s %s\n"
|
|||
|
indent res-key sign res-value)))))))
|
|||
|
(unless res-src-present
|
|||
|
(user-error "`src' must be set for the `resources'"))
|
|||
|
(setq res-string (concat res-string res-entry-str res-value-str res-param-str))))))
|
|||
|
(;; Front-matter with nested map values: blackfriday, custom front-matter.
|
|||
|
;; Only 1 level of nesting is supported.
|
|||
|
(and (listp value) ;Example value: '((legs . 4) ("eyes" . 2) (friends . (poo boo)))
|
|||
|
(eq 0 (cl-count-if (lambda (el) ;Check if value is a list of lists (or conses)
|
|||
|
(not (listp el)))
|
|||
|
value)))
|
|||
|
(let ((nested-parent-key key)
|
|||
|
(nested-alist value)
|
|||
|
(nested-parent-key-str "")
|
|||
|
(nested-keyval-str ""))
|
|||
|
;; (message "[nested entry DBG] = %s" nested-parent-key)
|
|||
|
;; (message "[nested alist DBG] = %S" nested-alist)
|
|||
|
(setq nested-parent-key-str (format "%s%s\n" nested-parent-key sign))
|
|||
|
(dolist (nested-pair nested-alist)
|
|||
|
(unless (consp nested-pair)
|
|||
|
(user-error "Ox-hugo: Custom front-matter values with nested maps need to be an alist of conses"))
|
|||
|
;; (message "[nested pair DBG] = %S" nested-pair)
|
|||
|
(let* ((nested-key (car nested-pair))
|
|||
|
(nested-key (cond
|
|||
|
((symbolp nested-key)
|
|||
|
(symbol-name nested-key))
|
|||
|
(t
|
|||
|
nested-key)))
|
|||
|
(nested-value (cdr nested-pair))
|
|||
|
(nested-value (cond
|
|||
|
((and nested-value
|
|||
|
(listp nested-value))
|
|||
|
(if (and (string= nested-parent-key "blackfriday")
|
|||
|
(or (string= nested-key "extensions")
|
|||
|
(string= nested-key "extensionsmask")))
|
|||
|
(org-hugo--get-yaml-list-string
|
|||
|
nested-key
|
|||
|
(mapcar #'org-hugo--return-valid-blackfriday-extension
|
|||
|
nested-value))
|
|||
|
(org-hugo--get-yaml-list-string nested-key nested-value)))
|
|||
|
((null nested-value)
|
|||
|
"false")
|
|||
|
((equal nested-value 't)
|
|||
|
"true")
|
|||
|
(t
|
|||
|
(org-hugo--yaml-quote-string nested-value)))))
|
|||
|
;; (message "nested DBG: %S KEY %S->%S VALUE %S->%S" nested-parent-key
|
|||
|
;; (car nested-pair) nested-key
|
|||
|
;; (cdr nested-pair) nested-value)
|
|||
|
(when nested-value
|
|||
|
(setq nested-keyval-str
|
|||
|
(concat nested-keyval-str
|
|||
|
(format "%s%s%s %s\n"
|
|||
|
indent nested-key sign nested-value))))))
|
|||
|
(when (org-string-nw-p nested-keyval-str)
|
|||
|
(setq nested-string (concat nested-string nested-parent-key-str
|
|||
|
nested-keyval-str)))))
|
|||
|
(t
|
|||
|
(setq front-matter
|
|||
|
(concat front-matter
|
|||
|
(format "%s%s %s\n"
|
|||
|
key
|
|||
|
sign
|
|||
|
(cond (;; Tags, categories, keywords, aliases,
|
|||
|
;; custom front-matter which are lists.
|
|||
|
(listp value)
|
|||
|
(org-hugo--get-yaml-list-string key value))
|
|||
|
(t
|
|||
|
(org-hugo--yaml-quote-string value nil)))))))))))
|
|||
|
(concat sep front-matter nested-string menu-string res-string sep)))
|
|||
|
|
|||
|
|
|||
|
(provide 'ox-hugo-deprecated)
|
|||
|
|
|||
|
;;; ox-hugo-deprecated.el ends here
|