diff options
| -rw-r--r-- | lisp/ChangeLog | 8 | ||||
| -rw-r--r-- | lisp/textmodes/rst.el | 3430 |
2 files changed, 3436 insertions, 2 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index b5f5e1684b9..740b5bdec45 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,7 @@ | |||
| 1 | 2008-06-20 Stefan Monnier <monnier@iro.umontreal.ca> | ||
| 2 | |||
| 3 | * textmodes/rst.el: New file. | ||
| 4 | |||
| 1 | 2008-06-20 Sam Steingold <sds@gnu.org> | 5 | 2008-06-20 Sam Steingold <sds@gnu.org> |
| 2 | 6 | ||
| 3 | * vc.el (vc-dir-hide-up-to-date): Accept a prefix argument to also | 7 | * vc.el (vc-dir-hide-up-to-date): Accept a prefix argument to also |
| @@ -33,8 +37,8 @@ | |||
| 33 | 37 | ||
| 34 | 2008-06-20 Jason Rumney <jasonr@gnu.org> | 38 | 2008-06-20 Jason Rumney <jasonr@gnu.org> |
| 35 | 39 | ||
| 36 | * international/fontset.el (setup-default-fontset): Specify script | 40 | * international/fontset.el (setup-default-fontset): Specify script |
| 37 | for latin use of iso10646-1. Fix use of lang tags. | 41 | for latin use of iso10646-1. Fix use of lang tags. |
| 38 | 42 | ||
| 39 | 2008-06-19 Miles Bader <miles@gnu.org> | 43 | 2008-06-19 Miles Bader <miles@gnu.org> |
| 40 | 44 | ||
diff --git a/lisp/textmodes/rst.el b/lisp/textmodes/rst.el new file mode 100644 index 00000000000..e7b5c9b2d33 --- /dev/null +++ b/lisp/textmodes/rst.el | |||
| @@ -0,0 +1,3430 @@ | |||
| 1 | ;;; rst.el --- Mode for viewing and editing reStructuredText-documents. | ||
| 2 | |||
| 3 | ;; Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 | ||
| 4 | ;; Free Software Foundation, Inc. | ||
| 5 | |||
| 6 | ;; Authors: Martin Blais <blais@furius.ca>, | ||
| 7 | ;; Stefan Merten <smerten@oekonux.de>, | ||
| 8 | ;; David Goodger <goodger@python.org> | ||
| 9 | |||
| 10 | ;; This file is part of GNU Emacs. | ||
| 11 | |||
| 12 | ;; GNU Emacs is free software: you can redistribute it and/or modify | ||
| 13 | ;; it under the terms of the GNU General Public License as published by | ||
| 14 | ;; the Free Software Foundation, either version 3 of the License, or | ||
| 15 | ;; (at your option) any later version. | ||
| 16 | |||
| 17 | ;; GNU Emacs is distributed in the hope that it will be useful, | ||
| 18 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 19 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 20 | ;; GNU General Public License for more details. | ||
| 21 | |||
| 22 | ;; You should have received a copy of the GNU General Public License | ||
| 23 | ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. | ||
| 24 | |||
| 25 | ;;; Commentary: | ||
| 26 | |||
| 27 | ;; This package provides major mode rst-mode, which supports documents marked up | ||
| 28 | ;; using the reStructuredText format. Support includes font locking as well as | ||
| 29 | ;; some convenience functions for editing. It does this by defining a Emacs | ||
| 30 | ;; major mode: rst-mode (ReST). This mode is derived from text-mode (and | ||
| 31 | ;; inherits much of it). This package also contains: | ||
| 32 | ;; | ||
| 33 | ;; - Functions to automatically adjust and cycle the section underline | ||
| 34 | ;; decorations; | ||
| 35 | ;; - A mode that displays the table of contents and allows you to jump anywhere | ||
| 36 | ;; from it; | ||
| 37 | ;; - Functions to insert and automatically update a TOC in your source | ||
| 38 | ;; document; | ||
| 39 | ;; - Font-lock highlighting of notable reStructuredText structures; | ||
| 40 | ;; - Some other convenience functions. | ||
| 41 | ;; | ||
| 42 | ;; See the accompanying document in the docutils documentation about | ||
| 43 | ;; the contents of this package and how to use it. | ||
| 44 | ;; | ||
| 45 | ;; For more information about reStructuredText, see | ||
| 46 | ;; http://docutils.sourceforge.net/rst.html | ||
| 47 | ;; | ||
| 48 | ;; For full details on how to use the contents of this file, see | ||
| 49 | ;; http://docutils.sourceforge.net/docs/user/emacs.html | ||
| 50 | ;; | ||
| 51 | ;; | ||
| 52 | ;; There are a number of convenient keybindings provided by rst-mode. The main | ||
| 53 | ;; one is | ||
| 54 | ;; | ||
| 55 | ;; C-c C-a (also C-=): rst-adjust | ||
| 56 | ;; | ||
| 57 | ;; Updates or rotates the section title around point or promotes/demotes the | ||
| 58 | ;; decorations within the region (see full details below). Note that C-= is a | ||
| 59 | ;; good binding, since it allows you to specify a negative arg easily with C-- | ||
| 60 | ;; C-= (easy to type), as well as ordinary prefix arg with C-u C-=. | ||
| 61 | ;; | ||
| 62 | ;; For more on bindings, see rst-mode-map below. There are also many variables | ||
| 63 | ;; that can be customized, look for defcustom and defvar in this file. | ||
| 64 | ;; | ||
| 65 | ;; If you use the table-of-contents feature, you may want to add a hook to | ||
| 66 | ;; update the TOC automatically everytime you adjust a section title:: | ||
| 67 | ;; | ||
| 68 | ;; (add-hook 'rst-adjust-hook 'rst-toc-update) | ||
| 69 | ;; | ||
| 70 | ;; Syntax highlighting: font-lock is enabled by default. If you want to turn off | ||
| 71 | ;; syntax highlighting to rst-mode, you can use the following:: | ||
| 72 | ;; | ||
| 73 | ;; (setq font-lock-global-modes '(not rst-mode ...)) | ||
| 74 | ;; | ||
| 75 | |||
| 76 | |||
| 77 | ;; CUSTOMIZATION | ||
| 78 | ;; | ||
| 79 | ;; rst | ||
| 80 | ;; --- | ||
| 81 | ;; This group contains some general customizable features. | ||
| 82 | ;; | ||
| 83 | ;; The group is contained in the wp group. | ||
| 84 | ;; | ||
| 85 | ;; rst-faces | ||
| 86 | ;; --------- | ||
| 87 | ;; This group contains all necessary for customizing fonts. The default | ||
| 88 | ;; settings use standard font-lock-*-face's so if you set these to your | ||
| 89 | ;; liking they are probably good in rst-mode also. | ||
| 90 | ;; | ||
| 91 | ;; The group is contained in the faces group as well as in the rst group. | ||
| 92 | ;; | ||
| 93 | ;; rst-faces-defaults | ||
| 94 | ;; ------------------ | ||
| 95 | ;; This group contains all necessary for customizing the default fonts used for | ||
| 96 | ;; section title faces. | ||
| 97 | ;; | ||
| 98 | ;; The general idea for section title faces is to have a non-default background | ||
| 99 | ;; but do not change the background. The section level is shown by the | ||
| 100 | ;; lightness of the background color. If you like this general idea of | ||
| 101 | ;; generating faces for section titles but do not like the details this group | ||
| 102 | ;; is the point where you can customize the details. If you do not like the | ||
| 103 | ;; general idea, however, you should customize the faces used in | ||
| 104 | ;; rst-adornment-faces-alist. | ||
| 105 | ;; | ||
| 106 | ;; Note: If you are using a dark background please make sure the variable | ||
| 107 | ;; frame-background-mode is set to the symbol dark. This triggers | ||
| 108 | ;; some default values which are probably right for you. | ||
| 109 | ;; | ||
| 110 | ;; The group is contained in the rst-faces group. | ||
| 111 | ;; | ||
| 112 | ;; All customizable features have a comment explaining their meaning. Refer to | ||
| 113 | ;; the customization of your Emacs (try ``M-x customize``). | ||
| 114 | |||
| 115 | |||
| 116 | ;;; DOWNLOAD | ||
| 117 | |||
| 118 | ;; The latest version of this file lies in the docutils source code repository: | ||
| 119 | ;; http://svn.berlios.de/svnroot/repos/docutils/trunk/docutils/tools/editors/emacs/rst.el | ||
| 120 | |||
| 121 | |||
| 122 | ;;; INSTALLATION | ||
| 123 | |||
| 124 | ;; Add the following lines to your `.emacs' file: | ||
| 125 | ;; | ||
| 126 | ;; (require 'rst) | ||
| 127 | ;; | ||
| 128 | ;; If you are using `.txt' as a standard extension for reST files as | ||
| 129 | ;; http://docutils.sourceforge.net/FAQ.html#what-s-the-standard-filename-extension-for-a-restructuredtext-file | ||
| 130 | ;; suggests you may use one of the `Local Variables in Files' mechanism Emacs | ||
| 131 | ;; provides to set the major mode automatically. For instance you may use:: | ||
| 132 | ;; | ||
| 133 | ;; .. -*- mode: rst -*- | ||
| 134 | ;; | ||
| 135 | ;; in the very first line of your file. The following code is useful if you want | ||
| 136 | ;; to automatically enter rst-mode from any file with compatible extensions: | ||
| 137 | ;; | ||
| 138 | ;; (setq auto-mode-alist | ||
| 139 | ;; (append '(("\\.txt$" . rst-mode) | ||
| 140 | ;; ("\\.rst$" . rst-mode) | ||
| 141 | ;; ("\\.rest$" . rst-mode)) auto-mode-alist)) | ||
| 142 | ;; | ||
| 143 | |||
| 144 | ;;; BUGS | ||
| 145 | |||
| 146 | ;; - rst-enumeration-region: Select a single paragraph, with the top at one | ||
| 147 | ;; blank line before the beginning, and it will fail. | ||
| 148 | ;; - The active region goes away when we shift it left or right, and this | ||
| 149 | ;; prevents us from refilling it automatically when shifting many times. | ||
| 150 | ;; - The suggested decorations when adjusting should not have to cycle | ||
| 151 | ;; below one below the last section decoration level preceding the | ||
| 152 | ;; cursor. We need to fix that. | ||
| 153 | |||
| 154 | ;;; TODO LIST | ||
| 155 | |||
| 156 | ;; rst-toc-insert features | ||
| 157 | ;; ------------------------ | ||
| 158 | ;; - rst-toc-insert: We should parse the contents:: options to figure out how | ||
| 159 | ;; deep to render the inserted TOC. | ||
| 160 | ;; - On load, detect any existing TOCs and set the properties for links. | ||
| 161 | ;; - TOC insertion should have an option to add empty lines. | ||
| 162 | ;; - TOC insertion should deal with multiple lines. | ||
| 163 | ;; - There is a bug on redo after undo of adjust when rst-adjust-hook uses the | ||
| 164 | ;; automatic toc update. The cursor ends up in the TOC and this is | ||
| 165 | ;; annoying. Gotta fix that. | ||
| 166 | ;; - numbering: automatically detect if we have a section-numbering directive in | ||
| 167 | ;; the corresponding section, to render the toc. | ||
| 168 | ;; | ||
| 169 | ;; bulleted and enumerated list items | ||
| 170 | ;; ---------------------------------- | ||
| 171 | ;; - We need to provide way to rebullet bulleted lists, and that would include | ||
| 172 | ;; automatic enumeration as well. | ||
| 173 | ;; | ||
| 174 | ;; Other | ||
| 175 | ;; ----- | ||
| 176 | ;; - It would be nice to differentiate between text files using | ||
| 177 | ;; reStructuredText_ and other general text files. If we had a | ||
| 178 | ;; function to automatically guess whether a .txt file is following the | ||
| 179 | ;; reStructuredText_ conventions, we could trigger rst-mode without | ||
| 180 | ;; having to hard-code this in every text file, nor forcing the user to | ||
| 181 | ;; add a local mode variable at the top of the file. | ||
| 182 | ;; We could perform this guessing by searching for a valid decoration | ||
| 183 | ;; at the top of the document or searching for reStructuredText_ | ||
| 184 | ;; directives further on. | ||
| 185 | ;; | ||
| 186 | ;; - We should support imenu in our major mode, with the menu filled with the | ||
| 187 | ;; section titles (this should be really easy). | ||
| 188 | ;; | ||
| 189 | ;; - We should rename "adornment" to "decoration" or vice-versa in this | ||
| 190 | ;; document (Stefan's code ("adornment") vs Martin ("decoration")), maybe some | ||
| 191 | ;; functions even overlap. | ||
| 192 | ;; | ||
| 193 | ;; - We need to automatically recenter on rst-forward-section movement commands. | ||
| 194 | |||
| 195 | |||
| 196 | ;;; HISTORY | ||
| 197 | ;; | ||
| 198 | |||
| 199 | ;;; CODE | ||
| 200 | |||
| 201 | |||
| 202 | (defgroup rst nil "Support for reStructuredText documents" | ||
| 203 | :group 'wp | ||
| 204 | :version "23.1" | ||
| 205 | :link '(url-link "http://docutils.sourceforge.net/rst.html")) | ||
| 206 | |||
| 207 | |||
| 208 | |||
| 209 | |||
| 210 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 211 | ;; Define some generic support functions. | ||
| 212 | |||
| 213 | (eval-when-compile (require 'cl)) ;; We need this for destructuring-bind below. | ||
| 214 | |||
| 215 | |||
| 216 | ;; From Emacs-22 | ||
| 217 | (unless (fboundp 'line-number-at-pos) | ||
| 218 | (defun line-number-at-pos (&optional pos) | ||
| 219 | "Return (narrowed) buffer line number at position POS. | ||
| 220 | If POS is nil, use current buffer location." | ||
| 221 | (let ((opoint (or pos (point))) start) | ||
| 222 | (save-excursion | ||
| 223 | (goto-char (point-min)) | ||
| 224 | (setq start (point)) | ||
| 225 | (goto-char opoint) | ||
| 226 | (forward-line 0) | ||
| 227 | (1+ (count-lines start (point)))))) ) | ||
| 228 | |||
| 229 | |||
| 230 | |||
| 231 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 232 | ;; Mode definition. | ||
| 233 | |||
| 234 | ;; Key bindings. | ||
| 235 | (defvar rst-mode-map | ||
| 236 | (let ((map (make-sparse-keymap))) | ||
| 237 | |||
| 238 | ;; | ||
| 239 | ;; Section Decorations. | ||
| 240 | ;; | ||
| 241 | ;; The adjustment function that decorates or rotates a section title. | ||
| 242 | (define-key map [(control c) (control a)] 'rst-adjust) | ||
| 243 | (define-key map [(control c) (control ?=)] 'rst-adjust) | ||
| 244 | (define-key map [(control ?=)] 'rst-adjust) ;; (Does not work on the Mac OSX.) | ||
| 245 | ;; Display the hierarchy of decorations implied by the current document contents. | ||
| 246 | (define-key map [(control c) (control h)] 'rst-display-decorations-hierarchy) | ||
| 247 | ;; Homogeneize the decorations in the document. | ||
| 248 | (define-key map [(control c) (control s)] 'rst-straighten-decorations) | ||
| 249 | ;; (define-key map [(control c) (control s)] 'rst-straighten-deco-spacing) | ||
| 250 | |||
| 251 | ;; | ||
| 252 | ;; Section Movement and Selection. | ||
| 253 | ;; | ||
| 254 | ;; Mark the subsection where the cursor is. | ||
| 255 | (define-key map [(control c) (control m)] 'rst-mark-section) | ||
| 256 | ;; Move forward/backward between section titles. | ||
| 257 | (define-key map [(control c) (control n)] 'rst-forward-section) | ||
| 258 | (define-key map [(control c) (control p)] 'rst-backward-section) | ||
| 259 | |||
| 260 | ;; | ||
| 261 | ;; Operating on Blocks of Text. | ||
| 262 | ;; | ||
| 263 | ;; Makes paragraphs in region as a bullet list. | ||
| 264 | (define-key map [(control c) (control b)] 'rst-bullet-list-region) | ||
| 265 | ;; Makes paragraphs in region as a enumeration. | ||
| 266 | (define-key map [(control c) (control e)] 'rst-enumerate-region) | ||
| 267 | ;; Converts bullets to an enumeration. | ||
| 268 | (define-key map [(control c) (control v)] 'rst-convert-bullets-to-enumeration) | ||
| 269 | ;; Makes region a line-block. | ||
| 270 | (define-key map [(control c) (control d)] 'rst-line-block-region) | ||
| 271 | ;; Make sure that all the bullets in the region are consistent. | ||
| 272 | (define-key map [(control c) (control w)] 'rst-straighten-bullets-region) | ||
| 273 | ;; Shift region left or right (taking into account of enumerations/bullets, etc.). | ||
| 274 | (define-key map [(control c) (control l)] 'rst-shift-region-left) | ||
| 275 | (define-key map [(control c) (control r)] 'rst-shift-region-right) | ||
| 276 | ;; Comment/uncomment the active region. | ||
| 277 | (define-key map [(control c) (control c)] 'comment-region) | ||
| 278 | |||
| 279 | ;; | ||
| 280 | ;; Table-of-Contents Features. | ||
| 281 | ;; | ||
| 282 | ;; Enter a TOC buffer to view and move to a specific section. | ||
| 283 | (define-key map [(control c) (control t)] 'rst-toc) | ||
| 284 | ;; Insert a TOC here. | ||
| 285 | (define-key map [(control c) (control i)] 'rst-toc-insert) | ||
| 286 | ;; Update the document's TOC (without changing the cursor position). | ||
| 287 | (define-key map [(control c) (control u)] 'rst-toc-update) | ||
| 288 | ;; Got to the section under the cursor (cursor must be in TOC). | ||
| 289 | (define-key map [(control c) (control f)] 'rst-goto-section) | ||
| 290 | |||
| 291 | ;; | ||
| 292 | ;; Converting Documents from Emacs. | ||
| 293 | ;; | ||
| 294 | ;; Run one of two pre-configured toolset commands on the document. | ||
| 295 | (define-key map [(control c) (?1)] 'rst-compile) | ||
| 296 | (define-key map [(control c) (?2)] 'rst-compile-alt-toolset) | ||
| 297 | ;; Convert the active region to pseudo-xml using the docutils tools. | ||
| 298 | (define-key map [(control c) (?3)] 'rst-compile-pseudo-region) | ||
| 299 | ;; Convert the current document to PDF and launch a viewer on the results. | ||
| 300 | (define-key map [(control c) (?4)] 'rst-compile-pdf-preview) | ||
| 301 | ;; Convert the current document to S5 slides and view in a web browser. | ||
| 302 | (define-key map [(control c) (?5)] 'rst-compile-slides-preview) | ||
| 303 | |||
| 304 | map) | ||
| 305 | "Keymap for ReStructuredText mode commands. This inherits from Text mode.") | ||
| 306 | |||
| 307 | |||
| 308 | ;; Abbrevs. | ||
| 309 | (defvar rst-mode-abbrev-table nil | ||
| 310 | "Abbrev table used while in rst mode.") | ||
| 311 | (define-abbrev-table 'rst-mode-abbrev-table | ||
| 312 | '( | ||
| 313 | ("contents" ".. contents::\n..\n " nil 0) | ||
| 314 | ("con" ".. contents::\n..\n " nil 0) | ||
| 315 | ("cont" "[...]" nil 0) | ||
| 316 | ("skip" "\n\n[...]\n\n " nil 0) | ||
| 317 | ("seq" "\n\n[...]\n\n " nil 0) | ||
| 318 | ;; FIXME: Add footnotes, links, and more. | ||
| 319 | )) | ||
| 320 | |||
| 321 | |||
| 322 | ;; Syntax table. | ||
| 323 | (defvar rst-mode-syntax-table | ||
| 324 | (let ((st (copy-syntax-table text-mode-syntax-table))) | ||
| 325 | |||
| 326 | (modify-syntax-entry ?$ "." st) | ||
| 327 | (modify-syntax-entry ?% "." st) | ||
| 328 | (modify-syntax-entry ?& "." st) | ||
| 329 | (modify-syntax-entry ?' "." st) | ||
| 330 | (modify-syntax-entry ?* "." st) | ||
| 331 | (modify-syntax-entry ?+ "." st) | ||
| 332 | (modify-syntax-entry ?. "_" st) | ||
| 333 | (modify-syntax-entry ?/ "." st) | ||
| 334 | (modify-syntax-entry ?< "." st) | ||
| 335 | (modify-syntax-entry ?= "." st) | ||
| 336 | (modify-syntax-entry ?> "." st) | ||
| 337 | (modify-syntax-entry ?\\ "\\" st) | ||
| 338 | (modify-syntax-entry ?| "." st) | ||
| 339 | (modify-syntax-entry ?_ "." st) | ||
| 340 | |||
| 341 | st) | ||
| 342 | "Syntax table used while in `rst-mode'.") | ||
| 343 | |||
| 344 | |||
| 345 | (defcustom rst-mode-hook nil | ||
| 346 | "Hook run when Rst Mode is turned on. The hook for Text Mode is run before | ||
| 347 | this one." | ||
| 348 | :group 'rst | ||
| 349 | :type '(hook)) | ||
| 350 | |||
| 351 | |||
| 352 | (defcustom rst-mode-lazy t | ||
| 353 | "*If non-nil Rst Mode font-locks comment, literal blocks, and section titles | ||
| 354 | correctly. Because this is really slow it switches on Lazy Lock Mode | ||
| 355 | automatically. You may increase Lazy Lock Defer Time for reasonable results. | ||
| 356 | |||
| 357 | If nil comments and literal blocks are font-locked only on the line they start. | ||
| 358 | |||
| 359 | The value of this variable is used when Rst Mode is turned on." | ||
| 360 | :group 'rst | ||
| 361 | :type '(boolean)) | ||
| 362 | |||
| 363 | |||
| 364 | ;;;###autoload | ||
| 365 | (define-derived-mode rst-mode text-mode "ReST" | ||
| 366 | :abbrev-table rst-mode-abbrev-table | ||
| 367 | :syntax-table rst-mode-syntax-table | ||
| 368 | :group 'rst | ||
| 369 | "Major mode for editing reStructuredText documents. | ||
| 370 | |||
| 371 | There are a number of convenient keybindings provided by | ||
| 372 | rst-mode. The main one is \[rst-adjust\], it updates or rotates | ||
| 373 | the section title around point or promotes/demotes the | ||
| 374 | decorations within the region (see full details below). Use | ||
| 375 | negative prefix arg to rotate in the other direction. | ||
| 376 | \\{rst-mode-map} | ||
| 377 | |||
| 378 | Turning on `rst-mode' calls the normal hooks `text-mode-hook' and | ||
| 379 | `rst-mode-hook'. This mode also supports font-lock highlighting. | ||
| 380 | You may customize `rst-mode-lazy' to toggle font-locking of | ||
| 381 | blocks." | ||
| 382 | |||
| 383 | (set (make-local-variable 'paragraph-separate) paragraph-start) | ||
| 384 | (set (make-local-variable 'indent-line-function) 'indent-relative-maybe) | ||
| 385 | (set (make-local-variable 'paragraph-start) | ||
| 386 | "\f\\|>*[ \t]*$\\|>*[ \t]*[-+*] \\|>*[ \t]*[0-9#]+\\. ") | ||
| 387 | (set (make-local-variable 'adaptive-fill-mode) t) | ||
| 388 | |||
| 389 | ;; FIXME: No need to reset this. | ||
| 390 | ;; (set (make-local-variable 'indent-line-function) 'indent-relative) | ||
| 391 | |||
| 392 | ;; The details of the following comment setup is important because it affects | ||
| 393 | ;; auto-fill, and it is pretty common in running text to have an ellipsis | ||
| 394 | ;; ("...") which trips because of the rest comment syntax (".. "). | ||
| 395 | (set (make-local-variable 'comment-start) ".. ") | ||
| 396 | (set (make-local-variable 'comment-start-skip) "^\\.\\. ") | ||
| 397 | (set (make-local-variable 'comment-multi-line) nil) | ||
| 398 | |||
| 399 | ;; Special variables | ||
| 400 | (make-local-variable 'rst-adornment-level-alist) | ||
| 401 | |||
| 402 | ;; Font lock | ||
| 403 | (set (make-local-variable 'font-lock-defaults) | ||
| 404 | '(rst-font-lock-keywords-function | ||
| 405 | t nil nil nil | ||
| 406 | (font-lock-multiline . t) | ||
| 407 | (font-lock-mark-block-function . mark-paragraph))) | ||
| 408 | (when (boundp 'font-lock-support-mode) | ||
| 409 | ;; rst-mode has its own mind about font-lock-support-mode | ||
| 410 | (make-local-variable 'font-lock-support-mode) | ||
| 411 | ;; jit-lock-mode replaced lazy-lock-mode in GNU Emacs 22 | ||
| 412 | (let ((jit-or-lazy-lock-mode | ||
| 413 | (cond | ||
| 414 | ((fboundp 'lazy-lock-mode) 'lazy-lock-mode) | ||
| 415 | ((fboundp 'jit-lock-mode) 'jit-lock-mode) | ||
| 416 | ;; if neither lazy-lock nor jit-lock is supported, | ||
| 417 | ;; tell user and disable rst-mode-lazy | ||
| 418 | (t (when rst-mode-lazy | ||
| 419 | (message "Disabled lazy fontification, because no known support mode found.") | ||
| 420 | (setq rst-mode-lazy nil)))))) | ||
| 421 | (cond | ||
| 422 | ((and (not rst-mode-lazy) (not font-lock-support-mode))) | ||
| 423 | ;; No support mode set and none required - leave it alone | ||
| 424 | ((or (not font-lock-support-mode) ;; No support mode set (but required) | ||
| 425 | (symbolp font-lock-support-mode)) ;; or a fixed mode for all | ||
| 426 | (setq font-lock-support-mode | ||
| 427 | (list (cons 'rst-mode (and rst-mode-lazy jit-or-lazy-lock-mode)) | ||
| 428 | (cons t font-lock-support-mode)))) | ||
| 429 | ((and (listp font-lock-support-mode) | ||
| 430 | (not (assoc 'rst-mode font-lock-support-mode))) | ||
| 431 | ;; A list of modes missing rst-mode | ||
| 432 | (setq font-lock-support-mode | ||
| 433 | (cons (cons 'rst-mode (and rst-mode-lazy jit-or-lazy-lock-mode)) | ||
| 434 | font-lock-support-mode)))))) | ||
| 435 | |||
| 436 | ) | ||
| 437 | |||
| 438 | |||
| 439 | ;;;###autoload | ||
| 440 | (define-minor-mode rst-minor-mode | ||
| 441 | "ReST Minor Mode. | ||
| 442 | Toggle ReST minor mode. | ||
| 443 | With no argument, this command toggles the mode. | ||
| 444 | Non-null prefix argument turns on the mode. | ||
| 445 | Null prefix argument turns off the mode. | ||
| 446 | |||
| 447 | When ReST minor mode is enabled, the ReST mode | ||
| 448 | keybindings are installed on top of the major | ||
| 449 | mode bindings. Use this for modes derived from | ||
| 450 | text-mode, like mail-mode.." | ||
| 451 | ;; The initial value. | ||
| 452 | nil | ||
| 453 | ;; The indicator for the mode line. | ||
| 454 | " ReST" | ||
| 455 | ;; The minor mode bindings. | ||
| 456 | rst-mode-map | ||
| 457 | :group 'rst) | ||
| 458 | |||
| 459 | ;; FIXME: can I somehow install these too? | ||
| 460 | ;; :abbrev-table rst-mode-abbrev-table | ||
| 461 | ;; :syntax-table rst-mode-syntax-table | ||
| 462 | |||
| 463 | |||
| 464 | |||
| 465 | |||
| 466 | |||
| 467 | ;; Bulleted item lists. | ||
| 468 | (defcustom rst-bullets | ||
| 469 | '(?- ?* ?+) | ||
| 470 | "List of all possible bullet characters for bulleted lists." | ||
| 471 | :group 'rst) | ||
| 472 | |||
| 473 | |||
| 474 | |||
| 475 | |||
| 476 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 477 | ;; Section Decoration Adjusment | ||
| 478 | ;; ============================ | ||
| 479 | ;; | ||
| 480 | ;; The following functions implement a smart automatic title sectioning feature. | ||
| 481 | ;; The idea is that with the cursor sitting on a section title, we try to get as | ||
| 482 | ;; much information from context and try to do the best thing automatically. | ||
| 483 | ;; This function can be invoked many times and/or with prefix argument to rotate | ||
| 484 | ;; between the various sectioning decorations. | ||
| 485 | ;; | ||
| 486 | ;; Definitions: the two forms of sectioning define semantically separate section | ||
| 487 | ;; levels. A sectioning DECORATION consists in: | ||
| 488 | ;; | ||
| 489 | ;; - a CHARACTER | ||
| 490 | ;; | ||
| 491 | ;; - a STYLE which can be either of 'simple' or 'over-and-under'. | ||
| 492 | ;; | ||
| 493 | ;; - an INDENT (meaningful for the over-and-under style only) which determines | ||
| 494 | ;; how many characters and over-and-under style is hanging outside of the | ||
| 495 | ;; title at the beginning and ending. | ||
| 496 | ;; | ||
| 497 | ;; Important note: an existing decoration must be formed by at least two | ||
| 498 | ;; characters to be recognized. | ||
| 499 | ;; | ||
| 500 | ;; Here are two examples of decorations (| represents the window border, column | ||
| 501 | ;; 0): | ||
| 502 | ;; | ||
| 503 | ;; | | ||
| 504 | ;; 1. char: '-' e |Some Title | ||
| 505 | ;; style: simple |---------- | ||
| 506 | ;; | | ||
| 507 | ;; 2. char: '=' |============== | ||
| 508 | ;; style: over-and-under | Some Title | ||
| 509 | ;; indent: 2 |============== | ||
| 510 | ;; | | ||
| 511 | ;; | ||
| 512 | ;; Some notes: | ||
| 513 | ;; | ||
| 514 | ;; - The underlining character that is used depends on context. The file is | ||
| 515 | ;; scanned to find other sections and an appropriate character is selected. | ||
| 516 | ;; If the function is invoked on a section that is complete, the character is | ||
| 517 | ;; rotated among the existing section decorations. | ||
| 518 | ;; | ||
| 519 | ;; Note that when rotating the characters, if we come to the end of the | ||
| 520 | ;; hierarchy of decorations, the variable rst-preferred-decorations is | ||
| 521 | ;; consulted to propose a new underline decoration, and if continued, we cycle | ||
| 522 | ;; the decorations all over again. Set this variable to nil if you want to | ||
| 523 | ;; limit the underlining character propositions to the existing decorations in | ||
| 524 | ;; the file. | ||
| 525 | ;; | ||
| 526 | ;; - A prefix argument can be used to alternate the style. | ||
| 527 | ;; | ||
| 528 | ;; - An underline/overline that is not extended to the column at which it should | ||
| 529 | ;; be hanging is dubbed INCOMPLETE. For example:: | ||
| 530 | ;; | ||
| 531 | ;; |Some Title | ||
| 532 | ;; |------- | ||
| 533 | ;; | ||
| 534 | ;; Examples of default invocation: | ||
| 535 | ;; | ||
| 536 | ;; |Some Title ---> |Some Title | ||
| 537 | ;; | |---------- | ||
| 538 | ;; | ||
| 539 | ;; |Some Title ---> |Some Title | ||
| 540 | ;; |----- |---------- | ||
| 541 | ;; | ||
| 542 | ;; | |------------ | ||
| 543 | ;; | Some Title ---> | Some Title | ||
| 544 | ;; | |------------ | ||
| 545 | ;; | ||
| 546 | ;; In over-and-under style, when alternating the style, a variable is | ||
| 547 | ;; available to select how much default indent to use (it can be zero). Note | ||
| 548 | ;; that if the current section decoration already has an indent, we don't | ||
| 549 | ;; adjust it to the default, we rather use the current indent that is already | ||
| 550 | ;; there for adjustment (unless we cycle, in which case we use the indent | ||
| 551 | ;; that has been found previously). | ||
| 552 | |||
| 553 | (defgroup rst-adjust nil | ||
| 554 | "Settings for adjustment and cycling of section title | ||
| 555 | decorations." | ||
| 556 | :group 'rst | ||
| 557 | :version "21.1") | ||
| 558 | |||
| 559 | (defcustom rst-preferred-decorations '( (?= over-and-under 1) | ||
| 560 | (?= simple 0) | ||
| 561 | (?- simple 0) | ||
| 562 | (?~ simple 0) | ||
| 563 | (?+ simple 0) | ||
| 564 | (?` simple 0) | ||
| 565 | (?# simple 0) | ||
| 566 | (?@ simple 0) ) | ||
| 567 | "Preferred ordering of section title decorations. | ||
| 568 | |||
| 569 | This sequence is consulted to offer a new decoration suggestion | ||
| 570 | when we rotate the underlines at the end of the existing | ||
| 571 | hierarchy of characters, or when there is no existing section | ||
| 572 | title in the file." | ||
| 573 | :group 'rst-adjust) | ||
| 574 | |||
| 575 | |||
| 576 | (defcustom rst-default-indent 1 | ||
| 577 | "Number of characters to indent the section title. | ||
| 578 | |||
| 579 | THis is used for when toggling decoration styles, when switching | ||
| 580 | from a simple decoration style to a over-and-under decoration | ||
| 581 | style." | ||
| 582 | :group 'rst-adjust) | ||
| 583 | |||
| 584 | |||
| 585 | (defvar rst-section-text-regexp "^[ \t]*\\S-*\\w\\S-*" | ||
| 586 | "Regular expression for valid section title text.") | ||
| 587 | |||
| 588 | |||
| 589 | (defun rst-line-homogeneous-p (&optional accept-special) | ||
| 590 | "Return true if the line is homogeneous. | ||
| 591 | |||
| 592 | Predicate that returns the unique char if the current line is | ||
| 593 | composed only of a single repeated non-whitespace character. This | ||
| 594 | returns the char even if there is whitespace at the beginning of | ||
| 595 | the line. | ||
| 596 | |||
| 597 | If ACCEPT-SPECIAL is specified we do not ignore special sequences | ||
| 598 | which normally we would ignore when doing a search on many lines. | ||
| 599 | For example, normally we have cases to ignore commonly occuring | ||
| 600 | patterns, such as :: or ...; with the flag do not ignore them." | ||
| 601 | (save-excursion | ||
| 602 | (back-to-indentation) | ||
| 603 | (unless (looking-at "\n") | ||
| 604 | (let ((c (thing-at-point 'char))) | ||
| 605 | (if (and (looking-at (format "[%s]+[ \t]*$" c)) | ||
| 606 | (or accept-special | ||
| 607 | (and | ||
| 608 | ;; Common patterns. | ||
| 609 | (not (looking-at "::[ \t]*$")) | ||
| 610 | (not (looking-at "\\.\\.\\.[ \t]*$")) | ||
| 611 | ;; Discard one char line | ||
| 612 | (not (looking-at ".[ \t]*$")) | ||
| 613 | ))) | ||
| 614 | (string-to-char c)) | ||
| 615 | )) | ||
| 616 | )) | ||
| 617 | |||
| 618 | (defun rst-line-homogeneous-nodent-p (&optional accept-special) | ||
| 619 | "Return true if the line is homogeneous with no indent. | ||
| 620 | See `rst-line-homogeneous-p' about ACCEPT-SPECIAL." | ||
| 621 | (save-excursion | ||
| 622 | (beginning-of-line) | ||
| 623 | (if (looking-at "^[ \t]+") | ||
| 624 | nil | ||
| 625 | (rst-line-homogeneous-p accept-special) | ||
| 626 | ))) | ||
| 627 | |||
| 628 | |||
| 629 | (defun rst-compare-decorations (deco1 deco2) | ||
| 630 | "Compare decorations. | ||
| 631 | Returns true if both DECO1 and DECO2 decorations are equal, | ||
| 632 | according to restructured text semantics (only the character and | ||
| 633 | the style are compared, the indentation does not matter." | ||
| 634 | (and (eq (car deco1) (car deco2)) | ||
| 635 | (eq (cadr deco1) (cadr deco2)))) | ||
| 636 | |||
| 637 | |||
| 638 | (defun rst-get-decoration-match (hier deco) | ||
| 639 | "Return the index (level) in hierarchy HIER of decoration DECO. | ||
| 640 | This basically just searches for the item using the appropriate | ||
| 641 | comparison and returns the index. We return nil if the item is | ||
| 642 | not found." | ||
| 643 | (let ((cur hier)) | ||
| 644 | (while (and cur (not (rst-compare-decorations (car cur) deco))) | ||
| 645 | (setq cur (cdr cur))) | ||
| 646 | cur)) | ||
| 647 | |||
| 648 | |||
| 649 | (defun rst-suggest-new-decoration (alldecos &optional prev) | ||
| 650 | "Suggest a new, different decoration from all that have been seen. | ||
| 651 | |||
| 652 | ALLDECOS is the set of all decorations, including the line | ||
| 653 | numbers. PREV is the optional previous decoration, in order to | ||
| 654 | suggest a better match." | ||
| 655 | |||
| 656 | ;; For all the preferred decorations... | ||
| 657 | (let* ( | ||
| 658 | ;; If 'prev' is given, reorder the list to start searching after the | ||
| 659 | ;; match. | ||
| 660 | (fplist | ||
| 661 | (cdr (rst-get-decoration-match rst-preferred-decorations prev))) | ||
| 662 | |||
| 663 | ;; List of candidates to search. | ||
| 664 | (curpotential (append fplist rst-preferred-decorations))) | ||
| 665 | (while | ||
| 666 | ;; For all the decorations... | ||
| 667 | (let ((cur alldecos) | ||
| 668 | found) | ||
| 669 | (while (and cur (not found)) | ||
| 670 | (if (rst-compare-decorations (car cur) (car curpotential)) | ||
| 671 | ;; Found it! | ||
| 672 | (setq found (car curpotential)) | ||
| 673 | (setq cur (cdr cur)))) | ||
| 674 | found) | ||
| 675 | |||
| 676 | (setq curpotential (cdr curpotential))) | ||
| 677 | |||
| 678 | (copy-list (car curpotential)) )) | ||
| 679 | |||
| 680 | (defun rst-delete-entire-line () | ||
| 681 | "Delete the entire current line without using the `kill-ring'." | ||
| 682 | (delete-region (line-beginning-position) (min (+ 1 (line-end-position)) | ||
| 683 | (point-max)))) | ||
| 684 | |||
| 685 | (defun rst-update-section (char style &optional indent) | ||
| 686 | "Unconditionally update the style of a section decoration. | ||
| 687 | |||
| 688 | Do this using the given character CHAR, with STYLE 'simple or | ||
| 689 | 'over-and-under, and with indent INDENT. If the STYLE is | ||
| 690 | 'simple, whitespace before the title is removed (indent is always | ||
| 691 | assume to be 0). | ||
| 692 | |||
| 693 | If there are existing overline and/or underline from the | ||
| 694 | existing decoration, they are removed before adding the | ||
| 695 | requested decoration." | ||
| 696 | |||
| 697 | (interactive) | ||
| 698 | (let (marker | ||
| 699 | len) | ||
| 700 | |||
| 701 | (end-of-line) | ||
| 702 | (setq marker (point-marker)) | ||
| 703 | |||
| 704 | ;; Fixup whitespace at the beginning and end of the line | ||
| 705 | (if (or (null indent) (eq style 'simple)) | ||
| 706 | (setq indent 0)) | ||
| 707 | (beginning-of-line) | ||
| 708 | (delete-horizontal-space) | ||
| 709 | (insert (make-string indent ? )) | ||
| 710 | |||
| 711 | (end-of-line) | ||
| 712 | (delete-horizontal-space) | ||
| 713 | |||
| 714 | ;; Set the current column, we're at the end of the title line | ||
| 715 | (setq len (+ (current-column) indent)) | ||
| 716 | |||
| 717 | ;; Remove previous line if it consists only of a single repeated character | ||
| 718 | (save-excursion | ||
| 719 | (forward-line -1) | ||
| 720 | (and (rst-line-homogeneous-p 1) | ||
| 721 | ;; Avoid removing the underline of a title right above us. | ||
| 722 | (save-excursion (forward-line -1) | ||
| 723 | (not (looking-at rst-section-text-regexp))) | ||
| 724 | (rst-delete-entire-line))) | ||
| 725 | |||
| 726 | ;; Remove following line if it consists only of a single repeated | ||
| 727 | ;; character | ||
| 728 | (save-excursion | ||
| 729 | (forward-line +1) | ||
| 730 | (and (rst-line-homogeneous-p 1) | ||
| 731 | (rst-delete-entire-line)) | ||
| 732 | ;; Add a newline if we're at the end of the buffer, for the subsequence | ||
| 733 | ;; inserting of the underline | ||
| 734 | (if (= (point) (buffer-end 1)) | ||
| 735 | (newline 1))) | ||
| 736 | |||
| 737 | ;; Insert overline | ||
| 738 | (if (eq style 'over-and-under) | ||
| 739 | (save-excursion | ||
| 740 | (beginning-of-line) | ||
| 741 | (open-line 1) | ||
| 742 | (insert (make-string len char)))) | ||
| 743 | |||
| 744 | ;; Insert underline | ||
| 745 | (forward-line +1) | ||
| 746 | (open-line 1) | ||
| 747 | (insert (make-string len char)) | ||
| 748 | |||
| 749 | (forward-line +1) | ||
| 750 | (goto-char marker) | ||
| 751 | )) | ||
| 752 | |||
| 753 | |||
| 754 | (defun rst-normalize-cursor-position () | ||
| 755 | "Normalize the cursor position. | ||
| 756 | If the cursor is on a decoration line or an empty line , place it | ||
| 757 | on the section title line (at the end). Returns the line offset | ||
| 758 | by which the cursor was moved. This works both over or under a | ||
| 759 | line." | ||
| 760 | (if (save-excursion (beginning-of-line) | ||
| 761 | (or (rst-line-homogeneous-p 1) | ||
| 762 | (looking-at "^[ \t]*$"))) | ||
| 763 | (progn | ||
| 764 | (beginning-of-line) | ||
| 765 | (cond | ||
| 766 | ((save-excursion (forward-line -1) | ||
| 767 | (beginning-of-line) | ||
| 768 | (and (looking-at rst-section-text-regexp) | ||
| 769 | (not (rst-line-homogeneous-p 1)))) | ||
| 770 | (progn (forward-line -1) -1)) | ||
| 771 | ((save-excursion (forward-line +1) | ||
| 772 | (beginning-of-line) | ||
| 773 | (and (looking-at rst-section-text-regexp) | ||
| 774 | (not (rst-line-homogeneous-p 1)))) | ||
| 775 | (progn (forward-line +1) +1)) | ||
| 776 | (t 0))) | ||
| 777 | 0 )) | ||
| 778 | |||
| 779 | |||
| 780 | (defun rst-find-all-decorations () | ||
| 781 | "Find all the decorations in the file. | ||
| 782 | Return a list of (line, decoration) pairs. Each decoration | ||
| 783 | consists in a (char, style, indent) triple. | ||
| 784 | |||
| 785 | This function does not detect the hierarchy of decorations, it | ||
| 786 | just finds all of them in a file. You can then invoke another | ||
| 787 | function to remove redundancies and inconsistencies." | ||
| 788 | |||
| 789 | (let (positions | ||
| 790 | (curline 1)) | ||
| 791 | ;; Iterate over all the section titles/decorations in the file. | ||
| 792 | (save-excursion | ||
| 793 | (goto-char (point-min)) | ||
| 794 | (while (< (point) (buffer-end 1)) | ||
| 795 | (if (rst-line-homogeneous-nodent-p) | ||
| 796 | (progn | ||
| 797 | (setq curline (+ curline (rst-normalize-cursor-position))) | ||
| 798 | |||
| 799 | ;; Here we have found a potential site for a decoration, | ||
| 800 | ;; characterize it. | ||
| 801 | (let ((deco (rst-get-decoration))) | ||
| 802 | (if (cadr deco) ;; Style is existing. | ||
| 803 | ;; Found a real decoration site. | ||
| 804 | (progn | ||
| 805 | (push (cons curline deco) positions) | ||
| 806 | ;; Push beyond the underline. | ||
| 807 | (forward-line 1) | ||
| 808 | (setq curline (+ curline 1)) | ||
| 809 | ))) | ||
| 810 | )) | ||
| 811 | (forward-line 1) | ||
| 812 | (setq curline (+ curline 1)) | ||
| 813 | )) | ||
| 814 | (reverse positions))) | ||
| 815 | |||
| 816 | |||
| 817 | (defun rst-infer-hierarchy (decorations) | ||
| 818 | "Build a hierarchy of decorations using the list of given DECORATIONS. | ||
| 819 | |||
| 820 | This function expects a list of (char, style, indent) decoration | ||
| 821 | specifications, in order that they appear in a file, and will | ||
| 822 | infer a hierarchy of section levels by removing decorations that | ||
| 823 | have already been seen in a forward traversal of the decorations, | ||
| 824 | comparing just the character and style. | ||
| 825 | |||
| 826 | Similarly returns a list of (char, style, indent), where each | ||
| 827 | list element should be unique." | ||
| 828 | |||
| 829 | (let ((hierarchy-alist (list))) | ||
| 830 | (dolist (x decorations) | ||
| 831 | (let ((char (car x)) | ||
| 832 | (style (cadr x))) | ||
| 833 | (unless (assoc (cons char style) hierarchy-alist) | ||
| 834 | (push (cons (cons char style) x) hierarchy-alist)) | ||
| 835 | )) | ||
| 836 | |||
| 837 | (mapcar 'cdr (nreverse hierarchy-alist)) | ||
| 838 | )) | ||
| 839 | |||
| 840 | |||
| 841 | (defun rst-get-hierarchy (&optional alldecos ignore) | ||
| 842 | "Return the hierarchy of section titles in the file. | ||
| 843 | |||
| 844 | Return a list of decorations that represents the hierarchy of | ||
| 845 | section titles in the file. Reuse the list of decorations | ||
| 846 | already computed in ALLDECOS if present. If the line number in | ||
| 847 | IGNORE is specified, the decoration found on that line (if there | ||
| 848 | is one) is not taken into account when building the hierarchy." | ||
| 849 | (let ((all (or alldecos (rst-find-all-decorations)))) | ||
| 850 | (setq all (assq-delete-all ignore all)) | ||
| 851 | (rst-infer-hierarchy (mapcar 'cdr all)))) | ||
| 852 | |||
| 853 | |||
| 854 | (defun rst-get-decoration (&optional point) | ||
| 855 | "Get the decoration at POINT. | ||
| 856 | |||
| 857 | Looks around point and finds the characteristics of the | ||
| 858 | decoration that is found there. We assume that the cursor is | ||
| 859 | already placed on the title line (and not on the overline or | ||
| 860 | underline). | ||
| 861 | |||
| 862 | This function returns a (char, style, indent) triple. If the | ||
| 863 | characters of overline and underline are different, we return | ||
| 864 | the underline character. The indent is always calculated. A | ||
| 865 | decoration can be said to exist if the style is not nil. | ||
| 866 | |||
| 867 | A point can be specified to go to the given location before | ||
| 868 | extracting the decoration." | ||
| 869 | |||
| 870 | (let (char style indent) | ||
| 871 | (save-excursion | ||
| 872 | (if point (goto-char point)) | ||
| 873 | (beginning-of-line) | ||
| 874 | (if (looking-at rst-section-text-regexp) | ||
| 875 | (let* ((over (save-excursion | ||
| 876 | (forward-line -1) | ||
| 877 | (rst-line-homogeneous-nodent-p))) | ||
| 878 | |||
| 879 | (under (save-excursion | ||
| 880 | (forward-line +1) | ||
| 881 | (rst-line-homogeneous-nodent-p))) | ||
| 882 | ) | ||
| 883 | |||
| 884 | ;; Check that the line above the overline is not part of a title | ||
| 885 | ;; above it. | ||
| 886 | (if (and over | ||
| 887 | (save-excursion | ||
| 888 | (and (equal (forward-line -2) 0) | ||
| 889 | (looking-at rst-section-text-regexp)))) | ||
| 890 | (setq over nil)) | ||
| 891 | |||
| 892 | (cond | ||
| 893 | ;; No decoration found, leave all return values nil. | ||
| 894 | ((and (eq over nil) (eq under nil))) | ||
| 895 | |||
| 896 | ;; Overline only, leave all return values nil. | ||
| 897 | ;; | ||
| 898 | ;; Note: we don't return the overline character, but it could | ||
| 899 | ;; perhaps in some cases be used to do something. | ||
| 900 | ((and over (eq under nil))) | ||
| 901 | |||
| 902 | ;; Underline only. | ||
| 903 | ((and under (eq over nil)) | ||
| 904 | (setq char under | ||
| 905 | style 'simple)) | ||
| 906 | |||
| 907 | ;; Both overline and underline. | ||
| 908 | (t | ||
| 909 | (setq char under | ||
| 910 | style 'over-and-under)) | ||
| 911 | ) | ||
| 912 | ) | ||
| 913 | ) | ||
| 914 | ;; Find indentation. | ||
| 915 | (setq indent (save-excursion (back-to-indentation) (current-column))) | ||
| 916 | ) | ||
| 917 | ;; Return values. | ||
| 918 | (list char style indent))) | ||
| 919 | |||
| 920 | |||
| 921 | (defun rst-get-decorations-around (&optional alldecos) | ||
| 922 | "Return the decorations around point. | ||
| 923 | |||
| 924 | Given the list of all decorations ALLDECOS (with positions), find | ||
| 925 | the decorations before and after the given point. A list of the | ||
| 926 | previous and next decorations is returned." | ||
| 927 | (let* ((all (or alldecos (rst-find-all-decorations))) | ||
| 928 | (curline (line-number-at-pos)) | ||
| 929 | prev next | ||
| 930 | (cur all)) | ||
| 931 | |||
| 932 | ;; Search for the decorations around the current line. | ||
| 933 | (while (and cur (< (caar cur) curline)) | ||
| 934 | (setq prev cur | ||
| 935 | cur (cdr cur))) | ||
| 936 | ;; 'cur' is the following decoration. | ||
| 937 | |||
| 938 | (if (and cur (caar cur)) | ||
| 939 | (setq next (if (= curline (caar cur)) (cdr cur) cur))) | ||
| 940 | |||
| 941 | (mapcar 'cdar (list prev next)) | ||
| 942 | )) | ||
| 943 | |||
| 944 | |||
| 945 | (defun rst-decoration-complete-p (deco) | ||
| 946 | "Return true if the decoration DECO around POINT is complete." | ||
| 947 | ;; Note: we assume that the detection of the overline as being the underline | ||
| 948 | ;; of a preceding title has already been detected, and has been eliminated | ||
| 949 | ;; from the decoration that is given to us. | ||
| 950 | |||
| 951 | ;; There is some sectioning already present, so check if the current | ||
| 952 | ;; sectioning is complete and correct. | ||
| 953 | (let* ((char (car deco)) | ||
| 954 | (style (cadr deco)) | ||
| 955 | (indent (caddr deco)) | ||
| 956 | (endcol (save-excursion (end-of-line) (current-column))) | ||
| 957 | ) | ||
| 958 | (if char | ||
| 959 | (let ((exps (concat "^" | ||
| 960 | (regexp-quote (make-string (+ endcol indent) char)) | ||
| 961 | "$"))) | ||
| 962 | (and | ||
| 963 | (save-excursion (forward-line +1) | ||
| 964 | (beginning-of-line) | ||
| 965 | (looking-at exps)) | ||
| 966 | (or (not (eq style 'over-and-under)) | ||
| 967 | (save-excursion (forward-line -1) | ||
| 968 | (beginning-of-line) | ||
| 969 | (looking-at exps)))) | ||
| 970 | )) | ||
| 971 | )) | ||
| 972 | |||
| 973 | |||
| 974 | (defun rst-get-next-decoration | ||
| 975 | (curdeco hier &optional suggestion reverse-direction) | ||
| 976 | "Get the next decoration for CURDECO, in given hierarchy HIER. | ||
| 977 | If suggesting, suggest for new decoration SUGGESTION. | ||
| 978 | REVERSE-DIRECTION is used to reverse the cycling order." | ||
| 979 | |||
| 980 | (let* ( | ||
| 981 | (char (car curdeco)) | ||
| 982 | (style (cadr curdeco)) | ||
| 983 | |||
| 984 | ;; Build a new list of decorations for the rotation. | ||
| 985 | (rotdecos | ||
| 986 | (append hier | ||
| 987 | ;; Suggest a new decoration. | ||
| 988 | (list suggestion | ||
| 989 | ;; If nothing to suggest, use first decoration. | ||
| 990 | (car hier)))) ) | ||
| 991 | (or | ||
| 992 | ;; Search for next decoration. | ||
| 993 | (cadr | ||
| 994 | (let ((cur (if reverse-direction rotdecos | ||
| 995 | (reverse rotdecos)))) | ||
| 996 | (while (and cur | ||
| 997 | (not (and (eq char (caar cur)) | ||
| 998 | (eq style (cadar cur))))) | ||
| 999 | (setq cur (cdr cur))) | ||
| 1000 | cur)) | ||
| 1001 | |||
| 1002 | ;; If not found, take the first of all decorations. | ||
| 1003 | suggestion | ||
| 1004 | ))) | ||
| 1005 | |||
| 1006 | |||
| 1007 | (defun rst-adjust () | ||
| 1008 | "Auto-adjust the decoration around point. | ||
| 1009 | |||
| 1010 | Adjust/rotate the section decoration for the section title | ||
| 1011 | around point or promote/demote the decorations inside the region, | ||
| 1012 | depending on if the region is active. This function is meant to | ||
| 1013 | be invoked possibly multiple times, and can vary its behaviour | ||
| 1014 | with a positive prefix argument (toggle style), or with a | ||
| 1015 | negative prefix argument (alternate behaviour). | ||
| 1016 | |||
| 1017 | This function is the main focus of this module and is a bit of a | ||
| 1018 | swiss knife. It is meant as the single most essential function | ||
| 1019 | to be bound to invoke to adjust the decorations of a section | ||
| 1020 | title in restructuredtext. It tries to deal with all the | ||
| 1021 | possible cases gracefully and to do `the right thing' in all | ||
| 1022 | cases. | ||
| 1023 | |||
| 1024 | See the documentations of `rst-adjust-decoration' and | ||
| 1025 | `rst-promote-region' for full details. | ||
| 1026 | |||
| 1027 | Prefix Arguments | ||
| 1028 | ================ | ||
| 1029 | |||
| 1030 | The method can take either (but not both) of | ||
| 1031 | |||
| 1032 | a. a (non-negative) prefix argument, which means to toggle the | ||
| 1033 | decoration style. Invoke with a prefix arg for example; | ||
| 1034 | |||
| 1035 | b. a negative numerical argument, which generally inverts the | ||
| 1036 | direction of search in the file or hierarchy. Invoke with C-- | ||
| 1037 | prefix for example." | ||
| 1038 | (interactive) | ||
| 1039 | |||
| 1040 | (let* (;; Save our original position on the current line. | ||
| 1041 | (origpt (set-marker (make-marker) (point))) | ||
| 1042 | |||
| 1043 | ;; Parse the positive and negative prefix arguments. | ||
| 1044 | (reverse-direction | ||
| 1045 | (and current-prefix-arg | ||
| 1046 | (< (prefix-numeric-value current-prefix-arg) 0))) | ||
| 1047 | (toggle-style | ||
| 1048 | (and current-prefix-arg (not reverse-direction)))) | ||
| 1049 | |||
| 1050 | (if (rst-portable-mark-active-p) | ||
| 1051 | ;; Adjust decorations within region. | ||
| 1052 | (rst-promote-region current-prefix-arg) | ||
| 1053 | ;; Adjust decoration around point. | ||
| 1054 | (rst-adjust-decoration toggle-style reverse-direction)) | ||
| 1055 | |||
| 1056 | ;; Run the hooks to run after adjusting. | ||
| 1057 | (run-hooks 'rst-adjust-hook) | ||
| 1058 | |||
| 1059 | ;; Make sure to reset the cursor position properly after we're done. | ||
| 1060 | (goto-char origpt) | ||
| 1061 | |||
| 1062 | )) | ||
| 1063 | |||
| 1064 | (defvar rst-adjust-hook nil | ||
| 1065 | "Hooks to be run after running `rst-adjust'.") | ||
| 1066 | |||
| 1067 | (defvar rst-new-decoration-down nil | ||
| 1068 | "If true, a new decoration being added will be initialized to | ||
| 1069 | be one level down from the previous decoration. If nil, a new | ||
| 1070 | decoration will be equal to the level of the previous | ||
| 1071 | decoration.") | ||
| 1072 | |||
| 1073 | (defun rst-adjust-decoration (&optional toggle-style reverse-direction) | ||
| 1074 | "Adjust/rotate the section decoration for the section title around point. | ||
| 1075 | |||
| 1076 | This function is meant to be invoked possibly multiple times, and | ||
| 1077 | can vary its behaviour with a true TOGGLE-STYLE argument, or with | ||
| 1078 | a REVERSE-DIRECTION argument. | ||
| 1079 | |||
| 1080 | General Behaviour | ||
| 1081 | ================= | ||
| 1082 | |||
| 1083 | The next action it takes depends on context around the point, and | ||
| 1084 | it is meant to be invoked possibly more than once to rotate among | ||
| 1085 | the various possibilities. Basically, this function deals with: | ||
| 1086 | |||
| 1087 | - adding a decoration if the title does not have one; | ||
| 1088 | |||
| 1089 | - adjusting the length of the underline characters to fit a | ||
| 1090 | modified title; | ||
| 1091 | |||
| 1092 | - rotating the decoration in the set of already existing | ||
| 1093 | sectioning decorations used in the file; | ||
| 1094 | |||
| 1095 | - switching between simple and over-and-under styles. | ||
| 1096 | |||
| 1097 | You should normally not have to read all the following, just | ||
| 1098 | invoke the method and it will do the most obvious thing that you | ||
| 1099 | would expect. | ||
| 1100 | |||
| 1101 | |||
| 1102 | Decoration Definitions | ||
| 1103 | ====================== | ||
| 1104 | |||
| 1105 | The decorations consist in | ||
| 1106 | |||
| 1107 | 1. a CHARACTER | ||
| 1108 | |||
| 1109 | 2. a STYLE which can be either of 'simple' or 'over-and-under'. | ||
| 1110 | |||
| 1111 | 3. an INDENT (meaningful for the over-and-under style only) | ||
| 1112 | which determines how many characters and over-and-under | ||
| 1113 | style is hanging outside of the title at the beginning and | ||
| 1114 | ending. | ||
| 1115 | |||
| 1116 | See source code for mode details. | ||
| 1117 | |||
| 1118 | |||
| 1119 | Detailed Behaviour Description | ||
| 1120 | ============================== | ||
| 1121 | |||
| 1122 | Here are the gory details of the algorithm (it seems quite | ||
| 1123 | complicated, but really, it does the most obvious thing in all | ||
| 1124 | the particular cases): | ||
| 1125 | |||
| 1126 | Before applying the decoration change, the cursor is placed on | ||
| 1127 | the closest line that could contain a section title. | ||
| 1128 | |||
| 1129 | Case 1: No Decoration | ||
| 1130 | --------------------- | ||
| 1131 | |||
| 1132 | If the current line has no decoration around it, | ||
| 1133 | |||
| 1134 | - search backwards for the last previous decoration, and apply | ||
| 1135 | the decoration one level lower to the current line. If there | ||
| 1136 | is no defined level below this previous decoration, we suggest | ||
| 1137 | the most appropriate of the `rst-preferred-decorations'. | ||
| 1138 | |||
| 1139 | If REVERSE-DIRECTION is true, we simply use the previous | ||
| 1140 | decoration found directly. | ||
| 1141 | |||
| 1142 | - if there is no decoration found in the given direction, we use | ||
| 1143 | the first of `rst-preferred-decorations'. | ||
| 1144 | |||
| 1145 | The prefix argument forces a toggle of the prescribed decoration | ||
| 1146 | style. | ||
| 1147 | |||
| 1148 | Case 2: Incomplete Decoration | ||
| 1149 | ----------------------------- | ||
| 1150 | |||
| 1151 | If the current line does have an existing decoration, but the | ||
| 1152 | decoration is incomplete, that is, the underline/overline does | ||
| 1153 | not extend to exactly the end of the title line (it is either too | ||
| 1154 | short or too long), we simply extend the length of the | ||
| 1155 | underlines/overlines to fit exactly the section title. | ||
| 1156 | |||
| 1157 | If the prefix argument is given, we toggle the style of the | ||
| 1158 | decoration as well. | ||
| 1159 | |||
| 1160 | REVERSE-DIRECTION has no effect in this case. | ||
| 1161 | |||
| 1162 | Case 3: Complete Existing Decoration | ||
| 1163 | ------------------------------------ | ||
| 1164 | |||
| 1165 | If the decoration is complete (i.e. the underline (overline) | ||
| 1166 | length is already adjusted to the end of the title line), we | ||
| 1167 | search/parse the file to establish the hierarchy of all the | ||
| 1168 | decorations (making sure not to include the decoration around | ||
| 1169 | point), and we rotate the current title's decoration from within | ||
| 1170 | that list (by default, going *down* the hierarchy that is present | ||
| 1171 | in the file, i.e. to a lower section level). This is meant to be | ||
| 1172 | used potentially multiple times, until the desired decoration is | ||
| 1173 | found around the title. | ||
| 1174 | |||
| 1175 | If we hit the boundary of the hierarchy, exactly one choice from | ||
| 1176 | the list of preferred decorations is suggested/chosen, the first | ||
| 1177 | of those decoration that has not been seen in the file yet (and | ||
| 1178 | not including the decoration around point), and the next | ||
| 1179 | invocation rolls over to the other end of the hierarchy (i.e. it | ||
| 1180 | cycles). This allows you to avoid having to set which character | ||
| 1181 | to use by always using the | ||
| 1182 | |||
| 1183 | If REVERSE-DIRECTION is true, the effect is to change the | ||
| 1184 | direction of rotation in the hierarchy of decorations, thus | ||
| 1185 | instead going *up* the hierarchy. | ||
| 1186 | |||
| 1187 | However, if there is a non-negative prefix argument, we do not | ||
| 1188 | rotate the decoration, but instead simply toggle the style of the | ||
| 1189 | current decoration (this should be the most common way to toggle | ||
| 1190 | the style of an existing complete decoration). | ||
| 1191 | |||
| 1192 | |||
| 1193 | Point Location | ||
| 1194 | ============== | ||
| 1195 | |||
| 1196 | The invocation of this function can be carried out anywhere | ||
| 1197 | within the section title line, on an existing underline or | ||
| 1198 | overline, as well as on an empty line following a section title. | ||
| 1199 | This is meant to be as convenient as possible. | ||
| 1200 | |||
| 1201 | |||
| 1202 | Indented Sections | ||
| 1203 | ================= | ||
| 1204 | |||
| 1205 | Indented section titles such as :: | ||
| 1206 | |||
| 1207 | My Title | ||
| 1208 | -------- | ||
| 1209 | |||
| 1210 | are illegal in restructuredtext and thus not recognized by the | ||
| 1211 | parser. This code will thus not work in a way that would support | ||
| 1212 | indented sections (it would be ambiguous anyway). | ||
| 1213 | |||
| 1214 | |||
| 1215 | Joint Sections | ||
| 1216 | ============== | ||
| 1217 | |||
| 1218 | Section titles that are right next to each other may not be | ||
| 1219 | treated well. More work might be needed to support those, and | ||
| 1220 | special conditions on the completeness of existing decorations | ||
| 1221 | might be required to make it non-ambiguous. | ||
| 1222 | |||
| 1223 | For now we assume that the decorations are disjoint, that is, | ||
| 1224 | there is at least a single line between the titles/decoration | ||
| 1225 | lines. | ||
| 1226 | |||
| 1227 | |||
| 1228 | Suggested Binding | ||
| 1229 | ================= | ||
| 1230 | |||
| 1231 | We suggest that you bind this function on C-=. It is close to | ||
| 1232 | C-- so a negative argument can be easily specified with a flick | ||
| 1233 | of the right hand fingers and the binding is unused in `text-mode'." | ||
| 1234 | (interactive) | ||
| 1235 | |||
| 1236 | ;; If we were invoked directly, parse the prefix arguments into the | ||
| 1237 | ;; arguments of the function. | ||
| 1238 | (if current-prefix-arg | ||
| 1239 | (setq reverse-direction | ||
| 1240 | (and current-prefix-arg | ||
| 1241 | (< (prefix-numeric-value current-prefix-arg) 0)) | ||
| 1242 | |||
| 1243 | toggle-style | ||
| 1244 | (and current-prefix-arg (not reverse-direction)))) | ||
| 1245 | |||
| 1246 | (let* (;; Check if we're on an underline around a section title, and move the | ||
| 1247 | ;; cursor to the title if this is the case. | ||
| 1248 | (moved (rst-normalize-cursor-position)) | ||
| 1249 | |||
| 1250 | ;; Find the decoration and completeness around point. | ||
| 1251 | (curdeco (rst-get-decoration)) | ||
| 1252 | (char (car curdeco)) | ||
| 1253 | (style (cadr curdeco)) | ||
| 1254 | (indent (caddr curdeco)) | ||
| 1255 | |||
| 1256 | ;; New values to be computed. | ||
| 1257 | char-new style-new indent-new | ||
| 1258 | ) | ||
| 1259 | |||
| 1260 | ;; We've moved the cursor... if we're not looking at some text, we have | ||
| 1261 | ;; nothing to do. | ||
| 1262 | (if (save-excursion (beginning-of-line) | ||
| 1263 | (looking-at rst-section-text-regexp)) | ||
| 1264 | (progn | ||
| 1265 | (cond | ||
| 1266 | ;;------------------------------------------------------------------- | ||
| 1267 | ;; Case 1: No Decoration | ||
| 1268 | ((and (eq char nil) (eq style nil)) | ||
| 1269 | |||
| 1270 | (let* ((alldecos (rst-find-all-decorations)) | ||
| 1271 | |||
| 1272 | (around (rst-get-decorations-around alldecos)) | ||
| 1273 | (prev (car around)) | ||
| 1274 | cur | ||
| 1275 | |||
| 1276 | (hier (rst-get-hierarchy alldecos)) | ||
| 1277 | ) | ||
| 1278 | |||
| 1279 | ;; Advance one level down. | ||
| 1280 | (setq cur | ||
| 1281 | (if prev | ||
| 1282 | (if (not reverse-direction) | ||
| 1283 | (or (funcall (if rst-new-decoration-down 'cadr 'car) | ||
| 1284 | (rst-get-decoration-match hier prev)) | ||
| 1285 | (rst-suggest-new-decoration hier prev)) | ||
| 1286 | prev) | ||
| 1287 | (copy-list (car rst-preferred-decorations)) | ||
| 1288 | )) | ||
| 1289 | |||
| 1290 | ;; Invert the style if requested. | ||
| 1291 | (if toggle-style | ||
| 1292 | (setcar (cdr cur) (if (eq (cadr cur) 'simple) | ||
| 1293 | 'over-and-under 'simple)) ) | ||
| 1294 | |||
| 1295 | (setq char-new (car cur) | ||
| 1296 | style-new (cadr cur) | ||
| 1297 | indent-new (caddr cur)) | ||
| 1298 | )) | ||
| 1299 | |||
| 1300 | ;;------------------------------------------------------------------- | ||
| 1301 | ;; Case 2: Incomplete Decoration | ||
| 1302 | ((not (rst-decoration-complete-p curdeco)) | ||
| 1303 | |||
| 1304 | ;; Invert the style if requested. | ||
| 1305 | (if toggle-style | ||
| 1306 | (setq style (if (eq style 'simple) 'over-and-under 'simple))) | ||
| 1307 | |||
| 1308 | (setq char-new char | ||
| 1309 | style-new style | ||
| 1310 | indent-new indent)) | ||
| 1311 | |||
| 1312 | ;;------------------------------------------------------------------- | ||
| 1313 | ;; Case 3: Complete Existing Decoration | ||
| 1314 | (t | ||
| 1315 | (if toggle-style | ||
| 1316 | |||
| 1317 | ;; Simply switch the style of the current decoration. | ||
| 1318 | (setq char-new char | ||
| 1319 | style-new (if (eq style 'simple) 'over-and-under 'simple) | ||
| 1320 | indent-new rst-default-indent) | ||
| 1321 | |||
| 1322 | ;; Else, we rotate, ignoring the decoration around the current | ||
| 1323 | ;; line... | ||
| 1324 | (let* ((alldecos (rst-find-all-decorations)) | ||
| 1325 | |||
| 1326 | (hier (rst-get-hierarchy alldecos (line-number-at-pos))) | ||
| 1327 | |||
| 1328 | ;; Suggestion, in case we need to come up with something | ||
| 1329 | ;; new | ||
| 1330 | (suggestion (rst-suggest-new-decoration | ||
| 1331 | hier | ||
| 1332 | (car (rst-get-decorations-around alldecos)))) | ||
| 1333 | |||
| 1334 | (nextdeco (rst-get-next-decoration | ||
| 1335 | curdeco hier suggestion reverse-direction)) | ||
| 1336 | |||
| 1337 | ) | ||
| 1338 | |||
| 1339 | ;; Indent, if present, always overrides the prescribed indent. | ||
| 1340 | (setq char-new (car nextdeco) | ||
| 1341 | style-new (cadr nextdeco) | ||
| 1342 | indent-new (caddr nextdeco)) | ||
| 1343 | |||
| 1344 | ))) | ||
| 1345 | ) | ||
| 1346 | |||
| 1347 | ;; Override indent with present indent! | ||
| 1348 | (setq indent-new (if (> indent 0) indent indent-new)) | ||
| 1349 | |||
| 1350 | (if (and char-new style-new) | ||
| 1351 | (rst-update-section char-new style-new indent-new)) | ||
| 1352 | )) | ||
| 1353 | |||
| 1354 | |||
| 1355 | ;; Correct the position of the cursor to more accurately reflect where it | ||
| 1356 | ;; was located when the function was invoked. | ||
| 1357 | (unless (= moved 0) | ||
| 1358 | (forward-line (- moved)) | ||
| 1359 | (end-of-line)) | ||
| 1360 | |||
| 1361 | )) | ||
| 1362 | |||
| 1363 | ;; Maintain an alias for compatibility. | ||
| 1364 | (defalias 'rst-adjust-section-title 'rst-adjust) | ||
| 1365 | |||
| 1366 | |||
| 1367 | (defun rst-promote-region (&optional demote) | ||
| 1368 | "Promote the section titles within the region. | ||
| 1369 | |||
| 1370 | With argument DEMOTE or a prefix argument, demote the | ||
| 1371 | section titles instead. The algorithm used at the boundaries of | ||
| 1372 | the hierarchy is similar to that used by `rst-adjust-decoration'." | ||
| 1373 | (interactive) | ||
| 1374 | |||
| 1375 | (let* ((demote (or current-prefix-arg demote)) | ||
| 1376 | (alldecos (rst-find-all-decorations)) | ||
| 1377 | (cur alldecos) | ||
| 1378 | |||
| 1379 | (hier (rst-get-hierarchy alldecos)) | ||
| 1380 | (suggestion (rst-suggest-new-decoration hier)) | ||
| 1381 | |||
| 1382 | (region-begin-line (line-number-at-pos (region-beginning))) | ||
| 1383 | (region-end-line (line-number-at-pos (region-end))) | ||
| 1384 | |||
| 1385 | marker-list | ||
| 1386 | ) | ||
| 1387 | |||
| 1388 | ;; Skip the markers that come before the region beginning | ||
| 1389 | (while (and cur (< (caar cur) region-begin-line)) | ||
| 1390 | (setq cur (cdr cur))) | ||
| 1391 | |||
| 1392 | ;; Create a list of markers for all the decorations which are found within | ||
| 1393 | ;; the region. | ||
| 1394 | (save-excursion | ||
| 1395 | (let (m line) | ||
| 1396 | (while (and cur (< (setq line (caar cur)) region-end-line)) | ||
| 1397 | (setq m (make-marker)) | ||
| 1398 | (goto-line line) | ||
| 1399 | (push (list (set-marker m (point)) (cdar cur)) marker-list) | ||
| 1400 | (setq cur (cdr cur)) )) | ||
| 1401 | |||
| 1402 | ;; Apply modifications. | ||
| 1403 | (let (nextdeco) | ||
| 1404 | (dolist (p marker-list) | ||
| 1405 | ;; Go to the decoration to promote. | ||
| 1406 | (goto-char (car p)) | ||
| 1407 | |||
| 1408 | ;; Rotate the next decoration. | ||
| 1409 | (setq nextdeco (rst-get-next-decoration | ||
| 1410 | (cadr p) hier suggestion demote)) | ||
| 1411 | |||
| 1412 | ;; Update the decoration. | ||
| 1413 | (apply 'rst-update-section nextdeco) | ||
| 1414 | |||
| 1415 | ;; Clear marker to avoid slowing down the editing after we're done. | ||
| 1416 | (set-marker (car p) nil) | ||
| 1417 | )) | ||
| 1418 | (setq deactivate-mark nil) | ||
| 1419 | ))) | ||
| 1420 | |||
| 1421 | |||
| 1422 | |||
| 1423 | (defun rst-display-decorations-hierarchy (&optional decorations) | ||
| 1424 | "Display the current file's section title decorations hierarchy. | ||
| 1425 | This function expects a list of (char, style, indent) triples in | ||
| 1426 | DECORATIONS." | ||
| 1427 | (interactive) | ||
| 1428 | |||
| 1429 | (if (not decorations) | ||
| 1430 | (setq decorations (rst-get-hierarchy))) | ||
| 1431 | (with-output-to-temp-buffer "*rest section hierarchy*" | ||
| 1432 | (let ((level 1)) | ||
| 1433 | (with-current-buffer standard-output | ||
| 1434 | (dolist (x decorations) | ||
| 1435 | (insert (format "\nSection Level %d" level)) | ||
| 1436 | (apply 'rst-update-section x) | ||
| 1437 | (goto-char (point-max)) | ||
| 1438 | (insert "\n") | ||
| 1439 | (incf level) | ||
| 1440 | )) | ||
| 1441 | ))) | ||
| 1442 | |||
| 1443 | (defun rst-straighten-decorations () | ||
| 1444 | "Redo all the decorations in the current buffer. | ||
| 1445 | This is done using our preferred set of decorations. This can be | ||
| 1446 | used, for example, when using somebody else's copy of a document, | ||
| 1447 | in order to adapt it to our preferred style." | ||
| 1448 | (interactive) | ||
| 1449 | (save-excursion | ||
| 1450 | (let* ((alldecos (rst-find-all-decorations)) | ||
| 1451 | (hier (rst-get-hierarchy alldecos)) | ||
| 1452 | |||
| 1453 | ;; Get a list of pairs of (level . marker) | ||
| 1454 | (levels-and-markers (mapcar | ||
| 1455 | (lambda (deco) | ||
| 1456 | (cons (position (cdr deco) hier :test 'equal) | ||
| 1457 | (let ((m (make-marker))) | ||
| 1458 | (goto-line (car deco)) | ||
| 1459 | (set-marker m (point)) | ||
| 1460 | m))) | ||
| 1461 | alldecos)) | ||
| 1462 | ) | ||
| 1463 | (dolist (lm levels-and-markers) | ||
| 1464 | ;; Go to the appropriate position | ||
| 1465 | (goto-char (cdr lm)) | ||
| 1466 | |||
| 1467 | ;; Apply the new styule | ||
| 1468 | (apply 'rst-update-section (nth (car lm) rst-preferred-decorations)) | ||
| 1469 | |||
| 1470 | ;; Reset the market to avoid slowing down editing until it gets GC'ed | ||
| 1471 | (set-marker (cdr lm) nil) | ||
| 1472 | ) | ||
| 1473 | ))) | ||
| 1474 | |||
| 1475 | |||
| 1476 | |||
| 1477 | |||
| 1478 | (defun rst-straighten-deco-spacing () | ||
| 1479 | "Adjust the spacing before and after decorations in the entire document. | ||
| 1480 | The spacing will be set to two blank lines before the first two | ||
| 1481 | section levels, and one blank line before any of the other | ||
| 1482 | section levels." | ||
| 1483 | ;; FIXME: we need to take care of subtitle at some point. | ||
| 1484 | (interactive) | ||
| 1485 | (save-excursion | ||
| 1486 | (let* ((alldecos (rst-find-all-decorations))) | ||
| 1487 | |||
| 1488 | ;; Work the list from the end, so that we don't have to use markers to | ||
| 1489 | ;; adjust for the changes in the document. | ||
| 1490 | (dolist (deco (nreverse alldecos)) | ||
| 1491 | ;; Go to the appropriate position. | ||
| 1492 | (goto-line (car deco)) | ||
| 1493 | (insert "@\n") | ||
| 1494 | ;; FIXME: todo, we | ||
| 1495 | ) | ||
| 1496 | ))) | ||
| 1497 | |||
| 1498 | |||
| 1499 | (defun rst-find-pfx-in-region (beg end pfx-re) | ||
| 1500 | "Find all the positions of prefixes in region between BEG and END. | ||
| 1501 | This is used to find bullets and enumerated list items. PFX-RE | ||
| 1502 | is a regular expression for matching the lines with items." | ||
| 1503 | (let (pfx) | ||
| 1504 | (save-excursion | ||
| 1505 | (goto-char beg) | ||
| 1506 | (while (< (point) end) | ||
| 1507 | (back-to-indentation) | ||
| 1508 | (when (and | ||
| 1509 | (looking-at pfx-re) | ||
| 1510 | (let ((pfx-col (current-column))) | ||
| 1511 | (save-excursion | ||
| 1512 | (forward-line -1) | ||
| 1513 | (back-to-indentation) | ||
| 1514 | (or (looking-at "^[ \t]*$") | ||
| 1515 | (> (current-column) pfx-col) | ||
| 1516 | (and (= (current-column) pfx-col) | ||
| 1517 | (looking-at pfx-re)))))) | ||
| 1518 | (setq pfx (cons (cons (point) (current-column)) | ||
| 1519 | pfx))) | ||
| 1520 | (forward-line 1)) ) | ||
| 1521 | (nreverse pfx))) | ||
| 1522 | |||
| 1523 | (defvar rst-re-bullets | ||
| 1524 | (format "\\([%s][ \t]\\)[^ \t]" (regexp-quote (concat rst-bullets))) | ||
| 1525 | "Regexp for finding bullets.") | ||
| 1526 | |||
| 1527 | (defvar rst-re-enumerations | ||
| 1528 | "\\(\\(#\\|[0-9]+\\)\\.[ \t]\\)[^ \t]" | ||
| 1529 | "Regexp for finding bullets.") | ||
| 1530 | |||
| 1531 | (defvar rst-re-items | ||
| 1532 | (format "\\(%s\\|%s\\)[^ \t]" | ||
| 1533 | (format "[%s][ \t]" (regexp-quote (concat rst-bullets))) | ||
| 1534 | "\\(#\\|[0-9]+\\)\\.[ \t]") | ||
| 1535 | "Regexp for finding bullets.") | ||
| 1536 | |||
| 1537 | (defvar rst-preferred-bullets | ||
| 1538 | '(?- ?* ?+) | ||
| 1539 | "List of favourite bullets to set for straightening bullets.") | ||
| 1540 | |||
| 1541 | (defun rst-straighten-bullets-region (beg end) | ||
| 1542 | "Make all the bulleted list items in the region consistent. | ||
| 1543 | The region is specified between BEG and END. You can use this | ||
| 1544 | after you have merged multiple bulleted lists to make them use | ||
| 1545 | the same/correct/consistent bullet characters. | ||
| 1546 | |||
| 1547 | See variable `rst-preferred-bullets' for the list of bullets to | ||
| 1548 | adjust. If bullets are found on levels beyond the | ||
| 1549 | `rst-preferred-bullets' list, they are not modified." | ||
| 1550 | (interactive "r") | ||
| 1551 | |||
| 1552 | (let ((bullets (rst-find-pfx-in-region beg end | ||
| 1553 | rst-re-bullets)) | ||
| 1554 | (levtable (make-hash-table :size 4))) | ||
| 1555 | |||
| 1556 | ;; Create a map of levels to list of positions. | ||
| 1557 | (dolist (x bullets) | ||
| 1558 | (let ((key (cdr x))) | ||
| 1559 | (puthash key | ||
| 1560 | (append (gethash key levtable (list)) | ||
| 1561 | (list (car x))) | ||
| 1562 | levtable))) | ||
| 1563 | |||
| 1564 | ;; Sort this map and create a new map of prefix char and list of positions. | ||
| 1565 | (let (poslist) | ||
| 1566 | (maphash (lambda (x y) (setq poslist (cons (cons x y) poslist))) levtable) | ||
| 1567 | |||
| 1568 | (mapcar* (lambda (x char) | ||
| 1569 | ;; Apply the characters. | ||
| 1570 | (dolist (pos (cdr x)) | ||
| 1571 | (goto-char pos) | ||
| 1572 | (delete-char 1) | ||
| 1573 | (insert (char-to-string char)))) | ||
| 1574 | |||
| 1575 | ;; Sorted list of indent . positions | ||
| 1576 | (sort poslist (lambda (x y) (<= (car x) (car y)))) | ||
| 1577 | |||
| 1578 | ;; List of preferred bullets. | ||
| 1579 | rst-preferred-bullets) | ||
| 1580 | |||
| 1581 | ))) | ||
| 1582 | |||
| 1583 | (defun rst-rstrip (str) | ||
| 1584 | "Strips the whitespace at the end of string STR." | ||
| 1585 | (string-match "[ \t\n]*\\'" str) | ||
| 1586 | (substring str 0 (match-beginning 0))) | ||
| 1587 | |||
| 1588 | (defun rst-get-stripped-line () | ||
| 1589 | "Return the line at cursor, stripped from whitespace." | ||
| 1590 | (re-search-forward "\\S-.*\\S-" (line-end-position)) | ||
| 1591 | (buffer-substring-no-properties (match-beginning 0) | ||
| 1592 | (match-end 0)) ) | ||
| 1593 | |||
| 1594 | (defun rst-section-tree (alldecos) | ||
| 1595 | "Get the hierarchical tree of section titles. | ||
| 1596 | |||
| 1597 | Returns a hierarchical tree of the sections titles in the | ||
| 1598 | document, for decorations ALLDECOS. This can be used to generate | ||
| 1599 | a table of contents for the document. The top node will always | ||
| 1600 | be a nil node, with the top level titles as children (there may | ||
| 1601 | potentially be more than one). | ||
| 1602 | |||
| 1603 | Each section title consists in a cons of the stripped title | ||
| 1604 | string and a marker to the section in the original text document. | ||
| 1605 | |||
| 1606 | If there are missing section levels, the section titles are | ||
| 1607 | inserted automatically, and the title string is set to nil, and | ||
| 1608 | the marker set to the first non-nil child of itself. | ||
| 1609 | Conceptually, the nil nodes--i.e. those which have no title--are | ||
| 1610 | to be considered as being the same line as their first non-nil | ||
| 1611 | child. This has advantages later in processing the graph." | ||
| 1612 | |||
| 1613 | (let* ((hier (rst-get-hierarchy alldecos)) | ||
| 1614 | (levels (make-hash-table :test 'equal :size 10)) | ||
| 1615 | lines) | ||
| 1616 | |||
| 1617 | (let ((lev 0)) | ||
| 1618 | (dolist (deco hier) | ||
| 1619 | ;; Compare just the character and indent in the hash table. | ||
| 1620 | (puthash (cons (car deco) (cadr deco)) lev levels) | ||
| 1621 | (incf lev))) | ||
| 1622 | |||
| 1623 | ;; Create a list of lines that contains (text, level, marker) for each | ||
| 1624 | ;; decoration. | ||
| 1625 | (save-excursion | ||
| 1626 | (setq lines | ||
| 1627 | (mapcar (lambda (deco) | ||
| 1628 | (goto-line (car deco)) | ||
| 1629 | (list (gethash (cons (cadr deco) (caddr deco)) levels) | ||
| 1630 | (rst-get-stripped-line) | ||
| 1631 | (let ((m (make-marker))) | ||
| 1632 | (beginning-of-line 1) | ||
| 1633 | (set-marker m (point))) | ||
| 1634 | )) | ||
| 1635 | alldecos))) | ||
| 1636 | |||
| 1637 | (let ((lcontnr (cons nil lines))) | ||
| 1638 | (rst-section-tree-rec lcontnr -1)))) | ||
| 1639 | |||
| 1640 | |||
| 1641 | (defun rst-section-tree-rec (decos lev) | ||
| 1642 | "Recursive guts of the section tree construction. | ||
| 1643 | DECOS is a cons cell whose cdr is the remaining list of | ||
| 1644 | decorations, and we change it as we consume them. LEV is the | ||
| 1645 | current level of that node. This function returns a pair of the | ||
| 1646 | subtree that was built. This treats the decos list | ||
| 1647 | destructively." | ||
| 1648 | |||
| 1649 | (let ((ndeco (cadr decos)) | ||
| 1650 | node | ||
| 1651 | children) | ||
| 1652 | |||
| 1653 | ;; If the next decoration matches our level | ||
| 1654 | (when (and ndeco (= (car ndeco) lev)) | ||
| 1655 | ;; Pop the next decoration and create the current node with it | ||
| 1656 | (setcdr decos (cddr decos)) | ||
| 1657 | (setq node (cdr ndeco)) ) | ||
| 1658 | ;; Else we let the node title/marker be unset. | ||
| 1659 | |||
| 1660 | ;; Build the child nodes | ||
| 1661 | (while (and (cdr decos) (> (caadr decos) lev)) | ||
| 1662 | (setq children | ||
| 1663 | (cons (rst-section-tree-rec decos (1+ lev)) | ||
| 1664 | children))) | ||
| 1665 | (setq children (reverse children)) | ||
| 1666 | |||
| 1667 | ;; If node is still unset, we use the marker of the first child. | ||
| 1668 | (when (eq node nil) | ||
| 1669 | (setq node (cons nil (cdaar children)))) | ||
| 1670 | |||
| 1671 | ;; Return this node with its children. | ||
| 1672 | (cons node children) | ||
| 1673 | )) | ||
| 1674 | |||
| 1675 | |||
| 1676 | (defun rst-section-tree-point (node &optional point) | ||
| 1677 | "Find tree node at point. | ||
| 1678 | Given a computed and valid section tree in NODE and a point | ||
| 1679 | POINT (default being the current point in the current buffer), | ||
| 1680 | find and return the node within the sectree where the cursor | ||
| 1681 | lives. | ||
| 1682 | |||
| 1683 | Return values: a pair of (parent path, container subtree). The | ||
| 1684 | parent path is simply a list of the nodes above the container | ||
| 1685 | subtree node that we're returning." | ||
| 1686 | |||
| 1687 | (let (path outtree) | ||
| 1688 | |||
| 1689 | (let* ((curpoint (or point (point)))) | ||
| 1690 | |||
| 1691 | ;; Check if we are before the current node. | ||
| 1692 | (if (and (cadar node) (>= curpoint (cadar node))) | ||
| 1693 | |||
| 1694 | ;; Iterate all the children, looking for one that might contain the | ||
| 1695 | ;; current section. | ||
| 1696 | (let ((curnode (cdr node)) | ||
| 1697 | last) | ||
| 1698 | |||
| 1699 | (while (and curnode (>= curpoint (cadaar curnode))) | ||
| 1700 | (setq last curnode | ||
| 1701 | curnode (cdr curnode))) | ||
| 1702 | |||
| 1703 | (if last | ||
| 1704 | (let ((sub (rst-section-tree-point (car last) curpoint))) | ||
| 1705 | (setq path (car sub) | ||
| 1706 | outtree (cdr sub))) | ||
| 1707 | (setq outtree node)) | ||
| 1708 | |||
| 1709 | ))) | ||
| 1710 | (cons (cons (car node) path) outtree) | ||
| 1711 | )) | ||
| 1712 | |||
| 1713 | |||
| 1714 | (defun rst-toc-insert (&optional pfxarg) | ||
| 1715 | "Insert a simple text rendering of the table of contents. | ||
| 1716 | By default the top level is ignored if there is only one, because | ||
| 1717 | we assume that the document will have a single title. | ||
| 1718 | |||
| 1719 | If a numeric prefix argument PFXARG is given, insert the TOC up | ||
| 1720 | to the specified level. | ||
| 1721 | |||
| 1722 | The TOC is inserted indented at the current column." | ||
| 1723 | |||
| 1724 | (interactive "P") | ||
| 1725 | |||
| 1726 | (let* (;; Check maximum level override | ||
| 1727 | (rst-toc-insert-max-level | ||
| 1728 | (if (and (integerp pfxarg) (> (prefix-numeric-value pfxarg) 0)) | ||
| 1729 | (prefix-numeric-value pfxarg) rst-toc-insert-max-level)) | ||
| 1730 | |||
| 1731 | ;; Get the section tree for the current cursor point. | ||
| 1732 | (sectree-pair | ||
| 1733 | (rst-section-tree-point | ||
| 1734 | (rst-section-tree (rst-find-all-decorations)))) | ||
| 1735 | |||
| 1736 | ;; Figure out initial indent. | ||
| 1737 | (initial-indent (make-string (current-column) ? )) | ||
| 1738 | (init-point (point))) | ||
| 1739 | |||
| 1740 | (when (cddr sectree-pair) | ||
| 1741 | (rst-toc-insert-node (cdr sectree-pair) 0 initial-indent "") | ||
| 1742 | |||
| 1743 | ;; Fixup for the first line. | ||
| 1744 | (delete-region init-point (+ init-point (length initial-indent))) | ||
| 1745 | |||
| 1746 | ;; Delete the last newline added. | ||
| 1747 | (delete-backward-char 1) | ||
| 1748 | ))) | ||
| 1749 | |||
| 1750 | |||
| 1751 | (defgroup rst-toc nil | ||
| 1752 | "Settings for reStructuredText table of contents." | ||
| 1753 | :group 'rst | ||
| 1754 | :version "21.1") | ||
| 1755 | |||
| 1756 | (defcustom rst-toc-indent 2 | ||
| 1757 | "Indentation for table-of-contents display. | ||
| 1758 | Also used for formatting insertion, when numbering is disabled." | ||
| 1759 | :group 'rst-toc) | ||
| 1760 | |||
| 1761 | (defcustom rst-toc-insert-style 'fixed | ||
| 1762 | "Insertion style for table-of-contents. | ||
| 1763 | Set this to one of the following values to determine numbering and | ||
| 1764 | indentation style: | ||
| 1765 | - plain: no numbering (fixed indentation) | ||
| 1766 | - fixed: numbering, but fixed indentation | ||
| 1767 | - aligned: numbering, titles aligned under each other | ||
| 1768 | - listed: numbering, with dashes like list items (EXPERIMENTAL)" | ||
| 1769 | :group 'rst-toc) | ||
| 1770 | |||
| 1771 | (defcustom rst-toc-insert-number-separator " " | ||
| 1772 | "Separator that goes between the TOC number and the title." | ||
| 1773 | :group 'rst-toc) | ||
| 1774 | |||
| 1775 | ;; This is used to avoid having to change the user's mode. | ||
| 1776 | (defvar rst-toc-insert-click-keymap | ||
| 1777 | (let ((map (make-sparse-keymap))) | ||
| 1778 | (define-key map [mouse-1] 'rst-toc-mode-mouse-goto) | ||
| 1779 | map) | ||
| 1780 | "(Internal) What happens when you click on propertized text in the TOC.") | ||
| 1781 | |||
| 1782 | (defcustom rst-toc-insert-max-level nil | ||
| 1783 | "If non-nil, maximum depth of the inserted TOC." | ||
| 1784 | :group 'rst-toc) | ||
| 1785 | |||
| 1786 | (defun rst-toc-insert-node (node level indent pfx) | ||
| 1787 | "Insert tree node NODE in table-of-contents. | ||
| 1788 | Recursive function that does printing of the inserted toc. LEVEL | ||
| 1789 | is the depth level of the sections in the tree. INDENT bis the | ||
| 1790 | indentation string. PFX is the prefix numbering, that includes | ||
| 1791 | the alignment necessary for all the children of level to | ||
| 1792 | align." | ||
| 1793 | |||
| 1794 | ;; Note: we do child numbering from the parent, so we start number the | ||
| 1795 | ;; children one level before we print them. | ||
| 1796 | (let ((do-print (> level 0)) | ||
| 1797 | (count 1)) | ||
| 1798 | (when do-print | ||
| 1799 | (insert indent) | ||
| 1800 | (let ((b (point))) | ||
| 1801 | (unless (equal rst-toc-insert-style 'plain) | ||
| 1802 | (insert pfx rst-toc-insert-number-separator)) | ||
| 1803 | (insert (or (caar node) "[missing node]")) | ||
| 1804 | ;; Add properties to the text, even though in normal text mode it | ||
| 1805 | ;; won't be doing anything for now. Not sure that I want to change | ||
| 1806 | ;; mode stuff. At least the highlighting gives the idea that this | ||
| 1807 | ;; is generated automatically. | ||
| 1808 | (put-text-property b (point) 'mouse-face 'highlight) | ||
| 1809 | (put-text-property b (point) 'rst-toc-target (cadar node)) | ||
| 1810 | (put-text-property b (point) 'keymap rst-toc-insert-click-keymap) | ||
| 1811 | |||
| 1812 | ) | ||
| 1813 | (insert "\n") | ||
| 1814 | |||
| 1815 | ;; Prepare indent for children. | ||
| 1816 | (setq indent | ||
| 1817 | (cond | ||
| 1818 | ((eq rst-toc-insert-style 'plain) | ||
| 1819 | (concat indent (make-string rst-toc-indent ? ))) | ||
| 1820 | |||
| 1821 | ((eq rst-toc-insert-style 'fixed) | ||
| 1822 | (concat indent (make-string rst-toc-indent ? ))) | ||
| 1823 | |||
| 1824 | ((eq rst-toc-insert-style 'aligned) | ||
| 1825 | (concat indent (make-string (+ (length pfx) 2) ? ))) | ||
| 1826 | |||
| 1827 | ((eq rst-toc-insert-style 'listed) | ||
| 1828 | (concat (substring indent 0 -3) | ||
| 1829 | (concat (make-string (+ (length pfx) 2) ? ) " - "))) | ||
| 1830 | )) | ||
| 1831 | ) | ||
| 1832 | |||
| 1833 | (if (or (eq rst-toc-insert-max-level nil) | ||
| 1834 | (< level rst-toc-insert-max-level)) | ||
| 1835 | (let ((do-child-numbering (>= level 0)) | ||
| 1836 | fmt) | ||
| 1837 | (if do-child-numbering | ||
| 1838 | (progn | ||
| 1839 | ;; Add a separating dot if there is already a prefix | ||
| 1840 | (if (> (length pfx) 0) | ||
| 1841 | (setq pfx (concat (rst-rstrip pfx) "."))) | ||
| 1842 | |||
| 1843 | ;; Calculate the amount of space that the prefix will require | ||
| 1844 | ;; for the numbers. | ||
| 1845 | (if (cdr node) | ||
| 1846 | (setq fmt (format "%%-%dd" | ||
| 1847 | (1+ (floor (log10 (length | ||
| 1848 | (cdr node)))))))) | ||
| 1849 | )) | ||
| 1850 | |||
| 1851 | (dolist (child (cdr node)) | ||
| 1852 | (rst-toc-insert-node child | ||
| 1853 | (1+ level) | ||
| 1854 | indent | ||
| 1855 | (if do-child-numbering | ||
| 1856 | (concat pfx (format fmt count)) pfx)) | ||
| 1857 | (incf count))) | ||
| 1858 | |||
| 1859 | ))) | ||
| 1860 | |||
| 1861 | |||
| 1862 | (defun rst-toc-insert-find-delete-contents () | ||
| 1863 | "Find and deletes an existing comment after the first contents directive. | ||
| 1864 | Delete that region. Return t if found and the cursor is left after the comment." | ||
| 1865 | (goto-char (point-min)) | ||
| 1866 | ;; We look for the following and the following only (in other words, if your | ||
| 1867 | ;; syntax differs, this won't work. If you would like a more flexible thing, | ||
| 1868 | ;; contact the author, I just can't imagine that this requirement is | ||
| 1869 | ;; unreasonable for now). | ||
| 1870 | ;; | ||
| 1871 | ;; .. contents:: [...anything here...] | ||
| 1872 | ;; .. | ||
| 1873 | ;; XXXXXXXX | ||
| 1874 | ;; XXXXXXXX | ||
| 1875 | ;; [more lines] | ||
| 1876 | ;; | ||
| 1877 | (let ((beg | ||
| 1878 | (re-search-forward "^\\.\\. contents[ \t]*::\\(.*\\)\n\\.\\." | ||
| 1879 | nil t)) | ||
| 1880 | last-real) | ||
| 1881 | (when beg | ||
| 1882 | ;; Look for the first line that starts at the first column. | ||
| 1883 | (forward-line 1) | ||
| 1884 | (beginning-of-line) | ||
| 1885 | (while (and | ||
| 1886 | (< (point) (point-max)) | ||
| 1887 | (or (and (looking-at "[ \t]+[^ \t]") (setq last-real (point)) t) | ||
| 1888 | (looking-at "[ \t]*$"))) | ||
| 1889 | (forward-line 1) | ||
| 1890 | ) | ||
| 1891 | (if last-real | ||
| 1892 | (progn | ||
| 1893 | (goto-char last-real) | ||
| 1894 | (end-of-line) | ||
| 1895 | (delete-region beg (point))) | ||
| 1896 | (goto-char beg)) | ||
| 1897 | t | ||
| 1898 | ))) | ||
| 1899 | |||
| 1900 | (defun rst-toc-update () | ||
| 1901 | "Automatically find the contents section of a document and update. | ||
| 1902 | Updates the inserted TOC if present. You can use this in your | ||
| 1903 | file-write hook to always make it up-to-date automatically." | ||
| 1904 | (interactive) | ||
| 1905 | (let ((p (point))) | ||
| 1906 | (save-excursion | ||
| 1907 | (when (rst-toc-insert-find-delete-contents) | ||
| 1908 | (insert "\n ") | ||
| 1909 | (rst-toc-insert) | ||
| 1910 | )) | ||
| 1911 | ;; Somehow save-excursion does not really work well. | ||
| 1912 | (goto-char p)) | ||
| 1913 | ;; Note: always return nil, because this may be used as a hook. | ||
| 1914 | ) | ||
| 1915 | |||
| 1916 | ;; Note: we cannot bind the TOC update on file write because it messes with | ||
| 1917 | ;; undo. If we disable undo, since it adds and removes characters, the | ||
| 1918 | ;; positions in the undo list are not making sense anymore. Dunno what to do | ||
| 1919 | ;; with this, it would be nice to update when saving. | ||
| 1920 | ;; | ||
| 1921 | ;; (add-hook 'write-contents-hooks 'rst-toc-update-fun) | ||
| 1922 | ;; (defun rst-toc-update-fun () | ||
| 1923 | ;; ;; Disable undo for the write file hook. | ||
| 1924 | ;; (let ((buffer-undo-list t)) (rst-toc-update) )) | ||
| 1925 | |||
| 1926 | (defalias 'rst-toc-insert-update 'rst-toc-update) ;; backwards compat. | ||
| 1927 | |||
| 1928 | ;;------------------------------------------------------------------------------ | ||
| 1929 | |||
| 1930 | (defun rst-toc-node (node level) | ||
| 1931 | "Recursive function that does insert NODE at LEVEL in the table-of-contents." | ||
| 1932 | |||
| 1933 | (if (> level 0) | ||
| 1934 | (let ((b (point))) | ||
| 1935 | ;; Insert line text. | ||
| 1936 | (insert (make-string (* rst-toc-indent (1- level)) ? )) | ||
| 1937 | (insert (or (caar node) "[missing node]")) | ||
| 1938 | |||
| 1939 | ;; Highlight lines. | ||
| 1940 | (put-text-property b (point) 'mouse-face 'highlight) | ||
| 1941 | |||
| 1942 | ;; Add link on lines. | ||
| 1943 | (put-text-property b (point) 'rst-toc-target (cadar node)) | ||
| 1944 | |||
| 1945 | (insert "\n") | ||
| 1946 | )) | ||
| 1947 | |||
| 1948 | (dolist (child (cdr node)) | ||
| 1949 | (rst-toc-node child (1+ level)))) | ||
| 1950 | |||
| 1951 | (defun rst-toc-count-lines (node target-node) | ||
| 1952 | "Count the number of lines from NODE to the TARGET-NODE node. | ||
| 1953 | This recursive function returns a cons of the number of | ||
| 1954 | additional lines that have been counted for its node and children | ||
| 1955 | and 't if the node has been found." | ||
| 1956 | |||
| 1957 | (let ((count 1) | ||
| 1958 | found) | ||
| 1959 | (if (eq node target-node) | ||
| 1960 | (setq found t) | ||
| 1961 | (let ((child (cdr node))) | ||
| 1962 | (while (and child (not found)) | ||
| 1963 | (let ((cl (rst-toc-count-lines (car child) target-node))) | ||
| 1964 | (setq count (+ count (car cl)) | ||
| 1965 | found (cdr cl) | ||
| 1966 | child (cdr child)))))) | ||
| 1967 | (cons count found))) | ||
| 1968 | |||
| 1969 | |||
| 1970 | (defun rst-toc () | ||
| 1971 | "Display a table-of-contents. | ||
| 1972 | Finds all the section titles and their decorations in the | ||
| 1973 | file, and displays a hierarchically-organized list of the | ||
| 1974 | titles, which is essentially a table-of-contents of the | ||
| 1975 | document. | ||
| 1976 | |||
| 1977 | The Emacs buffer can be navigated, and selecting a section | ||
| 1978 | brings the cursor in that section." | ||
| 1979 | (interactive) | ||
| 1980 | (let* ((curbuf (current-buffer)) | ||
| 1981 | |||
| 1982 | ;; Get the section tree | ||
| 1983 | (alldecos (rst-find-all-decorations)) | ||
| 1984 | (sectree (rst-section-tree alldecos)) | ||
| 1985 | |||
| 1986 | (our-node (cdr (rst-section-tree-point sectree))) | ||
| 1987 | line | ||
| 1988 | |||
| 1989 | ;; Create a temporary buffer. | ||
| 1990 | (buf (get-buffer-create rst-toc-buffer-name)) | ||
| 1991 | ) | ||
| 1992 | |||
| 1993 | (with-current-buffer buf | ||
| 1994 | (let ((inhibit-read-only t)) | ||
| 1995 | (rst-toc-mode) | ||
| 1996 | (delete-region (point-min) (point-max)) | ||
| 1997 | (insert (format "Table of Contents: %s\n" (or (caar sectree) ""))) | ||
| 1998 | (put-text-property (point-min) (point) | ||
| 1999 | 'face (list '(background-color . "gray"))) | ||
| 2000 | (rst-toc-node sectree 0) | ||
| 2001 | |||
| 2002 | ;; Count the lines to our found node. | ||
| 2003 | (let ((linefound (rst-toc-count-lines sectree our-node))) | ||
| 2004 | (setq line (if (cdr linefound) (car linefound) 0))) | ||
| 2005 | )) | ||
| 2006 | (display-buffer buf) | ||
| 2007 | (pop-to-buffer buf) | ||
| 2008 | |||
| 2009 | ;; Save the buffer to return to. | ||
| 2010 | (set (make-local-variable 'rst-toc-return-buffer) curbuf) | ||
| 2011 | |||
| 2012 | ;; Move the cursor near the right section in the TOC. | ||
| 2013 | (goto-line line) | ||
| 2014 | )) | ||
| 2015 | |||
| 2016 | |||
| 2017 | (defun rst-toc-mode-find-section () | ||
| 2018 | "Get the section from text property at point." | ||
| 2019 | (let ((pos (get-text-property (point) 'rst-toc-target))) | ||
| 2020 | (unless pos | ||
| 2021 | (error "No section on this line")) | ||
| 2022 | (unless (buffer-live-p (marker-buffer pos)) | ||
| 2023 | (error "Buffer for this section was killed")) | ||
| 2024 | pos)) | ||
| 2025 | |||
| 2026 | (defvar rst-toc-buffer-name "*Table of Contents*" | ||
| 2027 | "Name of the Table of Contents buffer.") | ||
| 2028 | |||
| 2029 | (defun rst-goto-section (&optional kill) | ||
| 2030 | "Go to the section the current line describes." | ||
| 2031 | (interactive) | ||
| 2032 | (let ((pos (rst-toc-mode-find-section))) | ||
| 2033 | (when kill | ||
| 2034 | (kill-buffer (get-buffer rst-toc-buffer-name))) | ||
| 2035 | (pop-to-buffer (marker-buffer pos)) | ||
| 2036 | (goto-char pos) | ||
| 2037 | ;; FIXME: make the recentering conditional on scroll. | ||
| 2038 | (recenter 5))) | ||
| 2039 | |||
| 2040 | (defun rst-toc-mode-goto-section () | ||
| 2041 | "Go to the section the current line describes and kill the toc buffer." | ||
| 2042 | (interactive) | ||
| 2043 | (rst-goto-section t)) | ||
| 2044 | |||
| 2045 | (defun rst-toc-mode-mouse-goto (event) | ||
| 2046 | "In `rst-toc' mode, go to the occurrence whose line you click on. | ||
| 2047 | EVENT is the input event." | ||
| 2048 | (interactive "e") | ||
| 2049 | (let (pos) | ||
| 2050 | (save-excursion | ||
| 2051 | (set-buffer (window-buffer (posn-window (event-end event)))) | ||
| 2052 | (save-excursion | ||
| 2053 | (goto-char (posn-point (event-end event))) | ||
| 2054 | (setq pos (rst-toc-mode-find-section)))) | ||
| 2055 | (pop-to-buffer (marker-buffer pos)) | ||
| 2056 | (goto-char pos) | ||
| 2057 | (recenter 5))) | ||
| 2058 | |||
| 2059 | (defun rst-toc-mode-mouse-goto-kill (event) | ||
| 2060 | (interactive "e") | ||
| 2061 | (call-interactively 'rst-toc-mode-mouse-goto event) | ||
| 2062 | (kill-buffer (get-buffer rst-toc-buffer-name))) | ||
| 2063 | |||
| 2064 | (defvar rst-toc-return-buffer nil | ||
| 2065 | "Buffer local variable that is used to return to the original | ||
| 2066 | buffer from the TOC.") | ||
| 2067 | |||
| 2068 | (defun rst-toc-quit-window () | ||
| 2069 | (interactive) | ||
| 2070 | (quit-window) | ||
| 2071 | (pop-to-buffer rst-toc-return-buffer)) | ||
| 2072 | |||
| 2073 | (defvar rst-toc-mode-map | ||
| 2074 | (let ((map (make-sparse-keymap))) | ||
| 2075 | (define-key map [mouse-1] 'rst-toc-mode-mouse-goto-kill) | ||
| 2076 | (define-key map [mouse-2] 'rst-toc-mode-mouse-goto) | ||
| 2077 | (define-key map "\C-m" 'rst-toc-mode-goto-section) | ||
| 2078 | (define-key map "f" 'rst-toc-mode-goto-section) | ||
| 2079 | (define-key map "q" 'rst-toc-quit-window) | ||
| 2080 | (define-key map "z" 'kill-this-buffer) | ||
| 2081 | map) | ||
| 2082 | "Keymap for `rst-toc-mode'.") | ||
| 2083 | |||
| 2084 | (put 'rst-toc-mode 'mode-class 'special) | ||
| 2085 | |||
| 2086 | (defun rst-toc-mode () | ||
| 2087 | "Major mode for output from \\[rst-toc], the table-of-contents for the document." | ||
| 2088 | (interactive) | ||
| 2089 | (kill-all-local-variables) | ||
| 2090 | (use-local-map rst-toc-mode-map) | ||
| 2091 | (setq major-mode 'rst-toc-mode) | ||
| 2092 | (setq mode-name "ReST-TOC") | ||
| 2093 | (setq buffer-read-only t) | ||
| 2094 | ) | ||
| 2095 | |||
| 2096 | ;; Note: use occur-mode (replace.el) as a good example to complete missing | ||
| 2097 | ;; features. | ||
| 2098 | |||
| 2099 | |||
| 2100 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 2101 | ;; | ||
| 2102 | ;; Section movement commands. | ||
| 2103 | ;; | ||
| 2104 | |||
| 2105 | (defun rst-forward-section (&optional offset) | ||
| 2106 | "Skip to the next restructured text section title. | ||
| 2107 | OFFSET specifies how many titles to skip. Use a negative OFFSET to move | ||
| 2108 | backwards in the file (default is to use 1)." | ||
| 2109 | (interactive) | ||
| 2110 | (let* (;; Default value for offset. | ||
| 2111 | (offset (or offset 1)) | ||
| 2112 | |||
| 2113 | ;; Get all the decorations in the file, with their line numbers. | ||
| 2114 | (alldecos (rst-find-all-decorations)) | ||
| 2115 | |||
| 2116 | ;; Get the current line. | ||
| 2117 | (curline (line-number-at-pos)) | ||
| 2118 | |||
| 2119 | (cur alldecos) | ||
| 2120 | (idx 0) | ||
| 2121 | ) | ||
| 2122 | |||
| 2123 | ;; Find the index of the "next" decoration w.r.t. to the current line. | ||
| 2124 | (while (and cur (< (caar cur) curline)) | ||
| 2125 | (setq cur (cdr cur)) | ||
| 2126 | (incf idx)) | ||
| 2127 | ;; 'cur' is the decoration on or following the current line. | ||
| 2128 | |||
| 2129 | (if (and (> offset 0) cur (= (caar cur) curline)) | ||
| 2130 | (incf idx)) | ||
| 2131 | |||
| 2132 | ;; Find the final index. | ||
| 2133 | (setq idx (+ idx (if (> offset 0) (- offset 1) offset))) | ||
| 2134 | (setq cur (nth idx alldecos)) | ||
| 2135 | |||
| 2136 | ;; If the index is positive, goto the line, otherwise go to the buffer | ||
| 2137 | ;; boundaries. | ||
| 2138 | (if (and cur (>= idx 0)) | ||
| 2139 | (goto-line (car cur)) | ||
| 2140 | (if (> offset 0) (goto-char (point-max)) (goto-char (point-min)))) | ||
| 2141 | )) | ||
| 2142 | |||
| 2143 | (defun rst-backward-section () | ||
| 2144 | "Like rst-forward-section, except move back one title. | ||
| 2145 | With a prefix argument, move backward by a page." | ||
| 2146 | (interactive) | ||
| 2147 | (rst-forward-section -1)) | ||
| 2148 | |||
| 2149 | (defun rst-mark-section (&optional arg allow-extend) | ||
| 2150 | "Select the section that point is currently in." | ||
| 2151 | ;; Cloned from mark-paragraph. | ||
| 2152 | (interactive "p\np") | ||
| 2153 | (unless arg (setq arg 1)) | ||
| 2154 | (when (zerop arg) | ||
| 2155 | (error "Cannot mark zero sections")) | ||
| 2156 | (cond ((and allow-extend | ||
| 2157 | (or (and (eq last-command this-command) (mark t)) | ||
| 2158 | (rst-portable-mark-active-p))) | ||
| 2159 | (set-mark | ||
| 2160 | (save-excursion | ||
| 2161 | (goto-char (mark)) | ||
| 2162 | (rst-forward-section arg) | ||
| 2163 | (point)))) | ||
| 2164 | (t | ||
| 2165 | (rst-forward-section arg) | ||
| 2166 | (push-mark nil t t) | ||
| 2167 | (rst-forward-section (- arg))))) | ||
| 2168 | |||
| 2169 | |||
| 2170 | |||
| 2171 | |||
| 2172 | |||
| 2173 | |||
| 2174 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 2175 | ;; Functions to work on item lists (e.g. indent/dedent, enumerate), which are | ||
| 2176 | ;; always 2 or 3 characters apart horizontally with rest. | ||
| 2177 | |||
| 2178 | ;; (FIXME: there is currently a bug that makes the region go away when we do that.) | ||
| 2179 | (defvar rst-shift-fill-region nil | ||
| 2180 | "Set to true if you want to automatically re-fill the region that is being | ||
| 2181 | shifted.") | ||
| 2182 | |||
| 2183 | (defun rst-find-leftmost-column (beg end) | ||
| 2184 | "Finds the leftmost column in the region." | ||
| 2185 | (let ((mincol 1000)) | ||
| 2186 | (save-excursion | ||
| 2187 | (goto-char beg) | ||
| 2188 | (while (< (point) end) | ||
| 2189 | (back-to-indentation) | ||
| 2190 | (unless (looking-at "[ \t]*$") | ||
| 2191 | (setq mincol (min mincol (current-column)))) | ||
| 2192 | (forward-line 1) | ||
| 2193 | )) | ||
| 2194 | mincol)) | ||
| 2195 | |||
| 2196 | |||
| 2197 | ;; What we really need to do is compute all the possible alignment possibilities | ||
| 2198 | ;; and then select one. | ||
| 2199 | ;; | ||
| 2200 | ;; .. line-block:: | ||
| 2201 | ;; | ||
| 2202 | ;; a) sdjsds | ||
| 2203 | ;; | ||
| 2204 | ;; - sdjsd jsjds | ||
| 2205 | ;; | ||
| 2206 | ;; sdsdsjdsj | ||
| 2207 | ;; | ||
| 2208 | ;; 11. sjdss jddjs | ||
| 2209 | ;; | ||
| 2210 | ;; * * * * * * * | ||
| 2211 | ;; | ||
| 2212 | ;; Move backwards, accumulate the beginning positions, and also the second | ||
| 2213 | ;; positions, in case the line matches the bullet pattern, and then sort. | ||
| 2214 | |||
| 2215 | (defun rst-compute-bullet-tabs (&optional pt) | ||
| 2216 | "Search backwards from point (or point PT if specified) to | ||
| 2217 | build the list of possible horizontal alignment points that | ||
| 2218 | includes the beginning and contents of a restructuredtext | ||
| 2219 | bulleted or enumerated list item. Return a sorted list | ||
| 2220 | of (column-number . line) pairs." | ||
| 2221 | (save-excursion | ||
| 2222 | (when pt (goto-char pt)) | ||
| 2223 | |||
| 2224 | ;; We work our way backwards and towards the left. | ||
| 2225 | (let ((leftcol 100000) ;; Current column. | ||
| 2226 | (tablist nil) ;; List of tab positions. | ||
| 2227 | ) | ||
| 2228 | |||
| 2229 | ;; Start by skipping the current line. | ||
| 2230 | (beginning-of-line 0) | ||
| 2231 | |||
| 2232 | ;; Search backwards for each line. | ||
| 2233 | (while (and (> (point) (point-min)) | ||
| 2234 | (> leftcol 0)) | ||
| 2235 | |||
| 2236 | ;; Skip empty lines. | ||
| 2237 | (unless (looking-at "^[ \t]*$") | ||
| 2238 | ;; Inspect the current non-empty line | ||
| 2239 | (back-to-indentation) | ||
| 2240 | |||
| 2241 | ;; Skip lines that are beyond the current column (we want to move | ||
| 2242 | ;; towards the left). | ||
| 2243 | (let ((col (current-column))) | ||
| 2244 | (when (< col leftcol) | ||
| 2245 | |||
| 2246 | ;; Add the beginning of the line as a tabbing point. | ||
| 2247 | (unless (memq col (mapcar 'car tablist)) | ||
| 2248 | (setq tablist (cons (cons col (point)) tablist))) | ||
| 2249 | |||
| 2250 | ;; Look at the line to figure out if it is a bulleted or enumerate | ||
| 2251 | ;; list item. | ||
| 2252 | (when (looking-at | ||
| 2253 | (concat | ||
| 2254 | "\\(?:" | ||
| 2255 | "\\(\\(?:[0-9a-zA-Z#]\\{1,3\\}[.):-]\\|[*+-]\\)[ \t]+\\)[^ \t\n]" | ||
| 2256 | "\\|" | ||
| 2257 | (format "\\(%s%s+[ \t]+\\)[^ \t\n]" | ||
| 2258 | (regexp-quote (thing-at-point 'char)) | ||
| 2259 | (regexp-quote (thing-at-point 'char))) | ||
| 2260 | "\\)" | ||
| 2261 | )) | ||
| 2262 | ;; Add the column of the contained item. | ||
| 2263 | (let* ((matchlen (length (or (match-string 1) (match-string 2)))) | ||
| 2264 | (newcol (+ col matchlen))) | ||
| 2265 | (unless (or (>= newcol leftcol) | ||
| 2266 | (memq (+ col matchlen) (mapcar 'car tablist))) | ||
| 2267 | (setq tablist (cons | ||
| 2268 | (cons (+ col matchlen) (+ (point) matchlen)) | ||
| 2269 | tablist)))) | ||
| 2270 | ) | ||
| 2271 | |||
| 2272 | (setq leftcol col) | ||
| 2273 | ))) | ||
| 2274 | |||
| 2275 | ;; Move backwards one line. | ||
| 2276 | (beginning-of-line 0)) | ||
| 2277 | |||
| 2278 | (sort tablist (lambda (x y) (<= (car x) (car y)))) | ||
| 2279 | ))) | ||
| 2280 | |||
| 2281 | (defun rst-debug-print-tabs (tablist) | ||
| 2282 | "A routine that inserts a line and places special characters at | ||
| 2283 | the tab points in the given tablist." | ||
| 2284 | (beginning-of-line) | ||
| 2285 | (insert (concat "\n" (make-string 1000 ? ) "\n")) | ||
| 2286 | (beginning-of-line 0) | ||
| 2287 | (dolist (col tablist) | ||
| 2288 | (beginning-of-line) | ||
| 2289 | (forward-char (car col)) | ||
| 2290 | (delete-char 1) | ||
| 2291 | (insert "@") | ||
| 2292 | )) | ||
| 2293 | |||
| 2294 | (defun rst-debug-mark-found (tablist) | ||
| 2295 | "A routine that inserts a line and places special characters at | ||
| 2296 | the tab points in the given tablist." | ||
| 2297 | (dolist (col tablist) | ||
| 2298 | (when (cdr col) | ||
| 2299 | (goto-char (cdr col)) | ||
| 2300 | (insert "@")))) | ||
| 2301 | |||
| 2302 | |||
| 2303 | (defvar rst-shift-basic-offset 2 | ||
| 2304 | "Basic horizontal shift distance when there is no preceding alignment tabs.") | ||
| 2305 | |||
| 2306 | (defun rst-shift-region-guts (find-next-fun offset-fun) | ||
| 2307 | "(See rst-shift-region-right for a description.)" | ||
| 2308 | (let* ((mbeg (set-marker (make-marker) (region-beginning))) | ||
| 2309 | (mend (set-marker (make-marker) (region-end))) | ||
| 2310 | (tabs (rst-compute-bullet-tabs mbeg)) | ||
| 2311 | (leftmostcol (rst-find-leftmost-column (region-beginning) (region-end))) | ||
| 2312 | ) | ||
| 2313 | ;; Add basic offset tabs at the end of the list. This is a better | ||
| 2314 | ;; implementation technique than hysteresis and a basic offset because it | ||
| 2315 | ;; insures that movement in both directions is consistently using the same | ||
| 2316 | ;; column positions. This makes it more predictable. | ||
| 2317 | (setq tabs | ||
| 2318 | (append tabs | ||
| 2319 | (mapcar (lambda (x) (cons x nil)) | ||
| 2320 | (let ((maxcol 120) | ||
| 2321 | (max-lisp-eval-depth 2000)) | ||
| 2322 | (flet ((addnum (x) | ||
| 2323 | (if (> x maxcol) | ||
| 2324 | nil | ||
| 2325 | (cons x (addnum | ||
| 2326 | (+ x rst-shift-basic-offset)))))) | ||
| 2327 | (addnum (or (caar (last tabs)) 0)))) | ||
| 2328 | ))) | ||
| 2329 | |||
| 2330 | ;; (For debugging.) | ||
| 2331 | ;;; (save-excursion (goto-char mbeg) (forward-char -1) (rst-debug-print-tabs tabs)))) | ||
| 2332 | ;;; (print tabs) | ||
| 2333 | ;;; (save-excursion (rst-debug-mark-found tabs)) | ||
| 2334 | |||
| 2335 | ;; Apply the indent. | ||
| 2336 | (indent-rigidly | ||
| 2337 | mbeg mend | ||
| 2338 | |||
| 2339 | ;; Find the next tab after the leftmost columnt. | ||
| 2340 | (let ((tab (funcall find-next-fun tabs leftmostcol))) | ||
| 2341 | |||
| 2342 | (if tab | ||
| 2343 | (progn | ||
| 2344 | (when (cdar tab) | ||
| 2345 | (message "Aligned on '%s'" | ||
| 2346 | (save-excursion | ||
| 2347 | (goto-char (cdar tab)) | ||
| 2348 | (buffer-substring-no-properties | ||
| 2349 | (line-beginning-position) | ||
| 2350 | (line-end-position)))) | ||
| 2351 | ) | ||
| 2352 | (- (caar tab) leftmostcol)) ;; Num chars. | ||
| 2353 | |||
| 2354 | ;; Otherwise use the basic offset | ||
| 2355 | (funcall offset-fun rst-shift-basic-offset) | ||
| 2356 | ))) | ||
| 2357 | |||
| 2358 | ;; Optionally reindent. | ||
| 2359 | (when rst-shift-fill-region | ||
| 2360 | (fill-region mbeg mend)) | ||
| 2361 | )) | ||
| 2362 | |||
| 2363 | (defun rst-shift-region-right (pfxarg) | ||
| 2364 | "Indent region ridigly, by a few characters to the right. This | ||
| 2365 | function first computes all possible alignment columns by | ||
| 2366 | inspecting the lines preceding the region for bulleted or | ||
| 2367 | enumerated list items. If the leftmost column is beyond the | ||
| 2368 | preceding lines, the region is moved to the right by | ||
| 2369 | rst-shift-basic-offset. With a prefix argument, do not | ||
| 2370 | automatically fill the region." | ||
| 2371 | (interactive "P") | ||
| 2372 | (let ((rst-shift-fill-region | ||
| 2373 | (if (not pfxarg) rst-shift-fill-region))) | ||
| 2374 | (rst-shift-region-guts (lambda (tabs leftmostcol) | ||
| 2375 | (let ((cur tabs)) | ||
| 2376 | (while (and cur (<= (caar cur) leftmostcol)) | ||
| 2377 | (setq cur (cdr cur))) | ||
| 2378 | cur)) | ||
| 2379 | 'identity | ||
| 2380 | ))) | ||
| 2381 | |||
| 2382 | (defun rst-shift-region-left (pfxarg) | ||
| 2383 | "Like rst-shift-region-right, except we move to the left. | ||
| 2384 | Also, if invoked with a negative prefix arg, the entire | ||
| 2385 | indentation is removed, up to the leftmost character in the | ||
| 2386 | region, and automatic filling is disabled." | ||
| 2387 | (interactive "P") | ||
| 2388 | (let ((mbeg (set-marker (make-marker) (region-beginning))) | ||
| 2389 | (mend (set-marker (make-marker) (region-end))) | ||
| 2390 | (leftmostcol (rst-find-leftmost-column | ||
| 2391 | (region-beginning) (region-end))) | ||
| 2392 | (rst-shift-fill-region | ||
| 2393 | (if (not pfxarg) rst-shift-fill-region))) | ||
| 2394 | |||
| 2395 | (when (> leftmostcol 0) | ||
| 2396 | (if (and pfxarg (< (prefix-numeric-value pfxarg) 0)) | ||
| 2397 | (progn | ||
| 2398 | (indent-rigidly (region-beginning) (region-end) (- leftmostcol)) | ||
| 2399 | (when rst-shift-fill-region | ||
| 2400 | (fill-region mbeg mend)) | ||
| 2401 | ) | ||
| 2402 | (rst-shift-region-guts (lambda (tabs leftmostcol) | ||
| 2403 | (let ((cur (reverse tabs))) | ||
| 2404 | (while (and cur (>= (caar cur) leftmostcol)) | ||
| 2405 | (setq cur (cdr cur))) | ||
| 2406 | cur)) | ||
| 2407 | '- | ||
| 2408 | )) | ||
| 2409 | ))) | ||
| 2410 | |||
| 2411 | |||
| 2412 | ;;------------------------------------------------------------------------------ | ||
| 2413 | |||
| 2414 | ;; FIXME: these next functions should become part of a larger effort to redo the | ||
| 2415 | ;; bullets in bulletted lists. The enumerate would just be one of the possible | ||
| 2416 | ;; outputs. | ||
| 2417 | ;; | ||
| 2418 | ;; FIXME: TODO we need to do the enumeration removal as well. | ||
| 2419 | |||
| 2420 | (defun rst-enumerate-region (beg end) | ||
| 2421 | "Add enumeration to all the leftmost paragraphs in the given region. | ||
| 2422 | The region is specified between BEG and END. With prefix argument, | ||
| 2423 | do all lines instead of just paragraphs." | ||
| 2424 | (interactive "r") | ||
| 2425 | (let ((count 0) | ||
| 2426 | (last-insert-len nil)) | ||
| 2427 | (rst-iterate-leftmost-paragraphs | ||
| 2428 | beg end (not current-prefix-arg) | ||
| 2429 | (let ((ins-string (format "%d. " (incf count)))) | ||
| 2430 | (setq last-insert-len (length ins-string)) | ||
| 2431 | (insert ins-string)) | ||
| 2432 | (insert (make-string last-insert-len ?\ )) | ||
| 2433 | ))) | ||
| 2434 | |||
| 2435 | (defun rst-bullet-list-region (beg end) | ||
| 2436 | "Add bullets to all the leftmost paragraphs in the given region. | ||
| 2437 | The region is specified between BEG and END. With prefix argument, | ||
| 2438 | do all lines instead of just paragraphs." | ||
| 2439 | (interactive "r") | ||
| 2440 | (rst-iterate-leftmost-paragraphs | ||
| 2441 | beg end (not current-prefix-arg) | ||
| 2442 | (insert "- ") | ||
| 2443 | (insert " ") | ||
| 2444 | )) | ||
| 2445 | |||
| 2446 | (defmacro rst-iterate-leftmost-paragraphs | ||
| 2447 | (beg end first-only body-consequent body-alternative) | ||
| 2448 | "FIXME This definition is old and deprecated / we need to move | ||
| 2449 | to the newer version below: | ||
| 2450 | |||
| 2451 | Call FUN at the beginning of each line, with an argument that | ||
| 2452 | specifies whether we are at the first line of a paragraph that | ||
| 2453 | starts at the leftmost column of the given region BEG and END. | ||
| 2454 | Set FIRST-ONLY to true if you want to callback on the first line | ||
| 2455 | of each paragraph only." | ||
| 2456 | `(save-excursion | ||
| 2457 | (let ((leftcol (rst-find-leftmost-column ,beg ,end)) | ||
| 2458 | (endm (set-marker (make-marker) ,end)) | ||
| 2459 | ,(when first-only '(in-par nil)) | ||
| 2460 | ) | ||
| 2461 | |||
| 2462 | (do* (;; Iterate lines | ||
| 2463 | (l (progn (goto-char ,beg) (back-to-indentation)) | ||
| 2464 | (progn (forward-line 1) (back-to-indentation))) | ||
| 2465 | |||
| 2466 | (previous nil valid) | ||
| 2467 | |||
| 2468 | (curcol (current-column) | ||
| 2469 | (current-column)) | ||
| 2470 | |||
| 2471 | (valid (and (= curcol leftcol) | ||
| 2472 | (not (looking-at "[ \t]*$"))) | ||
| 2473 | (and (= curcol leftcol) | ||
| 2474 | (not (looking-at "[ \t]*$")))) | ||
| 2475 | ) | ||
| 2476 | ((>= (point-marker) endm)) | ||
| 2477 | |||
| 2478 | (if (if ,first-only | ||
| 2479 | (and valid (not previous)) | ||
| 2480 | valid) | ||
| 2481 | ,body-consequent | ||
| 2482 | ,body-alternative) | ||
| 2483 | |||
| 2484 | )))) | ||
| 2485 | |||
| 2486 | |||
| 2487 | (defmacro rst-iterate-leftmost-paragraphs-2 (spec &rest body) | ||
| 2488 | "Evaluate BODY for each line in region defined by BEG END. | ||
| 2489 | LEFTMOST is set to true if the line is one of the leftmost of the | ||
| 2490 | entire paragraph. PARABEGIN is set to true if the line is the | ||
| 2491 | first of a paragraph." | ||
| 2492 | (destructuring-bind | ||
| 2493 | (beg end parabegin leftmost isleftmost isempty) spec | ||
| 2494 | |||
| 2495 | `(save-excursion | ||
| 2496 | (let ((,leftmost (rst-find-leftmost-column ,beg ,end)) | ||
| 2497 | (endm (set-marker (make-marker) ,end)) | ||
| 2498 | (in-par nil) | ||
| 2499 | ) | ||
| 2500 | |||
| 2501 | (do* (;; Iterate lines | ||
| 2502 | (l (progn (goto-char ,beg) (back-to-indentation)) | ||
| 2503 | (progn (forward-line 1) (back-to-indentation))) | ||
| 2504 | |||
| 2505 | (empty-line-previous nil ,isempty) | ||
| 2506 | |||
| 2507 | (,isempty (looking-at "[ \t]*$") | ||
| 2508 | (looking-at "[ \t]*$")) | ||
| 2509 | |||
| 2510 | (,parabegin (not ,isempty) | ||
| 2511 | (and empty-line-previous | ||
| 2512 | (not ,isempty))) | ||
| 2513 | |||
| 2514 | (,isleftmost (and (not ,isempty) | ||
| 2515 | (= (current-column) ,leftmost)) | ||
| 2516 | (and (not ,isempty) | ||
| 2517 | (= (current-column) ,leftmost))) | ||
| 2518 | ) | ||
| 2519 | ((>= (point-marker) endm)) | ||
| 2520 | |||
| 2521 | (progn ,@body) | ||
| 2522 | |||
| 2523 | ))))) | ||
| 2524 | |||
| 2525 | |||
| 2526 | ;; FIXME: there are some problems left with the following function | ||
| 2527 | ;; implementation: | ||
| 2528 | ;; | ||
| 2529 | ;; * It does not deal with a varying number of digits appropriately | ||
| 2530 | ;; * It does not deal with multiple levels independently, and it should. | ||
| 2531 | ;; | ||
| 2532 | ;; I suppose it does 90% of the job for now. | ||
| 2533 | |||
| 2534 | (defun rst-convert-bullets-to-enumeration (beg end) | ||
| 2535 | "Convert all the bulleted items and enumerated items in the | ||
| 2536 | region to enumerated lists, renumbering as necessary." | ||
| 2537 | (interactive "r") | ||
| 2538 | (let* (;; Find items and convert the positions to markers. | ||
| 2539 | (items (mapcar | ||
| 2540 | (lambda (x) | ||
| 2541 | (cons (let ((m (make-marker))) | ||
| 2542 | (set-marker m (car x)) | ||
| 2543 | m) | ||
| 2544 | (cdr x))) | ||
| 2545 | (rst-find-pfx-in-region beg end rst-re-items))) | ||
| 2546 | (count 1) | ||
| 2547 | ) | ||
| 2548 | (save-excursion | ||
| 2549 | (dolist (x items) | ||
| 2550 | (goto-char (car x)) | ||
| 2551 | (looking-at rst-re-items) | ||
| 2552 | (replace-match (format "%d. " count) nil nil nil 1) | ||
| 2553 | (incf count) | ||
| 2554 | )) | ||
| 2555 | )) | ||
| 2556 | |||
| 2557 | |||
| 2558 | |||
| 2559 | ;;------------------------------------------------------------------------------ | ||
| 2560 | |||
| 2561 | (defun rst-line-block-region (rbeg rend &optional pfxarg) | ||
| 2562 | "Toggle line block prefixes for a region. With prefix argument | ||
| 2563 | set the empty lines too." | ||
| 2564 | (interactive "r\nP") | ||
| 2565 | (let ((comment-start "| ") | ||
| 2566 | (comment-end "") | ||
| 2567 | (comment-start-skip "| ") | ||
| 2568 | (comment-style 'indent) | ||
| 2569 | (force current-prefix-arg)) | ||
| 2570 | (rst-iterate-leftmost-paragraphs-2 | ||
| 2571 | (rbeg rend parbegin leftmost isleft isempty) | ||
| 2572 | (if force | ||
| 2573 | (progn | ||
| 2574 | (move-to-column leftmost t) | ||
| 2575 | (delete-region (point) (+ (point) (- (current-indentation) leftmost))) | ||
| 2576 | (insert "| ")) | ||
| 2577 | (when (not isempty) | ||
| 2578 | (move-to-column leftmost) | ||
| 2579 | (delete-region (point) (+ (point) (- (current-indentation) leftmost))) | ||
| 2580 | (insert "| "))) | ||
| 2581 | ))) | ||
| 2582 | |||
| 2583 | |||
| 2584 | |||
| 2585 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 2586 | |||
| 2587 | (require 'font-lock) | ||
| 2588 | |||
| 2589 | (defgroup rst-faces nil "Faces used in Rst Mode" | ||
| 2590 | :group 'rst | ||
| 2591 | :group 'faces | ||
| 2592 | :version "21.1") | ||
| 2593 | |||
| 2594 | (defcustom rst-block-face 'font-lock-keyword-face | ||
| 2595 | "All syntax marking up a special block" | ||
| 2596 | :group 'rst-faces | ||
| 2597 | :type '(face)) | ||
| 2598 | |||
| 2599 | (defcustom rst-external-face 'font-lock-type-face | ||
| 2600 | "Field names and interpreted text" | ||
| 2601 | :group 'rst-faces | ||
| 2602 | :type '(face)) | ||
| 2603 | |||
| 2604 | (defcustom rst-definition-face 'font-lock-function-name-face | ||
| 2605 | "All other defining constructs" | ||
| 2606 | :group 'rst-faces | ||
| 2607 | :type '(face)) | ||
| 2608 | |||
| 2609 | (defcustom rst-directive-face | ||
| 2610 | ;; XEmacs compatibility | ||
| 2611 | (if (boundp 'font-lock-builtin-face) | ||
| 2612 | 'font-lock-builtin-face | ||
| 2613 | 'font-lock-preprocessor-face) | ||
| 2614 | "Directives and roles" | ||
| 2615 | :group 'rst-faces | ||
| 2616 | :type '(face)) | ||
| 2617 | |||
| 2618 | (defcustom rst-comment-face 'font-lock-comment-face | ||
| 2619 | "Comments" | ||
| 2620 | :group 'rst-faces | ||
| 2621 | :type '(face)) | ||
| 2622 | |||
| 2623 | (defcustom rst-emphasis1-face | ||
| 2624 | ;; XEmacs compatibility | ||
| 2625 | (if (facep 'italic) | ||
| 2626 | ''italic | ||
| 2627 | 'italic) | ||
| 2628 | "Simple emphasis" | ||
| 2629 | :group 'rst-faces | ||
| 2630 | :type '(face)) | ||
| 2631 | |||
| 2632 | (defcustom rst-emphasis2-face | ||
| 2633 | ;; XEmacs compatibility | ||
| 2634 | (if (facep 'bold) | ||
| 2635 | ''bold | ||
| 2636 | 'bold) | ||
| 2637 | "Double emphasis" | ||
| 2638 | :group 'rst-faces | ||
| 2639 | :type '(face)) | ||
| 2640 | |||
| 2641 | (defcustom rst-literal-face 'font-lock-string-face | ||
| 2642 | "Literal text" | ||
| 2643 | :group 'rst-faces | ||
| 2644 | :type '(face)) | ||
| 2645 | |||
| 2646 | (defcustom rst-reference-face 'font-lock-variable-name-face | ||
| 2647 | "References to a definition" | ||
| 2648 | :group 'rst-faces | ||
| 2649 | :type '(face)) | ||
| 2650 | |||
| 2651 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 2652 | |||
| 2653 | (defgroup rst-faces-defaults nil | ||
| 2654 | "Values used to generate default faces for section titles on all levels. | ||
| 2655 | Tweak these if you are content with how section title faces are built in | ||
| 2656 | general but you do not like the details." | ||
| 2657 | :group 'rst-faces | ||
| 2658 | :version "21.1") | ||
| 2659 | |||
| 2660 | (defun rst-define-level-faces () | ||
| 2661 | "Define the faces for the section title text faces from the values." | ||
| 2662 | ;; All variables used here must be checked in `rst-set-level-default' | ||
| 2663 | (let ((i 1)) | ||
| 2664 | (while (<= i rst-level-face-max) | ||
| 2665 | (let ((sym (intern (format "rst-level-%d-face" i))) | ||
| 2666 | (doc (format "Face for showing section title text at level %d" i)) | ||
| 2667 | (col (format (concat "%s" rst-level-face-format-light) | ||
| 2668 | rst-level-face-base-color | ||
| 2669 | (+ (* (1- i) rst-level-face-step-light) | ||
| 2670 | rst-level-face-base-light)))) | ||
| 2671 | (make-empty-face sym) | ||
| 2672 | (set-face-doc-string sym doc) | ||
| 2673 | (set-face-background sym col) | ||
| 2674 | (set sym sym) | ||
| 2675 | (setq i (1+ i)))))) | ||
| 2676 | |||
| 2677 | (defun rst-set-level-default (sym val) | ||
| 2678 | "Set a customized value affecting section title text face and recompute the | ||
| 2679 | faces." | ||
| 2680 | (custom-set-default sym val) | ||
| 2681 | ;; Also defines the faces initially when all values are available | ||
| 2682 | (and (boundp 'rst-level-face-max) | ||
| 2683 | (boundp 'rst-level-face-format-light) | ||
| 2684 | (boundp 'rst-level-face-base-color) | ||
| 2685 | (boundp 'rst-level-face-step-light) | ||
| 2686 | (boundp 'rst-level-face-base-light) | ||
| 2687 | (rst-define-level-faces))) | ||
| 2688 | |||
| 2689 | ;; Faces for displaying items on several levels; these definitions define | ||
| 2690 | ;; different shades of grey where the lightest one (i.e. least contrasting) is | ||
| 2691 | ;; used for level 1 | ||
| 2692 | (defcustom rst-level-face-max 6 | ||
| 2693 | "Maximum depth of levels for which section title faces are defined." | ||
| 2694 | :group 'rst-faces-defaults | ||
| 2695 | :type '(integer) | ||
| 2696 | :set 'rst-set-level-default) | ||
| 2697 | (defcustom rst-level-face-base-color "grey" | ||
| 2698 | "The base name of the color to be used for creating background colors in | ||
| 2699 | ection title faces for all levels." | ||
| 2700 | :group 'rst-faces-defaults | ||
| 2701 | :type '(string) | ||
| 2702 | :set 'rst-set-level-default) | ||
| 2703 | (defcustom rst-level-face-base-light | ||
| 2704 | (if (eq frame-background-mode 'dark) | ||
| 2705 | 15 | ||
| 2706 | 85) | ||
| 2707 | "The lightness factor for the base color. This value is used for level 1. The | ||
| 2708 | default depends on whether the value of `frame-background-mode' is `dark' or | ||
| 2709 | not." | ||
| 2710 | :group 'rst-faces-defaults | ||
| 2711 | :type '(integer) | ||
| 2712 | :set 'rst-set-level-default) | ||
| 2713 | (defcustom rst-level-face-format-light "%2d" | ||
| 2714 | "The format for the lightness factor appended to the base name of the color. | ||
| 2715 | This value is expanded by `format' with an integer." | ||
| 2716 | :group 'rst-faces-defaults | ||
| 2717 | :type '(string) | ||
| 2718 | :set 'rst-set-level-default) | ||
| 2719 | (defcustom rst-level-face-step-light | ||
| 2720 | (if (eq frame-background-mode 'dark) | ||
| 2721 | 7 | ||
| 2722 | -7) | ||
| 2723 | "The step width to use for the next color. The formula | ||
| 2724 | |||
| 2725 | `rst-level-face-base-light' | ||
| 2726 | + (`rst-level-face-max' - 1) * `rst-level-face-step-light' | ||
| 2727 | |||
| 2728 | must result in a color level which appended to `rst-level-face-base-color' | ||
| 2729 | using `rst-level-face-format-light' results in a valid color such as `grey50'. | ||
| 2730 | This color is used as background for section title text on level | ||
| 2731 | `rst-level-face-max'." | ||
| 2732 | :group 'rst-faces-defaults | ||
| 2733 | :type '(integer) | ||
| 2734 | :set 'rst-set-level-default) | ||
| 2735 | |||
| 2736 | (defcustom rst-adornment-faces-alist | ||
| 2737 | (let ((alist '((t . font-lock-keyword-face) | ||
| 2738 | (nil . font-lock-keyword-face))) | ||
| 2739 | (i 1)) | ||
| 2740 | (while (<= i rst-level-face-max) | ||
| 2741 | (nconc alist (list (cons i (intern (format "rst-level-%d-face" i))))) | ||
| 2742 | (setq i (1+ i))) | ||
| 2743 | alist) | ||
| 2744 | "Provides faces for the various adornment types. Key is a number (for the | ||
| 2745 | section title text of that level), t (for transitions) or nil (for section | ||
| 2746 | title adornment). If you generally do not like how section title text faces are | ||
| 2747 | set up tweak here. If the general idea is ok for you but you do not like the | ||
| 2748 | details check the Rst Faces Defaults group." | ||
| 2749 | :group 'rst-faces | ||
| 2750 | :type '(alist | ||
| 2751 | :key-type | ||
| 2752 | (choice | ||
| 2753 | (integer | ||
| 2754 | :tag | ||
| 2755 | "Section level (may not be bigger than `rst-level-face-max')") | ||
| 2756 | (boolean :tag "transitions (on) / section title adornment (off)")) | ||
| 2757 | :value-type (face)) | ||
| 2758 | :set-after '(rst-level-face-max)) | ||
| 2759 | |||
| 2760 | |||
| 2761 | |||
| 2762 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 2763 | ;; Font lock | ||
| 2764 | |||
| 2765 | (defvar rst-use-char-classes | ||
| 2766 | (string-match "[[:alpha:]]" "b") | ||
| 2767 | "Non-nil if we can use the character classes in our regexps.") | ||
| 2768 | |||
| 2769 | (defun rst-font-lock-keywords-function () | ||
| 2770 | "Returns keywords to highlight in rst mode according to current settings." | ||
| 2771 | ;; The reST-links in the comments below all relate to sections in | ||
| 2772 | ;; http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html | ||
| 2773 | (let* ( ;; This gets big - so let's define some abbreviations | ||
| 2774 | ;; horizontal white space | ||
| 2775 | (re-hws "[\t ]") | ||
| 2776 | ;; beginning of line with possible indentation | ||
| 2777 | (re-bol (concat "^" re-hws "*")) | ||
| 2778 | ;; Separates block lead-ins from their content | ||
| 2779 | (re-blksep1 (concat "\\(" re-hws "+\\|$\\)")) | ||
| 2780 | ;; explicit markup tag | ||
| 2781 | (re-emt "\\.\\.") | ||
| 2782 | ;; explicit markup start | ||
| 2783 | (re-ems (concat re-emt re-hws "+")) | ||
| 2784 | ;; inline markup prefix | ||
| 2785 | (re-imp1 (concat "\\(^\\|" re-hws "\\|[-'\"([{</:]\\)")) | ||
| 2786 | ;; inline markup suffix | ||
| 2787 | (re-ims1 (concat "\\(" re-hws "\\|[]-'\")}>/:.,;!?\\]\\|$\\)")) | ||
| 2788 | ;; symbol character | ||
| 2789 | (re-sym1 "\\(\\sw\\|\\s_\\)") | ||
| 2790 | ;; inline markup content begin | ||
| 2791 | (re-imbeg2 "\\(\\S \\|\\S \\([^") | ||
| 2792 | |||
| 2793 | ;; There seems to be a bug leading to error "Stack overflow in regexp | ||
| 2794 | ;; matcher" when "|" or "\\*" are the characters searched for | ||
| 2795 | (re-imendbeg | ||
| 2796 | (if (< emacs-major-version 21) | ||
| 2797 | "]" | ||
| 2798 | "\\]\\|\\\\.")) | ||
| 2799 | ;; inline markup content end | ||
| 2800 | (re-imend (concat re-imendbeg "\\)*[^\t \\\\]\\)")) | ||
| 2801 | ;; inline markup content without asterisk | ||
| 2802 | (re-ima2 (concat re-imbeg2 "*" re-imend)) | ||
| 2803 | ;; inline markup content without backquote | ||
| 2804 | (re-imb2 (concat re-imbeg2 "`" re-imend)) | ||
| 2805 | ;; inline markup content without vertical bar | ||
| 2806 | (re-imv2 (concat re-imbeg2 "|" re-imend)) | ||
| 2807 | ;; Supported URI schemes | ||
| 2808 | (re-uris1 "\\(acap\\|cid\\|data\\|dav\\|fax\\|file\\|ftp\\|gopher\\|http\\|https\\|imap\\|ldap\\|mailto\\|mid\\|modem\\|news\\|nfs\\|nntp\\|pop\\|prospero\\|rtsp\\|service\\|sip\\|tel\\|telnet\\|tip\\|urn\\|vemmi\\|wais\\)") | ||
| 2809 | ;; Line starting with adornment and optional whitespace; complete | ||
| 2810 | ;; adornment is in (match-string 1); there must be at least 3 | ||
| 2811 | ;; characters because otherwise explicit markup start would be | ||
| 2812 | ;; recognized | ||
| 2813 | (re-ado2 (concat "^\\(\\([" | ||
| 2814 | (if rst-use-char-classes | ||
| 2815 | "^[:word:][:space:][:cntrl:]" "^\\w \t\x00-\x1F") | ||
| 2816 | "]\\)\\2\\2+\\)" re-hws "*$")) | ||
| 2817 | ) | ||
| 2818 | (list | ||
| 2819 | ;; FIXME: Block markup is not recognized in blocks after explicit markup | ||
| 2820 | ;; start | ||
| 2821 | |||
| 2822 | ;; Simple `Body Elements`_ | ||
| 2823 | ;; `Bullet Lists`_ | ||
| 2824 | (list | ||
| 2825 | (concat re-bol "\\([-*+]" re-blksep1 "\\)") | ||
| 2826 | 1 rst-block-face) | ||
| 2827 | ;; `Enumerated Lists`_ | ||
| 2828 | (list | ||
| 2829 | (concat re-bol "\\((?\\(#\\|[0-9]+\\|[A-Za-z]\\|[IVXLCMivxlcm]+\\)[.)]" | ||
| 2830 | re-blksep1 "\\)") | ||
| 2831 | 1 rst-block-face) | ||
| 2832 | ;; `Definition Lists`_ FIXME: missing | ||
| 2833 | ;; `Field Lists`_ | ||
| 2834 | (list | ||
| 2835 | (concat re-bol "\\(:[^:\n]+:\\)" re-blksep1) | ||
| 2836 | 1 rst-external-face) | ||
| 2837 | ;; `Option Lists`_ | ||
| 2838 | (list | ||
| 2839 | (concat re-bol "\\(\\(\\(\\([-+/]\\|--\\)\\sw\\(-\\|\\sw\\)*" | ||
| 2840 | "\\([ =]\\S +\\)?\\)\\(,[\t ]\\)?\\)+\\)\\($\\|[\t ]\\{2\\}\\)") | ||
| 2841 | 1 rst-block-face) | ||
| 2842 | |||
| 2843 | ;; `Tables`_ FIXME: missing | ||
| 2844 | |||
| 2845 | ;; All the `Explicit Markup Blocks`_ | ||
| 2846 | ;; `Footnotes`_ / `Citations`_ | ||
| 2847 | (list | ||
| 2848 | (concat re-bol "\\(" re-ems "\\[[^[\n]+\\]\\)" re-blksep1) | ||
| 2849 | 1 rst-definition-face) | ||
| 2850 | ;; `Directives`_ / `Substitution Definitions`_ | ||
| 2851 | (list | ||
| 2852 | (concat re-bol "\\(" re-ems "\\)\\(\\(|[^|\n]+|[\t ]+\\)?\\)\\(" | ||
| 2853 | re-sym1 "+::\\)" re-blksep1) | ||
| 2854 | (list 1 rst-directive-face) | ||
| 2855 | (list 2 rst-definition-face) | ||
| 2856 | (list 4 rst-directive-face)) | ||
| 2857 | ;; `Hyperlink Targets`_ | ||
| 2858 | (list | ||
| 2859 | (concat re-bol "\\(" re-ems "_\\([^:\\`\n]\\|\\\\.\\|`[^`\n]+`\\)+:\\)" | ||
| 2860 | re-blksep1) | ||
| 2861 | 1 rst-definition-face) | ||
| 2862 | (list | ||
| 2863 | (concat re-bol "\\(__\\)" re-blksep1) | ||
| 2864 | 1 rst-definition-face) | ||
| 2865 | |||
| 2866 | ;; All `Inline Markup`_ | ||
| 2867 | ;; FIXME: Condition 5 preventing fontification of e.g. "*" not implemented | ||
| 2868 | ;; `Strong Emphasis`_ | ||
| 2869 | (list | ||
| 2870 | (concat re-imp1 "\\(\\*\\*" re-ima2 "\\*\\*\\)" re-ims1) | ||
| 2871 | 2 rst-emphasis2-face) | ||
| 2872 | ;; `Emphasis`_ | ||
| 2873 | (list | ||
| 2874 | (concat re-imp1 "\\(\\*" re-ima2 "\\*\\)" re-ims1) | ||
| 2875 | 2 rst-emphasis1-face) | ||
| 2876 | ;; `Inline Literals`_ | ||
| 2877 | (list | ||
| 2878 | (concat re-imp1 "\\(``" re-imb2 "``\\)" re-ims1) | ||
| 2879 | 2 rst-literal-face) | ||
| 2880 | ;; `Inline Internal Targets`_ | ||
| 2881 | (list | ||
| 2882 | (concat re-imp1 "\\(_`" re-imb2 "`\\)" re-ims1) | ||
| 2883 | 2 rst-definition-face) | ||
| 2884 | ;; `Hyperlink References`_ | ||
| 2885 | ;; FIXME: `Embedded URIs`_ not considered | ||
| 2886 | (list | ||
| 2887 | (concat re-imp1 "\\(\\(`" re-imb2 "`\\|\\(\\sw\\(\\sw\\|-\\)+\\sw\\)\\)__?\\)" re-ims1) | ||
| 2888 | 2 rst-reference-face) | ||
| 2889 | ;; `Interpreted Text`_ | ||
| 2890 | (list | ||
| 2891 | (concat re-imp1 "\\(\\(:" re-sym1 "+:\\)?\\)\\(`" re-imb2 "`\\)\\(\\(:" | ||
| 2892 | re-sym1 "+:\\)?\\)" re-ims1) | ||
| 2893 | (list 2 rst-directive-face) | ||
| 2894 | (list 5 rst-external-face) | ||
| 2895 | (list 8 rst-directive-face)) | ||
| 2896 | ;; `Footnote References`_ / `Citation References`_ | ||
| 2897 | (list | ||
| 2898 | (concat re-imp1 "\\(\\[[^]]+\\]_\\)" re-ims1) | ||
| 2899 | 2 rst-reference-face) | ||
| 2900 | ;; `Substitution References`_ | ||
| 2901 | (list | ||
| 2902 | (concat re-imp1 "\\(|" re-imv2 "|\\)" re-ims1) | ||
| 2903 | 2 rst-reference-face) | ||
| 2904 | ;; `Standalone Hyperlinks`_ | ||
| 2905 | (list | ||
| 2906 | ;; FIXME: This takes it easy by using a whitespace as delimiter | ||
| 2907 | (concat re-imp1 "\\(" re-uris1 ":\\S +\\)" re-ims1) | ||
| 2908 | 2 rst-definition-face) | ||
| 2909 | (list | ||
| 2910 | (concat re-imp1 "\\(" re-sym1 "+@" re-sym1 "+\\)" re-ims1) | ||
| 2911 | 2 rst-definition-face) | ||
| 2912 | |||
| 2913 | ;; Do all block fontification as late as possible so 'append works | ||
| 2914 | |||
| 2915 | ;; Sections_ / Transitions_ | ||
| 2916 | (append | ||
| 2917 | (list | ||
| 2918 | re-ado2) | ||
| 2919 | (if (not rst-mode-lazy) | ||
| 2920 | (list 1 rst-block-face) | ||
| 2921 | (list | ||
| 2922 | (list 'rst-font-lock-handle-adornment | ||
| 2923 | '(progn | ||
| 2924 | (setq rst-font-lock-adornment-point (match-end 1)) | ||
| 2925 | (point-max)) | ||
| 2926 | nil | ||
| 2927 | (list 1 '(cdr (assoc nil rst-adornment-faces-alist)) | ||
| 2928 | 'append t) | ||
| 2929 | (list 2 '(cdr (assoc rst-font-lock-level | ||
| 2930 | rst-adornment-faces-alist)) | ||
| 2931 | 'append t) | ||
| 2932 | (list 3 '(cdr (assoc nil rst-adornment-faces-alist)) | ||
| 2933 | 'append t))))) | ||
| 2934 | |||
| 2935 | ;; `Comments`_ | ||
| 2936 | (append | ||
| 2937 | (list | ||
| 2938 | (concat re-bol "\\(" re-ems "\\)\[^[|_]\\([^:\n]\\|:\\([^:\n]\\|$\\)\\)*$") | ||
| 2939 | |||
| 2940 | (list 1 rst-comment-face)) | ||
| 2941 | (if rst-mode-lazy | ||
| 2942 | (list | ||
| 2943 | (list 'rst-font-lock-find-unindented-line | ||
| 2944 | '(progn | ||
| 2945 | (setq rst-font-lock-indentation-point (match-end 1)) | ||
| 2946 | (point-max)) | ||
| 2947 | nil | ||
| 2948 | (list 0 rst-comment-face 'append))))) | ||
| 2949 | (append | ||
| 2950 | (list | ||
| 2951 | (concat re-bol "\\(" re-emt "\\)\\(\\s *\\)$") | ||
| 2952 | (list 1 rst-comment-face) | ||
| 2953 | (list 2 rst-comment-face)) | ||
| 2954 | (if rst-mode-lazy | ||
| 2955 | (list | ||
| 2956 | (list 'rst-font-lock-find-unindented-line | ||
| 2957 | '(progn | ||
| 2958 | (setq rst-font-lock-indentation-point 'next) | ||
| 2959 | (point-max)) | ||
| 2960 | nil | ||
| 2961 | (list 0 rst-comment-face 'append))))) | ||
| 2962 | |||
| 2963 | ;; `Literal Blocks`_ | ||
| 2964 | (append | ||
| 2965 | (list | ||
| 2966 | (concat re-bol "\\(\\([^.\n]\\|\\.[^.\n]\\).*\\)?\\(::\\)$") | ||
| 2967 | (list 3 rst-block-face)) | ||
| 2968 | (if rst-mode-lazy | ||
| 2969 | (list | ||
| 2970 | (list 'rst-font-lock-find-unindented-line | ||
| 2971 | '(progn | ||
| 2972 | (setq rst-font-lock-indentation-point t) | ||
| 2973 | (point-max)) | ||
| 2974 | nil | ||
| 2975 | (list 0 rst-literal-face 'append))))) | ||
| 2976 | |||
| 2977 | ;; `Doctest Blocks`_ | ||
| 2978 | (append | ||
| 2979 | (list | ||
| 2980 | (concat re-bol "\\(>>>\\|\\.\\.\\.\\)\\(.+\\)") | ||
| 2981 | (list 1 rst-block-face) | ||
| 2982 | (list 2 rst-literal-face))) | ||
| 2983 | ))) | ||
| 2984 | |||
| 2985 | |||
| 2986 | |||
| 2987 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 2988 | ;; Indented blocks | ||
| 2989 | |||
| 2990 | (defun rst-forward-indented-block (&optional column limit) | ||
| 2991 | "Move forward across one indented block. | ||
| 2992 | Find the next non-empty line which is not indented at least to COLUMN (defaults | ||
| 2993 | to the column of the point). Moves point to first character of this line or the | ||
| 2994 | first empty line immediately before it and returns that position. If there is | ||
| 2995 | no such line before LIMIT (defaults to the end of the buffer) returns nil and | ||
| 2996 | point is not moved." | ||
| 2997 | (interactive) | ||
| 2998 | (let ((clm (or column (current-column))) | ||
| 2999 | (start (point)) | ||
| 3000 | fnd beg cand) | ||
| 3001 | (if (not limit) | ||
| 3002 | (setq limit (point-max))) | ||
| 3003 | (save-match-data | ||
| 3004 | (while (and (not fnd) (< (point) limit)) | ||
| 3005 | (forward-line 1) | ||
| 3006 | (when (< (point) limit) | ||
| 3007 | (setq beg (point)) | ||
| 3008 | (if (looking-at "\\s *$") | ||
| 3009 | (setq cand (or cand beg)) ; An empty line is a candidate | ||
| 3010 | (move-to-column clm) | ||
| 3011 | ;; FIXME: No indentation [(zerop clm)] must be handled in some | ||
| 3012 | ;; useful way - though it is not clear what this should mean at all | ||
| 3013 | (if (string-match | ||
| 3014 | "^\\s *$" (buffer-substring-no-properties beg (point))) | ||
| 3015 | (setq cand nil) ; An indented line resets a candidate | ||
| 3016 | (setq fnd (or cand beg))))))) | ||
| 3017 | (goto-char (or fnd start)) | ||
| 3018 | fnd)) | ||
| 3019 | |||
| 3020 | ;; Stores the point where the current indentation ends if a number. If `next' | ||
| 3021 | ;; indicates `rst-font-lock-find-unindented-line' shall take the indentation | ||
| 3022 | ;; from the next line if this is not empty. If non-nil indicates | ||
| 3023 | ;; `rst-font-lock-find-unindented-line' shall take the indentation from the | ||
| 3024 | ;; next non-empty line. Also used as a trigger for | ||
| 3025 | ;; `rst-font-lock-find-unindented-line'. | ||
| 3026 | (defvar rst-font-lock-indentation-point nil) | ||
| 3027 | |||
| 3028 | (defun rst-font-lock-find-unindented-line (limit) | ||
| 3029 | (let* ((ind-pnt rst-font-lock-indentation-point) | ||
| 3030 | (beg-pnt ind-pnt)) | ||
| 3031 | ;; May run only once - enforce this | ||
| 3032 | (setq rst-font-lock-indentation-point nil) | ||
| 3033 | (when (and ind-pnt (not (numberp ind-pnt))) | ||
| 3034 | ;; Find indentation point in next line if any | ||
| 3035 | (setq ind-pnt | ||
| 3036 | (save-excursion | ||
| 3037 | (save-match-data | ||
| 3038 | (if (eq ind-pnt 'next) | ||
| 3039 | (when (and (zerop (forward-line 1)) (< (point) limit)) | ||
| 3040 | (setq beg-pnt (point)) | ||
| 3041 | (when (not (looking-at "\\s *$")) | ||
| 3042 | (looking-at "\\s *") | ||
| 3043 | (match-end 0))) | ||
| 3044 | (while (and (zerop (forward-line 1)) (< (point) limit) | ||
| 3045 | (looking-at "\\s *$"))) | ||
| 3046 | (when (< (point) limit) | ||
| 3047 | (setq beg-pnt (point)) | ||
| 3048 | (looking-at "\\s *") | ||
| 3049 | (match-end 0))))))) | ||
| 3050 | (when ind-pnt | ||
| 3051 | (goto-char ind-pnt) | ||
| 3052 | ;; Always succeeds because the limit set by PRE-MATCH-FORM is the | ||
| 3053 | ;; ultimate point to find | ||
| 3054 | (goto-char (or (rst-forward-indented-block nil limit) limit)) | ||
| 3055 | (set-match-data (list beg-pnt (point))) | ||
| 3056 | t))) | ||
| 3057 | |||
| 3058 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 3059 | ;; Adornments | ||
| 3060 | |||
| 3061 | ;; Stores the point where the current adornment ends. Also used as a trigger | ||
| 3062 | ;; for `rst-font-lock-handle-adornment'. | ||
| 3063 | (defvar rst-font-lock-adornment-point nil) | ||
| 3064 | |||
| 3065 | ;; Here `rst-font-lock-handle-adornment' stores the section level of the | ||
| 3066 | ;; current adornment or t for a transition. | ||
| 3067 | (defvar rst-font-lock-level nil) | ||
| 3068 | |||
| 3069 | ;; FIXME: It would be good if this could be used to markup section titles of | ||
| 3070 | ;; given level with a special key; it would be even better to be able to | ||
| 3071 | ;; customize this so it can be used for a generally available personal style | ||
| 3072 | ;; | ||
| 3073 | ;; FIXME: There should be some way to reset and reload this variable - probably | ||
| 3074 | ;; a special key | ||
| 3075 | ;; | ||
| 3076 | ;; FIXME: Some support for `outline-mode' would be nice which should be based | ||
| 3077 | ;; on this information | ||
| 3078 | (defvar rst-adornment-level-alist nil | ||
| 3079 | "Associates adornments with section levels. | ||
| 3080 | The key is a two character string. The first character is the adornment | ||
| 3081 | character. The second character distinguishes underline section titles (`u') | ||
| 3082 | from overline/underline section titles (`o'). The value is the section level. | ||
| 3083 | |||
| 3084 | This is made buffer local on start and adornments found during font lock are | ||
| 3085 | entered.") | ||
| 3086 | |||
| 3087 | ;; Returns section level for adornment key KEY. Adds new section level if KEY | ||
| 3088 | ;; is not found and ADD. If KEY is not a string it is simply returned. | ||
| 3089 | (defun rst-adornment-level (key &optional add) | ||
| 3090 | (let ((fnd (assoc key rst-adornment-level-alist)) | ||
| 3091 | (new 1)) | ||
| 3092 | (cond | ||
| 3093 | ((not (stringp key)) | ||
| 3094 | key) | ||
| 3095 | (fnd | ||
| 3096 | (cdr fnd)) | ||
| 3097 | (add | ||
| 3098 | (while (rassoc new rst-adornment-level-alist) | ||
| 3099 | (setq new (1+ new))) | ||
| 3100 | (setq rst-adornment-level-alist | ||
| 3101 | (append rst-adornment-level-alist (list (cons key new)))) | ||
| 3102 | new)))) | ||
| 3103 | |||
| 3104 | ;; Classifies adornment for section titles and transitions. ADORNMENT is the | ||
| 3105 | ;; complete adornment string as found in the buffer. END is the point after the | ||
| 3106 | ;; last character of ADORNMENT. For overline section adornment LIMIT limits the | ||
| 3107 | ;; search for the matching underline. Returns a list. The first entry is t for | ||
| 3108 | ;; a transition, or a key string for `rst-adornment-level' for a section title. | ||
| 3109 | ;; The following eight values forming four match groups as can be used for | ||
| 3110 | ;; `set-match-data'. First match group contains the maximum points of the whole | ||
| 3111 | ;; construct. Second and last match group matched pure section title adornment | ||
| 3112 | ;; while third match group matched the section title text or the transition. | ||
| 3113 | ;; Each group but the first may or may not exist. | ||
| 3114 | (defun rst-classify-adornment (adornment end limit) | ||
| 3115 | (save-excursion | ||
| 3116 | (save-match-data | ||
| 3117 | (goto-char end) | ||
| 3118 | (let ((ado-ch (aref adornment 0)) | ||
| 3119 | (ado-re (regexp-quote adornment)) | ||
| 3120 | (end-pnt (point)) | ||
| 3121 | (beg-pnt (progn | ||
| 3122 | (forward-line 0) | ||
| 3123 | (point))) | ||
| 3124 | (nxt-emp | ||
| 3125 | (save-excursion | ||
| 3126 | (or (not (zerop (forward-line 1))) | ||
| 3127 | (looking-at "\\s *$")))) | ||
| 3128 | (prv-emp | ||
| 3129 | (save-excursion | ||
| 3130 | (or (not (zerop (forward-line -1))) | ||
| 3131 | (looking-at "\\s *$")))) | ||
| 3132 | key beg-ovr end-ovr beg-txt end-txt beg-und end-und) | ||
| 3133 | (cond | ||
| 3134 | ((and nxt-emp prv-emp) | ||
| 3135 | ;; A transition | ||
| 3136 | (setq key t) | ||
| 3137 | (setq beg-txt beg-pnt) | ||
| 3138 | (setq end-txt end-pnt)) | ||
| 3139 | (prv-emp | ||
| 3140 | ;; An overline | ||
| 3141 | (setq key (concat (list ado-ch) "o")) | ||
| 3142 | (setq beg-ovr beg-pnt) | ||
| 3143 | (setq end-ovr end-pnt) | ||
| 3144 | (forward-line 1) | ||
| 3145 | (setq beg-txt (point)) | ||
| 3146 | (while (and (< (point) limit) (not end-txt)) | ||
| 3147 | (if (looking-at "\\s *$") | ||
| 3148 | ;; No underline found | ||
| 3149 | (setq end-txt (1- (point))) | ||
| 3150 | (when (looking-at (concat "\\(" ado-re "\\)\\s *$")) | ||
| 3151 | (setq end-und (match-end 1)) | ||
| 3152 | (setq beg-und (point)) | ||
| 3153 | (setq end-txt (1- beg-und)))) | ||
| 3154 | (forward-line 1))) | ||
| 3155 | (t | ||
| 3156 | ;; An underline | ||
| 3157 | (setq key (concat (list ado-ch) "u")) | ||
| 3158 | (setq beg-und beg-pnt) | ||
| 3159 | (setq end-und end-pnt) | ||
| 3160 | (setq end-txt (1- beg-und)) | ||
| 3161 | (setq beg-txt (progn | ||
| 3162 | (if (re-search-backward "^\\s *$" 1 'move) | ||
| 3163 | (forward-line 1)) | ||
| 3164 | (point))))) | ||
| 3165 | (list key | ||
| 3166 | (or beg-ovr beg-txt beg-und) | ||
| 3167 | (or end-und end-txt end-und) | ||
| 3168 | beg-ovr end-ovr beg-txt end-txt beg-und end-und))))) | ||
| 3169 | |||
| 3170 | ;; Handles adornments for font-locking section titles and transitions. Returns | ||
| 3171 | ;; three match groups. First and last match group matched pure overline / | ||
| 3172 | ;; underline adornment while second group matched section title text. Each | ||
| 3173 | ;; group may not exist. | ||
| 3174 | (defun rst-font-lock-handle-adornment (limit) | ||
| 3175 | (let ((ado-pnt rst-font-lock-adornment-point)) | ||
| 3176 | ;; May run only once - enforce this | ||
| 3177 | (setq rst-font-lock-adornment-point nil) | ||
| 3178 | (if ado-pnt | ||
| 3179 | (let* ((ado (rst-classify-adornment (match-string-no-properties 1) | ||
| 3180 | ado-pnt limit)) | ||
| 3181 | (key (car ado)) | ||
| 3182 | (mtc (cdr ado))) | ||
| 3183 | (setq rst-font-lock-level (rst-adornment-level key t)) | ||
| 3184 | (goto-char (nth 1 mtc)) | ||
| 3185 | (set-match-data mtc) | ||
| 3186 | t)))) | ||
| 3187 | |||
| 3188 | |||
| 3189 | |||
| 3190 | |||
| 3191 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 3192 | ;; Support for conversion from within Emacs | ||
| 3193 | |||
| 3194 | (defgroup rst-compile nil | ||
| 3195 | "Settings for support of conversion of reStructuredText | ||
| 3196 | document with \\[rst-compile]." | ||
| 3197 | :group 'rst | ||
| 3198 | :version "21.1") | ||
| 3199 | |||
| 3200 | (defvar rst-compile-toolsets | ||
| 3201 | '((html . ("rst2html.py" ".html" nil)) | ||
| 3202 | (latex . ("rst2latex.py" ".tex" nil)) | ||
| 3203 | (newlatex . ("rst2newlatex.py" ".tex" nil)) | ||
| 3204 | (pseudoxml . ("rst2pseudoxml.py" ".xml" nil)) | ||
| 3205 | (xml . ("rst2xml.py" ".xml" nil))) | ||
| 3206 | "An association list of the toolset to a list of the (command to use, | ||
| 3207 | extension of produced filename, options to the tool (nil or a | ||
| 3208 | string)) to be used for converting the document.") | ||
| 3209 | |||
| 3210 | ;; Note for Python programmers not familiar with association lists: you can set | ||
| 3211 | ;; values in an alists like this, e.g. : | ||
| 3212 | ;; (setcdr (assq 'html rst-compile-toolsets) | ||
| 3213 | ;; '("rst2html.py" ".htm" "--stylesheet=/docutils.css")) | ||
| 3214 | |||
| 3215 | |||
| 3216 | (defvar rst-compile-primary-toolset 'html | ||
| 3217 | "The default toolset for rst-compile.") | ||
| 3218 | |||
| 3219 | (defvar rst-compile-secondary-toolset 'latex | ||
| 3220 | "The default toolset for rst-compile with a prefix argument.") | ||
| 3221 | |||
| 3222 | (defun rst-compile-find-conf () | ||
| 3223 | "Look for the configuration file in the parents of the current path." | ||
| 3224 | (interactive) | ||
| 3225 | (let ((file-name "docutils.conf") | ||
| 3226 | (buffer-file (buffer-file-name))) | ||
| 3227 | ;; Move up in the dir hierarchy till we find a change log file. | ||
| 3228 | (let* ((dir (file-name-directory buffer-file)) | ||
| 3229 | (prevdir nil)) | ||
| 3230 | (while (and (or (not (string= dir prevdir)) | ||
| 3231 | (setq dir nil) | ||
| 3232 | nil) | ||
| 3233 | (not (file-exists-p (concat dir file-name)))) | ||
| 3234 | ;; Move up to the parent dir and try again. | ||
| 3235 | (setq prevdir dir) | ||
| 3236 | (setq dir (expand-file-name (file-name-directory | ||
| 3237 | (directory-file-name | ||
| 3238 | (file-name-directory dir))))) | ||
| 3239 | ) | ||
| 3240 | (or (and dir (concat dir file-name)) nil) | ||
| 3241 | ))) | ||
| 3242 | |||
| 3243 | |||
| 3244 | (require 'compile) | ||
| 3245 | |||
| 3246 | (defun rst-compile (&optional pfxarg) | ||
| 3247 | "Compile command to convert reST document into some output file. | ||
| 3248 | Attempts to find configuration file, if it can, overrides the | ||
| 3249 | options. There are two commands to choose from, with a prefix | ||
| 3250 | argument, select the alternative toolset." | ||
| 3251 | (interactive "P") | ||
| 3252 | ;; Note: maybe we want to check if there is a Makefile too and not do anything | ||
| 3253 | ;; if that is the case. I dunno. | ||
| 3254 | (let* ((toolset (cdr (assq (if pfxarg | ||
| 3255 | rst-compile-secondary-toolset | ||
| 3256 | rst-compile-primary-toolset) | ||
| 3257 | rst-compile-toolsets))) | ||
| 3258 | (command (car toolset)) | ||
| 3259 | (extension (cadr toolset)) | ||
| 3260 | (options (caddr toolset)) | ||
| 3261 | (conffile (rst-compile-find-conf)) | ||
| 3262 | (bufname (file-name-nondirectory buffer-file-name)) | ||
| 3263 | (outname (file-name-sans-extension bufname))) | ||
| 3264 | |||
| 3265 | ;; Set compile-command before invocation of compile. | ||
| 3266 | (set (make-local-variable 'compile-command) | ||
| 3267 | (mapconcat 'identity | ||
| 3268 | (list command | ||
| 3269 | (or options "") | ||
| 3270 | (if conffile | ||
| 3271 | (concat "--config=\"" conffile "\"") | ||
| 3272 | "") | ||
| 3273 | bufname | ||
| 3274 | (concat outname extension)) | ||
| 3275 | " ")) | ||
| 3276 | |||
| 3277 | ;; Invoke the compile command. | ||
| 3278 | (if (or compilation-read-command current-prefix-arg) | ||
| 3279 | (call-interactively 'compile) | ||
| 3280 | (compile compile-command)) | ||
| 3281 | )) | ||
| 3282 | |||
| 3283 | (defun rst-compile-alt-toolset () | ||
| 3284 | "Compile command with the alternative toolset." | ||
| 3285 | (interactive) | ||
| 3286 | (rst-compile 't)) | ||
| 3287 | |||
| 3288 | (defun rst-compile-pseudo-region () | ||
| 3289 | "Show the pseudo-XML rendering of the current active region, or | ||
| 3290 | of the entire buffer, if the region is not selected." | ||
| 3291 | (interactive) | ||
| 3292 | (with-output-to-temp-buffer "*pseudoxml*" | ||
| 3293 | (shell-command-on-region | ||
| 3294 | (if mark-active (region-beginning) (point-min)) | ||
| 3295 | (if mark-active (region-end) (point-max)) | ||
| 3296 | "rst2pseudoxml.py" | ||
| 3297 | standard-output))) | ||
| 3298 | |||
| 3299 | (defvar rst-pdf-program "xpdf" | ||
| 3300 | "Program used to preview PDF files.") | ||
| 3301 | |||
| 3302 | (defun rst-compile-pdf-preview () | ||
| 3303 | "Convert the document to a PDF file and launch a preview program." | ||
| 3304 | (interactive) | ||
| 3305 | (let* ((tmp-filename "/tmp/out.pdf") | ||
| 3306 | (command (format "rst2pdf.py %s %s && %s %s" | ||
| 3307 | buffer-file-name tmp-filename | ||
| 3308 | rst-pdf-program tmp-filename))) | ||
| 3309 | (start-process-shell-command "rst-pdf-preview" nil command) | ||
| 3310 | ;; Note: you could also use (compile command) to view the compilation | ||
| 3311 | ;; output. | ||
| 3312 | )) | ||
| 3313 | |||
| 3314 | (defvar rst-slides-program "firefox" | ||
| 3315 | "Program used to preview S5 slides.") | ||
| 3316 | |||
| 3317 | (defun rst-compile-slides-preview () | ||
| 3318 | "Convert the document to an S5 slide presentation and launch a preview program." | ||
| 3319 | (interactive) | ||
| 3320 | (let* ((tmp-filename "/tmp/slides.html") | ||
| 3321 | (command (format "rst2s5.py %s %s && %s %s" | ||
| 3322 | buffer-file-name tmp-filename | ||
| 3323 | rst-slides-program tmp-filename))) | ||
| 3324 | (start-process-shell-command "rst-slides-preview" nil command) | ||
| 3325 | ;; Note: you could also use (compile command) to view the compilation | ||
| 3326 | ;; output. | ||
| 3327 | )) | ||
| 3328 | |||
| 3329 | |||
| 3330 | |||
| 3331 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 3332 | ;; | ||
| 3333 | ;; Generic text functions that are more convenient than the defaults. | ||
| 3334 | ;; | ||
| 3335 | |||
| 3336 | (defun rst-replace-lines (fromchar tochar) | ||
| 3337 | "Replace flush-left lines, consisting of multiple FROMCHAR characters, | ||
| 3338 | with equal-length lines of TOCHAR." | ||
| 3339 | (interactive "\ | ||
| 3340 | cSearch for flush-left lines of char: | ||
| 3341 | cand replace with char: ") | ||
| 3342 | (save-excursion | ||
| 3343 | (let* ((fromstr (string fromchar)) | ||
| 3344 | (searchre (concat "^" (regexp-quote fromstr) "+ *$")) | ||
| 3345 | (found 0)) | ||
| 3346 | (condition-case err | ||
| 3347 | (while t | ||
| 3348 | (search-forward-regexp searchre) | ||
| 3349 | (setq found (1+ found)) | ||
| 3350 | (search-backward fromstr) ;; point will be *before* last char | ||
| 3351 | (setq p (1+ (point))) | ||
| 3352 | (beginning-of-line) | ||
| 3353 | (setq l (- p (point))) | ||
| 3354 | (rst-delete-entire-line) | ||
| 3355 | (insert-char tochar l)) | ||
| 3356 | (search-failed | ||
| 3357 | (message (format "%d lines replaced." found))))))) | ||
| 3358 | |||
| 3359 | (defun rst-join-paragraph () | ||
| 3360 | "Join lines in current paragraph into one line, removing end-of-lines." | ||
| 3361 | (interactive) | ||
| 3362 | (let ((fill-column 65000)) ; some big number | ||
| 3363 | (call-interactively 'fill-paragraph))) | ||
| 3364 | |||
| 3365 | (defun rst-force-fill-paragraph () | ||
| 3366 | "Fill paragraph at point, first joining the paragraph's lines into one. | ||
| 3367 | This is useful for filling list item paragraphs." | ||
| 3368 | (interactive) | ||
| 3369 | (rst-join-paragraph) | ||
| 3370 | (fill-paragraph nil)) | ||
| 3371 | |||
| 3372 | |||
| 3373 | ;; Generic character repeater function. | ||
| 3374 | ;; For sections, better to use the specialized function above, but this can | ||
| 3375 | ;; be useful for creating separators. | ||
| 3376 | (defun rst-repeat-last-character (&optional tofill) | ||
| 3377 | "Fills the current line up to the length of the preceding line (if not | ||
| 3378 | empty), using the last character on the current line. If the preceding line is | ||
| 3379 | empty, we use the fill-column. | ||
| 3380 | |||
| 3381 | If a prefix argument is provided, use the next line rather than the preceding | ||
| 3382 | line. | ||
| 3383 | |||
| 3384 | If the current line is longer than the desired length, shave the characters off | ||
| 3385 | the current line to fit the desired length. | ||
| 3386 | |||
| 3387 | As an added convenience, if the command is repeated immediately, the alternative | ||
| 3388 | column is used (fill-column vs. end of previous/next line)." | ||
| 3389 | (interactive) | ||
| 3390 | (let* ((curcol (current-column)) | ||
| 3391 | (curline (+ (count-lines (point-min) (point)) | ||
| 3392 | (if (eq curcol 0) 1 0))) | ||
| 3393 | (lbp (line-beginning-position 0)) | ||
| 3394 | (prevcol (if (and (= curline 1) (not current-prefix-arg)) | ||
| 3395 | fill-column | ||
| 3396 | (save-excursion | ||
| 3397 | (forward-line (if current-prefix-arg 1 -1)) | ||
| 3398 | (end-of-line) | ||
| 3399 | (skip-chars-backward " \t" lbp) | ||
| 3400 | (let ((cc (current-column))) | ||
| 3401 | (if (= cc 0) fill-column cc))))) | ||
| 3402 | (rightmost-column | ||
| 3403 | (cond (tofill fill-column) | ||
| 3404 | ((equal last-command 'rst-repeat-last-character) | ||
| 3405 | (if (= curcol fill-column) prevcol fill-column)) | ||
| 3406 | (t (save-excursion | ||
| 3407 | (if (= prevcol 0) fill-column prevcol))) | ||
| 3408 | )) ) | ||
| 3409 | (end-of-line) | ||
| 3410 | (if (> (current-column) rightmost-column) | ||
| 3411 | ;; shave characters off the end | ||
| 3412 | (delete-region (- (point) | ||
| 3413 | (- (current-column) rightmost-column)) | ||
| 3414 | (point)) | ||
| 3415 | ;; fill with last characters | ||
| 3416 | (insert-char (preceding-char) | ||
| 3417 | (- rightmost-column (current-column)))) | ||
| 3418 | )) | ||
| 3419 | |||
| 3420 | |||
| 3421 | (defun rst-portable-mark-active-p () | ||
| 3422 | "A portable function that returns non-nil if the mark is active." | ||
| 3423 | (cond | ||
| 3424 | ((fboundp 'region-active-p) (region-active-p)) | ||
| 3425 | ((boundp 'transient-mark-mode) transient-mark-mode mark-active))) | ||
| 3426 | |||
| 3427 | |||
| 3428 | |||
| 3429 | (provide 'rst) | ||
| 3430 | ;;; rst.el ends here | ||