add ox-hugo to org profile

This commit is contained in:
KemoNine 2022-11-07 22:54:27 -05:00
parent bdfdc60b30
commit be7e140d08
15 changed files with 9893 additions and 1 deletions

View File

@ -0,0 +1,48 @@
;;; org-hugo-auto-export-mode.el --- Minor mode for auto-exporting using ox-hugo -*- lexical-binding: t -*-
;; Authors: Kaushal Modi <kaushal.mod@gmail.com>, Evgeni Kolev <evgenysw@gmail.com>
;; URL: https://ox-hugo.scripter.co
;;; Commentary:
;;
;; This is a minor mode for enabling auto-exporting of Org files via
;; ox-hugo.
;;
;; *It is NOT a stand-alone package.*
;;; Usage:
;;
;; To enable this minor mode for a "content-org" directory, add below
;; to the .dir-locals.el:
;;
;; (("content-org/"
;; . ((org-mode . ((eval . (org-hugo-auto-export-mode)))))))
;;; Code:
(declare-function org-hugo-export-wim-to-md "ox-hugo")
(defun org-hugo-export-wim-to-md-after-save ()
"Function for `after-save-hook' to run `org-hugo-export-wim-to-md'.
The exporting happens only when Org Capture is not in progress."
(unless (eq real-this-command 'org-capture-finalize)
(save-excursion
(org-hugo-export-wim-to-md))))
;;;###autoload
(define-minor-mode org-hugo-auto-export-mode
"Toggle auto exporting the Org file using `ox-hugo'."
:global nil
:lighter ""
(if org-hugo-auto-export-mode
;; When the mode is enabled
(progn
(add-hook 'after-save-hook #'org-hugo-export-wim-to-md-after-save :append :local))
;; When the mode is disabled
(remove-hook 'after-save-hook #'org-hugo-export-wim-to-md-after-save :local)))
(provide 'org-hugo-auto-export-mode)
;;; org-hugo-auto-export-mode.el ends here

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,296 @@
;;; ox-hugo-autoloads.el --- automatically extracted autoloads -*- lexical-binding: t -*-
;;
;;; Code:
(add-to-list 'load-path (directory-file-name
(or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "org-hugo-auto-export-mode" "org-hugo-auto-export-mode.el"
;;;;;; (0 0 0 0))
;;; Generated autoloads from org-hugo-auto-export-mode.el
(autoload 'org-hugo-auto-export-mode "org-hugo-auto-export-mode" "\
Toggle auto exporting the Org file using `ox-hugo'.
This is a minor mode. If called interactively, toggle the
`Org-Hugo-Auto-Export mode' mode. If the prefix argument is
positive, enable the mode, and if it is zero or negative, disable
the mode.
If called from Lisp, toggle the mode if ARG is `toggle'. Enable
the mode if ARG is nil, omitted, or is a positive number.
Disable the mode if ARG is a negative number.
To check whether the minor mode is enabled in the current buffer,
evaluate `org-hugo-auto-export-mode'.
The mode's hook is called both when the mode is enabled and when
it is disabled.
\(fn &optional ARG)" t nil)
(register-definition-prefixes "org-hugo-auto-export-mode" '("org-hugo-export-wim-to-md-after-save"))
;;;***
;;;### (autoloads nil "ox-blackfriday" "ox-blackfriday.el" (0 0 0
;;;;;; 0))
;;; Generated autoloads from ox-blackfriday.el
(autoload 'org-blackfriday-export-as-markdown "ox-blackfriday" "\
Export current buffer to a Github Flavored Markdown buffer.
If narrowing is active in the current buffer, only export its
narrowed part.
If a region is active, export that region.
A non-nil optional argument ASYNC means the process should happen
asynchronously. The resulting buffer should be accessible
through the `org-export-stack' interface.
When optional argument SUBTREEP is non-nil, export the sub-tree
at point, extracting information from the heading properties
first.
When optional argument VISIBLE-ONLY is non-nil, don't export
contents of hidden elements.
Export is done in a buffer named \"*Org BLACKFRIDAY Export*\", which will
be displayed when `org-export-show-temporary-export-buffer' is
non-nil.
\(fn &optional ASYNC SUBTREEP VISIBLE-ONLY)" t nil)
(autoload 'org-blackfriday-convert-region-to-md "ox-blackfriday" "\
Convert text in the current region to Blackfriday Markdown.
The text is assumed to be in Org mode format.
This can be used in any buffer. For example, you can write an
itemized list in Org mode syntax in a Markdown buffer and use
this command to convert it." t nil)
(autoload 'org-blackfriday-export-to-markdown "ox-blackfriday" "\
Export current buffer to a Github Flavored Markdown file.
If narrowing is active in the current buffer, only export its
narrowed part.
If a region is active, export that region.
A non-nil optional argument ASYNC means the process should happen
asynchronously. The resulting file should be accessible through
the `org-export-stack' interface.
When optional argument SUBTREEP is non-nil, export the sub-tree
at point, extracting information from the heading properties
first.
When optional argument VISIBLE-ONLY is non-nil, don't export
contents of hidden elements.
Return output file's name.
\(fn &optional ASYNC SUBTREEP VISIBLE-ONLY)" t nil)
(autoload 'org-blackfriday-publish-to-blackfriday "ox-blackfriday" "\
Publish an Org file to Blackfriday Markdown file.
PLIST is the property list for the given project. FILENAME is
the filename of the Org file to be published. PUB-DIR is the
publishing directory.
Return output file name.
\(fn PLIST FILENAME PUB-DIR)" nil nil)
(register-definition-prefixes "ox-blackfriday" '("org-blackfriday-"))
;;;***
;;;### (autoloads nil "ox-hugo" "ox-hugo.el" (0 0 0 0))
;;; Generated autoloads from ox-hugo.el
(put 'org-hugo-base-dir 'safe-local-variable 'stringp)
(put 'org-hugo-goldmark 'safe-local-variable 'booleanp)
(put 'org-hugo-section 'safe-local-variable 'stringp)
(put 'org-hugo-front-matter-format 'safe-local-variable 'stringp)
(put 'org-hugo-footer 'safe-local-variable 'stringp)
(put 'org-hugo-preserve-filling 'safe-local-variable 'booleanp)
(put 'org-hugo-delete-trailing-ws 'safe-local-variable 'booleanp)
(put 'org-hugo-use-code-for-kbd 'safe-local-variable 'booleanp)
(put 'org-hugo-allow-spaces-in-tags 'safe-local-variable 'booleanp)
(put 'org-hugo-prefer-hyphen-in-tags 'safe-local-variable 'booleanp)
(put 'org-hugo-auto-set-lastmod 'safe-local-variable 'booleanp)
(put 'org-hugo-suppress-lastmod-period 'safe-local-variable 'floatp)
(put 'org-hugo-export-with-toc 'safe-local-variable (lambda (x) (or (booleanp x) (integerp x))))
(put 'org-hugo-export-with-section-numbers 'safe-local-variable (lambda (x) (or (booleanp x) (equal 'onlytoc x) (integerp x))))
(put 'org-hugo-default-static-subdirectory-for-externals 'safe-local-variable 'stringp)
(put 'org-hugo-export-creator-string 'safe-local-variable 'stringp)
(put 'org-hugo-date-format 'safe-local-variable 'stringp)
(put 'org-hugo-paired-shortcodes 'safe-local-variable 'stringp)
(put 'org-hugo-link-desc-insert-type 'safe-local-variable 'booleanp)
(put 'org-hugo-container-element 'safe-local-variable 'stringp)
(autoload 'org-hugo-slug "ox-hugo" "\
Convert string STR to a `slug' and return that string.
A `slug' is the part of a URL which identifies a particular page
on a website in an easy to read form.
Example: If STR is \"My First Post\", it will be converted to a
slug \"my-first-post\", which can become part of an easy to read
URL like \"https://example.com/posts/my-first-post/\".
In general, STR is a string. But it can also be a string with
Markdown markup because STR is often a post's sub-heading (which
can contain bold, italics, link, etc markup).
The `slug' generated from that STR follows these rules:
- Contain only lower case alphabet, number and hyphen characters
([[:alnum:]-]).
- Not have *any* HTML tag like \"<code>..</code>\",
\"<span class=..>..</span>\", etc.
- Not contain any URLs (if STR happens to be a Markdown link).
- Replace \".\" in STR with \"dot\", \"&\" with \"and\",
\"+\" with \"plus\".
- Replace parentheses with double-hyphens. So \"foo (bar) baz\"
becomes \"foo--bar--baz\".
- Replace non [[:alnum:]-] chars with spaces, and then one or
more consecutive spaces with a single hyphen.
- If ALLOW-DOUBLE-HYPHENS is non-nil, at most two consecutive
hyphens are allowed in the returned string, otherwise consecutive
hyphens are not returned.
- No hyphens allowed at the leading or trailing end of the slug.
\(fn STR &optional ALLOW-DOUBLE-HYPHENS)" nil nil)
(autoload 'org-hugo-export-as-md "ox-hugo" "\
Export current buffer to a Hugo-compatible Markdown buffer.
If narrowing is active in the current buffer, only export its
narrowed part.
If a region is active, export that region.
A non-nil optional argument ASYNC means the process should happen
asynchronously. The resulting buffer should be accessible
through the `org-export-stack' interface.
When optional argument SUBTREEP is non-nil, export the sub-tree
at point, extracting information from the heading properties
first.
When optional argument VISIBLE-ONLY is non-nil, don't export
contents of hidden elements.
Export is done in a buffer named \"*Org Hugo Export*\", which
will be displayed when `org-export-show-temporary-export-buffer'
is non-nil.
Return the buffer the export happened to.
\(fn &optional ASYNC SUBTREEP VISIBLE-ONLY)" t nil)
(autoload 'org-hugo-export-to-md "ox-hugo" "\
Export current buffer to a Hugo-compatible Markdown file.
This is the main exporting function which is called by both
`org-hugo--export-file-to-md' and
`org-hugo--export-subtree-to-md', and thus
`org-hugo-export-wim-to-md' too.
If narrowing is active in the current buffer, only export its
narrowed part.
If a region is active, export that region.
A non-nil optional argument ASYNC means the process should happen
asynchronously. The resulting file should be accessible through
the `org-export-stack' interface.
When optional argument SUBTREEP is non-nil, export the sub-tree
at point, extracting information from the heading properties
first.
When optional argument VISIBLE-ONLY is non-nil, don't export
contents of hidden elements.
Return output file's name.
\(fn &optional ASYNC SUBTREEP VISIBLE-ONLY)" t nil)
(autoload 'org-hugo-export-wim-to-md "ox-hugo" "\
Export the current subtree/all subtrees/current file to a Hugo post.
This is an Export \"What I Mean\" function:
- If the current subtree has the \"EXPORT_FILE_NAME\" property,
export only that subtree. Return the return value of
`org-hugo--export-subtree-to-md'.
- If the current subtree doesn't have that property, but one of
its parent subtrees has, export from that subtree's scope.
Return the return value of `org-hugo--export-subtree-to-md'.
- If there are no valid Hugo post subtrees (that have the
\"EXPORT_FILE_NAME\" property) in the Org buffer the subtrees
have that property, do file-based
export (`org-hugo--export-file-to-md'), regardless of the value
of ALL-SUBTREES. Return the return value of
`org-hugo--export-file-to-md'.
- If ALL-SUBTREES is non-nil and the Org buffer has at least 1
valid Hugo post subtree, export all those valid post subtrees.
Return a list of output files.
A non-nil optional argument ASYNC means the process should happen
asynchronously. The resulting file should be accessible through
the `org-export-stack' interface.
When optional argument VISIBLE-ONLY is non-nil, don't export
contents of hidden elements.
The optional argument NOERROR is passed to
`org-hugo--export-file-to-md'.
\(fn &optional ALL-SUBTREES ASYNC VISIBLE-ONLY NOERROR)" t nil)
(autoload 'org-hugo-debug-info "ox-hugo" "\
Get Emacs, Org and Hugo version and ox-hugo customization info.
The information is converted to Markdown format and copied to the
kill ring. The same information is displayed in the Messages
buffer and returned as a string in Org format." t nil)
(register-definition-prefixes "ox-hugo" '("org-hugo-"))
;;;***
;;;### (autoloads nil "ox-hugo-deprecated" "ox-hugo-deprecated.el"
;;;;;; (0 0 0 0))
;;; Generated autoloads from ox-hugo-deprecated.el
(register-definition-prefixes "ox-hugo-deprecated" '("org-hugo-"))
;;;***
;;;### (autoloads nil "ox-hugo-pandoc-cite" "ox-hugo-pandoc-cite.el"
;;;;;; (0 0 0 0))
;;; Generated autoloads from ox-hugo-pandoc-cite.el
(register-definition-prefixes "ox-hugo-pandoc-cite" '("org-hugo-pandoc-cite-"))
;;;***
;;;### (autoloads nil nil ("ox-hugo-pkg.el") (0 0 0 0))
;;;***
;; Local Variables:
;; version-control: never
;; no-byte-compile: t
;; no-update-autoloads: t
;; coding: utf-8
;; End:
;;; ox-hugo-autoloads.el ends here

View File

@ -0,0 +1,442 @@
;;; 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

View File

@ -0,0 +1,415 @@
;;; ox-hugo-pandoc-cite.el --- Pandoc Citations support for ox-hugo -*- lexical-binding: t -*-
;; Authors: Kaushal Modi <kaushal.mod@gmail.com>
;; URL: https://ox-hugo.scripter.co
;;; Commentary:
;; *This is NOT a stand-alone package.*
;;
;; It is used by ox-hugo to add support for parsing Pandoc Citations.
;;; Code:
(require 'org)
(declare-function org-hugo--plist-get-true-p "ox-hugo")
(declare-function org-hugo--front-matter-value-booleanize "ox-hugo")
(defcustom org-hugo-pandoc-cite-references-heading "References {#references}"
"Markdown title for Pandoc inserted references section."
:group 'org-export-hugo
:type 'string)
(defvar org-hugo--fm-yaml) ;Silence byte-compiler
(defvar org-hugo-pandoc-cite-pandoc-args-list
`("-f" "markdown"
"-t" ,(concat "markdown-citations"
"-simple_tables"
"+pipe_tables"
"-raw_attribute"
"-fenced_divs"
"-fenced_code_attributes"
"-bracketed_spans")
"--markdown-headings=atx"
"--id-prefix=fn:"
"--citeproc")
"Pandoc arguments used in `org-hugo-pandoc-cite--run-pandoc'.
-f markdown : Convert *from* Markdown
-t markdown : Convert *to* Markdown
-citations : Remove the \"citations\" extension. This will cause
citations to be expanded instead of being included as
markdown citations.
-simple_tables : Remove the \"simple_tables\" style.
+pipe_tables : Add the \"pipe_tables\" style insted that Blackfriday
understands.
-fenced_divs : Do not replace HTML <div> tags with Pandoc fenced
divs \":::\".
-fenced_code_attributes : Create fenced code blocks like
\"``` lang .. ```\" instead of \"``` {.lang} .. ```\".
-bracketed_spans : Do not replace HTML <span> tags with Pandoc
bracketed class notation \"{.some-class}\".
--atx-headers : Use \"# foo\" style heading for output markdown.
--id-prefix=fn: : Create footnote ID's like \"[^fn:1]\" instead of
\"[^1]\" to be consistent with default ox-hugo
exported Markdown footnote style.
These arguments are added to the `pandoc' call in addition to the
\"--bibliography\", output file (\"-o\") and input file
arguments.")
(defvar org-hugo-pandoc-cite-pandoc-meta-data
'("nocite" "csl" "link-citations")
"List of meta-data fields specific to Pandoc.")
(defvar org-hugo-pandoc-cite--run-pandoc-buffer "*Pandoc Citations*"
"Buffer to contain the `pandoc' run output and errors.")
(defvar org-hugo-pandoc-cite--references-header-regexp
"^<div id=\"refs\" class=\"references[^>]+>"
"Regexp to match the Pandoc-inserted references header string.
This string is present only if Pandoc has resolved one or more
references.
Pandoc 2.11.4.")
(defvar org-hugo-pandoc-cite--reference-entry-regexp
"^<div id=\"ref-[^\"]+\" .*csl-entry[^>]+>"
"Regexp to match the Pandoc-inserted reference entry strings.
Pandoc 2.11.4.")
(defun org-hugo-pandoc-cite--restore-fm-in-orig-outfile (orig-outfile fm &optional orig-full-contents)
"Restore the intended front-matter format in ORIG-OUTFILE.
ORIG-OUTFILE is the Org exported file name.
FM is the intended front-matter format.
ORIG-FULL-CONTENTS is a string of ORIG-OUTFILE contents. If this
is nil it is created in this function.
If FM is already in YAML format, this function doesn't do
anything. Otherwise, the YAML format front-matter in
ORIG-OUTFILE is replaced with TOML format."
(unless (string= fm org-hugo--fm-yaml)
(unless orig-full-contents
(setq orig-full-contents (with-temp-buffer
(insert-file-contents orig-outfile)
(buffer-substring-no-properties
(point-min) (point-max)))))
(setq fm (org-hugo-pandoc-cite--remove-pandoc-meta-data fm))
(let* ((orig-contents-only
(replace-regexp-in-string
;; The `orig-contents-only' will always be in YAML.
;; Delete that first.
"\\`---\n\\(.\\|\n\\)+\n---\n" "" orig-full-contents))
(toml-fm-plus-orig-contents (concat fm orig-contents-only)))
;; (message "[ox-hugo-pandoc-cite] orig-contents-only: %S" orig-contents-only)
(write-region toml-fm-plus-orig-contents nil orig-outfile))))
(defun org-hugo-pandoc-cite--run-pandoc (orig-outfile bib-list)
"Run the `pandoc' process and return the generated file name.
ORIG-OUTFILE is the Org exported file name.
BIB-LIST is a list of one or more bibliography files."
;; First kill the Pandoc run buffer if already exists (from a
;; previous run).
(when (get-buffer org-hugo-pandoc-cite--run-pandoc-buffer)
(kill-buffer org-hugo-pandoc-cite--run-pandoc-buffer))
(let* ((pandoc-outfile (make-temp-file ;ORIG_FILE_BASENAME.RANDOM.md
(concat (file-name-base orig-outfile) ".")
nil ".md"))
(bib-args (mapcar (lambda (bib-file)
(concat "--bibliography="
bib-file))
bib-list))
(pandoc-arg-list (append
org-hugo-pandoc-cite-pandoc-args-list
bib-args
`("-o" ,pandoc-outfile ,orig-outfile))) ;-o <OUTPUT FILE> <INPUT FILE>
(pandoc-arg-list-str (mapconcat #'identity pandoc-arg-list " "))
exit-code)
(message (concat "[ox-hugo] Post-processing citations using Pandoc command:\n"
" pandoc " pandoc-arg-list-str))
(setq exit-code (apply 'call-process
(append
`("pandoc" nil
,org-hugo-pandoc-cite--run-pandoc-buffer :display)
pandoc-arg-list)))
(unless (= 0 exit-code)
(user-error (format "[ox-hugo] Pandoc execution failed. See the %S buffer"
org-hugo-pandoc-cite--run-pandoc-buffer)))
pandoc-outfile))
(defun org-hugo-pandoc-cite--remove-pandoc-meta-data (fm)
"Remove Pandoc meta-data from front-matter string FM and return it.
The list of Pandoc specific meta-data is defined in
`org-hugo-pandoc-cite-pandoc-meta-data'."
(with-temp-buffer
(insert fm)
(goto-char (point-min))
(let ((regexp (format "^%s\\(:\\| =\\) "
(regexp-opt org-hugo-pandoc-cite-pandoc-meta-data 'words))))
(delete-matching-lines regexp))
(buffer-substring-no-properties (point-min) (point-max))))
(defun org-hugo-pandoc-cite--fix-pandoc-output (content loffset info)
"Fix the Pandoc output CONTENT and return it.
LOFFSET is the heading level offset.
Required fixes:
- Prepend Pandoc inserted \"references\" class div with
`org-hugo-pandoc-cite-references-heading'.
- When not using Goldmark (Hugo v0.60.0+), add the Blackfriday
required \"<div></div>\" hack to Pandoc divs with \"ref\" id's.
- Unescape the Hugo shortcodes: \"{{\\\\=< shortcode \\\\=>}}\" ->
\"{{< shortcode >}}\"
INFO is a plist used as a communication channel."
(with-temp-buffer
(insert content)
(let ((case-fold-search nil))
(goto-char (point-min))
;; Prepend the Pandoc inserted "references" class div with
;; `org-hugo-pandoc-cite-references-heading' heading in Markdown.
(save-excursion
;; There should be at max only one replacement needed for
;; this.
(when (re-search-forward org-hugo-pandoc-cite--references-header-regexp nil :noerror)
(let ((references-heading ""))
(when (org-string-nw-p org-hugo-pandoc-cite-references-heading)
(let ((level-mark (make-string (+ loffset 1) ?#)))
(setq references-heading (concat level-mark " " org-hugo-pandoc-cite-references-heading))))
(replace-match (concat references-heading "\n\n\\&"
(unless (org-hugo--plist-get-true-p info :hugo-goldmark)
"\n <div></div>\n")))))) ;See footnote 1
;; Add the Blackfriday required hack to Pandoc ref divs.
(unless (org-hugo--plist-get-true-p info :hugo-goldmark)
(save-excursion
(while (re-search-forward org-hugo-pandoc-cite--reference-entry-regexp nil :noerror)
(replace-match "\\&\n <div></div>")))) ;See footnote 1
;; Fix Hugo shortcodes.
(save-excursion
(let ((regexp (concat "{{\\\\<"
"\\(\\s-\\|\n\\)+"
"\\(?1:[[:ascii:][:nonascii:]]+?\\)"
"\\(\\s-\\|\n\\)+"
"\\\\>}}")))
(while (re-search-forward regexp nil :noerror)
(let* ((sc-body (match-string-no-properties 1))
(sc-body-no-newlines (replace-regexp-in-string "\n" " " sc-body))
;; Remove all backslashes except for the one
;; preceding double-quotes, like in:
;; {{< figure src="nested-boxes.svg" caption="<span class=\"figure-number\">Figure 1: </span>
;; PlantUML generated figure showing nested boxes" >}}
(sc-body-no-backlash (replace-regexp-in-string
"\"\"" "\\\\\\\\\""
(replace-regexp-in-string
(rx "\\" (group anything)) "\\1" sc-body-no-newlines))))
(replace-match (format "{{< %s >}}" sc-body-no-backlash) :fixedcase)))))
;; Fix square bracket. \[ abc \] -> [ abc ]
(save-excursion
(let ((regexp (concat
"\\\\\\["
"\\(.+\\)"
"\\\\\\]")))
(while (re-search-forward regexp nil :noerror)
(let* ((sc-body (match-string-no-properties 1)))
;; (message "square bracket [%s]" sc-body)
(replace-match (format "[%s]" sc-body) :fixedcase)))))
(buffer-substring-no-properties (point-min) (point-max)))))
(defun org-hugo-pandoc-cite--parse-citations (info orig-outfile)
"Parse Pandoc Citations in ORIG-OUTFILE and update that file.
INFO is a plist used as a communication channel.
ORIG-OUTFILE is the Org exported file name."
(let ((bib-list (let ((bib-raw
(org-string-nw-p
(or (org-entry-get nil "EXPORT_BIBLIOGRAPHY" :inherit)
(format "%s" (plist-get info :bibliography))))))
(when bib-raw
;; Multiple bibliographies can be comma or
;; newline separated. The newline separated
;; bibliographies work only for the
;; #+bibliography keyword; example:
;;
;; #+bibliography: bibliographies-1.bib
;; #+bibliography: bibliographies-2.bib
;;
;; If using the subtree properties they need to
;; be comma-separated (now don't use commas in
;; those file names, you will suffer):
;;
;; :EXPORT_BIBLIOGRAPHY: bibliographies-1.bib, bibliographies-2.bib
(let ((bib-list-1 (org-split-string bib-raw "[,\n]")))
;; - Don't allow spaces around bib names.
;; - Remove duplicate bibliographies.
(delete-dups
(mapcar (lambda (bib-file)
(let ((fname (org-trim bib-file)))
(unless (file-exists-p fname)
(user-error "[ox-hugo] Bibliography file %S does not exist"
fname))
fname))
bib-list-1)))))))
(if bib-list
(let ((fm (plist-get info :front-matter))
(loffset (string-to-number
(or (org-entry-get nil "EXPORT_HUGO_LEVEL_OFFSET" :inherit)
(plist-get info :hugo-level-offset))))
(pandoc-outfile (org-hugo-pandoc-cite--run-pandoc orig-outfile bib-list)))
;; (message "[ox-hugo parse citations] fm :: %S" fm)
;; (message "[ox-hugo parse citations] loffset :: %S" loffset)
;; (message "[ox-hugo parse citations] pandoc-outfile :: %S" pandoc-outfile)
(let* ((pandoc-outfile-contents (with-temp-buffer
(insert-file-contents pandoc-outfile)
(buffer-substring-no-properties
(point-min) (point-max))))
(content-has-references (string-match-p
org-hugo-pandoc-cite--references-header-regexp
pandoc-outfile-contents)))
;; Prepend the original ox-hugo generated front-matter to
;; Pandoc output, only if the Pandoc output contains
;; references.
(if content-has-references
(let* ((contents-fixed (org-hugo-pandoc-cite--fix-pandoc-output
pandoc-outfile-contents loffset info))
(fm (org-hugo-pandoc-cite--remove-pandoc-meta-data fm))
(fm-plus-content (concat fm "\n" contents-fixed)))
(write-region fm-plus-content nil orig-outfile))
(org-hugo-pandoc-cite--restore-fm-in-orig-outfile orig-outfile fm)
(message (concat "[ox-hugo] Using the original Ox-hugo output instead "
"of Pandoc output as it contained no References"))))
(delete-file pandoc-outfile)
(with-current-buffer org-hugo-pandoc-cite--run-pandoc-buffer
(if (> (point-max) 1) ;buffer is not empty
(message
(format
(concat "[ox-hugo] See the %S buffer for possible Pandoc warnings.\n"
" Review the exported Markdown file for possible missing citations.")
org-hugo-pandoc-cite--run-pandoc-buffer))
;; Kill the Pandoc run buffer if it is empty.
(kill-buffer org-hugo-pandoc-cite--run-pandoc-buffer))))
(message "[ox-hugo] No bibliography file was specified"))))
(defun org-hugo-pandoc-cite--parse-citations-maybe (info)
"Check if Pandoc needs to be run to parse citations; and run it.
INFO is a plist used as a communication channel."
;; (message "pandoc citations keyword: %S"
;; (org-hugo--plist-get-true-p info :hugo-pandoc-citations))
;; (message "pandoc citations prop: %S"
;; (org-entry-get nil "EXPORT_HUGO_PANDOC_CITATIONS" :inherit))
(let* ((orig-outfile (plist-get info :outfile))
(fm (plist-get info :front-matter))
(has-nocite (string-match-p "^nocite\\(:\\| =\\) " fm))
(orig-outfile-contents (with-temp-buffer
(insert-file-contents orig-outfile)
(buffer-substring-no-properties
(point-min) (point-max))))
;; http://pandoc.org/MANUAL.html#citations
;; Each citation must have a key, composed of `@' + the
;; citation identifier from the database, and may optionally
;; have a prefix, a locator, and a suffix. The citation key
;; must begin with a letter, digit, or _, and may contain
;; alphanumerics, _, and internal punctuation characters
;; (:.#$%&-+?<>~/).
;; A minus sign (-) before the @ will suppress mention of the
;; author in the citation.
(valid-citation-key-char-regexp "a-zA-Z0-9_:.#$%&+?<>~/-")
(citation-key-regexp (concat "[^" valid-citation-key-char-regexp "]"
"\\(-?@[a-zA-Z0-9_]"
"[" valid-citation-key-char-regexp "]+\\)"))
(has-@ (string-match-p citation-key-regexp orig-outfile-contents)))
;; Either the nocite front-matter should be there, or the
;; citation keys should be present in the `orig-outfile'.
(if (or has-nocite has-@)
(progn
(unless (executable-find "pandoc")
(user-error "[ox-hugo] pandoc executable not found in PATH"))
(org-hugo-pandoc-cite--parse-citations info orig-outfile))
(org-hugo-pandoc-cite--restore-fm-in-orig-outfile
orig-outfile fm orig-outfile-contents))))
(defun org-hugo-pandoc-cite--meta-data-generator (data)
"Return YAML front-matter to pass citation meta-data to Pandoc.
DATA is the alist containing all the post meta-data for
front-matter generation.
Pandoc accepts `csl', `nocite' and `link-citations' variables via
a YAML front-matter.
References:
- https://pandoc.org/MANUAL.html#citation-rendering
- https://pandoc.org/MANUAL.html#including-uncited-items-in-the-bibliography
- https://pandoc.org/MANUAL.html#other-relevant-metadata-fields"
(let* ((yaml ())
(link-citations (cdr (assoc 'link-citations data)))
(link-citations (if (symbolp link-citations)
(symbol-name link-citations)
link-citations))
(csl (cdr (assoc 'csl data)))
(nocite (cdr (assoc 'nocite data))))
(push "---" yaml)
(when link-citations
(push (format "link-citations: %s"
(org-hugo--front-matter-value-booleanize link-citations))
yaml))
(when csl
(push (format "csl: %S" csl) yaml))
(when nocite
(push (format "nocite: [%s]"
(string-join
(mapcar (lambda (elem)
(format "%S" (symbol-name elem)))
nocite)
", "))
yaml))
(push "---\n" yaml)
;; (message "[org-hugo-pandoc-cite--meta-data-generator DBG] yaml: %S" yaml)
(string-join (nreverse yaml) "\n")))
(provide 'ox-hugo-pandoc-cite)
;;; Footnotes
;;;; Footnote 1
;; The empty HTML element tags like "<div></div>" is a hack to get
;; around a Blackfriday limitation. Details:
;; https://github.com/kaushalmodi/ox-hugo/issues/93.
;;; ox-hugo-pandoc-cite.el ends here

View File

@ -0,0 +1,14 @@
(define-package "ox-hugo" "20221028.1631" "Hugo Markdown Back-End for Org Export Engine"
'((emacs "26.3")
(tomelr "0.4.3"))
:commit "a66063a9915c859c57944564f0b8dbc7949d4449" :authors
'(("Kaushal Modi" . "kaushal.modi@gmail.com")
("Matt Price" . "moptop99@gmail.com"))
:maintainer
'("Kaushal Modi" . "kaushal.modi@gmail.com")
:keywords
'("org" "markdown" "docs")
:url "https://ox-hugo.scripter.co")
;; Local Variables:
;; no-byte-compile: t
;; End:

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1 @@
Good signature from 066DAFCB81E42C40 GNU ELPA Signing Agent (2019) <elpasign@elpa.gnu.org> (trust undefined) created at 2022-05-12T05:05:02-0400 using RSA

View File

@ -0,0 +1,5 @@
.github
doc
test
Makefile
LICENSE

View File

@ -0,0 +1,235 @@
# This file is auto-generated by running 'make changelog' from the repo root.
* Changelog
All notable changes to this project will be documented in this file.
** *0.4.2* - <2022-05-11>
[[https://github.com/kaushalmodi/tomelr/compare/19d128f0d2fd4ea8d4bf92cb1f5a235468b45d00...e45b0e43e80cc9df796027674a412708050ec8d6][19d128f...e45b0e4]]
*** :bug: Bug Fixes
:PROPERTIES:
:CUSTOM_ID: bug-fixes-v0.4.2
:END:
- Don't allow multi-line strings to indent by more than 2 spaces … The `tomelr-indent-multi-line-strings` variable is set to `t' mainly … by ox-hugo. So these multi-line strings will most likely be pars… ([[https://github.com/kaushalmodi/tomelr/commit/e45b0e43e80cc9df796027674a412708050ec8d6][e45b0e4]])
*** :recycle: Refactor
:PROPERTIES:
:CUSTOM_ID: refactor-v0.4.2
:END:
- Use append instead of push+reverse ([[https://github.com/kaushalmodi/tomelr/commit/7f331a8c0d4ab1f25b6f8b8749f8cb7a6ad274a6][7f331a8]])
** *0.4.0* - <2022-05-11>
[[https://github.com/kaushalmodi/tomelr/compare/2820bf1af3e5482df8aa1c9c35bd0d7333ce6a68...a5b2a0e6251ce62cd2ce515b961dba513966fcb9][2820bf1...a5b2a0e]]
*** :bug: Bug Fixes
:PROPERTIES:
:CUSTOM_ID: bug-fixes-v0.4.0
:END:
- Case of table arrays in nested sub tables ([[https://github.com/kaushalmodi/tomelr/commit/0f7a6cf7f40717b3fd7735f3ee78978e2d031bdb][0f7a6cf]])
** *0.3.0* - <2022-05-05>
[[https://github.com/kaushalmodi/tomelr/compare/8fc2257ec072a3fc3316c7f311722db50b37558e...2820bf1af3e5482df8aa1c9c35bd0d7333ce6a68][8fc2257...2820bf1]]
*** :bug: Bug Fixes
:PROPERTIES:
:CUSTOM_ID: bug-fixes-v0.3.0
:END:
- Make plist parsing work on emacs 26.3 … The fix was to make tomelr depend on the newer map v3.2.1 and seq … v2.23 versions from GNU ELPA. ([[https://github.com/kaushalmodi/tomelr/commit/2820bf1af3e5482df8aa1c9c35bd0d7333ce6a68][2820bf1]])
** *0.2.3* - <2022-05-03>
[[https://github.com/kaushalmodi/tomelr/compare/4e2edfe073d2a057a37b159d4e67282aa132f596...884674e168cbef35275a325f707c588ac2b5c866][4e2edfe...884674e]]
*** :memo: Documentation
:PROPERTIES:
:CUSTOM_ID: documentation-v0.2.3
:END:
- Add installation instructions now that this is in GNU ELPA ([[https://github.com/kaushalmodi/tomelr/commit/9aa308665daa507655285d601d3e13657cb4523e][9aa3086]])
** *0.2.0* - <2022-05-03>
[[https://github.com/kaushalmodi/tomelr/compare/568de5efb250c0bb4f19495c69b8b42b41fb186d...b4be72f240038d2db27540effcdd63e649b4df57][568de5e...b4be72f]]
*** :sparkles: Features
:PROPERTIES:
:CUSTOM_ID: features-v0.2.0
:END:
- Add option for indenting multi-line strings … New defvar `tomelr-indent-multi-line-strings`. ([[https://github.com/kaushalmodi/tomelr/commit/3362213172237f40ff0d9aa3ddf12b4bb00a3564][3362213]])
*** :recycle: Refactor
:PROPERTIES:
:CUSTOM_ID: refactor-v0.2.0
:END:
- Rename tomelr predicate functions for consistency ([[https://github.com/kaushalmodi/tomelr/commit/b4be72f240038d2db27540effcdd63e649b4df57][b4be72f]])
** *0.1.0* - <2022-05-03>
[[https://github.com/kaushalmodi/tomelr/compare/4434ccc64b1e311b53e8ecc906113bba2e16fa98...568de5efb250c0bb4f19495c69b8b42b41fb186d][4434ccc...568de5e]]
*** :sparkles: Features
:PROPERTIES:
:CUSTOM_ID: features-v0.1.0
:END:
- Support string keys ([[https://github.com/kaushalmodi/tomelr/commit/ed13b73e9b68ac2c51f3545ac337bbfeba063a42][ed13b73]])
- Auto-coerce string to boolean ([[https://github.com/kaushalmodi/tomelr/commit/ebe5959174812ffc3cf7d88040b854599b15a88a][ebe5959]])
- Auto-coerce string to integers ([[https://github.com/kaushalmodi/tomelr/commit/a25d952a17d344ac3d7396ae78a34e21b9ada14e][a25d952]])
*** :bug: Bug Fixes
:PROPERTIES:
:CUSTOM_ID: bug-fixes-v0.1.0
:END:
- Auto-stringify symbols like 1.10.1 ([[https://github.com/kaushalmodi/tomelr/commit/ae983711be15d95abd22ae4d7b8c116031de60a0][ae98371]])
- Auto-stringify and auto-quote symbol values ([[https://github.com/kaushalmodi/tomelr/commit/ec381fd723c9801caa2353a40d41e8cc8096ea29][ec381fd]])
- Boolean coercing when value is a symbol true or false ([[https://github.com/kaushalmodi/tomelr/commit/c2d1328c4404e6af920dc431ba57ee00eef4ba36][c2d1328]])
- Integer coercing of a number strings with underscores ([[https://github.com/kaushalmodi/tomelr/commit/a676192b435474fbff53fe361dbf983e3b8ac799][a676192]])
*** :recycle: Refactor
:PROPERTIES:
:CUSTOM_ID: refactor-v0.1.0
:END:
- Don't attempt to triple-quote TOML keys … Triple-quote only when the `type' input of `tomelr--print-stringlike' … is nil. ([[https://github.com/kaushalmodi/tomelr/commit/334b7cba54001708e6819b9df0abf0c553c0d0a2][334b7cb]])
- Minor code reorg ([[https://github.com/kaushalmodi/tomelr/commit/b2ba4c46b59d7baa4a6d02ba64657c08776d2d0e][b2ba4c4]])
*** :hammer: Testing
:PROPERTIES:
:CUSTOM_ID: testing-v0.1.0
:END:
- Add a test for string scalar with blank lines ([[https://github.com/kaushalmodi/tomelr/commit/57bed2cca8b648d2abc6da525a3420b3e968efb4][57bed2c]])
** *0.0.2* - <2022-05-02>
[[https://github.com/kaushalmodi/tomelr/compare/3aa4dc1dbdce5875166b9db76b6de0a0ad679b33...45542fb234fcc4fea50a5fed0c7682d0d3db0f9b][3aa4dc1...45542fb]]
*** :bug: Bug Fixes
:PROPERTIES:
:CUSTOM_ID: bug-fixes-v0.0.2
:END:
- TT with key with array value are detected correctly … Use json-alist-p and json-plist-p for TOML Table detection. This … uncomplicated the TOML Table logic quite a bit. … Caveat: Lists of plist need t… ([[https://github.com/kaushalmodi/tomelr/commit/044b5e1a042aa1058792af607b1d7cd4cc70d144][044b5e1]])
- List format array of plists now detected as TOML Table Array … Also simplify tomelr--toml-table-array-p. ([[https://github.com/kaushalmodi/tomelr/commit/171e5a76824f30730a9e80384a18f3888dd3cc2a][171e5a7]])
- Compatibility for emacs 26.3 … listp also works instead of proper-list-p here. So use that instead. … proper-list-p was introduced in emacs 27.x. ([[https://github.com/kaushalmodi/tomelr/commit/d86fd721ce4746550038e53dffe34885b06e9225][d86fd72]])
*** :memo: Documentation
:PROPERTIES:
:CUSTOM_ID: documentation-v0.0.2
:END:
- Remove an invalid example ([[https://github.com/kaushalmodi/tomelr/commit/dc9b2a63f8536d0ee14e480af5f8f273b1a117a9][dc9b2a6]])
*** :recycle: Refactor
:PROPERTIES:
:CUSTOM_ID: refactor-v0.0.2
:END:
- Clean up unused code … Use json-alist-p and json-plist-p directly where applicable. ([[https://github.com/kaushalmodi/tomelr/commit/f9d670e1656f1400b544ff27980657cbf5f8357b][f9d670e]])
- Remove unnecessary tomelr-encode-keyword … Also, The "keyword" term was confusing here; "boolean" makes more … sense. ([[https://github.com/kaushalmodi/tomelr/commit/41ccea4ebe0619bd6d38d3d8c2174e0b27587df0][41ccea4]])
- Use `tomelr--toml-table-p` ([[https://github.com/kaushalmodi/tomelr/commit/4386d99a8596fa244c818b8ae9f341feeeb0b677][4386d99]])
*** :hammer: Testing
:PROPERTIES:
:CUSTOM_ID: testing-v0.0.2
:END:
- Add tests for json.el functions used in tomelr ([[https://github.com/kaushalmodi/tomelr/commit/406f4922a8677f07d14190d48061ae60169825d5][406f492]])
*** :bento: Other
:PROPERTIES:
:CUSTOM_ID: other-v0.0.2
:END:
- Revert "doc: Update the medley example" … This reverts commit commit # [[https://github.com/kaushalmodi/tomelr/commit/26f1fc2f3c0245e69c8c72b0cd01024f9d53078b][26f1fc2]]. ([[https://github.com/kaushalmodi/tomelr/commit/df0e73334f918ee9de7e1f0a7cd0fb9037a79faa][df0e733]])
** *0.0.1* - <2022-04-30>
*** :boom: Breaking
:PROPERTIES:
:CUSTOM_ID: breaking-v0.0.1
:END:
- Set boolean false using :false value … This is so that null vs false can be distinguished in JSON. … If a lisp data value is nil, that key will be absent in TOML. ([[https://github.com/kaushalmodi/tomelr/commit/2ea3b5e032629a3974e2733f849cf47259e80e0d][2ea3b5e]])
*** :sparkles: Features
:PROPERTIES:
:CUSTOM_ID: features-v0.0.1
:END:
- Add s-exp->toml examples and spec ([[https://github.com/kaushalmodi/tomelr/commit/8bc506af5acd6e8f3ce47890185c5f4db1c3eb3e][8bc506a]])
- Add plist example ([[https://github.com/kaushalmodi/tomelr/commit/846676a172d2bdd39e1e8b5628a7e88a3605f68b][846676a]])
- First cut -- Port json-encode from json.el to tomelr-encode … Contains only the fixes needed to make the boolean key-value pair look … right in TOML. ([[https://github.com/kaushalmodi/tomelr/commit/52dc93201deb02a3d380d841e839f5f3e5f32c95][52dc932]])
- Encode to multi-line TOML string automatically … .. if the string has newlines or quote chars. ([[https://github.com/kaushalmodi/tomelr/commit/7d8d41f15b6d5a2d2325160490482b133c56f845][7d8d41f]])
- Recognize local date format YYYY-MM-DD ([[https://github.com/kaushalmodi/tomelr/commit/1d65064ffa0c6e1d5e9cb14a31de8ada38dc3395][1d65064]])
- Recognize RFC 3339 formatted date-time + offset ([[https://github.com/kaushalmodi/tomelr/commit/91800b26b8bff6b89fce887fbcadb9e956f412dd][91800b2]])
- Skip converting keys whose values are nil ([[https://github.com/kaushalmodi/tomelr/commit/69217d47a65cb987d7d1ce32d3db5566a169ceca][69217d4]])
- Convert Lisp lists to TOML arrays ([[https://github.com/kaushalmodi/tomelr/commit/96c890a68b9a587283bc7522c3893370cc522ca6][96c890a]])
- Support basic TOML tables ([[https://github.com/kaushalmodi/tomelr/commit/cedb75df72f9aed0ad990b631f32d71f6ba1b79d][cedb75d]])
- Support nested TOML tables ([[https://github.com/kaushalmodi/tomelr/commit/a1f434f03a761c50cd9813e27d5441d6b2c2902d][a1f434f]])
- Add basic support for S-exp plists -> TOML conversion … Support added for scalars and lists. … Pending: tables, arrays of tables, etc. ([[https://github.com/kaushalmodi/tomelr/commit/2810504e840d8038b9a06fff732889f0f8cc73c8][2810504]])
- Support basic TOML Table Arrays ([[https://github.com/kaushalmodi/tomelr/commit/ad8366d904dea6fc3f4af5bf57bcd92c6b37f57e][ad8366d]])
- Make a very basic nested array of TTA work ([[https://github.com/kaushalmodi/tomelr/commit/a7b3a5703729682e88d6352932e235cbe04deb28][a7b3a57]])
- Support (lightly tested) nested TOML Table Arrays ([[https://github.com/kaushalmodi/tomelr/commit/10a1994aedcbd95c35096b257cf1e9e6fd4554cb][10a1994]])
- Implement everything planned in the initial spec … Fix converting of array of TOML tables represented by S-exp vectors. ([[https://github.com/kaushalmodi/tomelr/commit/e2b313ca3b3e4c98c18749671ac59bc1fe319c52][e2b313c]])
*** :bug: Bug Fixes
:PROPERTIES:
:CUSTOM_ID: bug-fixes-v0.0.1
:END:
- Dates will be strings in Lisp … refactor: Move "lists of lists" to a different section ([[https://github.com/kaushalmodi/tomelr/commit/28642f2e787a5424ebff30bbb6f7df2af54d6329][28642f2]])
- Require subr-x for older Emacs versions ([[https://github.com/kaushalmodi/tomelr/commit/af40c0b40f8d3fe61ac711c00a32d6747d4e55e7][af40c0b]])
- Use `=` and `length` separately instead of `length=` … length= does not exist on 27.2 and older Emacs versions. … It was added in Emacs 28.1 in … https://git.savannah.gnu.org/cgit/emacs.git/comm… ([[https://github.com/kaushalmodi/tomelr/commit/98c9b8c1fc9eb3fbc0016d6692ae8aed95bbe003][98c9b8c]])
- Don't run plist to TOML conversion test on emacs 26.3 and older ([[https://github.com/kaushalmodi/tomelr/commit/c0962ba15f0cf7ff944e822f623b2800b5ebfd73][c0962ba]])
- Attempt to make tomelr--toml-table-p more robust ([[https://github.com/kaushalmodi/tomelr/commit/ca9245038a74f272b246979271cbf2adef09eb89][ca92450]])
- Support TOML tables specified as plists ([[https://github.com/kaushalmodi/tomelr/commit/4c419bcee218a95d6669a5b198d1b71f6a8e7691][4c419bc]])
- Support TOML tables arrays specified as plist vector ([[https://github.com/kaushalmodi/tomelr/commit/cff1f8aa890d8c08fe26243870d59aa39f602156][cff1f8a]])
- Stricter condition before starting TOML table array check ([[https://github.com/kaushalmodi/tomelr/commit/38160ef271493293166f81ce1a3d52b58a484a8e][38160ef]])
- Don't let array of TOML tables be recognized as TOML tables ([[https://github.com/kaushalmodi/tomelr/commit/0eb4fa04ac3e6741f743ba451b1ec7a019989b5e][0eb4fa0]])
- Don't let TOML tables be recognized as TOML tables arrays ([[https://github.com/kaushalmodi/tomelr/commit/5959b90ffa499281306473c83b669353ecb85073][5959b90]])
- Correct the spec for nested array of tables ([[https://github.com/kaushalmodi/tomelr/commit/baf81228bc812de55e4df9340dd34cc8cc5a2ab8][baf8122]])
- Better detection of nested TTA, but still wip … This fix also breaks the plist support for TTA ([[https://github.com/kaushalmodi/tomelr/commit/0f4e7b4f2c40a2cdce735d614eba9b7ac4640d06][0f4e7b4]])
- Detect TT with sub-tables correctly ([[https://github.com/kaushalmodi/tomelr/commit/b64eb07e99e9ab45cc88dc6b628f8bc828a0dc28][b64eb07]])
- Detect nested TTA correctly when not present in first TT key ([[https://github.com/kaushalmodi/tomelr/commit/a33dbd1286cd1f539c1e07bd21dc60464dd2f667][a33dbd1]])
*** :memo: Documentation
:PROPERTIES:
:CUSTOM_ID: documentation-v0.0.1
:END:
- Add LOGBOOK drawer example ([[https://github.com/kaushalmodi/tomelr/commit/d96a3b235b9dc7181f8140cf23b75d28a853c941][d96a3b2]])
- Discover `json-encoding-pretty-print` variable! ([[https://github.com/kaushalmodi/tomelr/commit/732140041e91528a7ee3c730ce10bac0931698c4][7321400]])
- Add spec for nested tables and arrays of tables ([[https://github.com/kaushalmodi/tomelr/commit/bb85106ee98c1ee04100db9d298510b3f57e0751][bb85106]])
*** :recycle: Refactor
:PROPERTIES:
:CUSTOM_ID: refactor-v0.0.1
:END:
- Move TOML Table detection logic to a separate fn ([[https://github.com/kaushalmodi/tomelr/commit/3c068fb9d9319d2876de359d2bc9068b857e091b][3c068fb]])
*** :hammer: Testing
:PROPERTIES:
:CUSTOM_ID: testing-v0.0.1
:END:
- Add test for boolean scalar key-value pairs ([[https://github.com/kaushalmodi/tomelr/commit/05d2cafcd989b977fa3e9d05e293e9f8bae22fc4][05d2caf]])
- Add test for integer scalar key-value pairs ([[https://github.com/kaushalmodi/tomelr/commit/c872e9efc1bcf0d9310160f825032c602500c346][c872e9e]])
- Add test for float scalar key-value pairs ([[https://github.com/kaushalmodi/tomelr/commit/9c91e0dc07291aae8a8b2b4dd1cea52583165e14][9c91e0d]])
- Add test for TOML Array of Arrays ([[https://github.com/kaushalmodi/tomelr/commit/f37841cc781ce322ba31806cf9ef1ca7578f5714][f37841c]])
- Test that 'false is also considered as boolean false in TOML ([[https://github.com/kaushalmodi/tomelr/commit/6bbe740e52d40a5d87d62805af3ed89cc16779b9][6bbe740]])
- Test `tomelr--toml-table-p` ([[https://github.com/kaushalmodi/tomelr/commit/0d4674f782bee99ee36aca079ede57adeccc384f][0d4674f]])
# This file is generated by git-cliff by running 'make changelog' from the repo root.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,26 @@
;;; tomelr-autoloads.el --- automatically extracted autoloads -*- lexical-binding: t -*-
;;
;;; Code:
(add-to-list 'load-path (directory-file-name
(or (file-name-directory #$) (car load-path))))
;;;### (autoloads nil "tomelr" "tomelr.el" (0 0 0 0))
;;; Generated autoloads from tomelr.el
(register-definition-prefixes "tomelr" '("tomelr-"))
;;;***
;;;### (autoloads nil nil ("tomelr-pkg.el") (0 0 0 0))
;;;***
;; Local Variables:
;; version-control: never
;; no-byte-compile: t
;; no-update-autoloads: t
;; coding: utf-8
;; End:
;;; tomelr-autoloads.el ends here

View File

@ -0,0 +1,2 @@
;; Generated package description from tomelr.el -*- no-byte-compile: t -*-
(define-package "tomelr" "0.4.3" "Convert S-expressions to TOML" '((emacs "26.3") (map "3.2.1") (seq "2.23")) :commit "670e0a08f625175fd80137cf69e799619bf8a381" :authors '(("Kaushal Modi" . "kaushal.modi@gmail.com")) :maintainer '("Kaushal Modi" . "kaushal.modi@gmail.com") :keywords '("data" "tools" "toml" "serialization" "config") :url "https://github.com/kaushalmodi/tomelr/")

View File

@ -0,0 +1,487 @@
;;; tomelr.el --- Convert S-expressions to TOML -*- lexical-binding: t -*-
;; Copyright (C) 2022 Free Software Foundation, Inc.
;; Author: Kaushal Modi <kaushal.modi@gmail.com>
;; Version: 0.4.3
;; Package-Requires: ((emacs "26.3") (map "3.2.1") (seq "2.23"))
;; Keywords: data, tools, toml, serialization, config
;; URL: https://github.com/kaushalmodi/tomelr/
;; This file is not part of GNU Emacs.
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
;; tomelr.el is a library for converting Lisp data expressions or
;; S-expressions to TOML format (https://toml.io/en/).
;; It has one entry point `tomelr-encode' which accepts a Lisp data
;; expression, usually in an alist or plist form, and return a string
;; representing the TOML serializaitno format.
;; Example using an alist as input:
;;
;; (tomelr-encode '((title . "My title")
;; (author . "Me")
;; (params . ((foo . 123)))))
;;
;; Output:
;;
;; title = "My title"
;; author = "Me"
;; [params]
;; foo = 123
;; Example using an plist as input:
;;
;; (tomelr-encode '(:title "My title"
;; :author "Me"
;; :params (:foo 123)))
;;
;; Above snippet will give as the same TOML output shown above.
;; See the README.org on https://github.com/kaushalmodi/tomelr/ for
;; more examples and package details.
;;; Code:
(require 'json)
(require 'map)
(require 'subr-x) ;For `string-trim' on Emacs versions 27.2 and older
;;; Variables
(defvar tomelr-false '(:false 'false)
"S-exp values to be interpreted as TOML `false'.")
(defvar tomelr-encoding-default-indentation " "
"String used for a single indentation level during encoding.
This value is repeated for each further nested element.")
(defvar tomelr-coerce-to-types '(boolean integer)
"List of TOML types to which the TOML strings will be attempted to be coerced.
Valid symbols that can be present in this list: boolean, integer, float
For example, if this list contains `boolean' and if a string
value is exactly \"true\", it will coerce to TOML boolean
`true'.")
(defvar tomelr-indent-multi-line-strings nil
"Indent the multi-line TOML strings when non-nil.
This option injects spaces after each newline to present the
multi-line strings in a more readable format.
*Note: This option should be set to non-nil only if the TOML
string data is insensitive to horizontal space. Good examples of
this would be Org, Markdown or HTML strings.")
;;;; Internal Variables
(defvar tomelr--print-indentation-prefix "\n"
"String used to start indentation during encoding.")
(defvar tomelr--print-indentation-depth -1
"Current indentation level during encoding.
Dictates repetitions of `tomelr-encoding-default-indentation'.")
(defvar tomelr--print-table-hierarchy ()
"Internal variable used to save TOML Table hierarchies.
This variable is used for both TOML Tables and Arrays of TOML
Tables.")
(defvar tomelr--print-keyval-separator " = "
"String used to separate key-value pairs during encoding.")
(defvar tomelr--date-time-regexp
(concat "\\`[[:digit:]]\\{4\\}-[[:digit:]]\\{2\\}-[[:digit:]]\\{2\\}"
"\\(?:[T ][[:digit:]]\\{2\\}:[[:digit:]]\\{2\\}:[[:digit:]]\\{2\\}\\(?:\\.[[:digit:]]+\\)*"
"\\(?:Z\\|[+-][[:digit:]]\\{2\\}:[[:digit:]]\\{2\\}\\)*\\)*\\'")
"Regexp to match RFC 3339 formatted date-time with offset.
- https://toml.io/en/v1.0.0#offset-date-time
- https://tools.ietf.org/html/rfc3339#section-5.8
Examples:
1979-05-27
1979-05-27T07:32:00Z
1979-05-27 07:32:00Z
1979-05-27T00:32:00-07:00
1979-05-27T00:32:00.999999+04:00.")
;;; Error conditions
(define-error 'tomelr-error "Unknown TOML error")
(define-error 'tomelr-key-format "Bad TOML object key" 'tomelr-error)
;;; Utilities
(defmacro tomelr--with-output-to-string (&rest body)
"Eval BODY in a temporary buffer bound to `standard-output'.
Return the resulting buffer contents as a string."
(declare (indent 0) (debug t))
`(with-output-to-string
(with-current-buffer standard-output
;; This affords decent performance gains.
(setq-local inhibit-modification-hooks t)
,@body)))
(defmacro tomelr--with-indentation (&rest body)
"Eval BODY with the TOML encoding nesting incremented by one step.
This macro sets up appropriate variable bindings for
`tomelr--print-indentation' to produce the correct indentation."
(declare (debug t) (indent 0))
`(let ((tomelr--print-indentation-depth (1+ tomelr--print-indentation-depth)))
,@body))
(defun tomelr--print-indentation ()
"Insert the current indentation for TOML encoding at point."
(insert tomelr--print-indentation-prefix)
(dotimes (_ tomelr--print-indentation-depth)
(insert tomelr-encoding-default-indentation)))
;;; Encoding
;;;; Booleans
(defun tomelr--print-boolean (object)
"Insert TOML boolean true or false at point if OBJECT is a boolean.
Return nil if OBJECT is not recognized as a TOML boolean."
(prog1 (setq object (cond ((or
(eq object t)
(and (member 'boolean tomelr-coerce-to-types)
(member object '("true" true))))
"true")
((or
(member object tomelr-false)
(and (member 'boolean tomelr-coerce-to-types)
(member object '("false" false))))
"false")))
(and object (insert object))))
;;;; Strings
(defun tomelr--print-string (string)
"Insert a TOML representation of STRING at point.
Return the same STRING passed as input."
;; (message "[tomelr--print-string DBG] string = `%s'" string)
(let ((special-chars '((?b . ?\b) ;U+0008
(?f . ?\f) ;U+000C
(?\\ . ?\\)))
(special-chars-re (rx (in ?\" ?\\ cntrl ?\u007F))) ;cntrl is same as (?\u0000 . ?\u001F)
;; Use multi-line string quotation if the string contains a "
;; char or a newline - """STRING""".
(multi-line (string-match-p "\n\\|\"" string))
begin-q end-q)
(cond
(multi-line
;; From https://toml.io/en/v1.0.0#string, Any Unicode
;; character may be used except those that must be escaped:
;; backslash and the control characters other than tab, line
;; feed, and carriage return (U+0000 to U+0008, U+000B,
;; U+000C, U+000E to U+001F, U+007F).
(setq special-chars-re (rx (in ?\\
(?\u0000 . ?\u0008)
?\u000B ?\u000C
(?\u000E . ?\u001F)
?\u007F)))
(setq begin-q "\"\"\"\n")
(setq end-q "\"\"\"")
(when tomelr-indent-multi-line-strings
(let (;; Fix the indentation of multi-line strings to 2
;; spaces. If the indentation is increased to 4 or more
;; spaces, those strings will get parsed as code blocks
;; by Markdown parsers.
(indentation " "))
(setq string
(concat
indentation ;Indent the first line in the multi-line string
(replace-regexp-in-string
"\\(\n\\)\\([^\n]\\)" ;Don't indent blank lines
(format "\\1%s\\2" indentation)
string)
"\n" indentation ;Indent the closing """ at the end of the multi-line string
)))))
(t ;Basic quotation "STRING"
(push '(?\" . ?\") special-chars)
(push '(?t . ?\t) special-chars) ;U+0009
(push '(?n . ?\n) special-chars) ;U+000A
(push '(?r . ?\r) special-chars) ;U+000D
(setq begin-q "\"")
(setq end-q begin-q)))
(and begin-q (insert begin-q))
(goto-char (prog1 (point) (princ string)))
(while (re-search-forward special-chars-re nil :noerror)
(let ((char (preceding-char)))
(delete-char -1)
(insert ?\\ (or
;; Escape special characters
(car (rassq char special-chars))
;; Fallback: UCS code point in \uNNNN form.
(format "u%04x" char)))))
(and end-q (insert end-q))
string))
(defun tomelr--print-stringlike (object &optional key-type)
"Insert OBJECT encoded as a TOML string at point.
Possible values of KEY-TYPE are `normal-key', `table-key',
`table-array-key', or nil.
Return nil if OBJECT cannot be encoded as a TOML string."
;; (message "[tomelr--print-stringlike DBG] object = %S (type = %S) key type = %S"
;; object (type-of object) key-type)
(let ((str (cond ;; Object is a normal, TT or TTA key
(key-type
(cond
((stringp object)
(if (string-match-p "\\`[A-Za-z0-9_-]+\\'" object)
;; https://toml.io/en/v1.0.0#keys
;; Bare keys may only contain ASCII letters, ASCII digits,
;; underscores, and dashes (A-Za-z0-9_-).
object
;; Wrap string in double-quotes if it
;; doesn't contain only A-Za-z0-9_- chars.
(format "\"%s\"" object)))
;; Plist keys as in (:foo 123)
((keywordp object)
(string-trim-left (symbol-name object) ":"))
;; Alist keys as in ((foo . 123))
((symbolp object)
(symbol-name object))
(t
(user-error "[tomelr--print-stringlike] Unhandled case of key-type"))))
;; Cases where object is a key value.
((symbolp object)
(symbol-name object))
((stringp object)
object))))
;; (message "[tomelr--print-stringlike DBG] str = %S" str)
(when (member key-type '(table-key table-array-key))
;; (message "[tomelr--print-stringlike DBG] %S is symbol, type = %S, depth = %d"
;; object key-type tomelr--print-indentation-depth)
(if (null (nth tomelr--print-indentation-depth tomelr--print-table-hierarchy))
(setq tomelr--print-table-hierarchy
(append tomelr--print-table-hierarchy (list str)))
;; Throw away table keys collected at higher depths, if
;; any, from earlier runs of this function.
(setq tomelr--print-table-hierarchy
(seq-take tomelr--print-table-hierarchy (1+ tomelr--print-indentation-depth)))
(setf (nth tomelr--print-indentation-depth tomelr--print-table-hierarchy) str))
;; (message "[tomelr--print-stringlike DBG] table hier: %S" tomelr--print-table-hierarchy)
)
(cond
;; TT keys
((equal key-type 'table-key)
(princ (format "[%s]" (string-join tomelr--print-table-hierarchy "."))))
;; TTA keys
((equal key-type 'table-array-key)
(princ (format "[[%s]]" (string-join tomelr--print-table-hierarchy "."))))
;; Normal keys (Alist and Plist keys)
((equal key-type 'normal-key)
(princ str))
(str
(cond
((or
;; RFC 3339 Date/Time
(string-match-p tomelr--date-time-regexp str)
;; Coercing
;; Integer that can be stored in the system as a fixnum.
;; For example, if `object' 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 object)) 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 (or (symbolp object)
(member 'integer tomelr-coerce-to-types))
(string-match-p "\\`[+-]?[[:digit:]_]+\\'" str)
(if (functionp #'fixnump) ;`fixnump' and `bignump' get introduced in Emacs 27.x
(fixnump (string-to-number str))
;; On older Emacsen, `integerp' behaved the same as the
;; new `fixnump'.
(integerp (string-to-number str)))))
(princ str))
(t
(tomelr--print-string str))))
(t
nil))))
(defun tomelr--print-key (key &optional key-type)
"Insert a TOML key representation of KEY at point.
KEY-TYPE represents the type of key: `normal-key', `table-key' or
`table-array-key'.
Signal `tomelr-key-format' if it cannot be encoded as a string."
(or (tomelr--print-stringlike key key-type)
(signal 'tomelr-key-format (list key))))
;;;; Objects
;; `tomelr-alist-p' is a slightly modified version of `json-alist-p'.
;; It fixes this scenario: (json-alist-p '((:a 1))) return t, which is wrong.
;; '((:a 1)) is an array of plist format maps, and not an alist.
;; (tomelr-alist-p '((:a 1))) returns nil as expected.
(defun tomelr-alist-p (list)
"Non-nil if and only if LIST is an alist with simple keys."
(declare (pure t) (side-effect-free error-free))
(while (and (consp (car-safe list))
(not (json-plist-p (car-safe list)))
(atom (caar list)))
;; (message "[tomelr-alist-p DBG] INSIDE list = %S, car = %S, caar = %S, atom of caar = %S"
;; list (car-safe list) (caar list) (atom (caar list)))
(setq list (cdr list)))
;; (message "[tomelr-alist-p DBG] out 2 list = %S, is alist? %S" list (null list))
(null list))
(defun tomelr-toml-table-p (object)
"Return non-nil if OBJECT can represent a TOML Table.
Recognize both alist and plist format maps as TOML Tables.
Examples:
- Alist format: \\='((a . 1) (b . \"foo\"))
- Plist format: \\='(:a 1 :b \"foo\")"
(or (tomelr-alist-p object)
(json-plist-p object)))
(defun tomelr--print-pair (key val)
"Insert TOML representation of KEY - VAL pair at point."
(let ((key-type (cond
((tomelr-toml-table-p val) 'table-key)
((tomelr-toml-table-array-p val) 'table-array-key)
(t 'normal-key))))
;; (message "[tomelr--print-pair DBG] key = %S, val = %S, key-type = %S"
;; key val key-type)
(when val ;Don't print the key if val is nil
(tomelr--print-indentation) ;Newline before each key in a key-value pair
(tomelr--print-key key key-type)
;; Skip putting the separator for table and table array keys.
(unless (member key-type '(table-key table-array-key))
(insert tomelr--print-keyval-separator))
(tomelr--print val))))
(defun tomelr--print-map (map)
"Insert a TOML representation of MAP at point.
This works for any MAP satisfying `mapp'."
;; (message "[tomelr--print-map DBG] map = %S" map)
(unless (map-empty-p map)
(tomelr--with-indentation
(map-do #'tomelr--print-pair map))))
;;;; Lists (including alists and plists)
(defun tomelr--print-list (list)
"Insert a TOML representation of LIST at point."
(cond ((tomelr-toml-table-p list)
(tomelr--print-map list))
((listp list)
(tomelr--print-array list))
((signal 'tomelr-error (list list)))))
;;;; Arrays
(defun tomelr-toml-table-array-p (object)
"Return non-nil if OBJECT can represent a TOML Table Array.
Definition of a TOML Table Array (TTA):
- OBJECT is TTA if it is of type ((TT1) (TT2) ..) where each element is a
TOML Table (TT)."
(when (or (listp object)
(vectorp object))
(seq-every-p
(lambda (elem) (tomelr-toml-table-p elem))
object)))
(defun tomelr--print-tta-key ()
"Print TOML Table Array key."
;; (message "[tomelr--print-array DBG] depth = %d" tomelr--print-indentation-depth)
;; Throw away table keys collected at higher depths, if
;; any, from earlier runs of this function.
(setq tomelr--print-table-hierarchy
(seq-take tomelr--print-table-hierarchy (1+ tomelr--print-indentation-depth)))
(tomelr--print-indentation)
(insert
(format "[[%s]]" (string-join tomelr--print-table-hierarchy "."))))
(defun tomelr--print-array (array)
"Insert a TOML representation of ARRAY at point."
;; (message "[tomelr--print-array DBG] array = %S, TTA = %S"
;; array (tomelr-toml-table-array-p array))
(cond
((tomelr-toml-table-array-p array)
(unless (= 0 (length array))
(let ((first t))
(mapc (lambda (elt)
(if first
(setq first nil)
(tomelr--print-tta-key))
(tomelr--print elt))
array))))
(t
(insert "[")
(unless (= 0 (length array))
(tomelr--with-indentation
(let ((first t))
(mapc (lambda (elt)
(if first
(setq first nil)
(insert ", "))
(tomelr--print elt))
array))))
(insert "]"))))
;;;; Print wrapper
(defun tomelr--print (object)
"Insert a TOML representation of OBJECT at point.
See `tomelr-encode' that returns the same as a string."
(cond ((tomelr--print-boolean object))
((listp object) (tomelr--print-list object))
((tomelr--print-stringlike object))
((numberp object) (prin1 object))
((arrayp object) (tomelr--print-array object))
((signal 'tomelr-error (list object)))))
;;; User API
(defun tomelr-encode (object)
"Return a TOML representation of OBJECT as a string.
If an error is detected during encoding, an error based on
`tomelr-error' is signaled."
(setq tomelr--print-table-hierarchy ())
(string-trim
(tomelr--with-output-to-string (tomelr--print object))))
(provide 'tomelr)
;;; tomelr.el ends here

View File

@ -63,7 +63,7 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; additional packages
(add-to-list 'package-selected-packages
'(org-super-agenda)
'(ox-hugo org-super-agenda)
)
@ -92,6 +92,10 @@
(setq org-support-shift-select t)
(setq org-src-fontify-natively t)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ox-hugo for blog
(with-eval-after-load 'ox (require 'ox-hugo))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; tags
(load "~/.emacs.d.profiles/org/config-org-tags")