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