Subject: [Wei-Wei Guo] A patch for rst.el

From: Stefan Monnier <[email-masked]>
Date: Tue, 28 Apr 2009 10:32:34 -0400

tag 1610 +patch
thanks

Subject: A patch for rst.el
From: Wei-Wei Guo <[email-masked]>
To: [email-masked]
Date: Tue, 28 Apr 2009 21:29:53 +0800
List-Id: "Emacs development discussions." <emacs-devel.gnu.org>

Dear all,

I made a patch for rst.el, see the attachment.

I sent a rst.el patch months ago and Glenn Morris filed it as a wishlist item:

    http://debbugs.gnu.org/cgi/bugreport.cgi?bug=1610

I promoted the functionalities recently so I send it here again. Added functionalities
include:

    - Insert bullet list and enumeration by 'M-RET'.
    - Insert directives and options by 'C-c C-d'.
    - Insert option by 'C-c C-o'.
    - Insert hyperlink, footnote, and citation by 'C-c C-h'.
    - Jump within hyperlinks by 'C-c l', 'C-c n', and 'C-c t'.
    - jump within footnotes, and citation by 'C-c r', 'C-c m', and 'C-c u'.
    - Add your own directives by function 'rst-add-directives'.

Hope it useful.

Best wishes,
Wei-Wei
--- rst.el	2009-04-01 08:28:16.000000000 +0800
+++ rst.el.new	2009-04-28 17:36:38.000000000 +0800
@@ -36,6 +36,8 @@
 ;;   from it;
 ;; - Functions to insert and automatically update a TOC in your source
 ;;   document;
+;; - Function to insert list, processing item bullets and enumerations 
+;;   automatically;
 ;; - Font-lock highlighting of notable reStructuredText structures;
 ;; - Some other convenience functions.
 ;;
@@ -166,11 +168,6 @@
 ;; - numbering: automatically detect if we have a section-numbering directive in
 ;;   the corresponding section, to render the toc.
 ;;
-;; bulleted and enumerated list items
-;; ----------------------------------
-;; - We need to provide way to rebullet bulleted lists, and that would include
-;;   automatic enumeration as well.
-;;
 ;; Other
 ;; -----
 ;; - It would be nice to differentiate between text files using
@@ -239,14 +236,14 @@
     ;; Section Decorations.
     ;;
     ;; The adjustment function that decorates or rotates a section title.
-    (define-key map [(control c) (control a)] 'rst-adjust)
-    (define-key map [(control c) (control ?=)] 'rst-adjust)
+    ;(define-key map [(control c) (control a)] 'rst-adjust)
+    ;(define-key map [(control c) (control ?=)] 'rst-adjust)
     (define-key map [(control ?=)] 'rst-adjust) ;; (Does not work on the Mac OSX.)
     ;; Display the hierarchy of decorations implied by the current document contents.
-    (define-key map [(control c) (control h)] 'rst-display-decorations-hierarchy)
+    (define-key map [(control c) (control t)] 'rst-display-decorations-hierarchy)
     ;; Homogeneize the decorations in the document.
     (define-key map [(control c) (control s)] 'rst-straighten-decorations)
-;;    (define-key map [(control c) (control s)] 'rst-straighten-deco-spacing)
+    ;(define-key map [(control c) (control s)] 'rst-straighten-deco-spacing)
 
     ;;
     ;; Section Movement and Selection.
@@ -254,39 +251,75 @@
     ;; Mark the subsection where the cursor is.
     (define-key map [(control c) (control m)] 'rst-mark-section)
     ;; Move forward/backward between section titles.
-    (define-key map [(control c) (control n)] 'rst-forward-section)
-    (define-key map [(control c) (control p)] 'rst-backward-section)
+    (define-key map [(meta n)] 'rst-forward-section)
+    (define-key map [(meta p)] 'rst-backward-section)
 
     ;;
     ;; Operating on Blocks of Text.
     ;;
+    ;; Inserts bullet list or enumeration list.
+    (define-key map [(meta return)] 'rst-insert-list)
+    ;; Inserts definition list.
+    ;(define-key map [(control c) t] 'rst-insert-definition)
+    ;; Inserts field list.
+    ;(define-key map [(control c) f] 'rst-insert-field)
     ;; Makes paragraphs in region as a bullet list.
-    (define-key map [(control c) (control b)] 'rst-bullet-list-region)
+    ;(define-key map [(control c) (control b)] 'rst-bullet-list-region)
     ;; Makes paragraphs in region as a enumeration.
-    (define-key map [(control c) (control e)] 'rst-enumerate-region)
+    ;(define-key map [(control c) (control e)] 'rst-enumerate-region)
     ;; Converts bullets to an enumeration.
-    (define-key map [(control c) (control v)] 'rst-convert-bullets-to-enumeration)
+    ;(define-key map [(control c) (control v)] 'rst-convert-bullets-to-enumeration)
     ;; Makes region a line-block.
-    (define-key map [(control c) (control d)] 'rst-line-block-region)
+    ;(define-key map [(control c) (control d)] 'rst-line-block-region)
     ;; Make sure that all the bullets in the region are consistent.
-    (define-key map [(control c) (control w)] 'rst-straighten-bullets-region)
+    ;(define-key map [(control c) (control w)] 'rst-straighten-bullets-region)
     ;; Shift region left or right (taking into account of enumerations/bullets, etc.).
     (define-key map [(control c) (control l)] 'rst-shift-region-left)
     (define-key map [(control c) (control r)] 'rst-shift-region-right)
     ;; Comment/uncomment the active region.
-    (define-key map [(control c) (control c)] 'comment-region)
+    ;(define-key map [(control c) (control c)] 'comment-region)
+
+    ;; Insert option or directive.
+    (define-key map [(control c) (control o)] 'rst-insert-option)
+    (define-key map [(control c) (control d)] 'rst-insert-directive)
+    ;; Insert text replace definition.
+    ;(define-key map [(control c) t] 'rst-insert-replace)
+    ;; Insert image and figures
+    ;(define-key map [(control c) p] 'rst-insert-image)
+    ;(define-key map [(control c) m] 'rst-insert-figure)
+    ;; Insert admonition
+    ;(define-key map [(control c) t] 'rst-insert-admonition)
+
+    ;; 
+    ;; Hypylink, Footnote, and Citation Features.
+    ;; 
+    (define-key map [(control c) (control h)] 'rst-insert-link)
+    ;; Insert hyperlink
+    ;(define-key map [(control c) l] 'rst-insert-inline-link)
+    ;; Insert footnote
+    ;(define-key map [(control c) f] 'rst-insert-footnote)
+    ;; Insert citation
+    ;(define-key map [(control c) c] 'rst-insert-citation)
+    ;; Hyperlink jumping
+    (define-key map [(control c) (l)] 'rst-link-jump-to-reference)
+    (define-key map [(control c) (n)] 'rst-link-jump-within-targets)
+    (define-key map [(control c) (t)] 'rst-link-jump-to-target)
+    ;; Footnote and citation jumping
+    (define-key map [(control c) (r)] 'rst-footnote-citation-jump-to-reference)
+    (define-key map [(control c) (m)] 'rst-footnote-citation-jump-within-targets)
+    (define-key map [(control c) (u)] 'rst-footnote-citation-jump-to-target)
 
     ;;
     ;; Table-of-Contents Features.
     ;;
     ;; Enter a TOC buffer to view and move to a specific section.
     (define-key map [(control c) (control t)] 'rst-toc)
-    ;; Insert a TOC here.
-    (define-key map [(control c) (control i)] 'rst-toc-insert)
+    ;; Insert a TOC here. use `rst-insert-directive' instead
+    ;(define-key map [(control c) i] 'rst-toc-insert)
     ;; Update the document's TOC (without changing the cursor position).
     (define-key map [(control c) (control u)] 'rst-toc-update)
     ;; Got to the section under the cursor (cursor must be in TOC).
-    (define-key map [(control c) (control f)] 'rst-goto-section)
+    ;(define-key map [(control c) (control f)] 'rst-goto-section)
 
     ;;
     ;; Converting Documents from Emacs.
@@ -344,8 +377,8 @@

 (defcustom rst-mode-hook nil
-  "Hook run when Rst mode is turned on.
-The hook for Text mode is run before this one."
+  "Hook run when Rst Mode is turned on.
+The hook for Text Mode is run before this one."
   :group 'rst
   :type '(hook))
 
@@ -1504,6 +1537,66 @@
     )))

+;=================================================
+; list related functions.
+
+;==============
+; Borrowed from a2r.el (version 1.3), writen by Lawrence Mitchell <[email-masked]>
+; I need to make some tiny changes on the functions, so I put it here. 
+; -- Wei-Wei Guo
+
+(defconst arabic-to-roman
+  '((1000 .   "M") (900  .  "CM") (500  .   "D") (400  .  "CD")
+    (100  .   "C") (90   .  "XC") (50   .   "L") (40   .  "XL")
+    (10   .   "X") (9    .  "IX") (5    .   "V") (4    .  "IV")
+    (1    .   "I"))
+  "List of maps between Arabic numbers and their Roman numeral equivalents.")
+
+(defun arabic-to-roman (num &optional arg)
+  "Convert Arabic number NUM to its Roman numeral representation.
+
+Obviously, NUM must be greater than zero.  Don't blame me, blame the
+Romans, I mean \"what have the Romans ever _done_ for /us/?\" (with
+apologies to Monty Python).
+If optional prefix ARG is non-nil, insert in current buffer."
+  (let ((map arabic-to-roman)
+        res)
+    (while (and map (> num 0))
+      (if (or (= num (caar map))
+              (> num (caar map)))
+          (setq res (concat res (cdar map))
+                num (- num (caar map)))
+        (setq map (cdr map))))
+    res))
+
+(defconst roman-to-arabic
+  '(("M"  .  1000) ("CM" .   900) ("D"  .   500) ("CD" .   400)
+    ("C"  .   100) ("XC" .    90) ("L"  .    50) ("XL" .    40)
+    ("X"  .    10) ("IX" .     9) ("V"  .     5) ("IV" .     4)
+    ("I"  .     1))
+  "List of maps between Roman numerals and their Arabic equivalents.")
+
+(defun roman-to-arabic (string &optional arg)
+  "Convert STRING of Roman numerals to an Arabic number.
+
+If STRING contains a letter which isn't a valid Roman numeral, the rest
+of the string from that point onwards is ignored.
+
+Hence:
+MMD == 2500
+and
+MMDFLXXVI == 2500.
+If optional ARG is non-nil, insert in current buffer."
+  (let ((res 0)
+        (map roman-to-arabic))
+    (while map
+      (if (string-match (concat "^" (caar map)) string)
+          (setq res (+ res (cdar map))
+                string (replace-match "" nil t string))
+        (setq map (cdr map))))
+    res))
+;==============
+
 (defun rst-find-pfx-in-region (beg end pfx-re)
   "Find all the positions of prefixes in region between BEG and END.
 This is used to find bullets and enumerated list items.  PFX-RE
@@ -1528,23 +1621,221 @@
 	(forward-line 1)) )
     (nreverse pfx)))
 
+(defun rst-insert-list-pos (newitem)
+  "Arrage relative position of a newly inserted list item.
+
+Adding a new list might consider three situations:
+
+ (a) Current line is a blank line.
+ (b) Previous line is a blank line.
+ (c) Following line is a blank line.
+
+When (a) and (b), just add the new list at current line. 
+
+when (a) and not (b), add a blank line before adding the new list.
+
+When not (a), add a blank line and a new line at current point. 
+
+Other situations are just ignored and left to users themselves."
+  (if (save-excursion
+        (beginning-of-line)
+        (looking-at "^[ \t]*$"))
+      (if (save-excursion
+            (forward-line -1)
+            (looking-at "^[ \t]*$"))
+          (insert (concat newitem " "))
+        (insert (concat "\n" newitem " ")))
+    (progn 
+      (insert (concat "\n\n" newitem " ")))))
+
+(defvar rst-initial-enums
+  '("#." "1." "a." "A." "I." "i." "(1)" "(a)" "(A)" "(I)" "(i)" "1)" "a)" "A)" "I)" "i)")
+  "List of initial enumerates.")
+
+(defvar rst-initial-items
+  (append (mapcar 'char-to-string rst-bullets) rst-initial-enums)
+  "List of initial items. It's collection of bullets and enumerations")
+
+(defun rst-insert-list-new-item ()
+  "Insert a new list item.
+
+User is asked to select the item style first, for example (a), i), +. Use TAB 
+for completition and choices.
+
+If user selects bullets or #, it's just added with position arranged by 
+`rst-insert-list-new-pos'. 
+
+If user selects enumerates, a further prompt is given. User need to input a 
+starting item, for example 'e' for 'A)' style. The position is also arranged by
+`rst-insert-list-new-pos'.
+"
+  (interactive)
+  (let (itemstyle itemno itemfirst)
+    (setq itemstyle (completing-read "Providing perfered item (default '#.'): "
+                                     rst-initial-items nil t nil nil "#."))
+    (when (string-match "[aA1Ii]" itemstyle)
+      (setq itemfirst (match-string 0 itemstyle))
+      (cond ((equal itemfirst "a") 
+             (progn 
+               (setq itemno (read-string "Providing starting (default a): " nil nil "a"))
+               (setq itemstyle (replace-match
+                                (downcase itemno)
+                                nil nil itemstyle))))
+            ((equal itemfirst "A") 
+             (progn 
+               (setq itemno (read-string "Providing starting (default A): " nil nil "A"))
+               (setq itemstyle (replace-match
+                                (upcase itemno)
+                                nil nil itemstyle))))
+            ((equal itemfirst "I") 
+             (progn 
+               (setq itemno (read-number "Providing starting (default 1): " 1))
+               (string-match "[aA1Ii]" itemstyle)
+               (setq itemstyle (replace-match
+                                (arabic-to-roman itemno)
+                                nil nil itemstyle))))
+            ((equal itemfirst "i") 
+             (progn 
+               (setq itemno (read-number "Providing starting (default 1): " 1))
+               (string-match "[aA1Ii]" itemstyle)
+               (setq itemstyle (replace-match
+                                (downcase (arabic-to-roman itemno))
+                                nil nil itemstyle))))
+            ((equal itemfirst "1") 
+             (progn 
+               (setq itemno (read-number "Providing starting (default 1): " 1))
+               (string-match "[aA1Ii]" itemstyle)
+               (setq itemstyle (replace-match
+                                (number-to-string itemno)
+                                nil nil itemstyle))))
+            ))
+    (rst-insert-list-pos itemstyle)))
+
 (defvar rst-re-bullets
   (format "\\([%s][ \t]\\)[^ \t]" (regexp-quote (concat rst-bullets)))
   "Regexp for finding bullets.")
 
-;; (defvar rst-re-enumerations
-;;   "\\(\\(#\\|[0-9]+\\)\\.[ \t]\\)[^ \t]"
-;;   "Regexp for finding bullets.")
+(defvar rst-re-enumerates
+  (format "^[ \t]*\\(%s\\|%s\\)[ \t]"
+          "\\([0-9]+\\|[a-zA-Z]\\|[IVXLCDMivxlcdm]+\\)\\."
+          "(?\\([0-9]+\\|[a-zA-Z]\\|[IVXLCDMivxlcdm]+\\))")
+  "Regexp for finding enumerates (# is not included).")
 
 (defvar rst-re-items
-  (format "\\(%s\\|%s\\)[^ \t]"
-	  (format "[%s][ \t]" (regexp-quote (concat rst-bullets)))
-	  "\\(#\\|[0-9]+\\)\\.[ \t]")
-  "Regexp for finding bullets.")
+  (format "^[ \t]*\\(%s\\|%s\\|%s\\)[ \t]"
+          (format "[%s]" (regexp-quote (concat rst-bullets)))
+          "\\(#\\|[a-z]\\|[0-9]+\\|[A-Z]\\|[IVXLCDM]+\\|[ivxlcdm]+\\)\\."
+          "(?\\([a-z]\\|[0-9]+\\|[A-Z]\\|[IVXLCDM]+\\|[ivxlcdm]+\\))")
+  "Regexp for finding bullets and enumerates.")
 
-(defvar rst-preferred-bullets
-  '(?- ?* ?+)
-  "List of favourite bullets to set for straightening bullets.")
+(defun rst-list-match-string (reg)
+  "Match a regex in a line and return the matched string by match-string.
+
+If nothing matched, a empty string is returned."
+  (let (matched)
+    (save-excursion
+      (end-of-line)
+      (if (re-search-backward reg (line-beginning-position) t)
+          (setq matched (match-string 0))
+        (setq matched "")))
+    matched))
+
+(defun rst-insert-list-continue ()
+  "Insert a list item with current list style and indentation level.
+
+The function works for all style of bullet lists and enumeration lists. Only one 
+thing need to be noticed: 
+
+List style alphabetical list, such as 'a.', and roman numerical list, such as 'i.', 
+have some overlapping items, for example 'v.' The function can deal with the 
+problem elegantly in most situations. But when those overlapped list proceeded 
+by a blank line, it is hard to determine which type to use automatically. The 
+function uses roman numerical list defaultly. If you want alphabetical list, just 
+use a prefix (\\[universal-argument]).
+"
+  (interactive)
+  (let (curitem newitem itemno previtem tmpitem)
+    (setq curitem (rst-list-match-string rst-re-items))
+    (cond ((string-match (format "#.\\|[%s]" 
+                                 (regexp-quote (concat rst-bullets))) curitem)
+           (setq newitem curitem))
+          ((string-match "[0-9]+" curitem)
+           (progn
+             (setq itemno (1+
+                           (string-to-number
+                            (match-string 0 curitem))))
+             (setq newitem (replace-match
+                            (number-to-string itemno)
+                            nil nil curitem))))
+          ((and (string-match "[IVXLCDMivxlcdm]+" curitem)
+                (progn 
+                  (setq tmpitem (match-string 0 curitem))
+                  (or (> (length tmpitem) 1) 
+                      (and (= (length tmpitem) 1) 
+                           (null current-prefix-arg)
+                           (progn
+                             (save-excursion
+                               (forward-line -1)
+                               (setq previtem (rst-list-match-string rst-re-enumerates))
+                               (when (string-match "[a-zA-Z]+" previtem)
+                                 (setq previtem (match-string 0 previtem))))
+                             (or (> (length previtem) 1)
+                                 (= (length previtem) 0)))))))
+           (progn
+             (setq itemno (1+ (roman-to-arabic tmpitem)))
+             (string-match "[IVXLCDMivxlcdm]+" curitem)
+             (if (isearch-no-upper-case-p tmpitem nil)
+                 (setq newitem (replace-match
+                                (downcase (arabic-to-roman itemno))
+                                nil nil curitem))
+               (setq newitem (replace-match
+                              (arabic-to-roman itemno)
+                              nil nil curitem)))))
+          ((string-match "[a-zA-Z]" curitem)
+           (progn
+             (setq itemno (1+
+                           (string-to-char
+                            (match-string 0 curitem))))
+             (setq newitem (replace-match
+                            (char-to-string itemno)
+                            nil nil curitem)))))
+    (insert (concat "\n" newitem))))
+
+
+(defun rst-insert-list ()
+  "Insert a list item at the current point.
+
+The command can insert a new list or a continuing list. When it is called at a 
+non-list line, it will promote to insert new list. When it is called at a list 
+line, it will insert a list with the same list style. 
+
+1. When inserting a new list: 
+
+User is asked to select the item style first, for example (a), i), +. Use TAB 
+for completition and choices.
+
+ (a) If user selects bullets or #, it's just added. 
+ (b) If user selects enumerates, a further prompt is given. User need to input a 
+starting item, for example 'e' for 'A)' style. 
+
+The position of the new list is arranged according whether or not the current line 
+and the previous line are blank lines.
+
+2. When continuing a list, one thing need to be noticed: 
+
+List style alphabetical list, such as 'a.', and roman numerical list, such as 'i.', 
+have some overlapping items, for example 'v.' The function can deal with the 
+problem elegantly in most situations. But when those overlapped list proceeded 
+by a blank line, it is hard to determine which type to use automatically. The 
+function uses roman numerical list defaultly. If you want alphabetical list, just 
+use a prefix (\\[universal-argument]).
+"
+  (interactive)
+  (if (equal (rst-list-match-string rst-re-items) "")
+      (rst-insert-list-new-item)
+    (rst-insert-list-continue)))
+
+;==============
 
 (defun rst-straighten-bullets-region (beg end)
   "Make all the bulleted list items in the region consistent.
@@ -1552,9 +1843,9 @@
 after you have merged multiple bulleted lists to make them use
 the same/correct/consistent bullet characters.
 
-See variable `rst-preferred-bullets' for the list of bullets to
-adjust.  If bullets are found on levels beyond the
-`rst-preferred-bullets' list, they are not modified."
+See variable `rst-bullets' for the list of bullets to adjust.  
+If bullets are found on levels beyond the `rst-bullets' list, 
+they are not modified."
   (interactive "r")
 
   (let ((bullets (rst-find-pfx-in-region beg end
@@ -1573,7 +1864,7 @@
     (let ((poslist ()))                 ; List of (indent . positions).
       (maphash (lambda (x y) (push (cons x y) poslist)) levtable)
 
-      (let ((bullets rst-preferred-bullets))
+      (let ((bullets rst-bullets))
         (dolist (x (sort poslist 'car-less-than-car))
           (when bullets
             ;; Apply the characters.
@@ -1583,6 +1874,9 @@
               (insert (string (car bullets))))
             (setq bullets (cdr bullets))))))))
 
+;=================================================
+
+
 (defun rst-rstrip (str)
   "Strips the whitespace at the end of string STR."
   (string-match "[ \t\n]*\\'" str)
@@ -1908,7 +2202,7 @@
   (let ((p (point)))
     (save-excursion
       (when (rst-toc-insert-find-delete-contents)
-        (insert "\n    ")
+        (insert "\n   ")
 	(rst-toc-insert)
 	))
     ;; Somehow save-excursion does not really work well.
@@ -2816,7 +3110,7 @@
       1 rst-block-face)
      ;; `Enumerated Lists`_
      (list
-      (concat re-bol "\\((?\\(#\\|[0-9]+\\|[A-Za-z]\\|[IVXLCMivxlcm]+\\)[.)]"
+      (concat re-bol "\\((?\\(#\\|[0-9]+\\|[A-Za-z]\\|[IVXLCDMivxlcdm]+\\)[.)]"
 	      re-blksep1 "\\)")
       1 rst-block-face)
      ;; `Definition Lists`_ FIXME: missing
@@ -3182,6 +3476,624 @@
 	(set-match-data mtc)
 	t))))
 
+
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; directives and hyperlinks.
+
+;===== directive type list and command =====
+
+(defvar rst-directive-type-alist
+  '(("definition" . rst-insert-definition) 
+    ("field" . rst-insert-field) 
+    ("admonition" . rst-insert-admonition)
+    ("image" . rst-insert-image) 
+    ("figure" . rst-insert-figure)
+    ("topic" . rst-insert-topic) 
+    ("sidebar" . rst-insert-sidebar) 
+    ("line-block" . rst-insert-line-block) 
+    ("parsed-literal" . rst-insert-parsed-literal) 
+    ("rubric" . rst-insert-rubric) 
+    ("epigraph" . rst-insert-epigraph) 
+    ("highlights" . rst-insert-highlights) 
+    ("pull-quote" . rst-insert-pull-quote) 
+    ("compound" . rst-insert-compound) 
+    ("container" . rst-insert-container) 
+    ("table" . rst-insert-table) 
+    ("csv-table" . rst-insert-csv-table)
+    ("list-table" . rst-insert-list-table)
+    ("contents" . rst-insert-contents) 
+    ("sectnum" . rst-insert-sectnum) 
+    ("replace" . rst-insert-replace) 
+    ("unicode" . rst-insert-unicode) 
+    ("date" . rst-insert-date) 
+    ("include" . rst-insert-include) 
+    ("raw" . rst-insert-raw))
+  "List of directive inserting functions of directive types.")
+
+(defvar rst-directive-types
+  '("definition" "field" "admonition" 
+    "image" "figure" 
+    "topic" "sidebar" "line-block" "parsed-literal" "rubric" "epigraph" 
+    "highlights" "pull-quote" "compound" "container" 
+    "table" "csv-table" "list-table"
+    "contents" "sectnum" "include" "raw"
+    "replace" "unicode" "date"
+)
+  "List of directive types")
+
+(defvar rst-directive-option-list
+  '(("definition" rst-option-definition t) 
+    ("field" rst-option-field t) 
+    ("admonition" rst-option-admonition nil)
+    ("image" rst-option-image nil) 
+    ("figure" rst-option-figure t)
+    ("topic" nil t) 
+    ("sidebar" rst-option-sidebar t)
+    ("line-block" nil t) 
+    ("parsed-literal" nil t) 
+    ("rubric" nil nil) 
+    ("epigraph" nil t) 
+    ("highlights" nil t) 
+    ("pull-quote" nil t) 
+    ("compound" nil t) 
+    ("container" nil t) 
+    ("table" nil t) 
+    ("csv-table" rst-option-csv-table t)
+    ("list-table" rst-option-list-table t)
+    ("contents" rst-contents-option nil) 
+    ("sectnum" rst-sectnum-option nil) 
+    ("replace" nil nil) 
+    ("unicode" rst-option-unicode nil) 
+    ("date" nil nil) 
+    ("include" rst-include-option nil) 
+    ("raw" rst-option-raw t))
+  "List of option functions of directive types.")
+
+(defun rst-add-directive-type (type directfunc optalist content)
+  "Adding new directive to directive alist and completion list.
+
+Use the following way to add directive type.
+
+  (rst-add-directive-type \"definition\" 
+                          'rst-insert-definition 
+                          'rst-directive-options 
+                          'content-presence-boolean)
+"
+  (add-to-list 'rst-directive-types type)
+  (add-to-list 'rst-directive-type-alist (cons type directfunc))
+  (add-to-list 'rst-directive-option-list (list type optalist content)))
+
+(defun rst-add-directives (directlist)
+  "Meta function of add directives. 
+
+Elements of directives should arranged as 
+
+   (type funciton option-list content-boolean). 
+"
+  (dolist (direct directlist)
+    (eval (cons 'rst-add-directive-type direct))))
+
+(defun rst-insert-directive ()
+  "Meta-function of all directives."
+  (interactive)
+  (let (type optlist)
+    (setq type (completing-read "Providing directive type: " rst-directive-types))
+    (funcall (cdr (assoc type rst-directive-type-alist)))
+    (setq optlist (eval (car (cdr (assoc type rst-directive-option-list)))))
+    (if optlist
+        (while (y-or-n-p "Set directive option(s)? ")
+          (rst-option-directive optlist)))
+    (if (eval (cadr (cdr (assoc type rst-directive-option-list))))
+        (insert "\n   ")
+      (newline))))
+
+;==== directive and list definitions ====
+
+;--- list looks like directive ---
+
+(defun rst-insert-definition ()
+  "Insert a definition list"
+  (interactive)
+  (let (term classifiers classel)
+    (setq term (read-string "Providing the definition's term: "))
+    (setq classifiers (read-string "Providing classifier(s) (if many, seperated by ', '): "))
+    (if (equal classifiers "")
+        (insert term "\n    ")
+      (progn
+        (setq classifiers (split-string classifiers ", "))
+        (dolist (tmpclass classifiers)
+          (setq classel (concat classel " : " tmpclass)))
+        (insert term classel "\n    ")))))
+
+(defun rst-insert-field ()
+  "Insert a field list."
+  (interactive)
+  (let (field value)
+    (setq field (read-string "Providing field: "))
+    (save-excursion
+      (beginning-of-line)
+      (insert (concat ":" field ": ")))))
+
+;--- function for defining directives ---
+
+(defun rst-insert-directive-type (type &optional argument)
+  "Insert the first line of directive"
+  (insert (concat ".. " type ":: " argument "\n")))
+
+(defun rst-insert-directive-option (option &optional value)
+  "Insert an option line of directive"
+  (insert (concat "   :" option ": " value "\n")))
+
+(defun rst-insert-option ()
+  "Insert a directive option."
+  (interactive)
+  (let (option value)
+    (save-excursion
+      (beginning-of-line)
+      (when (looking-at "^\\.\\. \\sw+::")
+        (setq option (read-string "Providing directive option: "))
+        (setq value (read-string "Providing option value: "))
+        (newline)
+        (rst-insert-directive-option option value)))))
+
+(defun rst-option-directive (optalist)
+  "Insert directive options in directive inserting function."
+  (let (optlist option type value)
+    (setq optlist (mapcar 'car optalist))
+    (setq option (completing-read "Providing option: " optlist))
+    (setq type (car (cdr (assoc option optalist))))
+    (setq value
+          (cond 
+           ((equal type "flag") nil)
+           ((equal type "option") (completing-read 
+                                   "Providing optional value: " 
+                                   (cadr (cdr (assoc option optalist)))))
+           ((equal type "number") (number-to-string 
+                                   (read-number "Providing numeric value: ")))
+           ((equal type "string") (read-string "Providing value: "))))
+    (rst-insert-directive-option option value)))
+
+;--- directives ---
+
+(defun rst-insert-admonition ()
+  "Insert a admonition."
+  (interactive)
+  (let (admon argu)
+    (setq admon (read-string "Providing admonition type: "))
+    (setq argu (read-string "Providing admonition description: "))
+    (rst-insert-directive-type admon argu)))
+
+(defun rst-insert-image ()
+  "Insert a image."
+  (interactive)
+  (let (arg)
+    (setq arg (read-string "Providing image and its path: "))
+    (rst-insert-directive-type "image" arg)))
+
+(defvar rst-option-image
+'(("align" "option" ("top" "middle" "bottom" "left" "center" "right"))
+  ("width" "number" 300)
+  ("height" "number" 300)
+  ("scale" "number" 80)
+  ("alt" "string" "")
+  ("target" "string" "")))
+
+(defun rst-insert-figure ()
+  "Insert a image."
+  (interactive)
+  (let (arg)
+    (setq arg (read-string "Providing figure and its path: "))
+    (rst-insert-directive-type "figure" arg)))
+
+(defvar rst-option-figure
+'(("align" "option" ("left" "center" "right"))
+  ("width" "number" 300)
+  ("height" "number" 300)
+  ("scale" "number" 80)
+  ("figwidth" "string" "350")
+  ("alt" "string" "")
+  ("target" "string" "")))
+
+(defun rst-insert-topic ()
+  "Insert a topic."
+  (interactive)
+  (let (arg)
+    (setq arg (read-string "Providing topic title: "))
+    (rst-insert-directive-type "topic" arg)))
+
+(defun rst-insert-sidebar ()
+  "Insert a sidebar."
+  (interactive)
+  (let (arg)
+    (setq arg (read-string "Providing sidebar title: "))
+    (rst-insert-directive-type "sidebar" arg)))
+
+(defvar rst-option-sidebar
+'(("subtitle" "string" "")))
+
+(defun rst-insert-line-block ()
+  "Insert a line block."
+  (interactive)
+  (rst-insert-directive-type "line-block"))
+
+(defun rst-insert-parsed-literal ()
+  "Insert a parsed literal."
+  (interactive)
+  (rst-insert-directive-type "parsed-literal"))
+
+(defun rst-insert-rubric ()
+  "Insert a rubric title."
+  (interactive)
+  (let (arg)
+    (setq arg (read-string "Providing rubric title: "))
+    (rst-insert-directive-type "rubric" arg)))
+
+(defun rst-insert-epigraph ()
+  "Insert a epigraph."
+  (interactive)
+  (rst-insert-directive-type "epigraph"))
+
+(defun rst-insert-highlights ()
+  "Insert a highlights."
+  (interactive)
+  (rst-insert-directive-type "highlights"))
+
+(defun rst-insert-pull-quote ()
+  "Insert a pull quote."
+  (interactive)
+  (rst-insert-directive-type "pull-quote"))
+
+(defun rst-insert-compound ()
+  "Insert a compound."
+  (interactive)
+  (rst-insert-directive-type "compound"))
+
+(defun rst-insert-container ()
+  "Insert a container."
+  (interactive)
+  (let (arg)
+    (setq arg (read-string "Providing container title: "))
+    (rst-insert-directive-type "container" arg)))
+
+(defun rst-insert-table ()
+  "Insert a table."
+  (interactive)
+  (let (arg)
+    (setq arg (read-string "Providing table title: "))
+    (rst-insert-directive-type "table" arg)))
+
+(defun rst-insert-csv-table ()
+  "Insert a table."
+  (interactive)
+  (let (arg)
+    (setq arg (read-string "Providing table title: "))
+    (rst-insert-directive-type "csv-table" arg)))
+
+(defvar rst-option-csv-table
+'(("widths" "string" "")
+  ("header-rows" "number" 0)
+  ("stub-columns" "number" 0)
+  ("header" "string" "")
+  ("file" "string" "")
+  ("url" "string" "")
+  ("encoding" "string" "")
+  ("delim" "string" "")
+  ("quote" "string" "")
+  ("keepspace" "flag" nil)
+  ("escape" "string" "")))
+
+(defun rst-insert-list-table ()
+  "Insert a table."
+  (interactive)
+  (let (arg)
+    (setq arg (read-string "Providing table title: "))
+    (rst-insert-directive-type "list-table" arg)))
+
+(defvar rst-option-list-table
+'(("widths" "string" "")
+  ("header-rows" "number" 0)
+  ("stub-columns" "number" 0)))
+
+(defun rst-insert-contents ()
+  "Insert a contents."
+  (interactive)
+  (let (arg)
+    (setq arg (read-string "Providing contents title: "))
+    (rst-insert-directive-type "contents" arg)))
+
+(defvar rst-option-contents
+'(("backlinks" "option" ("entry" "top" "none"))
+  ("depth" "number" 2)
+  ("local" "flag" nil)))
+
+(defun rst-insert-sectnum ()
+  "Set section-autonumbering."
+  (interactive)
+  (rst-insert-directive-type "sectnum"))
+
+(defvar rst-option-sectnum
+'(("prefix" "string" "")
+  ("suffix" "string" "")
+  ("depth" "number" 2)
+  ("start" "number" 1)))
+
+(defun rst-insert-replace ()
+  "Insert the head of word replace."
+  (interactive)
+  (let (tag)
+    (setq tag (read-string "Providing replaced word: "))
+    (rst-insert-directive-type (concat "|" tag "| replace"))))
+
+(defun rst-insert-unicode ()
+  "Insert unicode replacement."
+  (interactive)
+  (let (tag)
+    (setq tag (read-string "Providing unicode string: "))
+    (rst-insert-directive-type (concat "|" tag "| unicode"))))
+
+(defvar rst-option-unicode
+  '(("ltrim" "flag" nil)
+    ("rtrim" "flag" nil)
+    ("trim" "flag" nil)))
+
+(defun rst-insert-date ()
+  "Insert date or time."
+  (interactive)
+  (let (type value)
+    (setq type (completing-read "Insert date or time? " '("date" "time")))
+    (cond
+     ((equal type "date") 
+      (setq value (read-string "Providing date format: " nil nil "%Y-%m-%d")))
+     ((equal type "time") 
+      (setq value (read-string "Providing time format: " nil nil "%H:%M"))))
+    (rst-insert-directive-type (concat "|" type "| date") value)))
+
+(defun rst-insert-include ()
+  "Insert an external file."
+  (interactive)
+  (let (arg)
+    (setq arg (read-string "Providing file path: "))
+    (rst-insert-directive-type "include" arg)))
+
+(defvar rst-option-include
+  '(("start-after" "string" "")
+    ("end-before" "string" "")
+    ("encoding" "string" "")
+    ("literal" "flag" nil)))
+
+(defun rst-insert-raw ()
+  "Insert raw data."
+  (interactive)
+  (let (arg)
+    (setq arg (read-string "Providing raw data type: "))
+    (rst-insert-directive-type "raw" arg)))
+
+(defvar rst-option-raw
+  '(("file" "string" "")
+    ("url" "string" "")
+    ("encoding" "string" "")))
+
+
+;==== links ====
+
+;--- link inserting ---
+
+(defvar rst-link-type-alist
+  '(("hyperlink" . rst-insert-inline-link) 
+    ("footnote" . rst-insert-footnote) 
+    ("citation" . rst-insert-citation))
+  "List of link types.")
+
+(defvar rst-link-type
+  '("hyperlink" "footnote" "citation")
+  "List of link types for completion")
+
+(defun rst-insert-link ()
+  "Meta-function of all directives."
+  (interactive)
+  (let (type)
+    (setq type (completing-read "Providing link type: " rst-link-type))
+    (funcall (cdr (assoc type rst-link-type-alist)))))
+
+(defun rst-insert-inline-link ()
+  "Insert a inline link with both target and reference."
+  (interactive)
+  (let (link target reference)
+    (setq link (read-string "Providing link name: "))
+    (if (string-match " " link)
+        (progn
+          (setq target (concat "`" link "`_"))
+          (setq reference (concat ".. _`" link "`: ")))
+      (progn
+        (setq target (concat link "_"))
+        (setq reference (concat ".. _" link ": "))))
+    (save-excursion
+      (if (equal (char-before) (string-to-char " "))
+          (insert target " ")
+        (insert (concat " " target " ")))
+      (end-of-line)
+      (insert (concat "\n\n" reference)))))
+
+(defun rst-insert-footnote ()
+  "Insert a inline footnote with both target and reference."
+  (interactive)
+  (let (footnote target reference)
+    (setq footnote (read-string "Providing footnote name: "))
+    (setq target (concat "[#" footnote "]_"))
+    (setq reference (concat ".. [#" footnote "] "))
+    (save-excursion
+      (if (equal (char-before) (string-to-char " "))
+          (insert target " ")
+        (insert (concat " " target " ")))
+      (end-of-line)
+      (insert (concat "\n\n" reference)))))
+
+(defun rst-insert-citation ()
+  "Insert a inline citation with both target and reference."
+  (interactive)
+  (let (citation target reference)
+    (setq citation (read-string "Providing citation name: "))
+    (setq target (concat "[" citation "]_"))
+    (setq reference (concat ".. [" citation "] "))
+    (save-excursion
+      (if (equal (char-before) (string-to-char " "))
+          (insert target " ")
+        (insert (concat " " target " ")))
+      (end-of-line)
+      (insert (concat "\n\n" reference)))))
+
+;--- link jumping ---
+
+(defun rst-hyper-link-reference-match ()
+  "Match link target around the point."
+  (let (link reference target)
+    (save-excursion
+      (if (search-forward "_" 
+                          (save-excursion 
+                            (forward-sentence) 
+                            (point)) 
+                          t 1)
+          (progn
+            (backward-char)
+            (unless (equal (char-before) ?\\)
+              (if (equal (char-before) ?`)
+                  (progn
+                    (forward-char)
+                    (re-search-backward "`[[:alnum:][:punct:][:space:]]+`_" 
+                                        (save-excursion 
+                                          (search-backward "`" nil t 2) 
+                                          (point)) 
+                                        t)
+                    (setq reference (match-string 0))
+                    (setq link (substring reference 0 -1)))
+                (progn
+                  (forward-char)
+                  (re-search-backward " \\sw+_" 
+                                      (save-excursion 
+                                        (search-backward " ") 
+                                        (point)) 
+                                      t)
+                  (setq reference (match-string 0))
+                  (setq link (substring reference 1 -1)))))
+            (setq target (concat ".. _" link ":")))))
+    (list reference target)))
+
+(defun rst-link-jump-to-target ()
+  "Jump from intertext link reference to link target."
+  (interactive)
+  (let ((target (elt (rst-hyper-link-reference-match) 1)))
+    (when (save-excursion
+            (goto-char (point-min))
+            (search-forward target))
+      (goto-char (point-min))
+      (search-forward target))))
+
+(defun rst-link-jump-within-references ()
+  "Jump within references of an intertext link, if exist."
+  (interactive)
+  (let ((reference (elt (rst-hyper-link-reference-match) 0)))
+    (if (save-excursion
+          (search-forward reference nil t 1))
+        (progn
+          (search-forward reference nil t 1)
+          (backward-char 1))
+      (when (y-or-n-p "No link reference behind. Search from the beginning?")
+        (goto-char (point-min))
+        (search-forward reference nil t 1)
+        (backward-char 1)))))
+
+(defun rst-hyper-link-target-match ()
+  "Match link reference at the target line."
+  (let (link reference target)
+    (save-excursion
+      (when (search-backward ".. _" (line-beginning-position) t 1)
+        (re-search-forward 
+         "^\\.\\. _`?[[:alnum:][:punct:][:space:]]+`?: " 
+         (line-end-position) t 1)
+        (setq target (match-string 0))))
+    (setq link (substring target 4 -2))
+    (if (equal (substring link 0 1) "`")
+        (setq reference (concat link "_"))
+      (setq reference (concat " " link "_")))
+    (list reference target)))
+
+(defun rst-link-jump-to-reference ()
+  "Jump from intertext link target to link reference."
+  (interactive)
+  (let ((reference (elt (rst-hyper-link-target-match) 0)))
+    (when (save-excursion
+            (goto-char (point-max))
+            (search-backward reference))
+      (goto-char (point-max))
+      (search-backward reference))))
+
+;--- footnote and citation ---
+
+(defun rst-footnote-citation-reference-match ()
+  "Match footnote or citation reference around the point."
+  (let (link reference target)
+    (save-excursion
+      (when (search-forward "]_" 
+                            (save-excursion 
+                              (forward-sentence) 
+                              (point)) 
+                            t 1)
+        (re-search-backward "\\[[[:alnum:][:punct:][:space:]]+\\]_" 
+                            (save-excursion 
+                              (search-backward "[" nil t 1) 
+                              (point)) 
+                            t)
+        (setq reference (match-string 0))))
+    (setq link (substring reference 1 -2))
+    (setq target (concat ".. [" link "]"))
+    (list reference target)))
+
+(defun rst-footnote-citation-target-match ()
+  "Match footnote or citation reference at the target line."
+  (let (link reference target)
+    (save-excursion
+      (when (search-backward ".. [" (line-beginning-position) t 1)
+        (re-search-forward 
+         "^\\.\\. \\[[[:alnum:][:punct:][:space:]]+\\] " 
+         (line-end-position) t 1)
+        (setq target (match-string 0))))
+    (setq link (substring target 4 -2))
+    (setq reference (concat " [" link "]_"))
+    (list reference target)))
+
+(defun rst-footnote-citation-jump-to-target ()
+  "Jump from footnote or citation reference to target."
+  (interactive)
+  (let ((target (elt (rst-footnote-citation-reference-match) 1)))
+    (when (save-excursion
+            (goto-char (point-min))
+            (search-forward target))
+      (goto-char (point-min))
+      (search-forward target))))
+
+(defun rst-footnote-citation-jump-within-references ()
+  "Jump within references of an footnote or citation, if exist."
+  (interactive)
+  (let ((reference (elt (rst-footnote-citation-reference-match) 0)))
+    (if (save-excursion
+          (search-forward reference nil t 1))
+        (progn
+          (search-forward reference nil t 1)
+          (backward-char 1))
+      (when (y-or-n-p "No link reference behind. Search from the beginning?")
+        (goto-char (point-min))
+        (search-forward reference nil t 1)
+        (backward-char 2)))))
+
+(defun rst-footnote-citation-jump-to-reference ()
+  "Jump from footnote or citation target to reference."
+  (interactive)
+  (let ((reference (elt (rst-footnote-citation-target-match) 0)))
+    (when (save-excursion
+            (goto-char (point-max))
+            (search-backward reference))
+      (goto-char (point-max))
+      (search-backward reference))))