diff options
| -rw-r--r-- | etc/NEWS | 2 | ||||
| -rw-r--r-- | lisp/ChangeLog | 12 | ||||
| -rw-r--r-- | lisp/textmodes/rst.el | 282 |
3 files changed, 189 insertions, 107 deletions
| @@ -419,6 +419,8 @@ the experience for Sphinx users. | |||
| 419 | 419 | ||
| 420 | *** Package version in `rst-version'. | 420 | *** Package version in `rst-version'. |
| 421 | 421 | ||
| 422 | *** Support `imenu' and `which-func'. | ||
| 423 | |||
| 422 | ** New `derived-mode' filter for Ibuffer, bound to `/ M'. | 424 | ** New `derived-mode' filter for Ibuffer, bound to `/ M'. |
| 423 | `/ m' is now bound to filter by used-mode, which used to be bound to `/ M'. | 425 | `/ m' is now bound to filter by used-mode, which used to be bound to `/ M'. |
| 424 | 426 | ||
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 8b99fc29252..fd7bc3defec 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,15 @@ | |||
| 1 | 2012-09-20 Stefan Merten <smerten@oekonux.de> | ||
| 2 | |||
| 3 | * rst.el: Integrate support for `imenu' and `which-function'. | ||
| 4 | Fixes feature request bug#11711. | ||
| 5 | (rst-mode): Create `imenu-create-index-function'. | ||
| 6 | (rst-get-stripped-line): Delete after refactoring. | ||
| 7 | (rst-section-tree, rst-section-tree-rec) | ||
| 8 | (rst-section-tree-point): Refactor and document properly. | ||
| 9 | (rst-imenu-find-adornments-for-position) | ||
| 10 | (rst-imenu-convert-cell, rst-imenu-create-index): New | ||
| 11 | function. | ||
| 12 | |||
| 1 | 2012-09-20 Stefan Monnier <monnier@iro.umontreal.ca> | 13 | 2012-09-20 Stefan Monnier <monnier@iro.umontreal.ca> |
| 2 | 14 | ||
| 3 | * emacs-lisp/macroexp.el (macroexp--obsolete-warning): New function. | 15 | * emacs-lisp/macroexp.el (macroexp--obsolete-warning): New function. |
diff --git a/lisp/textmodes/rst.el b/lisp/textmodes/rst.el index 47a821c0148..56b0ee47e4a 100644 --- a/lisp/textmodes/rst.el +++ b/lisp/textmodes/rst.el | |||
| @@ -112,6 +112,9 @@ | |||
| 112 | 112 | ||
| 113 | ;; FIXME: Use `testcover'. | 113 | ;; FIXME: Use `testcover'. |
| 114 | 114 | ||
| 115 | ;; FIXME: The adornment classification often called `ado' should be a | ||
| 116 | ;; `defstruct'. | ||
| 117 | |||
| 115 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | 118 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| 116 | ;; Support for `testcover' | 119 | ;; Support for `testcover' |
| 117 | 120 | ||
| @@ -214,7 +217,7 @@ and before TAIL-RE and DELIM-RE in VAR or DEFAULT for no match." | |||
| 214 | ;; Use CVSHeader to really get information from CVS and not other version | 217 | ;; Use CVSHeader to really get information from CVS and not other version |
| 215 | ;; control systems. | 218 | ;; control systems. |
| 216 | (defconst rst-cvs-header | 219 | (defconst rst-cvs-header |
| 217 | "$CVSHeader: sm/rst_el/rst.el,v 1.309.2.1 2012-09-17 17:30:49 stefan Exp $") | 220 | "$CVSHeader: sm/rst_el/rst.el,v 1.324 2012-09-20 18:52:46 stefan Exp $") |
| 218 | (defconst rst-cvs-rev | 221 | (defconst rst-cvs-rev |
| 219 | (rst-extract-version "\\$" "CVSHeader: \\S + " "[0-9]+\\(?:\\.[0-9]+\\)+" | 222 | (rst-extract-version "\\$" "CVSHeader: \\S + " "[0-9]+\\(?:\\.[0-9]+\\)+" |
| 220 | " .*" rst-cvs-header "0.0") | 223 | " .*" rst-cvs-header "0.0") |
| @@ -844,6 +847,12 @@ highlighting. | |||
| 844 | (set (make-local-variable 'uncomment-region-function) | 847 | (set (make-local-variable 'uncomment-region-function) |
| 845 | 'rst-uncomment-region) | 848 | 'rst-uncomment-region) |
| 846 | 849 | ||
| 850 | ;; Imenu and which function. | ||
| 851 | ;; FIXME: Check documentation of `which-function' for alternative ways to | ||
| 852 | ;; determine the current function name. | ||
| 853 | (set (make-local-variable 'imenu-create-index-function) | ||
| 854 | 'rst-imenu-create-index) | ||
| 855 | |||
| 847 | ;; Font lock. | 856 | ;; Font lock. |
| 848 | (set (make-local-variable 'font-lock-defaults) | 857 | (set (make-local-variable 'font-lock-defaults) |
| 849 | '(rst-font-lock-keywords | 858 | '(rst-font-lock-keywords |
| @@ -2170,126 +2179,112 @@ adjust. If bullets are found on levels beyond the | |||
| 2170 | ;; Table of contents | 2179 | ;; Table of contents |
| 2171 | ;; ================= | 2180 | ;; ================= |
| 2172 | 2181 | ||
| 2173 | (defun rst-get-stripped-line () | 2182 | ;; FIXME: Return value should be a `defstruct'. |
| 2174 | "Return the line at cursor, stripped from whitespace." | ||
| 2175 | (re-search-forward (rst-re "\\S .*\\S ") (line-end-position)) | ||
| 2176 | (buffer-substring-no-properties (match-beginning 0) | ||
| 2177 | (match-end 0)) ) | ||
| 2178 | |||
| 2179 | (defun rst-section-tree () | 2183 | (defun rst-section-tree () |
| 2180 | "Get the hierarchical tree of section titles. | 2184 | "Return the hierarchical tree of section titles. |
| 2181 | 2185 | A tree entry looks like ((TITLE MARKER) CHILD...). TITLE is the | |
| 2182 | Returns a hierarchical tree of the sections titles in the | 2186 | stripped text of the section title. MARKER is a marker for the |
| 2183 | document. This can be used to generate a table of contents for | 2187 | beginning of the title text. For the top node or a missing |
| 2184 | the document. The top node will always be a nil node, with the | 2188 | section level node TITLE is nil and MARKER points to the title |
| 2185 | top level titles as children (there may potentially be more than | 2189 | text of the first child. Each CHILD is another tree entry. The |
| 2186 | one). | 2190 | CHILD list may be empty." |
| 2187 | |||
| 2188 | Each section title consists in a cons of the stripped title | ||
| 2189 | string and a marker to the section in the original text document. | ||
| 2190 | |||
| 2191 | If there are missing section levels, the section titles are | ||
| 2192 | inserted automatically, and the title string is set to nil, and | ||
| 2193 | the marker set to the first non-nil child of itself. | ||
| 2194 | Conceptually, the nil nodes--i.e.\ those which have no title--are | ||
| 2195 | to be considered as being the same line as their first non-nil | ||
| 2196 | child. This has advantages later in processing the graph." | ||
| 2197 | |||
| 2198 | (let ((hier (rst-get-hierarchy)) | 2191 | (let ((hier (rst-get-hierarchy)) |
| 2199 | (levels (make-hash-table :test 'equal :size 10)) | 2192 | (ch-sty2level (make-hash-table :test 'equal :size 10)) |
| 2200 | lines) | 2193 | lev-ttl-mrk-l) |
| 2201 | 2194 | ||
| 2202 | (let ((lev 0)) | 2195 | (let ((lev 0)) |
| 2203 | (dolist (ado hier) | 2196 | (dolist (ado hier) |
| 2204 | ;; Compare just the character and indent in the hash table. | 2197 | ;; Compare just the character and indent in the hash table. |
| 2205 | (puthash (cons (car ado) (cadr ado)) lev levels) | 2198 | (puthash (cons (car ado) (cadr ado)) lev ch-sty2level) |
| 2206 | (incf lev))) | 2199 | (incf lev))) |
| 2207 | 2200 | ||
| 2208 | ;; Create a list of lines that contains (text, level, marker) for each | 2201 | ;; Create a list that contains (LEVEL TITLE MARKER) for each adornment. |
| 2209 | ;; adornment. | ||
| 2210 | (save-excursion | 2202 | (save-excursion |
| 2211 | (setq lines | 2203 | (setq lev-ttl-mrk-l |
| 2212 | (mapcar (lambda (ado) | 2204 | (mapcar (lambda (ado) |
| 2213 | (goto-char (point-min)) | 2205 | (goto-char (point-min)) |
| 2214 | (forward-line (1- (car ado))) | 2206 | (1value ;; This should really succeed. |
| 2215 | (list (gethash (cons (cadr ado) (caddr ado)) levels) | 2207 | (forward-line (1- (car ado)))) |
| 2216 | (rst-get-stripped-line) | 2208 | (list (gethash (cons (cadr ado) (caddr ado)) ch-sty2level) |
| 2217 | (progn | 2209 | ;; Get title. |
| 2218 | (beginning-of-line 1) | 2210 | (save-excursion |
| 2219 | (point-marker)))) | 2211 | (if (re-search-forward |
| 2212 | (rst-re "\\S .*\\S ") (line-end-position) t) | ||
| 2213 | (buffer-substring-no-properties | ||
| 2214 | (match-beginning 0) (match-end 0)) | ||
| 2215 | "")) | ||
| 2216 | (point-marker))) | ||
| 2220 | (rst-find-all-adornments)))) | 2217 | (rst-find-all-adornments)))) |
| 2221 | (let ((lcontnr (cons nil lines))) | 2218 | (cdr (rst-section-tree-rec lev-ttl-mrk-l -1)))) |
| 2222 | (rst-section-tree-rec lcontnr -1)))) | 2219 | |
| 2223 | 2220 | ;; FIXME: Return value should be a `defstruct'. | |
| 2224 | 2221 | (defun rst-section-tree-rec (remaining lev) | |
| 2225 | (defun rst-section-tree-rec (ados lev) | 2222 | "Process the first entry of REMAINING expected to be on level LEV. |
| 2226 | "Recursive guts of the section tree construction. | 2223 | REMAINING is the remaining list of adornments consisting |
| 2227 | ADOS is a cons cell whose cdr is the remaining list of | 2224 | of (LEVEL TITLE MARKER) entries. |
| 2228 | adornments, and we change it as we consume them. LEV is | 2225 | |
| 2229 | the current level of that node. This function returns a | 2226 | Return (UNPROCESSED (TITLE MARKER) CHILD...) for the first entry |
| 2230 | pair of the subtree that was built. This treats the ADOS | 2227 | of REMAINING where TITLE is nil if the expected level is not |
| 2231 | list destructively." | 2228 | matched. UNPROCESSED is the list of still unprocessed entries. |
| 2232 | 2229 | Each CHILD is a child of this entry in the same format but | |
| 2233 | (let ((nado (cadr ados)) | 2230 | without UNPROCESSED." |
| 2234 | node | 2231 | (let ((cur (car remaining)) |
| 2235 | children) | 2232 | (unprocessed remaining) |
| 2236 | 2233 | ttl-mrk children) | |
| 2237 | ;; If the next adornment matches our level. | 2234 | ;; If the current adornment matches expected level. |
| 2238 | (when (and nado (= (car nado) lev)) | 2235 | (when (and cur (= (car cur) lev)) |
| 2239 | ;; Pop the next adornment and create the current node with it. | 2236 | ;; Consume the current entry and create the current node with it. |
| 2240 | (setcdr ados (cddr ados)) | 2237 | (setq unprocessed (cdr remaining)) |
| 2241 | (setq node (cdr nado)) ) | 2238 | (setq ttl-mrk (cdr cur))) |
| 2242 | ;; Else we let the node title/marker be unset. | 2239 | |
| 2243 | 2240 | ;; Build the child nodes as long as they have deeper level. | |
| 2244 | ;; Build the child nodes. | 2241 | (while (and unprocessed (> (caar unprocessed) lev)) |
| 2245 | (while (and (cdr ados) (> (caadr ados) lev)) | 2242 | (let ((rem-children (rst-section-tree-rec unprocessed (1+ lev)))) |
| 2246 | (setq children | 2243 | (setq children (cons (cdr rem-children) children)) |
| 2247 | (cons (rst-section-tree-rec ados (1+ lev)) | 2244 | (setq unprocessed (car rem-children)))) |
| 2248 | children))) | ||
| 2249 | (setq children (reverse children)) | 2245 | (setq children (reverse children)) |
| 2250 | 2246 | ||
| 2251 | ;; If node is still unset, we use the marker of the first child. | 2247 | (cons unprocessed |
| 2252 | (when (eq node nil) | 2248 | (cons (or ttl-mrk |
| 2253 | (setq node (cons nil (cdaar children)))) | 2249 | ;; Node on this level missing - use nil as text and the |
| 2254 | 2250 | ;; marker of the first child. | |
| 2255 | ;; Return this node with its children. | 2251 | (cons nil (cdaar children))) |
| 2256 | (cons node children))) | 2252 | children)))) |
| 2257 | 2253 | ||
| 2258 | 2254 | (defun rst-section-tree-point (tree &optional point) | |
| 2259 | (defun rst-section-tree-point (node &optional point) | 2255 | "Return section containing POINT by returning the closest node in TREE. |
| 2260 | "Find tree node at point. | 2256 | TREE is a section tree as returned by `rst-section-tree' |
| 2261 | Given a computed and valid section tree in NODE and a point | 2257 | consisting of (NODE CHILD...) entries. POINT defaults to the |
| 2262 | POINT (default being the current point in the current buffer), | 2258 | current point. A NODE must have the structure (IGNORED MARKER |
| 2263 | find and return the node within the section tree where the cursor | 2259 | ...). |
| 2264 | lives. | 2260 | |
| 2265 | 2261 | Return (PATH NODE CHILD...). NODE is the node where POINT is in | |
| 2266 | Return values: a pair of (parent path, container subtree). | 2262 | if any. PATH is a list of nodes from the top of the tree down to |
| 2267 | The parent path is simply a list of the nodes above the | 2263 | and including NODE. List of CHILD are the children of NODE if |
| 2268 | container subtree node that we're returning." | 2264 | any." |
| 2269 | 2265 | (setq point (or point (point))) | |
| 2270 | (let (path outtree) | 2266 | (let ((cur (car tree)) |
| 2271 | 2267 | (children (cdr tree))) | |
| 2272 | (let* ((curpoint (or point (point)))) | 2268 | ;; Point behind current node? |
| 2273 | 2269 | (if (and (cadr cur) (>= point (cadr cur))) | |
| 2274 | ;; Check if we are before the current node. | 2270 | ;; Iterate all the children, looking for one that might contain the |
| 2275 | (if (and (cadar node) (>= curpoint (cadar node))) | 2271 | ;; current section. |
| 2276 | 2272 | (let (found) | |
| 2277 | ;; Iterate all the children, looking for one that might contain the | 2273 | (while (and children (>= point (cadaar children))) |
| 2278 | ;; current section. | 2274 | (setq found children |
| 2279 | (let ((curnode (cdr node)) | 2275 | children (cdr children))) |
| 2280 | last) | 2276 | (if found |
| 2281 | 2277 | ;; Found section containing point in children. | |
| 2282 | (while (and curnode (>= curpoint (cadaar curnode))) | 2278 | (let ((sub (rst-section-tree-point (car found) point))) |
| 2283 | (setq last curnode | 2279 | ;; Extend path with current node and return NODE CHILD... from |
| 2284 | curnode (cdr curnode))) | 2280 | ;; sub. |
| 2285 | 2281 | (cons (cons cur (car sub)) (cdr sub))) | |
| 2286 | (if last | 2282 | ;; Point in this section: Start a new path with current node and |
| 2287 | (let ((sub (rst-section-tree-point (car last) curpoint))) | 2283 | ;; return current NODE CHILD... |
| 2288 | (setq path (car sub) | 2284 | (cons (list cur) tree))) |
| 2289 | outtree (cdr sub))) | 2285 | ;; Current node behind point: start a new path with current node and |
| 2290 | (setq outtree node))))) | 2286 | ;; no NODE CHILD... |
| 2291 | (cons (cons (car node) path) outtree))) | 2287 | (list (list cur))))) |
| 2292 | |||
| 2293 | 2288 | ||
| 2294 | (defgroup rst-toc nil | 2289 | (defgroup rst-toc nil |
| 2295 | "Settings for reStructuredText table of contents." | 2290 | "Settings for reStructuredText table of contents." |
| @@ -4132,6 +4127,79 @@ buffer, if the region is not selected." | |||
| 4132 | )) | 4127 | )) |
| 4133 | 4128 | ||
| 4134 | 4129 | ||
| 4130 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
| 4131 | ;; Imenu support. | ||
| 4132 | |||
| 4133 | ;; FIXME: Integrate this properly. Consider a key binding. | ||
| 4134 | |||
| 4135 | ;; Based on code from Masatake YAMATO <yamato@redhat.com>. | ||
| 4136 | |||
| 4137 | (defun rst-imenu-find-adornments-for-position (adornments pos) | ||
| 4138 | "Find adornments cell in ADORNMENTS for position POS." | ||
| 4139 | (let ((a nil)) | ||
| 4140 | (while adornments | ||
| 4141 | (if (and (car adornments) | ||
| 4142 | (eq (car (car adornments)) pos)) | ||
| 4143 | (setq a adornments | ||
| 4144 | adornments nil) | ||
| 4145 | (setq adornments (cdr adornments)))) | ||
| 4146 | a)) | ||
| 4147 | |||
| 4148 | (defun rst-imenu-convert-cell (elt adornments) | ||
| 4149 | "Convert a cell ELT in a tree returned from `rst-section-tree' to imenu index. | ||
| 4150 | ADORNMENTS is used as hint information for conversion." | ||
| 4151 | (let* ((kar (car elt)) | ||
| 4152 | (kdr (cdr elt)) | ||
| 4153 | (title (car kar))) | ||
| 4154 | (if kar | ||
| 4155 | (let* ((p (marker-position (cadr kar))) | ||
| 4156 | (adornments | ||
| 4157 | (rst-imenu-find-adornments-for-position adornments p)) | ||
| 4158 | (a (car adornments)) | ||
| 4159 | (adornments (cdr adornments)) | ||
| 4160 | ;; FIXME: Overline adornment characters need to be in front so | ||
| 4161 | ;; they become visible even for long title lines. May be | ||
| 4162 | ;; an additional level number is also useful. | ||
| 4163 | (title (format "%s%s%s" | ||
| 4164 | (make-string (1+ (nth 3 a)) (nth 1 a)) | ||
| 4165 | title | ||
| 4166 | (if (eq (nth 2 a) 'simple) | ||
| 4167 | "" | ||
| 4168 | (char-to-string (nth 1 a)))))) | ||
| 4169 | (cons title | ||
| 4170 | (if (null kdr) | ||
| 4171 | p | ||
| 4172 | (cons | ||
| 4173 | ;; A bit ugly but this make which-func happy. | ||
| 4174 | (cons title p) | ||
| 4175 | (mapcar (lambda (elt0) | ||
| 4176 | (rst-imenu-convert-cell elt0 adornments)) | ||
| 4177 | kdr))))) | ||
| 4178 | nil))) | ||
| 4179 | |||
| 4180 | ;; FIXME: Document title and subtitle need to be handled properly. They should | ||
| 4181 | ;; get an own "Document" top level entry. | ||
| 4182 | (defun rst-imenu-create-index () | ||
| 4183 | "Create index for imenu. | ||
| 4184 | Return as described for `imenu--index-alist'." | ||
| 4185 | (rst-reset-section-caches) | ||
| 4186 | (let ((tree (rst-section-tree)) | ||
| 4187 | ;; Translate line notation to point notation. | ||
| 4188 | (adornments (save-excursion | ||
| 4189 | (mapcar (lambda (ln-ado) | ||
| 4190 | (cons (progn | ||
| 4191 | (goto-char (point-min)) | ||
| 4192 | (forward-line (1- (car ln-ado))) | ||
| 4193 | ;; FIXME: Need to consider | ||
| 4194 | ;; `imenu-use-markers' here? | ||
| 4195 | (point)) | ||
| 4196 | (cdr ln-ado))) | ||
| 4197 | (rst-find-all-adornments))))) | ||
| 4198 | (delete nil (mapcar (lambda (elt) | ||
| 4199 | (rst-imenu-convert-cell elt adornments)) | ||
| 4200 | tree)))) | ||
| 4201 | |||
| 4202 | |||
| 4135 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | 4203 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
| 4136 | ;; Generic text functions that are more convenient than the defaults. | 4204 | ;; Generic text functions that are more convenient than the defaults. |
| 4137 | 4205 | ||