diff --git a/lisp/ox-rst/ox-rst-autoloads.el b/lisp/ox-rst/ox-rst-autoloads.el
new file mode 100644
index 00000000..535496bc
--- /dev/null
+++ b/lisp/ox-rst/ox-rst-autoloads.el
@@ -0,0 +1,90 @@
+;;; ox-rst-autoloads.el --- automatically extracted autoloads (do not edit) -*- lexical-binding: t -*-
+;; Generated by the `loaddefs-generate' function.
+
+;; This file is part of GNU Emacs.
+
+;;; Code:
+
+(add-to-list 'load-path (or (and load-file-name (directory-file-name (file-name-directory load-file-name))) (car load-path)))
+
+
+
+;;; Generated autoloads from ox-rst.el
+
+(autoload 'org-rst-export-as-rst "ox-rst" "\
+Export current buffer to a reStructuredText 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 headline 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 RST Export*\", which will
+be displayed when `org-export-show-temporary-export-buffer' is
+non-nil.
+
+(fn &optional ASYNC SUBTREEP VISIBLE-ONLY BODY-ONLY EXT-PLIST)" t)
+(autoload 'org-rst-convert-region-to-rst "ox-rst" "\
+Assume the current region has Org syntax, and convert it to
+reStructuredText.
+This can be used in any buffer. For example, you can write an
+itemized list in Org syntax in a Markdown buffer and use this command
+to convert it." t)
+(autoload 'org-rst-export-to-rst "ox-rst" "\
+Export current buffer to a reStructuredText 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 headline 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 BODY-ONLY EXT-PLIST)" t)
+(autoload 'org-rst-publish-to-rst "ox-rst" "\
+Publish an org file to reStructuredText.
+
+FILENAME is the filename of the Org file to be published. PLIST
+is the property list for the given project. PUB-DIR is the
+publishing directory.
+
+Return output file name.
+
+(fn PLIST FILENAME PUB-DIR)")
+(register-definition-prefixes "ox-rst" '("my-org-export-inline-image-p" "org-"))
+
+;;; End of scraped data
+
+(provide 'ox-rst-autoloads)
+
+;; Local Variables:
+;; version-control: never
+;; no-byte-compile: t
+;; no-update-autoloads: t
+;; no-native-compile: t
+;; coding: utf-8-emacs-unix
+;; End:
+
+;;; ox-rst-autoloads.el ends here
diff --git a/lisp/ox-rst/ox-rst-pkg.el b/lisp/ox-rst/ox-rst-pkg.el
new file mode 100644
index 00000000..de537eaf
--- /dev/null
+++ b/lisp/ox-rst/ox-rst-pkg.el
@@ -0,0 +1,11 @@
+;; -*- no-byte-compile: t; lexical-binding: nil -*-
+(define-package "ox-rst" "20250428.534"
+ "Export reStructuredText using org-mode."
+ '((emacs "25.1")
+ (org "8.3"))
+ :url "https://github.com/msnoigrs/ox-rst"
+ :commit "b73eff187eebac24b457688bfd27f09eff434860"
+ :revdesc "b73eff187eeb"
+ :keywords '("org" "rst" "rest" "restructuredtext")
+ :authors '(("Masanao Igarashi" . "syoux2@gmail.com"))
+ :maintainers '(("Masanao Igarashi" . "syoux2@gmail.com")))
diff --git a/lisp/ox-rst/ox-rst.el b/lisp/ox-rst/ox-rst.el
new file mode 100644
index 00000000..1d66f88d
--- /dev/null
+++ b/lisp/ox-rst/ox-rst.el
@@ -0,0 +1,1733 @@
+;;; ox-rst.el --- Export reStructuredText using org-mode. -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2015-2025 Masanao Igarashi
+
+;; 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 2 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 GNU Emacs. If not, see .
+
+;; Author: Masanao Igarashi
+;; Keywords: org, rst, reST, reStructuredText
+;; Package-Version: 20250428.534
+;; Package-Revision: b73eff187eeb
+;; URL: https://github.com/msnoigrs/ox-rst
+;; Package-Requires: ((emacs "25.1") (org "8.3"))
+
+;;; Commentary:
+;; This library implements an reStructuredText back-end for
+;; Org generic exporter.
+
+;;; Code:
+
+(require 'org-macs)
+(org-assert-version)
+
+(require 'cl-lib)
+(require 'ox)
+(require 'ox-publish)
+
+
+;;; Define Back-End
+(org-export-define-backend 'rst
+ '((bold . org-rst-bold)
+ (center-block . org-rst-center-block)
+ (clock . org-rst-clock)
+ (code . org-rst-code)
+ (drawer . org-rst-drawer)
+ (dynamic-block . org-rst-dynamic-block)
+ (entity . org-rst-entity)
+ (example-block . org-rst-example-block)
+ (export-block . org-rst-export-block)
+ (export-snippet . org-rst-export-snippet)
+ (fixed-width . org-rst-example-block)
+ (footnote-reference . org-rst-footnote-reference)
+ (headline . org-rst-headline)
+ (horizontal-rule . org-rst-horizontal-rule)
+ (inline-src-block . org-rst-inline-src-block)
+ (inlinetask . org-rst-inlinetask)
+ (inner-template . org-rst-inner-template)
+ (italic . org-rst-italic)
+ (item . org-rst-item)
+ (keyword . org-rst-keyword)
+ (latex-environment . org-rst-latex-environment)
+ (latex-fragment . org-rst-latex-fragment)
+ (line-break . org-rst-line-break)
+ (link . org-rst-link)
+ (node-property . org-rst-node-property)
+ (paragraph . org-rst-paragraph)
+ (plain-list . org-rst-plain-list)
+ (plain-text . org-rst-plain-text)
+ (planning . org-rst-planning)
+ (property-drawer . org-rst-property-drawer)
+ (quote-block . org-rst-quote-block)
+ (radio-target . org-rst-radio-target)
+ (section . org-rst-section)
+ (special-block . org-rst-special-block)
+ (src-block . org-rst-src-block)
+ (statistics-cookie . org-rst-statistics-cookie)
+ (strike-through . org-rst-strike-through)
+ (subscript . org-rst-subscript)
+ (superscript . org-rst-superscript)
+ (table . org-rst-table)
+ (table-cell . org-rst-table-cell)
+ (table-row . org-rst-table-row)
+ (target . org-rst-target)
+ (template . org-rst-template)
+ (timestamp . org-rst-timestamp)
+ (underline . org-rst-underline)
+ (verbatim . org-rst-verbatim)
+ (verse-block . org-rst-verse-block)
+ ;; Pseudo objects and elements.
+ (latex-math-block . org-rst-math-block))
+ :menu-entry
+ '(?r "Export to reStructuredText"
+ ((?R "As reStructuredText buffer" org-rst-export-as-rst)
+ (?r "As reStructuredText file" org-rst-export-to-rst)))
+ :options-alist
+ '((:subtitle "SUBTITLE" nil nil parse)
+ (:rst-link-use-abs-url nil "rst-link-use-abs-url" org-rst-link-use-abs-url)
+ (:rst-inline-images nil nil org-rst-inline-images)
+ (:rst-inline-image-rules nil nil org-rst-inline-image-rules)
+ (:rst-link-org-files-as-rst nil nil org-rst-link-org-files-as-rst)
+ (:rst-link-home "RST_LINK_HOME" nil org-rst-link-home)
+ (:rst-link-use-ref-role nil nil org-rst-link-use-ref-role)
+ (:rst-extension nil nil org-rst-extension)
+ (:rst-file-link-use-ref-role nil nil org-rst-file-link-use-ref-role)
+ (:rst-text-markup-alist nil nil org-rst-text-markup-alist)
+ (:rst-quote-margin nil nil org-rst-quote-margin)
+ (:rst-headline-underline-characters nil nil org-rst-headline-underline-characters)
+ (:rst-headline-spacing nil nil org-rst-headline-spacing)
+ (:rst-paragraph-spacing nil nil org-rst-paragraph-spacing)
+ (:rst-format-drawer-function nil nil org-rst-format-drawer-function)
+ (:rst-format-inlinetask-function nil nil org-rst-format-inlinetask-function)
+ (:rst-code-block nil nil org-rst-code-block)
+ (:rst-pygments-langs nil nil org-rst-pygments-langs))
+ :filters-alist '((:filter-options . org-rst-math-block-options-filter)
+ (:filter-headline . org-rst-filter-headline-blank-lines)
+ (:filter-parse-tree . (org-rst-math-block-tree-filter
+ org-rst-separate-elements
+ org-rst-filter-paragraph-spacing))))
+
+
+;;; Internal Variables
+
+
+
+;;; User Configurable Variables
+
+(defgroup org-export-rst nil
+ "Options for exporting Org mode files to reStructuredText."
+ :tag "Org RST"
+ :group 'org-export)
+
+
+(defcustom org-rst-extension "rst"
+ "The extension for exported reStructuredText files."
+ :group 'org-export-rst
+ :type 'string)
+
+
+(defcustom org-rst-link-org-files-as-rst t
+ "Non-nil means make file links to `file.org' point to `file.rst'.
+When `org-mode' is exporting an `org-mode' file to reStructuredText,
+links to non-rst files are directly put into a href tag in
+reStructuredText.
+However, links to other Org mode files (recognized by the extension
+`.org.) should become links to the corresponding reStructuredText
+file, assuming that the linked `org-mode' file will also be
+converted to reStructuredText.
+When nil, the links still point to the plain \".org\" file."
+ :group 'org-export-rst
+ :type 'boolean)
+
+
+(defcustom org-rst-link-home ""
+ "Where should the \"HOME\" link of exported rst files lead?"
+ :group 'org-export-rst
+ :type '(string :tag "File or URL"))
+
+
+(defcustom org-rst-link-use-abs-url nil
+ "Should we prepend relative links with RST_LINK_HOME?"
+ :group 'org-export-rst
+ :type 'boolean)
+
+;;;; Links :: Inline images
+
+(defcustom org-rst-inline-images t
+ "Non-nil means inline images into exported reStructuredText.
+This is done using an image directive or an figure directive.
+When nil, an anchor with reference is used to link to the image."
+ :group 'org-export-rst
+ :type 'boolean)
+
+(defcustom org-rst-inline-image-rules
+ `(("file" . ,(regexp-opt '(".jpeg" ".jpg" ".png" ".gif" ".svg" ".svgz" ".webp" ".avif")))
+ ("http" . ,(regexp-opt '(".jpeg" ".jpg" ".png" ".gif" ".svg" ".svgz" ".webp" ".avif")))
+ ("https" . ,(regexp-opt '(".jpeg" ".jpg" ".png" ".gif" ".svg" ".svgz" ".webp" ".avif"))))
+ "Rules characterizing image files that can be inlined into reStructuredText.
+A rule consists in an association whose key is the type of link
+to consider, and value is a regexp that will be matched against
+link's path."
+ :group 'org-export-rst
+ :type '(alist :key-type (string :tag "Type")
+ :value-type (regexp :tag "Path")))
+
+(defcustom org-rst-link-use-ref-role nil
+ "Non-nil means export internal links using :ref: role."
+ :group 'org-export-rst
+ :type 'boolean)
+
+(defcustom org-rst-file-link-use-ref-role nil
+ "Non-nil means export internal file links using :ref: role."
+ :group 'org-export-rst
+ :type 'boolean)
+
+(defcustom org-rst-text-markup-alist '((bold . "**%s**")
+ (code . verb)
+ (italic . "*%s*")
+ (verbatim . verb))
+ "Alist of reStructredText expressions to convert text markup.
+
+The key must be a symbol among `bold', `code', `italic',
+`verbatim'. The value is a formatting string to
+wrap fontified text with.
+
+Value can also be set to the following symbols: `verb'.
+
+If no association can be found for a given markup, text will be
+returned as-is."
+ :group 'org-export-rst
+ :type 'alist
+ :options '(bold code italic verbatim))
+
+
+(defcustom org-rst-quote-margin 4
+ "Width of margin used for quoting text, in characters.
+This margin is applied on left side of the text."
+ :group 'org-export-rst
+ :type 'integer)
+
+
+(defcustom org-rst-headline-spacing '(1 . 1)
+ "Number of blank lines inserted around headlines.
+
+This variable can be set to a cons cell. In that case, its car
+represents the number of blank lines present before headline
+contents whereas its cdr reflects the number of blank lines after
+contents.
+
+A nil value replicates the number of blank lines found in the
+original Org buffer at the same place."
+ :group 'org-export-rst
+ :type '(choice
+ (const :tag "Replicate original spacing" nil)
+ (cons :tag "Set a uniform spacing"
+ (integer :tag "Number of blank lines before contents")
+ (integer :tag "Number of blank lines after contents"))))
+
+
+(defcustom org-rst-paragraph-spacing 'auto
+ "Number of white lines between paragraphs.
+If the value is an integer, add this number of blank lines
+between contiguous paragraphs. If is it the symbol `auto', keep
+the same number of blank lines as in the original document."
+ :group 'org-export-rst
+ :type '(choice
+ (integer :tag "Number of blank lines")
+ (const :tag "Preserve original spacing" auto)))
+
+
+(defcustom org-rst-headline-underline-characters '(?- ?~ ?^ ?: ?' ?\ ?_)
+ "List of underline characters for each headline level."
+ :group 'org-export-rst
+ :type '(repeat character))
+
+;;;; Drawers
+
+(defcustom org-rst-format-drawer-function (lambda (_name contents) contents)
+ "Function called to format a drawer in reStructuredText code.
+
+The function must accept two parameters:
+ NAME the drawer name, like \"LOGBOOK\"
+ CONTENTS the contents of the drawer.
+
+The function should return the string to be exported.
+
+For example, the variable could be set to the following function
+in order to mimic default behaviour:
+
+\(defun org-rst-format-drawer-default \(name contents\)
+ \"Format a drawer element for reStructuredText export.\"
+ contents\)"
+ :group 'org-export-rst
+ :type 'function)
+
+
+;;;; Inlinetasks
+
+(defcustom org-rst-format-inlinetask-function nil
+ "Function called to format an inlinetask in reStructuredText code.
+
+The function must accept six parameters:
+ TODO the todo keyword, as a string
+ TODO-TYPE the todo type, a symbol among `todo', `done' and nil.
+ PRIORITY the inlinetask priority, as a string
+ NAME the inlinetask name, as a string.
+ TAGS the inlinetask tags, as a list of strings.
+ CONTENTS the contents of the inlinetask, as a string.
+
+The function should return the string to be exported."
+ :group 'org-export-rst
+ :type 'function)
+
+
+;;;; Src blocks
+
+(defcustom org-rst-code-block 'code
+ "The directive used to export SRC-BLOCKs."
+ :group 'org-export-rst
+ :type '(choice
+ (const :tag "Use a code-block directive" code-block)
+ (const :tag "Use a code directive" code)
+ (const :tag "Use a literal block" nil))
+ :safe (lambda (s) (memq s '(code-block code nil)))
+ )
+
+(defcustom org-rst-pygments-langs
+ '((emacs-lisp "common-lisp") (lisp "common-lisp")
+ (cc "c++")
+ (cperl "perl")
+ (latex "tex")
+ (shell-script "bash")
+ (caml "ocaml")
+ (sqlite3 "sqlite"))
+ "Alist mapping languages to their listing language counterpart.
+The key is a symbol, the major mode symbol without the \"-mode\".
+The value is the string that should be inserted as the language
+parameter for the listings package. If the mode name and the
+listings name are the same, the language does not need an entry
+in this list - but it does not hurt if it is present."
+ :group 'org-export-rst
+ :type '(repeat
+ (list
+ (symbol :tag "Major mode ")
+ (string :tag "Pygments language"))))
+
+
+
+;;; Internal Functions
+
+(defun org-rst--justify-lines (s text-width how)
+ "Justify all lines in string S.
+TEXT-WIDTH is an integer specifying maximum length of a line.
+HOW determines the type of justification: it can be `left',
+`right', `full' or `center'."
+ (with-temp-buffer
+ (insert s)
+ (goto-char (point-min))
+ (let ((fill-column text-width)
+ ;; Disable `adaptive-fill-mode' so it doesn't prevent
+ ;; filling lines matching `adaptive-fill-regexp'.
+ (adaptive-fill-mode nil))
+ (while (< (point) (point-max))
+ (justify-current-line how)
+ (forward-line)))
+ (buffer-string)))
+
+
+(defun org-rst--indent-string (s width)
+ "Indent string S by WIDTH white spaces.
+Empty lines are not indented."
+ (when (stringp s)
+ (replace-regexp-in-string
+ "\\(^\\)\\(?:.*\\S-\\)" (make-string width ? ) s nil nil 1)))
+
+
+(defun org-rst--make-attribute-string (attributes)
+ "Return a list of attributes, as a string.
+ATTRIBUTES is a plist where values are either strings or nil. An
+attributes with a nil value will be omitted from the result."
+ (let (output)
+ (dolist (item attributes (mapconcat 'identity (nreverse output) "\n"))
+ (cond ((null item) (pop output))
+ ((symbolp item) (push (substring (symbol-name item) 1) output))
+ (t (let ((key (org-trim (car output)))
+ (value (replace-regexp-in-string "\"" "\\\""
+ (replace-regexp-in-string
+ "\\\\" "\\\\" (org-trim item)))))
+ (setcar output (format " :%s: %s" key value))))))))
+
+
+(defun org-rst--build-title
+ (element info &optional underline notags toc)
+ "Format ELEMENT title and return it.
+
+ELEMENT is either an `headline' or `inlinetask' element. INFO is
+a plist used as a communication channel.
+
+When optional argument UNDERLINE is non-nil, underline title,
+without the tags, according to `org-rst-underline'
+specifications.
+
+If optional argument NOTAGS is non-nil, no tags will be added to
+the title.
+
+When optional argument TOC is non-nil, use optional title if
+possible. It doesn't apply to `inlinetask' elements."
+ (let* ((headlinep (org-element-type-p element 'headline))
+ (numbers
+ ;; Numbering is specific to headlines.
+ (and headlinep (org-export-numbered-headline-p element info)
+ ;; All tests passed: build numbering string.
+ (concat
+ (mapconcat
+ 'number-to-string
+ (org-export-get-headline-number element info) ".")
+ " ")))
+ (text
+ (org-trim
+ (org-export-data
+ (if (and toc headlinep) (org-export-get-alt-title element info)
+ (org-element-property :title element))
+ info)))
+ (todo
+ (and (plist-get info :with-todo-keywords)
+ (let ((todo (org-element-property :todo-keyword element)))
+ (and todo (concat (org-export-data todo info) " ")))))
+ (tags (and (not notags)
+ (plist-get info :with-tags)
+ (let ((tag-list (org-export-get-tags element info)))
+ (and tag-list
+ (org-make-tag-string tag-list)))))
+ (priority
+ (and (plist-get info :with-priority)
+ (let ((char (org-element-property :priority element)))
+ (and char (format "(#%c) " char)))))
+ (first-part (concat numbers todo priority text)))
+ (concat
+ first-part
+ ;; Align tags, if any.
+ (when tags
+ (format
+ (format " %%%ds" (string-width tags))
+ tags))
+ ;; Maybe underline text, if ELEMENT type is `headline' and an
+ ;; underline character has been defined.
+ (when (and underline headlinep)
+ (let ((under-char
+ (nth (1- (org-export-get-relative-level element info))
+ org-rst-headline-underline-characters)))
+ (and under-char
+ (concat "\n"
+ (make-string (string-width first-part) under-char))))))))
+
+
+(defun org-rst--text-markup (text markup info)
+ "Format TEXT depending on MARKUP text markup.
+INFO is a plist used as a communication channel.
+See `org-rst-text-markup-alist' for details."
+ (let ((fmt (cdr (assq markup (plist-get info :rst-text-markup-alist))))
+ (text (replace-regexp-in-string "[ \t\n]+" " " text)))
+ (cond
+ ;; No format string: Return raw text.
+ ((not fmt) text)
+ ;; Handle the `verb' special case: Protect some
+ ;; special chars and use "\\" escape.
+ ((eq 'verb fmt)
+ (let ((rtn "")
+ char)
+ (while (string-match "\\`*" text)
+ (setq char (match-string 0 text))
+ (when (> (match-beginning 0) 0)
+ (setq rtn (concat rtn (substring text 0 (match-beginning 0)))))
+ (setq text (substring text (1+ (match-beginning 0))))
+ (setq char (concat "\\" char)
+ rtn (concat rtn char)))
+ (setq text (concat rtn text)
+ fmt "``%s``")
+ (format fmt text)))
+ ;; Else use format string.
+ (t (format fmt text)))))
+
+
+(defun org-rst--checkbox (item _info)
+ "Return checkbox string for ITEM or nil.
+INFO is a plist used as a communication channel."
+ ;(let ((utf8p (eq (plist-get info :ascii-charset) 'utf-8)))
+ ; (case (org-element-property :checkbox item)
+ ; (on (if utf8p "☑ " "[X] "))
+ ; (off (if utf8p "☐ " "[ ] "))
+ ; (trans (if utf8p "☒ " "[-] ")))))
+ (cl-case (org-element-property :checkbox item)
+ (on "☑ ")
+ (off "☐ ")
+ (trans "☒ ")))
+
+
+
+;;; Template
+
+(defun org-rst-template--document-title (info)
+ "Return document title, as a string.
+INFO is a plist used as a communication channel."
+ (let* (;; Links in the title will not be resolved later, so we make
+ ;; sure their path is located right after them.
+ (with-title (plist-get info :with-title))
+ (title (if with-title
+ (org-export-data (plist-get info :title) info)
+ ""))
+ (subtitle (if with-title
+ (org-export-data (plist-get info :subtitle) info)
+ ""))
+ (author (and (plist-get info :with-author)
+ (let ((auth (plist-get info :author)))
+ (and auth (org-export-data auth info)))))
+ (email (and (plist-get info :with-email)
+ (org-export-data (plist-get info :email) info)))
+ (date (and (plist-get info :with-date)
+ (org-export-data (org-export-get-date info) info)))
+ (titleline (make-string (string-width title) ?=))
+ (subtitleline (make-string (string-width subtitle) ?-))
+ (title (if (not (string= title ""))
+ (concat titleline "\n"
+ title "\n"
+ titleline "\n") ""))
+ (subtitle (if (not (string= subtitle ""))
+ (concat subtitleline "\n"
+ subtitle "\n"
+ subtitleline "\n") "")))
+ (cond
+ ((string= title "")
+ (concat
+ (when (org-string-nw-p author) (concat " :Author: " author "\n"))
+ (when (org-string-nw-p email) (concat " :Contact: " email "\n"))
+ (when (org-string-nw-p date) (concat " :Date: " date "\n"))))
+ (t
+ (concat
+ title
+ subtitle
+ (when (org-string-nw-p author) (concat "\n :Author: " author))
+ (when (org-string-nw-p email) (concat "\n :Contact: " email))
+ (when (org-string-nw-p date) (concat "\n :Date: " date))
+ "\n")))))
+
+
+(defun org-rst-template (contents info)
+ "Return complete document string after reStructuredText conversion.
+CONTENTS is the transcoded contents string. INFO is a plist
+holding export options."
+ (concat
+ ;; Build title block.
+ (concat (org-rst-template--document-title info)
+ "\n"
+ ;; 2. Table of contents.
+ (let ((depth (plist-get info :with-toc)))
+ (when depth ".. contents::\n\n")))
+ ;; Document's body.
+ contents
+ ;; Creator. Justify it to the bottom right.
+ (and (plist-get info :with-creater)
+ (concat
+ "\n :Creator: "
+ (plist-get info :creator) "\n"))))
+
+
+
+;;; Transcode Functions
+
+;;;; Bold
+
+(defun org-rst-bold (_bold contents info)
+ "Transcode BOLD from Org to reStructuredText.
+CONTENTS is the text with bold markup. INFO is a plist holding
+contextual information."
+ (org-rst--text-markup contents 'bold info))
+
+
+;;;; Center Block
+
+(defun org-rst-center-block (_center-block contents _info)
+ "Transcode a CENTER-BLOCK element from Org to reStructuredText.
+CONTENTS holds the contents of the center block. INFO is a plist
+holding contextual information."
+ contents)
+
+
+;;;; Clock
+
+(defun org-rst-clock (clock _contents _info)
+ "Transcode a CLOCK object from Org to reStructuredText.
+CONTENTS is nil. INFO is a plist holding contextual
+information."
+ (concat org-clock-string " "
+ (org-timestamp-translate (org-element-property :value clock))
+ (let ((time (org-element-property :duration clock)))
+ (and time
+ (concat " => "
+ (apply 'format
+ "%2s:%02s"
+ (org-split-string time ":")))))))
+
+
+;;;; Code
+
+(defun org-rst-code (code _contents info)
+ "Transcode a CODE object from Org to reStructuredText.
+CONTENTS is nil. INFO is a plist used as a communication
+channel."
+ (org-rst--text-markup (org-element-property :value code) 'code info))
+
+
+;;;; Drawer
+
+(defun org-rst-drawer (drawer contents info)
+ "Transcode a DRAWER element from Org to reStructuredText.
+CONTENTS holds the contents of the block. INFO is a plist
+holding contextual information."
+ (funcall (plist-get info :rst-format-drawer-function)
+ (org-element-property :drawer-name drawer)
+ contents))
+
+
+;;;; Dynamic Block
+
+(defun org-rst-dynamic-block (_dynamic-block contents _info)
+ "Transcode a DYNAMIC-BLOCK element from Org to reStructuredText.
+CONTENTS holds the contents of the block. INFO is a plist
+holding contextual information."
+ contents)
+
+
+;;;; Entity
+
+(defun org-rst-entity (entity _contents _info)
+ "Transcode an ENTITY object from Org to reStructuredText.
+CONTENTS are the definition itself. INFO is a plist holding
+contextual information."
+ (let ((ent (org-element-property :latex entity)))
+ (if (org-element-property :latex-math-p entity)
+ (format ":math:`%s`" ent)
+ (org-element-property :utf-8 entity))))
+
+
+;;;; Example Block
+
+(defun org-rst-example-block (example-block _contents _info)
+ "Transcode an EXAMPLE-BLOCK element from Org to reStructuredText.
+CONTENTS is nil. INFO is a plist holding contextual
+information."
+ (let* ((example (org-remove-indentation
+ (org-element-property :value example-block)))
+ (label (org-element-property :name example-block))
+ (attributes
+ (org-export-read-attribute :attr_rst example-block))
+ (class (plist-get attributes :class)))
+ (when example
+ (concat
+ "::\n"
+ (when class (format " :class: %s\n" class))
+ (when label (format " :name: %s\n" label))
+ "\n"
+ (org-rst--indent-string example org-rst-quote-margin)))))
+
+
+;;;; Export Block
+
+(defun org-rst-export-block (export-block _contents _info)
+ "Transcode a EXPORT-BLOCK element from Org to reStructuredText.
+CONTENTS is nil. INFO is a plist holding contextual information."
+ (when (member (org-element-property :type export-block) '("RST" "REST" "RESTRUCTUREDTEXT"))
+ (org-element-property :value export-block)))
+
+
+;;;; Export Snippet
+
+(defun org-rst-export-snippet (export-snippet _contents _info)
+ "Transcode a EXPORT-SNIPPET object from Org to reStructuredText.
+CONTENTS is nil. INFO is a plist holding contextual information."
+ (when (eq (org-export-snippet-backend export-snippet) 'rst)
+ (org-element-property :value export-snippet)))
+
+
+;;;; Footnote Definition
+
+;(defun org-rst-footnote-definition (footnote-definition contents info)
+; "Transcode a FOOTNOTE-DEFINITION element from Org to reStructuredText.
+;CONTENTS is nil. INFO is a plist holding contextual information."
+; (replace-regexp-in-string
+; "^" ".. "
+; (org-remove-indentation
+; (org-element-property :value footnote-definition))))
+
+
+;;;; Footnote Reference
+
+(defun org-rst-footnote-reference (footnote-reference _contents info)
+ "Transcode a FOOTNOTE-REFERENCE element from Org to reStructuredText.
+CONTENTS is nil. INFO is a plist holding contextual information."
+ (format " [%s]_ " (org-export-get-footnote-number footnote-reference info)))
+
+
+;;;; Headline
+
+(defun org-rst-headline (headline contents info)
+ "Transcode a HEADLINE element from Org to reStructuredText.
+CONTENTS holds the contents of the headline. INFO is a plist
+holding contextual information."
+ ;; Don't export footnote section, which will be handled at the end
+ ;; of the template.
+ (unless (org-element-property :footnote-section-p headline)
+ (let* (;; Blank lines between headline and its contents.
+ ;; `org-rst-headline-spacing', when set, overwrites
+ ;; original buffer's spacing.
+ (pre-blanks
+ (make-string
+ (if org-rst-headline-spacing (car org-rst-headline-spacing)
+ (org-element-property :pre-blank headline)) ?\n))
+ (id (org-element-property :ID headline))
+ (customid (org-element-property :CUSTOM_ID headline)))
+ (concat
+ (if customid
+ (format ".. _%s:\n\n" customid)
+ (if id (format ".. _%s:\n\n" id) ""))
+ (org-rst--build-title headline info 'underline)
+ "\n" pre-blanks
+ contents))))
+
+
+;;;; Horizontal Rule
+
+(defun org-rst-horizontal-rule (_horizontal-rule _contents _info)
+ "Transcode an HORIZONTAL-RULE object from Org to reStructuredText.
+CONTENTS is nil. INFO is a plist holding contextual information."
+ "\n------------\n")
+
+;;;; Inline Src Block
+
+(defun org-rst-inline-src-block (inline-src-block _contents info)
+ "Transcode an INLINE-SRC-BLOCK element from Org to reStructuredText.
+CONTENTS holds the contents of the item. INFO is a plist holding
+contextual information."
+ (org-rst--text-markup
+ (org-element-property :value inline-src-block) 'verbatim info))
+
+
+;;;; Inlinetask
+
+(defun org-rst-inlinetask (inlinetask contents info)
+ "Transcode an INLINETASK element from Org to reStructuredText.
+CONTENTS holds the contents of the block. INFO is a plist
+holding contextual information."
+ (let ((title (org-export-data (org-element-property :title inlinetask) info))
+ (todo (and (plist-get info :with-todo-keywords)
+ (let ((todo (org-element-property :todo-keyword inlinetask)))
+ (and todo (org-export-data todo info)))))
+ (todo-type (org-element-property :todo-type inlinetask))
+ (tags (and (plist-get info :with-tags)
+ (org-export-get-tags inlinetask info)))
+ (priority (and (plist-get info :with-priority)
+ (org-element-property :priority inlinetask))))
+ ;; If `org-rst-format-inlinetask-function' is provided, call it
+ ;; with appropriate arguments.
+ (if (functionp org-rst-format-inlinetask-function)
+ (funcall org-rst-format-inlinetask-function
+ todo todo-type priority title tags contents)
+ ;; Otherwise, use a default template.
+ (let ((full-title
+ (concat
+ (when todo (format "%s" todo))
+ (when priority (format "\#%c " priority))
+ title
+ (when tags (format ":%s:"
+ (mapconcat 'identity tags ":"))))))
+ (format (concat "%s\n\n"
+ "%s\n")
+ full-title contents)))))
+
+
+;;;; Inner template
+
+(defun org-rst-inner-template (contents info)
+ "Return complete document string after reStructuredText conversion.
+CONTENTS is the transcoded contents string. INFO is a plist
+holding export options."
+ (org-element-normalize-string
+ (concat
+ ;; 1. Document's body.
+ contents
+ ;; 2. Footnote definitions.
+ (let ((definitions (org-export-collect-footnote-definitions info)))
+ (when definitions
+ (concat
+ "\n\n"
+ (mapconcat
+ (lambda (ref)
+ (let* ((id (format ".. [%s] " (car ref)))
+ (def (nth 2 ref))
+ (lines (split-string (org-export-data def info) "\n+[ \t\n]*"))
+ (fntext (concat (car lines) "\n"
+ (apply 'concat (mapcar
+ #'(lambda (x) (if (> (length x) 0)
+ (concat (org-rst--indent-string x org-rst-quote-margin) "\n")))
+ (cdr lines)))))
+ )
+ (concat id fntext)))
+ definitions "\n")))))))
+
+
+;;;; Italic
+
+(defun org-rst-italic (_italic contents info)
+ "Transcode ITALIC from Org to reStructuredText.
+CONTENTS is the text with italic markup. INFO is a plist holding
+contextual information."
+ (org-rst--text-markup contents 'italic info))
+
+
+;;;; Item
+
+(defun org-rst-item (item contents info)
+ "Transcode ITEM element into reStructuredText format.
+CONTENTS is the item contents. INFO is a plist used as
+a communication channel."
+ (let* ((checkbox (org-rst--checkbox item info))
+ (list-type (org-element-property :type (org-element-parent item)))
+ (tag (let
+ ((tag (org-element-property :tag item)))
+ (and tag (concat (org-export-data tag info) checkbox))))
+ (bullet
+ ;; First parent of ITEM is always the plain-list. Get
+ ;; `:type' property from it.
+ (org-list-bullet-string
+ (cond
+ ((eq list-type 'ordered)
+ ;; Return correct number for ITEM, paying attention to
+ ;; counters.
+ (let* ((struct (org-element-property :structure item))
+ (bul (org-element-property :bullet item))
+ (num (number-to-string
+ (car (last (org-list-get-item-number
+ (org-element-begin item)
+ struct
+ (org-list-prevs-alist struct)
+ (org-list-parents-alist struct)))))))
+ (replace-regexp-in-string "[0-9]+" num bul)))
+ (tag "")
+ (t "-"))))
+ (width (if tag 4 (string-width bullet)))
+ )
+ (concat
+ (if tag tag (concat bullet checkbox))
+ (let ((contents (org-rst--indent-string contents width)))
+ (if (and (not tag)
+ (org-element-type-p (car (org-element-contents item)) 'paragraph))
+ (org-trim contents)
+ (concat "\n" contents))))))
+
+
+;;;; Keyword
+
+(defun org-rst-keyword (keyword _contents _info)
+ "Transcode a KEYWORD element from Org to reStructuredText.
+CONTENTS is nil. INFO is a plist holding contextual information."
+ (let ((key (org-element-property :key keyword))
+ (value (org-element-property :value keyword)))
+ (cond
+ ((string= key "RST") value))))
+
+
+;;;; Latex Environment
+
+(defun org-rst-latex-environment (latex-environment _contents info)
+ "Transcode a LATEX-ENVIRONMENT element from Org to reStructuredText.
+CONTENTS is nil. INFO is a plist holding contextual
+information."
+ (when (plist-get info :with-latex)
+ (org-remove-indentation (org-element-property :value latex-environment))))
+
+
+;;;; Latex Fragment
+
+(defun org-rst-latex-fragment (latex-fragment _contents _info)
+ "Transcode a LATEX-FRAGMENT object from Org to reStructuredText.
+CONTENTS is nil. INFO is a plist holding contextual
+information."
+ (let ((value (org-element-property :value latex-fragment)))
+ (cond
+ ((string-match "\\`\\(\\$\\{2\\}\\)\\([^\000]*\\)\\1\\'" value)
+ (format ".. math::\n\n%s"
+ (org-rst--indent-string
+ (org-trim (match-string 2 value)) org-rst-quote-margin)))
+ ((string-match "\\`\\(\\$\\{1\\}\\)\\([^\000]*\\)\\1\\'" value)
+ (format ":math:`%s`" (org-trim (match-string 2 value))))
+ ((string-match "\\`\\\\(\\([^\000]*\\)\\\\)\\'" value)
+ (format ":math:`%s`" (org-trim (match-string 1 value))))
+ ((string-match "\\`\\\\\\[\\([^\000]*\\)\\\\\\]\\'" value)
+ (format "\.. math::\n\n%s"
+ (org-rst--indent-string
+ (org-trim (match-string 1 value)) org-rst-quote-margin)))
+ (t value))))
+
+
+;;;; Line Break
+
+(defun org-rst-line-break (_line-break _contents _info)
+ "Transcode a LINE-BREAK object from Org to reStructuredText.
+CONTENTS is nil. INFO is a plist holding contextual
+ information."
+ hard-newline)
+
+
+;;;; Link
+
+(defun org-rst-inline-image-p (link info)
+ "Non-nil when LINK is meant to appear as an image.
+INFO is a plist used as a communication channel. LINK is an
+inline image when it has no description and targets an image
+file (see `org-rst-inline-image-rules' for more information), or
+if its description is a single link targeting an image file."
+ (if (not (org-element-contents link))
+ (org-export-inline-image-p
+ link (plist-get info :rst-inline-image-rules))
+ (not
+ (let ((link-count 0))
+ (org-element-map (org-element-contents link)
+ (cons 'plain-text org-element-all-objects)
+ (lambda (obj)
+ (cl-case (org-element-type obj)
+ (plain-text (org-string-nw-p obj))
+ (link (if (= link-count 1) t
+ (cl-incf link-count)
+ (not (org-export-inline-image-p
+ obj (plist-get info :rst-inline-image-rules)))))
+ (otherwise t)))
+ info t)))))
+
+
+(defun my-org-export-inline-image-p (link &optional rules)
+ (let ((case-fold-search t)
+ (rules (or rules org-export-default-inline-image-rule)))
+ (catch 'exit
+ (mapc
+ (lambda (rule)
+ (if (string-match (cdr rule) link)
+ (throw 'exit t)))
+ rules)
+ ;; Return nil if no rule matched.
+ nil)))
+
+
+(defun org-rst-link (link desc info)
+ "Transcode a LINK object from Org to reStructuredText.
+
+DESC is the description part of the link, or the empty string.
+INFO is a plist holding contextual information."
+ (let* ((home (when (plist-get info :rst-link-home)
+ (org-trim (plist-get info :rst-link-home))))
+ (use-abs-url (plist-get info :rst-link-use-abs-url))
+ (link-org-files-as-rst-maybe
+ (function
+ (lambda (raw-path info)
+ "Treat links to `file.org' as links to `file.rst', if needed.
+ See `org-rst-link-org-files-as-rst'."
+ (cond
+ ((and (plist-get info :rst-link-org-files-as-rst)
+ (string= ".org"
+ (downcase (file-name-extension raw-path "."))))
+ (concat (file-name-sans-extension raw-path) "."
+ (plist-get info :rst-extension)))
+ (t raw-path)))))
+ (type (org-element-property :type link))
+ (search-option (org-element-property :search-option link))
+ (raw-path (org-element-property :path link))
+ ;; Ensure DESC really exists, or set it to nil.
+ (desc (and (not (string= desc "")) desc))
+ (path (cond
+ ((string= type "file")
+ ;; Treat links to ".org" files as ".rst", if needed.
+ (setq raw-path
+ (funcall link-org-files-as-rst-maybe raw-path info))
+ (cond ((and home use-abs-url)
+ (setq raw-path
+ (concat (file-name-as-directory home) raw-path)))
+ (t raw-path)))
+ (t (concat type ":" raw-path))))
+ (attributes-plist
+ (org-combine-plists
+ ;; Extract attributes from parent's paragraph. HACK: Only
+ ;; do this for the first link in parent (inner image link
+ ;; for inline images). This is needed as long as
+ ;; attributes cannot be set on a per link basis.
+ (let* ((parent (org-element-parent-element link))
+ (link (let ((container (org-element-parent link)))
+ (if (and (org-element-type-p container 'link)
+ (org-rst-inline-image-p link info))
+ container
+ link))))
+ (and (eq link (org-element-map parent 'link #'identity info t))
+ (org-export-read-attribute :attr_rst parent)))
+ ;; Also add attributes from link itself. Currently, those
+ ;; need to be added programmatically before `org-rst-link'
+ ;; is invoked, for example, by backends building upon HTML
+ ;; export.
+ (org-export-read-attribute :attr_rst link)))
+ (attributes
+ (let ((attr (org-rst--make-attribute-string attributes-plist)))
+ (if (org-string-nw-p attr) (concat "\n" attr "\n") ""))))
+ (cond
+ ;; Link type is handled by a special function.
+ ((org-export-custom-protocol-maybe link desc 'rst info))
+ ;; Image file.
+ ((and (plist-get info :rst-inline-images)
+ (org-export-inline-image-p
+ link (plist-get info :rst-inline-image-rules)))
+ (let* ((ipath (if (not (file-name-absolute-p raw-path)) raw-path
+ (expand-file-name raw-path)))
+ (caption (org-export-get-caption
+ (org-element-parent-element link)))
+ (linkname
+ (org-element-property :name (org-element-parent-element link)))
+ (label (if linkname (format ".. _%s:\n\n" linkname) "")))
+ (if caption (format "%s.. figure:: %s%s\n\n %s\n"
+ label ipath attributes
+ (org-export-data caption info))
+ (format "%s.. image:: %s%s\n" label ipath attributes))))
+ ((and (plist-get info :rst-inline-images)
+ desc
+ (my-org-export-inline-image-p
+ desc (plist-get info :rst-inline-image-rules)))
+ (format ".. image:: %s\n :target: %s%s" desc path attributes))
+ ;; Radio link: Transcode target's contents and use them as link's
+ ;; description.
+ ((string= type "radio")
+ (let ((destination (org-export-resolve-radio-link link info)))
+ (when destination
+ (format "`%s <%s>`_"
+ path
+ (org-export-data (org-element-contents destination) info)))))
+ ;; Links pointing to a headline: Find destination and build
+ ;; appropriate referencing command.
+ ((member type '("custom-id" "fuzzy" "id"))
+ (let ((destination (if (string= type "fuzzy")
+ (org-export-resolve-fuzzy-link link info)
+ (org-export-resolve-id-link link info))))
+ (cl-case (org-element-type destination)
+ ;; Id link points to an external file.
+ (plain-text
+ (if desc (format "`%s <%s>`_" desc destination)
+ (format "`%s`_" destination)))
+ ;; Fuzzy link points nowhere.
+ ;; ('nil
+ ;; (let ((rawlink
+ ;; (org-export-data (org-element-property :raw-link link) info)))
+ ;; (if desc (format "`%s <%s>`_" desc rawlink)
+ ;; (format "`%s`_" rawlink))))
+ ;; LINK points to a headline.
+ (headline
+ (if (member type '("custom-id" "id"))
+ (if (plist-get info :rst-link-use-ref-role)
+ (if desc (format " :ref:`%s <%s>`" desc raw-path)
+ (format " :ref:`%s`" raw-path))
+ (format "`%s`_" raw-path))
+ (format "`%s`_" (org-rst--build-title destination info nil))))
+ ;; Fuzzy link points to a target.
+ (otherwise
+ (if (not desc) (format "`%s`_" raw-path)
+ (format "`%s <%s>`_" desc raw-path))))))
+ ;; Coderef: replace link with the reference name or the
+ ;; equivalent line number. It is not supported in ReST.
+ ((string= type "coderef")
+ (format (org-export-get-coderef-format path desc)
+ (org-export-resolve-coderef path info)))
+ ((and (plist-get info :rst-file-link-use-ref-role)
+ (string= type "file")
+ search-option)
+ (let ((ref (replace-regexp-in-string "^#" "" search-option)))
+ (if desc
+ (format ":ref:`%s <%s>`" desc ref)
+ (format ":ref:`%s`" ref))))
+ ;; Link type is handled by a special function.
+ ;((functionp (setq protocol (nth 2 (assoc type org-link-protocols))))
+ ; (funcall protocol (org-link-unescape path) desc 'latex))
+ ;; External link with a description part.
+ ((and path desc) (format "`%s <%s>`_" desc path))
+ ;; External link without a description part.
+ (path (format "`%s <%s>`_"
+ (replace-regexp-in-string "^//" "" path) path))
+ ;; No path, only description. Try to do something useful.
+ (t (format "`%s <%s>`_" desc desc)))))
+
+
+;;;; Node Property
+
+(defun org-rst-node-property (node-property _contents _info)
+ "Transcode a NODE-PROPERTY element from Org to reStructuredText.
+CONTENTS is nil. INFO is a plist holding contextual
+information."
+ (format "%s:%s"
+ (org-element-property :key node-property)
+ (let ((value (org-element-property :value node-property)))
+ (if value (concat " " value) ""))))
+
+
+;;;; Paragraph
+
+(defun org-rst-paragraph (_paragraph contents info)
+ "Transcode a PARAGRAPH element from Org to reStructuredText.
+CONTENTS is the contents of the paragraph, as a string. INFO is
+the plist used as a communication channel."
+ (when (plist-get info :preserve-breaks)
+ (let ((lines (split-string contents "\n+[ \t\n]*")))
+ (cond ((> (length lines) 2)
+ (setq contents (apply 'concat (mapcar
+ #'(lambda (x) (if (> (length x) 0) (concat "| " x "\n") x))
+ lines)))))))
+ contents)
+
+
+;;;; Plain List
+
+(defun org-rst-plain-list (_plain-list contents _info)
+ "Transcode a PLAIN-LIST element from Org to reStructuredText.
+CONTENTS is the contents of the list. INFO is a plist holding
+contextual information."
+ contents)
+
+
+;;;; Plain Text
+
+(defun org-rst-plain-text (text info)
+ "Transcode a TEXT string from Org to reStructuredText.
+TEXT is the string to transcode. INFO is a plist holding
+contextual information."
+ (when (plist-get info :with-smart-quotes)
+ (setq text (org-export-activate-smart-quotes text :utf-8 info)))
+ ;; Protect `, *, _ and \
+ (setq text (replace-regexp-in-string "[`*_\\]" "\\\\\\&" text))
+ ;; Protect ..
+ (setq text (replace-regexp-in-string "^[\s-]*\\.\\. [^\\[]" "\\\\\\&" text))
+ ;; Protect ::
+ (setq text (replace-regexp-in-string "::" "\\\\:\\\\:" text))
+ ;; Return value.
+ text)
+
+
+;;;; Planning
+
+(defun org-rst-planning (planning _contents _info)
+ "Transcode a PLANNING element from Org to reStructuredText.
+CONTENTS is nil. INFO is a plist used as a communication
+channel."
+ (mapconcat
+ 'identity
+ (delq nil
+ (list (let ((closed (org-element-property :closed planning)))
+ (when closed
+ (concat org-closed-string " "
+ (org-timestamp-translate closed))))
+ (let ((deadline (org-element-property :deadline planning)))
+ (when deadline
+ (concat org-deadline-string " "
+ (org-timestamp-translate deadline))))
+ (let ((scheduled (org-element-property :scheduled planning)))
+ (when scheduled
+ (concat org-scheduled-string " "
+ (org-timestamp-translate scheduled))))))
+ " "))
+
+
+;;;; Property Drawer
+
+(defun org-rst-property-drawer (_property-drawer contents _info)
+ "Transcode a PROPERTY-DRAWER element from Org to reStructuredText.
+CONTENTS holds the contents of the drawer. INFO is a plist
+holding contextual information."
+ (when (org-string-nw-p contents)
+ (concat
+ "::\n\n"
+ (org-rst--indent-string contents org-rst-quote-margin))))
+
+
+;;;; Pseudo Object: LaTeX Math Block
+
+;; `latex-math-block' objects have the following property:
+;; `:post-blank'.
+
+(defun org-rst--wrap-latex-math-block (data info)
+ "Merge contiguous math objects in a pseudo-object container.
+DATA is a parse tree or a secondary string. INFO is a plist
+containing export options. Modify DATA by side-effect and return it."
+ (let ((valid-object-p
+ (function
+ ;; Non-nil when OBJ can be added to the latex math block.
+ (lambda (obj)
+ (cl-case (org-element-type obj)
+ (entity (org-element-property :latex-math-p obj))
+ (latex-fragment
+ (let ((value (org-element-property :value obj)))
+ (or (string-match-p "\\`\\\\([^\000]*\\\\)\\'" value)
+ (string-match-p "\\`\\$[^\000]*\\$\\'" value)
+ (string-match-p "\\`\\\\\\[[^\000]*\\\\\\]\\'" value))))
+ ((subscript superscript) t))))))
+ (org-element-map data '(entity latex-fragment subscript superscript)
+ (lambda (object)
+ ;; Skip objects already wrapped.
+ (when (and (not (org-element-type-p
+ (org-element-property :parent object)
+ 'latex-math-block))
+ (funcall valid-object-p object))
+ (let ((math-block (list 'latex-math-block nil))
+ (next-elements (org-export-get-next-element object info t))
+ (last object))
+ ;; Wrap MATH-BLOCK around OBJECT in DATA.
+ (org-element-insert-before math-block object)
+ (org-element-extract object)
+ (org-element-adopt-elements math-block object)
+ (when (zerop (or (org-element-property :post-blank object) 0))
+ ;; MATH-BLOCK swallows consecutive math objects.
+ (catch 'exit
+ (dolist (next next-elements)
+ (if (not (funcall valid-object-p next)) (throw 'exit nil)
+ (org-element-extract next)
+ (org-element-adopt-elements math-block next)
+ ;; Eschew the case: \beta$x$ -> \(\betax\).
+ (unless (memq (org-element-type next)
+ '(subscript superscript))
+ (org-element-put-property last :post-blank 1))
+ (setq last next)
+ (when (> (or (org-element-property :post-blank next) 0) 0)
+ (throw 'exit nil))))))
+ (org-element-put-property
+ math-block :post-blank (org-element-property :post-blank last)))))
+ info nil '(subscript superscript latex-math-block) t)
+ ;; Return updated DATA.
+ data))
+
+(defun org-rst-math-block-tree-filter (tree _backend info)
+ (org-rst--wrap-latex-math-block tree info))
+
+(defun org-rst-math-block-options-filter (info _backend)
+ (dolist (prop '(:author :date :title) info)
+ (plist-put info prop
+ (org-rst--wrap-latex-math-block (plist-get info prop) info))))
+
+(defun org-rst-math-block (_math-block contents _info)
+ "Transcode a MATH-BLOCK object from Org to reStructuredText.
+CONTENTS is a string. INFO is a plist used as a communication
+channel."
+ (let* ((value (org-trim contents))
+ (value
+ (if (> (string-width value) 2)
+ (if (string= ".." (substring value 0 2))
+ (format "\n\n%s\n\n" value)
+ value))))
+ (format "%s" value)))
+
+
+;;;; Quote Block
+
+(defun org-rst-quote-block (quote-block contents _info)
+ "Transcode a QUOTE-BLOCK element from Org to reStructuredText.
+CONTENTS holds the contents of the block. INFO is a plist
+holding contextual information."
+ (let* ((attributes
+ (org-export-read-attribute :attr_rst quote-block))
+ (directive (plist-get attributes :directive))
+ (title (plist-get attributes :title))
+ (subtitle (plist-get attributes :subtitle))
+ (margin (plist-get attributes :margin))
+ (class (plist-get attributes :class))
+ (label (org-element-property :name quote-block)))
+ (cond ((and margin contents)
+ (org-rst--indent-string contents (string-to-number margin)))
+ (directive
+ (concat
+ (format ".. %s::" directive)
+ (when title (format " %s" title))
+ "\n"
+ (when (and subtitle (string= "sidebar" directive))
+ (format " :subtitle: %s\n" subtitle))
+ (when (and class (not (string= "container" directive)))
+ (format " :class: %s\n" class))
+ (when label (format " :name: %s\n" label))
+ "\n"
+ (when contents
+ (org-rst--indent-string contents org-rst-quote-margin))))
+ (t
+ (concat
+ "::\n"
+ (when class (format " :class: %s\n" class))
+ (when label (format " :name: %s\n" label))
+ "\n"
+ (when contents
+ (org-rst--indent-string contents org-rst-quote-margin)))))))
+
+
+;;;; Radio Target
+
+(defun org-rst-radio-target (_radio-target contents _info)
+ "Transcode a RADIO-TARGET object from Org to reStructuredText.
+CONTENTS is the contents of the target. INFO is a plist holding
+contextual information."
+ contents)
+
+
+;;;; Section
+
+(defun org-rst-section (_section contents _info)
+ "Transcode a SECTION element from Org to reStructuredText.
+CONTENTS holds the contents of the section. INFO is a plist
+holding contextual information."
+ contents)
+
+
+;;;; Special Block
+
+(defun org-rst-special-block (special-block contents _info)
+ "Transcode a SPECIAL-BLOCK element from Org to reStructuredText.
+CONTENTS holds the contents of the block. INFO is a plist
+holding contextual information."
+ (let* ((attributes
+ (org-export-read-attribute :attr_rst special-block))
+ (title (plist-get attributes :title))
+ (class (plist-get attributes :class))
+ (label (org-element-property :name special-block))
+ (type (org-element-property :type special-block)))
+ (concat
+ (format ".. %s::" type)
+ (when title (format " %s" title))
+ "\n"
+ (when class (format " :class: %s\n" class))
+ (when label (format " :name: %s\n" label))
+ "\n"
+ (when contents
+ (org-rst--indent-string contents org-rst-quote-margin)))))
+
+;;;; Src Block
+
+(defun org-rst-src-block (src-block _contents info)
+ "Transcode a SRC-BLOCK element from Org to reStructuredText.
+CONTENTS holds the contents of the item. INFO is a plist holding
+contextual information."
+ (when (org-string-nw-p (org-element-property :value src-block))
+ (let* ((lang (org-element-property :language src-block))
+ (label (org-element-property :name src-block))
+ (value (org-remove-indentation
+ (org-element-property :value src-block)))
+ (num-start (org-export-get-loc src-block info))
+ (codeblockd (plist-get info :rst-code-block))
+ (attributes
+ (org-export-read-attribute :attr_rst src-block))
+ (class (plist-get attributes :class)))
+ (cond
+ ;; Case 1.
+ ((eq codeblockd 'code-block)
+ (let ((lst-lang
+ (or (cadr (assq (intern lang) org-rst-pygments-langs)) lang)))
+ (concat
+ (format ".. code-block:: %s\n" lst-lang)
+ (when num-start (format " :lineno-start: %s\n" (1+ num-start)))
+ (when class (format " :class: %s\n" class))
+ (when label (format " :name: %s\n" label))
+ "\n"
+ (org-rst--indent-string value org-rst-quote-margin))))
+ ;; Case 2. code.
+ ((eq codeblockd 'code)
+ (let ((lst-lang
+ (or (cadr (assq (intern lang) org-rst-pygments-langs)) lang)))
+ (concat
+ (format ".. code:: %s\n" lst-lang)
+ (when num-start (format " :number-lines: %s\n" (1+ num-start)))
+ (when class (format " :class: %s\n" class))
+ (when label (format " :name: %s\n" label))
+ "\n"
+ (org-rst--indent-string value org-rst-quote-margin))))
+ (t
+ (concat
+ "::\n"
+ (when class (format " :class: %s\n" class))
+ (when label (format " :name: %s\n" label))
+ "\n"
+ (org-rst--indent-string value org-rst-quote-margin)))))))
+
+
+;;;; Statistics Cookie
+
+(defun org-rst-statistics-cookie (statistics-cookie _contents _info)
+ "Transcode a STATISTICS-COOKIE object from Org to reStructuredText.
+CONTENTS is nil. INFO is a plist holding contextual information."
+ (org-element-property :value statistics-cookie))
+
+
+;;;; Strike-Through
+
+(defun org-rst-strike-through (_strike-through contents _info)
+ "Transcode STRIKE-THROUGH from Org to reStructuredText.
+CONTENTS is the text with strike-through markup. INFO is a plist
+holding contextual information."
+ contents)
+
+
+;;;; Subscript
+
+(defun org-rst-subscript (_subscript contents _info)
+ "Transcode a SUBSCRIPT object from Org to reStructuredText.
+CONTENTS is the contents of the object. INFO is a plist holding
+contextual information."
+ (format "\\ :sub:`%s`\\ " contents))
+
+
+;;;; Superscript
+
+(defun org-rst-superscript (_superscript contents _info)
+ "Transcode a SUPERSCRIPT object from Org to reStructuredText.
+CONTENTS is the contents of the object. INFO is a plist holding
+contextual information."
+ (format "\\ :sup:`%s`\\ " contents))
+
+
+;;;; Table
+
+(defun org-rst-table-first-row-data-cells (table info)
+ "Transcode the first row of TABLE.
+INFO is a plist used as a communication channel."
+ (let ((table-row
+ (org-element-map table 'table-row
+ (lambda (row)
+ (unless (eq (org-element-property :type row) 'rule) row))
+ info 'first-match))
+ (special-column-p (org-export-table-has-special-column-p table)))
+ (if (not special-column-p) (org-element-contents table-row)
+ (cdr (org-element-contents table-row)))))
+
+(defun org-rst-table (table contents info)
+ "Transcode a TABLE element from Org to reStructuredText.
+CONTENTS is the contents of the table. INFO is a plist holding
+contextual information."
+ (let* ((caption (org-export-get-caption table))
+ (attributes
+ (org-export-read-attribute :attr_rst table))
+ (class (plist-get attributes :class))
+ (label (org-element-property :name table)))
+ (concat
+ (if caption (format ".. table:: %s\n" (org-export-data caption info))
+ ".. table::\n")
+ (when class (format " :class: %s\n" class))
+ (when label (format " :name: %s\n" label))
+ "\n"
+ (org-rst--indent-string contents org-rst-quote-margin))))
+
+
+;;;; Table Cell
+
+(defun org-rst--table-cell-width (table-cell info)
+ "Return width of TABLE-CELL.
+
+INFO is a plist used as a communication channel.
+
+Width of a cell is determined either by a width cookie in the
+same column as the cell, or by the maximum cell's length in that
+column."
+ (let* ((row (org-element-parent table-cell))
+ (table (org-element-parent row))
+ (col (let ((cells (org-element-contents row)))
+ (- (length cells) (length (memq table-cell cells)))))
+ (cache
+ (or (plist-get info :rst-table-cell-width-cache)
+ (plist-get (setq info
+ (plist-put info :rst-table-cell-width-cache
+ (make-hash-table :test 'equal)))
+ :rst-table-cell-width-cache)))
+ (key (cons table col)))
+ (or (gethash key cache)
+ (puthash
+ key
+ (let ((cookie-width (org-export-table-cell-width table-cell info)))
+ (or cookie-width
+ (let ((contents-width
+ (let ((max-width 0))
+ (org-element-map table 'table-row
+ (lambda (row)
+ (setq max-width
+ (max (string-width
+ (org-export-data
+ (org-element-contents
+ (elt (org-element-contents row) col))
+ info))
+ max-width)))
+ info)
+ max-width)))
+ (cond ((not cookie-width) contents-width)
+ (t cookie-width)))))
+ cache))))
+
+
+(defun org-rst-table-cell (table-cell contents info)
+ "Transcode a TABLE-CELL object from Org to reStructuredText.
+CONTENTS is the cell contents. INFO is a plist used as
+a communication channel."
+ (let ((width (org-rst--table-cell-width table-cell info)))
+ ;; Align contents correctly within the cell.
+ (let* ((indent-tabs-mode nil)
+ (data
+ (if contents
+ (org-rst--justify-lines
+ contents width
+ (org-export-table-cell-alignment table-cell info)) "\\")))
+ (setq contents
+ (concat data
+ (make-string (max 0 (- width (string-width data))) ? ))))
+ ;; Return cell.
+ (concat (format " %s " contents)
+ (when (org-export-get-next-element table-cell info) "|"))))
+
+
+;;;; Table Row
+
+(defun org-rst-table-row (table-row contents info)
+ "Transcode a TABLE-ROW element from Org to reStructuredText.
+CONTENTS is the row contents. INFO is a plist used as
+a communication channel."
+ (let ((borders (org-export-table-cell-borders
+ (org-element-map table-row 'table-cell 'identity info t)
+ info)))
+ (if (not (and (memq 'bottom borders) (memq 'top borders)))
+ (let* ((rowgroup-number (org-export-table-row-group table-row info))
+ (row-number (org-export-table-row-number table-row info))
+ (line-bit
+ (cond
+ ((not (= 1 rowgroup-number))
+ ?-)
+ ((org-export-table-has-header-p
+ (org-element-lineage table-row 'table) info)
+ ?=)
+ (t ?-)))
+ (makeline
+ (function
+ (lambda (_rowcontents linebit)
+ (format "+%s+"
+ (mapconcat
+ 'identity
+ (mapcar
+ (lambda (table-cell)
+ (make-string (string-width table-cell)
+ linebit))
+ (split-string contents "|"))
+ "+")))))
+ (hline (format "+%s+"
+ (mapconcat
+ 'identity
+ (mapcar
+ (lambda (table-cell)
+ (make-string (string-width table-cell)
+ line-bit))
+ (split-string contents "|"))
+ "+"))))
+ (concat
+ (when (= 0 row-number)
+ (concat (funcall makeline contents ?-) "\n"))
+ "|" contents "|\n" hline))
+ nil
+ )))
+
+
+;;;; Target
+
+(defun org-rst-target (target _contents _info)
+ "Transcode a TARGET object from Org to reStructuredText.
+CONTENTS is nil. INFO is a plist holding contextual
+information."
+ (format " _`%s` " (org-element-property :value target)))
+
+
+;;;; Timestamp
+
+(defun org-rst-timestamp (timestamp _contents info)
+ "Transcode a TIMESTAMP object from Org to reStructuredText.
+CONTENTS is nil. INFO is a plist holding contextual
+information."
+ (org-rst-plain-text (org-timestamp-translate timestamp) info))
+
+
+;;;; Underline
+
+(defun org-rst-underline (_underline contents _info)
+ "Transcode UNDERLINE from Org to reStructuredText.
+CONTENTS is the text with underline markup. INFO is a plist
+holding contextual information."
+ contents)
+
+
+;;;; Verbatim
+
+(defun org-rst-verbatim (verbatim _contents info)
+ "Transcode a VERBATIM object from Org to reStructredText.
+CONTENTS is nil. INFO is a plist used as a communication
+channel."
+ (org-rst--text-markup (org-element-property :value verbatim) 'verbatim info))
+
+
+;;;; Verse Block
+
+(defun org-rst-verse-block (_verse-block contents _info)
+ "Transcode a VERSE-BLOCK element from Org to reStructuredText.
+CONTENTS is verse block contents. INFO is a plist holding
+contextual information."
+ (let ((lines (split-string contents "\n")))
+ (cond ((> (length lines) 0)
+ (mapconcat
+ (function (lambda (x) (if (> (string-width x) 0)
+ (concat "| " x "\n") ""))) lines "")))))
+
+
+;;; Filters
+
+(defun org-rst-separate-elements (tree _backend _info)
+ "Make sure elements are separated by at least one blank line.
+
+TREE is the parse tree being exported. BACKEND is the export
+back-end used. INFO is a plist used as a communication channel.
+
+Assume BACKEND is `rst'."
+ (org-element-map tree org-element-all-elements
+ (lambda (elem)
+ (unless (or (org-element-type-p elem 'org-data)
+ (org-element-type-p elem 'table-row))
+ (org-element-put-property
+ elem :post-blank
+ (let ((post-blank (org-element-property :post-blank elem)))
+ (if (not post-blank) 1 (max 1 post-blank)))))))
+ ;; Return updated tree.
+ tree)
+
+(defun org-rst-filter-headline-blank-lines (headline _back-end _info)
+ "Filter controlling number of blank lines after a headline.
+
+HEADLINE is a string representing a transcoded headline.
+BACK-END is symbol specifying back-end used for export. INFO is
+plist containing the communication channel.
+
+This function only applies to `rst' back-end. See
+`org-rst-headline-spacing' for information."
+ (if (not org-rst-headline-spacing) headline
+ (let ((blanks (make-string (1+ (cdr org-rst-headline-spacing)) ?\n)))
+ (replace-regexp-in-string "\n\\(?:\n[ \t]*\\)*\\'" blanks headline))))
+
+(defun org-rst-filter-paragraph-spacing (tree _back-end info)
+ "Filter controlling number of blank lines between paragraphs.
+
+TREE is the parse tree. BACK-END is the symbol specifying
+back-end used for export. INFO is a plist used as
+a communication channel.
+
+See `org-rst-paragraph-spacing' for information."
+ (when (wholenump org-rst-paragraph-spacing)
+ (org-element-map tree 'paragraph
+ (lambda (p)
+ (when (org-element-type-p (org-export-get-next-element p info)
+ 'paragraph)
+ (org-element-put-property
+ p :post-blank org-rst-paragraph-spacing)))))
+ tree)
+
+
+
+;;; End-user functions
+
+;;;###autoload
+(defun org-rst-export-as-rst
+ (&optional async subtreep visible-only body-only ext-plist)
+ "Export current buffer to a reStructuredText 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 headline 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 RST Export*\", which will
+be displayed when `org-export-show-temporary-export-buffer' is
+non-nil."
+ (interactive)
+ (org-export-to-buffer 'rst "*Org RST Export*"
+ async subtreep visible-only body-only ext-plist (lambda () (rst-mode))))
+
+;;;###autoload
+(defun org-rst-convert-region-to-rst ()
+ "Assume the current region has Org syntax, and convert it to
+reStructuredText.
+This can be used in any buffer. For example, you can write an
+itemized list in Org syntax in a Markdown buffer and use this command
+to convert it."
+ (interactive)
+ (org-export-replace-region-by 'rst))
+
+(defalias 'org-export-region-to-rst #'org-rst-convert-region-to-rst)
+
+;;;###autoload
+(defun org-rst-export-to-rst
+ (&optional async subtreep visible-only body-only ext-plist)
+ "Export current buffer to a reStructuredText 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 headline properties
+first.
+
+When optional argument VISIBLE-ONLY is non-nil, don't export
+contents of hidden elements.
+
+Return output file's name."
+ (interactive)
+ (let* ((extension (concat "." (or (plist-get ext-plist :rst-extension)
+ org-rst-extension
+ "rst")))
+ (file (org-export-output-file-name extension subtreep)))
+ (org-export-to-file 'rst file
+ async subtreep visible-only body-only ext-plist)))
+
+;;;###autoload
+(defun org-rst-publish-to-rst (plist filename pub-dir)
+ "Publish an org file to reStructuredText.
+
+FILENAME is the filename of the Org file to be published. PLIST
+is the property list for the given project. PUB-DIR is the
+publishing directory.
+
+Return output file name."
+ (org-publish-org-to 'rst filename ".rst" plist pub-dir))
+
+
+;;; provide
+
+(provide 'ox-rst)
+
+;;; ox-rst.el ends here
diff --git a/lisp/update-autoloads.el b/lisp/update-autoloads.el
index 2e305ad2..ae841f3e 100644
--- a/lisp/update-autoloads.el
+++ b/lisp/update-autoloads.el
@@ -63,6 +63,7 @@
(package-generate-autoloads "org-appear" (concat config-dir "lisp/org-appear"))
(package-generate-autoloads "org-contrib" (concat config-dir "lisp/org-contrib"))
(package-generate-autoloads "ox-pandoc" (concat config-dir "lisp/ox-pandoc"))
+ (package-generate-autoloads "ox-rst" (concat config-dir "lisp/ox-rst"))
(package-generate-autoloads "rainbow-mode" (concat config-dir "lisp/rainbow-mode"))
(package-generate-autoloads "spacemacs-theme" (concat config-dir "lisp/spacemacs-theme"))
(package-generate-autoloads "srefactor" (concat config-dir "lisp/srefactor"))