Commit | Line | Data |
---|---|---|
3afbc435 | 1 | ;;; reftex-index.el --- index support with RefTeX |
f2e3589a GM |
2 | |
3 | ;; Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, | |
d7a0267c | 4 | ;; 2006, 2007 Free Software Foundation, Inc. |
3ba2590f | 5 | |
6fbeb429 | 6 | ;; Author: Carsten Dominik <dominik@science.uva.nl> |
ce545621 | 7 | ;; Maintainer: auctex-devel@gnu.org |
5d2a58e0 | 8 | ;; Version: 4.31 |
3ba2590f RS |
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 | |
5a9dffec | 14 | ;; the Free Software Foundation; either version 3, or (at your option) |
3ba2590f RS |
15 | ;; 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; see the file COPYING. If not, write to the | |
27e81652 TTN |
24 | ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
25 | ;; Boston, MA 02110-1301, USA. | |
1a9461d0 | 26 | |
3afbc435 PJ |
27 | ;;; Commentary: |
28 | ||
29 | ;;; Code: | |
30 | ||
7c4d13cc | 31 | (eval-when-compile (require 'cl)) |
1a9461d0 CD |
32 | (provide 'reftex-index) |
33 | (require 'reftex) | |
34 | ;;; | |
35 | ||
3b919c9f | 36 | ;; START remove for XEmacs release |
1a9461d0 CD |
37 | (defvar mark-active) |
38 | (defvar zmacs-regions) | |
48ffe14f | 39 | (defvar transient-mark-mode) |
7b07114a | 40 | (defvar TeX-master) |
3b919c9f | 41 | ;; END remove for XEmacs release |
f29263b3 DN |
42 | |
43 | (declare-function texmathp "ext:texmathp" ()) | |
44 | ||
7c4d13cc | 45 | (defun reftex-index-selection-or-word (&optional arg phrase) |
1a9461d0 CD |
46 | "Put selection or the word near point into the default index macro. |
47 | This uses the information in `reftex-index-default-macro' to make an index | |
48 | entry. The phrase indexed is the current selection or the word near point. | |
49 | When called with one `C-u' prefix, let the user have a chance to edit the | |
50 | index entry. When called with 2 `C-u' as prefix, also ask for the index | |
51 | macro and other stuff. | |
52 | When called inside TeX math mode as determined by the `texmathp.el' library | |
53 | which is part of AUCTeX, the string is first processed with the | |
54 | `reftex-index-math-format', which see." | |
55 | (interactive "P") | |
56 | (let* ((use-default (not (equal arg '(16)))) ; check for double prefix | |
3666daf6 | 57 | ;; check if we have an active selection |
4ea0e84a | 58 | (active (if (featurep 'xemacs) |
3666daf6 CD |
59 | (and zmacs-regions (region-exists-p)) ; XEmacs |
60 | (and transient-mark-mode mark-active))) ; Emacs | |
7b07114a | 61 | (beg (if active |
3666daf6 | 62 | (region-beginning) |
7b07114a | 63 | (save-excursion |
3666daf6 CD |
64 | (skip-syntax-backward "w\\") (point)))) |
65 | (end (if active | |
66 | (region-end) | |
7b07114a | 67 | (save-excursion |
3666daf6 CD |
68 | (skip-syntax-forward "w\\") (point)))) |
69 | (sel (buffer-substring beg end)) | |
70 | (mathp (condition-case nil (texmathp) (error nil))) | |
71 | (current-prefix-arg nil) ; we want to call reftex-index without prefix. | |
72 | key def-char def-tag full-entry) | |
1a9461d0 | 73 | |
7c4d13cc | 74 | (if phrase |
3666daf6 CD |
75 | (progn |
76 | (reftex-index-visit-phrases-buffer) | |
77 | (reftex-index-new-phrase sel)) | |
7c4d13cc CD |
78 | |
79 | (if (equal sel "") | |
3666daf6 CD |
80 | ;; Nothing selected, no word, so use full reftex-index command |
81 | (reftex-index) | |
82 | ;; OK, we have something to index here. | |
83 | ;; Add the dollars when necessary | |
84 | (setq key (if mathp | |
85 | (format reftex-index-math-format sel) | |
86 | sel)) | |
87 | ;; Get info from `reftex-index-default-macro' | |
88 | (setq def-char (if use-default (car reftex-index-default-macro))) | |
89 | (setq def-tag (if use-default (nth 1 reftex-index-default-macro))) | |
90 | ;; Does the user want to edit the entry? | |
91 | (setq full-entry (if arg | |
92 | (reftex-index-complete-key | |
93 | def-tag nil (cons key 0)) | |
94 | key)) | |
95 | ;; Delete what is in the buffer and make the index entry | |
96 | (delete-region beg end) | |
97 | (reftex-index def-char full-entry def-tag sel))))) | |
7b07114a | 98 | |
7c4d13cc | 99 | (defun reftex-index (&optional char key tag sel no-insert) |
1a9461d0 CD |
100 | "Query for an index macro and insert it along with its argments. |
101 | The index macros available are those defined in `reftex-index-macro' or | |
102 | by a call to `reftex-add-index-macros', typically from an AUCTeX style file. | |
103 | RefteX provides completion for the index tag and the index key, and | |
104 | will prompt for other arguments." | |
105 | ||
106 | (interactive) | |
107 | ||
108 | ;; Ensure access to scanning info | |
109 | (reftex-ensure-index-support t) | |
110 | (reftex-access-scan-info current-prefix-arg) | |
111 | ||
112 | ;; Find out which macro we are going to use | |
113 | (let* ((char (or char | |
3666daf6 CD |
114 | (reftex-select-with-char reftex-query-index-macro-prompt |
115 | reftex-query-index-macro-help))) | |
116 | (macro (nth 1 (assoc char reftex-key-to-index-macro-alist))) | |
117 | (entry (or (assoc macro reftex-index-macro-alist) | |
118 | (error "No index macro associated with %c" char))) | |
119 | (ntag (nth 1 entry)) | |
120 | (tag (or tag (nth 1 entry))) | |
121 | (nargs (nth 4 entry)) | |
122 | (nindex (nth 5 entry)) | |
123 | (opt-args (nth 6 entry)) | |
124 | (repeat (nth 7 entry)) | |
125 | opt tag1 value) | |
1a9461d0 CD |
126 | |
127 | ;; Get the supported arguments | |
128 | (if (stringp tag) | |
3666daf6 | 129 | (setq tag1 tag) |
1a9461d0 CD |
130 | (setq tag1 (or (reftex-index-complete-tag tag opt-args) ""))) |
131 | (setq key (or key | |
3666daf6 CD |
132 | (reftex-index-complete-key |
133 | (if (string= tag1 "") "idx" tag1) | |
134 | (member nindex opt-args)))) | |
1a9461d0 CD |
135 | |
136 | ;; Insert the macro and ask for any additional args | |
137 | (insert macro) | |
138 | (loop for i from 1 to nargs do | |
139 | (setq opt (member i opt-args) | |
3666daf6 CD |
140 | value (cond ((= nindex i) key) |
141 | ((equal ntag i) tag1) | |
142 | (t (read-string (concat "Macro arg nr. " | |
143 | (int-to-string i) | |
144 | (if opt " (optional)" "") | |
145 | ": "))))) | |
1a9461d0 | 146 | (unless (and opt (string= value "")) |
3666daf6 | 147 | (insert (if opt "[" "{") value (if opt "]" "}")))) |
7c4d13cc | 148 | (and repeat (stringp sel) (insert sel)) |
1a9461d0 | 149 | (and key reftex-plug-into-AUCTeX (fboundp 'LaTeX-add-index-entries) |
3666daf6 | 150 | (LaTeX-add-index-entries key)) |
1a9461d0 CD |
151 | (reftex-index-update-taglist tag1) |
152 | (reftex-notice-new))) | |
153 | ||
154 | (defun reftex-default-index () | |
155 | (cond ((null reftex-index-default-tag) nil) | |
3666daf6 CD |
156 | ((stringp reftex-index-default-tag) reftex-index-default-tag) |
157 | (t (or (get reftex-docstruct-symbol 'default-index-tag) | |
158 | "idx")))) | |
1a9461d0 CD |
159 | |
160 | (defun reftex-update-default-index (tag &optional tag-list) | |
161 | (if (and (not (equal tag "")) | |
3666daf6 CD |
162 | (stringp tag) |
163 | (eq reftex-index-default-tag 'last) | |
164 | (or (null tag-list) | |
165 | (member tag tag-list))) | |
1a9461d0 CD |
166 | (put reftex-docstruct-symbol 'default-index-tag tag))) |
167 | ||
168 | (defun reftex-index-complete-tag (&optional itag opt-args) | |
169 | ;; Ask the user for a tag, completing on known tags. | |
170 | ;; ITAG is the argument number which contains the tag. | |
171 | ;; OPT-ARGS is a list of optional argument indices, as given by | |
172 | ;; `reftex-parse-args'. | |
173 | (let* ((opt (and (integerp itag) (member itag opt-args))) | |
5b76833f RF |
174 | (index-tags (cdr (assq 'index-tags |
175 | (symbol-value reftex-docstruct-symbol)))) | |
176 | (default (reftex-default-index)) | |
177 | (prompt (concat "Index tag" | |
178 | (if (or opt default) | |
179 | (format " (%s): " | |
180 | (concat | |
181 | (if opt "optional" "") | |
182 | (if default | |
183 | (concat (if opt ", " "") | |
184 | (format "default %s" default)) | |
185 | ""))) | |
186 | ": "))) | |
187 | (tag (completing-read prompt (mapcar 'list index-tags)))) | |
1a9461d0 CD |
188 | (if (and default (equal tag "")) (setq tag default)) |
189 | (reftex-update-default-index tag) | |
190 | tag)) | |
191 | ||
192 | (defun reftex-index-select-tag () | |
193 | ;; Have the user select an index tag. | |
194 | ;; FIXME: should we cache tag-alist, prompt and help? | |
7b07114a | 195 | (let* ((index-tags (cdr (assoc 'index-tags |
3666daf6 CD |
196 | (symbol-value reftex-docstruct-symbol)))) |
197 | (default (reftex-default-index))) | |
7b07114a | 198 | (cond |
1a9461d0 CD |
199 | ((null index-tags) |
200 | (error "No index tags available")) | |
201 | ||
202 | ((= (length index-tags) 1) | |
203 | ;; Just one index, use it | |
204 | (car index-tags)) | |
7b07114a | 205 | |
1a9461d0 CD |
206 | ((> (length index-tags) 1) |
207 | ;; Several indices, ask. | |
208 | (let* ((tags (copy-sequence index-tags)) | |
3666daf6 CD |
209 | (cnt 0) |
210 | tag-alist i val len tag prompt help rpl) | |
211 | ;; Move idx and glo up in the list to ensure ?i and ?g shortcuts | |
212 | (if (member "glo" tags) | |
213 | (setq tags (cons "glo" (delete "glo" tags)))) | |
214 | (if (member "idx" tags) | |
215 | (setq tags (cons "idx" (delete "idx" tags)))) | |
216 | ;; Find unique shortcuts for each index. | |
217 | (while (setq tag (pop tags)) | |
218 | (setq len (length tag) | |
219 | i -1 | |
220 | val nil) | |
221 | (catch 'exit | |
222 | (while (and (< (incf i) len) (null val)) | |
223 | (unless (assq (aref tag i) tag-alist) | |
224 | (push (list (aref tag i) | |
225 | tag | |
7b07114a | 226 | (concat (substring tag 0 i) |
3666daf6 CD |
227 | "[" (substring tag i (incf i)) "]" |
228 | (substring tag i))) | |
229 | tag-alist) | |
230 | (throw 'exit t))) | |
7b07114a | 231 | (push (list (+ ?0 (incf cnt)) tag |
3666daf6 CD |
232 | (concat "[" (int-to-string cnt) "]:" tag)) |
233 | tag-alist))) | |
234 | (setq tag-alist (nreverse tag-alist)) | |
235 | ;; Compute Prompt and Help strings | |
236 | (setq prompt | |
237 | (concat | |
238 | (format "Select Index%s: " | |
239 | (if default (format " (Default <%s>)" default) "")) | |
240 | (mapconcat (lambda(x) (nth 2 x)) tag-alist " "))) | |
241 | (setq help | |
242 | (concat "Select an Index\n===============\n" | |
243 | (if default | |
244 | (format "[^M] %s (the default)\n" default) | |
245 | "") | |
7b07114a | 246 | (mapconcat (lambda(x) |
3666daf6 CD |
247 | (apply 'format "[%c] %s" x)) |
248 | tag-alist "\n"))) | |
249 | ;; Query the user for an index-tag | |
250 | (setq rpl (reftex-select-with-char prompt help 3 t)) | |
251 | (message "") | |
252 | (if (and default (equal rpl ?\C-m)) | |
253 | default | |
254 | (if (assq rpl tag-alist) | |
255 | (progn | |
256 | (reftex-update-default-index (nth 1 (assq rpl tag-alist))) | |
257 | (nth 1 (assq rpl tag-alist))) | |
258 | (error "No index tag associated with %c" rpl))))) | |
1a9461d0 CD |
259 | (t (error "This should not happen (reftex-index-select-tag)"))))) |
260 | ||
261 | (defun reftex-index-complete-key (&optional tag optional initial) | |
262 | ;; Read an index key, with completion. | |
263 | ;; Restrict completion table on index tag TAG. | |
264 | ;; OPTIONAL indicates if the arg is optional. | |
265 | (let* ((table (reftex-sublist-nth | |
3666daf6 CD |
266 | (symbol-value reftex-docstruct-symbol) 6 |
267 | (lambda(x) (and (eq (car x) 'index) | |
268 | (string= (nth 1 x) (or tag "")))) | |
269 | t)) | |
270 | (prompt (concat "Index key" (if optional " (optional)" "") ": ")) | |
271 | (key (completing-read prompt table nil nil initial))) | |
1a9461d0 CD |
272 | key)) |
273 | ||
274 | (defun reftex-index-update-taglist (newtag) | |
7b07114a | 275 | ;; add NEWTAG to the list of available index tags. |
1a9461d0 CD |
276 | (let ((cell (assoc 'index-tags (symbol-value reftex-docstruct-symbol)))) |
277 | (and newtag (cdr cell) (not (member newtag (cdr cell))) | |
3666daf6 | 278 | (push newtag (cdr cell))))) |
1a9461d0 | 279 | |
1a9461d0 CD |
280 | (defvar reftex-index-map (make-sparse-keymap) |
281 | "Keymap used for *Index* buffers.") | |
282 | ||
283 | (defvar reftex-index-menu) | |
284 | ||
285 | (defvar reftex-last-index-file nil | |
286 | "Stores the file name from which `reftex-display-index' was called.") | |
287 | (defvar reftex-index-tag nil | |
288 | "Stores the tag of the index in an index buffer.") | |
289 | ||
290 | (defvar reftex-index-return-marker (make-marker) | |
291 | "Marker which makes it possible to return from index to old position.") | |
292 | ||
293 | (defvar reftex-index-restriction-indicator nil) | |
294 | (defvar reftex-index-restriction-data nil) | |
295 | ||
296 | (defun reftex-index-mode () | |
297 | "Major mode for managing Index buffers for LaTeX files. | |
298 | This buffer was created with RefTeX. | |
299 | Press `?' for a summary of important key bindings, or check the menu. | |
300 | ||
301 | Here are all local bindings. | |
302 | ||
303 | \\{reftex-index-map}" | |
304 | (interactive) | |
305 | (kill-all-local-variables) | |
306 | (setq major-mode 'reftex-index-mode | |
3666daf6 | 307 | mode-name "RefTeX Index") |
1a9461d0 CD |
308 | (use-local-map reftex-index-map) |
309 | (set (make-local-variable 'revert-buffer-function) 'reftex-index-revert) | |
310 | (set (make-local-variable 'reftex-index-restriction-data) nil) | |
311 | (set (make-local-variable 'reftex-index-restriction-indicator) nil) | |
312 | (setq mode-line-format | |
3666daf6 CD |
313 | (list "---- " 'mode-line-buffer-identification |
314 | " " 'global-mode-string | |
315 | " R<" 'reftex-index-restriction-indicator ">" | |
316 | " -%-")) | |
1a9461d0 | 317 | (setq truncate-lines t) |
7ac7387b CD |
318 | (when (featurep 'xemacs) |
319 | ;; XEmacs needs the call to make-local-hook | |
320 | (make-local-hook 'post-command-hook) | |
321 | (make-local-hook 'pre-command-hook)) | |
1a9461d0 CD |
322 | (make-local-variable 'reftex-last-follow-point) |
323 | (easy-menu-add reftex-index-menu reftex-index-map) | |
324 | (add-hook 'post-command-hook 'reftex-index-post-command-hook nil t) | |
325 | (add-hook 'pre-command-hook 'reftex-index-pre-command-hook nil t) | |
7b07114a | 326 | (run-hooks 'reftex-index-mode-hook)) |
1a9461d0 CD |
327 | |
328 | (defconst reftex-index-help | |
329 | " AVAILABLE KEYS IN INDEX BUFFER | |
330 | ============================== | |
331 | ! A..Z Goto the section of entries starting with this letter. | |
332 | n / p next-entry / previous-entry | |
333 | SPC / TAB Show/Goto the corresponding entry in the LaTeX document. | |
334 | RET Goto the entry and hide the *Index* window (also on mouse-2). | |
335 | q / k Hide/Kill *Index* buffer. | |
336 | C-c = Switch to the TOC buffer. | |
337 | f / c Toggle follow mode / Toggle display of [c]ontext. | |
338 | g Refresh *Index* buffer. | |
339 | r / C-u r Reparse the LaTeX document / Reparse entire LaTeX document. | |
340 | s Switch to a different index (for documents with multiple indices). | |
341 | e / C-k Edit/Kill the entry. | |
342 | * | @ Edit specific part of entry: [*]key [|]attribute [@]visual | |
343 | With prefix: kill that part. | |
5829a569 | 344 | \( ) Toggle entry's beginning/end of page range property. |
1a9461d0 | 345 | _ ^ Add/Remove parent key (to make this item a subitem). |
1a9461d0 CD |
346 | } / { Restrict Index to a single document section / Widen. |
347 | < / > When restricted, move restriction to previous/next section.") | |
348 | ||
349 | (defun reftex-index-show-entry (data &optional no-revisit) | |
350 | ;; Find an index entry associated with DATA and display it highlighted | |
351 | ;; in another window. NO-REVISIT means we are not allowed to visit | |
352 | ;; files for this. | |
353 | ;; Note: This function just looks for the nearest match of the | |
354 | ;; context string and may fail if the entry moved and an identical | |
355 | ;; entry is close to the old position. Frequent rescans make this | |
7b07114a | 356 | ;; safer. |
1a9461d0 | 357 | (let* ((file (nth 3 data)) |
3666daf6 CD |
358 | (literal (nth 2 data)) |
359 | (pos (nth 4 data)) | |
360 | (re (regexp-quote literal)) | |
361 | (match | |
362 | (cond | |
363 | ((or (not no-revisit) | |
364 | (reftex-get-buffer-visiting file)) | |
365 | (switch-to-buffer-other-window | |
366 | (reftex-get-file-buffer-force file nil)) | |
367 | (goto-char (or pos (point-min))) | |
368 | (or (looking-at re) | |
369 | (reftex-nearest-match re (length literal)))) | |
274f1353 | 370 | (t (message "%s" reftex-no-follow-message) nil)))) |
1a9461d0 CD |
371 | (when match |
372 | (goto-char (match-beginning 0)) | |
373 | (recenter '(4)) | |
374 | (reftex-highlight 0 (match-beginning 0) (match-end 0) (current-buffer))) | |
375 | match)) | |
376 | ||
f3c18bd0 | 377 | (defun reftex-display-index (&optional tag overriding-restriction redo |
3666daf6 | 378 | &rest locations) |
1a9461d0 CD |
379 | "Display a buffer with an index compiled from the current document. |
380 | When the document has multiple indices, first prompts for the correct one. | |
381 | When index support is turned off, offer to turn it on. | |
382 | With one or two `C-u' prefixes, rescan document first. | |
383 | With prefix 2, restrict index to current document section. | |
384 | With prefix 3, restrict index to region." | |
385 | ||
386 | (interactive) | |
387 | ||
388 | ;; Ensure access to scanning info and rescan buffer if prefix are is '(4). | |
389 | (let ((current-prefix-arg current-prefix-arg)) | |
390 | (reftex-ensure-index-support t) | |
391 | (reftex-access-scan-info current-prefix-arg)) | |
392 | ||
393 | (set-marker reftex-index-return-marker (point)) | |
394 | (setq reftex-last-follow-point 1) | |
395 | ||
396 | ;; Determine the correct index to process | |
397 | (let* ((docstruct (symbol-value reftex-docstruct-symbol)) | |
3666daf6 CD |
398 | (docstruct-symbol reftex-docstruct-symbol) |
399 | (index-tag (or tag (reftex-index-select-tag))) | |
400 | (master (reftex-TeX-master-file)) | |
401 | (calling-file (buffer-file-name)) | |
402 | (restriction | |
403 | (or overriding-restriction | |
7b07114a | 404 | (and (not redo) |
3666daf6 CD |
405 | (reftex-get-restriction current-prefix-arg docstruct)))) |
406 | (locations | |
407 | ;; See if we are on an index macro as initial position | |
408 | (or locations | |
409 | (let* ((what-macro (reftex-what-macro-safe 1)) | |
410 | (macro (car what-macro)) | |
411 | (here-I-am (when (member macro reftex-macros-with-index) | |
412 | (save-excursion | |
7b07114a | 413 | (goto-char (+ (cdr what-macro) |
3666daf6 CD |
414 | (length macro))) |
415 | (reftex-move-over-touching-args) | |
416 | (reftex-where-am-I))))) | |
417 | (if (eq (car (car here-I-am)) 'index) | |
418 | (list (car here-I-am)))))) | |
419 | buffer-name) | |
1a9461d0 CD |
420 | |
421 | (setq buffer-name (reftex-make-index-buffer-name index-tag)) | |
422 | ||
423 | ;; Goto the buffer and put it into the correct mode | |
7b07114a | 424 | |
1a9461d0 | 425 | (when (or restriction current-prefix-arg) |
3666daf6 | 426 | (reftex-kill-buffer buffer-name)) |
1a9461d0 CD |
427 | |
428 | (if (get-buffer-window buffer-name) | |
3666daf6 | 429 | (select-window (get-buffer-window buffer-name)) |
1a9461d0 | 430 | (let ((default-major-mode 'reftex-index-mode)) |
3666daf6 | 431 | (switch-to-buffer buffer-name))) |
1a9461d0 CD |
432 | |
433 | (or (eq major-mode 'reftex-index-mode) (reftex-index-mode)) | |
434 | ||
435 | ;; If the buffer is currently restricted, empty it to force update. | |
436 | (when reftex-index-restriction-data | |
437 | (reftex-erase-buffer)) | |
438 | (set (make-local-variable 'reftex-last-index-file) calling-file) | |
439 | (set (make-local-variable 'reftex-index-tag) index-tag) | |
440 | (set (make-local-variable 'reftex-docstruct-symbol) docstruct-symbol) | |
441 | (if restriction | |
3666daf6 CD |
442 | (setq reftex-index-restriction-indicator (car restriction) |
443 | reftex-index-restriction-data (cdr restriction)) | |
f3c18bd0 | 444 | (if (not redo) |
3666daf6 CD |
445 | (setq reftex-index-restriction-indicator nil |
446 | reftex-index-restriction-data nil))) | |
1a9461d0 CD |
447 | (when (= (buffer-size) 0) |
448 | ;; buffer is empty - fill it | |
449 | (message "Building %s buffer..." buffer-name) | |
450 | ||
451 | (setq buffer-read-only nil) | |
452 | (insert (format | |
453 | "INDEX <%s> on %s | |
454 | Restriction: <%s> | |
455 | SPC=view TAB=goto RET=goto+hide [e]dit [q]uit [r]escan [f]ollow [?]Help | |
456 | ------------------------------------------------------------------------------ | |
457 | " index-tag (abbreviate-file-name master) | |
458 | (if (eq (car (car reftex-index-restriction-data)) 'toc) | |
459 | (nth 2 (car reftex-index-restriction-data)) | |
460 | reftex-index-restriction-indicator))) | |
461 | ||
462 | (if (reftex-use-fonts) | |
463 | (put-text-property 1 (point) 'face reftex-index-header-face)) | |
464 | (put-text-property 1 (point) 'intangible t) | |
465 | ||
466 | (reftex-insert-index docstruct index-tag) | |
467 | (goto-char (point-min)) | |
468 | (run-hooks 'reftex-display-copied-context-hook) | |
469 | (message "Building %s buffer...done." buffer-name) | |
470 | (setq buffer-read-only t)) | |
471 | (and locations (apply 'reftex-find-start-point (point) locations)) | |
472 | (if reftex-index-restriction-indicator | |
473 | (message "Index restricted: <%s>" reftex-index-restriction-indicator)))) | |
474 | ||
475 | (defun reftex-insert-index (docstruct tag &optional update-one remark) | |
476 | ;; Insert an index into the current buffer. Entries are from the | |
477 | ;; DOCSTRUCT. | |
478 | ;; TAG is the subindex to process. | |
479 | ;; UPDATE-ONE: When non-nil, delete the entry at point and replace | |
480 | ;; it with whatever the DOCSTRUCT contains. | |
481 | ;; REMARK can be a note to add to the entry. | |
482 | (let* ((all docstruct) | |
3666daf6 CD |
483 | (indent " ") |
484 | (context reftex-index-include-context) | |
485 | (context-indent (concat indent " ")) | |
486 | (section-chars (mapcar 'identity reftex-index-section-letters)) | |
487 | (this-section-char 0) | |
488 | (font (reftex-use-fonts)) | |
489 | (bor (car reftex-index-restriction-data)) | |
490 | (eor (nth 1 reftex-index-restriction-data)) | |
491 | (mouse-face | |
492 | (if (memq reftex-highlight-selection '(mouse both)) | |
493 | reftex-mouse-selected-face | |
494 | nil)) | |
495 | (index-face (reftex-verified-face reftex-label-face | |
496 | 'font-lock-constant-face | |
497 | 'font-lock-reference-face)) | |
498 | sublist cell from to first-char) | |
1a9461d0 CD |
499 | |
500 | ;; Make the sublist and sort it | |
501 | (when bor | |
502 | (setq all (or (memq bor all) all))) | |
503 | ||
504 | (while (setq cell (pop all)) | |
505 | (if (eq cell eor) | |
3666daf6 CD |
506 | (setq all nil) |
507 | (and (eq (car cell) 'index) | |
508 | (equal (nth 1 cell) tag) | |
509 | (push cell sublist)))) | |
1a9461d0 | 510 | (setq sublist (sort (nreverse sublist) |
3666daf6 | 511 | (lambda (a b) (string< (nth 8 a) (nth 8 b))))) |
1a9461d0 CD |
512 | |
513 | (when update-one | |
514 | ;; Delete the entry at place | |
515 | (and (bolp) (forward-char 1)) | |
516 | (delete-region (previous-single-property-change (1+ (point)) :data) | |
7b07114a | 517 | (or (next-single-property-change (point) :data) |
3666daf6 | 518 | (point-max)))) |
1a9461d0 CD |
519 | |
520 | ;; Walk through the list and insert all entries | |
521 | (while (setq cell (pop sublist)) | |
522 | (unless update-one | |
3666daf6 CD |
523 | (setq first-char (upcase (string-to-char (nth 6 cell)))) |
524 | (when (and (not (equal first-char this-section-char)) | |
525 | (member first-char section-chars)) | |
526 | ;; There is a new initial letter, so start a new section | |
527 | (reftex-index-insert-new-letter first-char font) | |
528 | (setq section-chars (delete first-char section-chars) | |
529 | this-section-char first-char)) | |
530 | (when (= this-section-char 0) | |
531 | (setq this-section-char ?!) | |
532 | (reftex-index-insert-new-letter this-section-char font))) | |
1a9461d0 CD |
533 | |
534 | (setq from (point)) | |
535 | (insert indent (nth 7 cell)) | |
536 | (when font | |
3666daf6 | 537 | (setq to (point)) |
7b07114a | 538 | (put-text-property |
3666daf6 CD |
539 | (- (point) (length (nth 7 cell))) to |
540 | 'face index-face) | |
541 | (goto-char to)) | |
1a9461d0 CD |
542 | |
543 | (when (or remark (nth 9 cell)) | |
3666daf6 CD |
544 | (and (< (current-column) 40) |
545 | ;; FIXME: maybe this is too slow? | |
546 | (insert (make-string (max (- 40 (current-column)) 0) ?\ ))) | |
547 | (and (nth 9 cell) (insert " " (substring (nth 5 cell) (nth 9 cell)))) | |
548 | (and remark (insert " " remark))) | |
1a9461d0 CD |
549 | |
550 | (insert "\n") | |
551 | (setq to (point)) | |
552 | ||
553 | (when context | |
3666daf6 CD |
554 | (insert context-indent (nth 2 cell) "\n") |
555 | (setq to (point))) | |
1a9461d0 CD |
556 | (put-text-property from to :data cell) |
557 | (when mouse-face | |
3666daf6 CD |
558 | (put-text-property from (1- to) |
559 | 'mouse-face mouse-face)) | |
1a9461d0 CD |
560 | (goto-char to)))) |
561 | ||
562 | ||
563 | (defun reftex-index-insert-new-letter (letter &optional font) | |
564 | ;; Start a new section in the index | |
565 | (let ((from (point))) | |
7b07114a | 566 | (insert "\n" letter letter letter |
3666daf6 | 567 | "-----------------------------------------------------------------") |
1a9461d0 CD |
568 | (when font |
569 | (put-text-property from (point) 'face reftex-index-section-face)) | |
570 | (insert "\n"))) | |
571 | ||
572 | (defun reftex-get-restriction (arg docstruct) | |
573 | ;; Interprete the prefix ARG and derive index restriction specs. | |
574 | (let* ((beg (min (point) (or (condition-case nil (mark) (error nil)) | |
3666daf6 CD |
575 | (point-max)))) |
576 | (end (max (point) (or (condition-case nil (mark) (error nil)) | |
577 | (point-min)))) | |
578 | bor eor label here-I-am) | |
1a9461d0 CD |
579 | (cond |
580 | ((eq arg 2) | |
581 | (setq here-I-am (car (reftex-where-am-I)) | |
3666daf6 CD |
582 | bor (if (eq (car here-I-am) 'toc) |
583 | here-I-am | |
584 | (reftex-last-assoc-before-elt | |
585 | 'toc here-I-am docstruct)) | |
586 | eor (car (memq (assq 'toc (cdr (memq bor docstruct))) docstruct)) | |
587 | label (nth 6 bor))) | |
1a9461d0 CD |
588 | ((eq arg 3) |
589 | (save-excursion | |
3666daf6 CD |
590 | (setq label "region") |
591 | (goto-char beg) | |
592 | (setq bor (car (reftex-where-am-I))) | |
593 | (setq bor (nth 1 (memq bor docstruct))) | |
594 | (goto-char end) | |
595 | (setq eor (nth 1 (memq (car (reftex-where-am-I)) docstruct))))) | |
1a9461d0 CD |
596 | (t nil)) |
597 | (if (and label (or bor eor)) | |
3666daf6 | 598 | (list label bor eor) |
1a9461d0 CD |
599 | nil))) |
600 | ||
601 | (defun reftex-index-pre-command-hook () | |
602 | ;; Used as pre command hook in *Index* buffer | |
603 | (reftex-unhighlight 0) | |
604 | (reftex-unhighlight 1)) | |
605 | ||
606 | (defun reftex-index-post-command-hook () | |
607 | ;; Used in the post-command-hook for the *Index* buffer | |
608 | (when (get-text-property (point) :data) | |
609 | (and (> (point) 1) | |
3666daf6 CD |
610 | (not (get-text-property (point) 'intangible)) |
611 | (memq reftex-highlight-selection '(cursor both)) | |
612 | (reftex-highlight 1 | |
613 | (or (previous-single-property-change (1+ (point)) :data) | |
614 | (point-min)) | |
615 | (or (next-single-property-change (point) :data) | |
616 | (point-max))))) | |
1a9461d0 CD |
617 | (if (integerp reftex-index-follow-mode) |
618 | ;; Remove delayed action | |
619 | (setq reftex-index-follow-mode t) | |
620 | (and reftex-index-follow-mode | |
3666daf6 CD |
621 | (not (equal reftex-last-follow-point (point))) |
622 | ;; Show context in other window | |
623 | (setq reftex-last-follow-point (point)) | |
624 | (condition-case nil | |
625 | (reftex-index-visit-location nil (not reftex-revisit-to-follow)) | |
626 | (error t))))) | |
1a9461d0 CD |
627 | |
628 | (defun reftex-index-show-help () | |
629 | "Show a summary of special key bindings." | |
630 | (interactive) | |
631 | (with-output-to-temp-buffer "*RefTeX Help*" | |
632 | (princ reftex-index-help)) | |
633 | (reftex-enlarge-to-fit "*RefTeX Help*" t) | |
634 | ;; If follow mode is active, arrange to delay it one command | |
635 | (if reftex-index-follow-mode | |
636 | (setq reftex-index-follow-mode 1))) | |
637 | ||
638 | (defun reftex-index-next (&optional arg) | |
639 | "Move to next selectable item." | |
640 | (interactive "p") | |
641 | (setq reftex-callback-fwd t) | |
642 | (or (eobp) (forward-char 1)) | |
7b07114a | 643 | (goto-char (or (next-single-property-change (point) :data) |
3666daf6 | 644 | (point))) |
1a9461d0 | 645 | (unless (get-text-property (point) :data) |
7b07114a | 646 | (goto-char (or (next-single-property-change (point) :data) |
3666daf6 | 647 | (point))))) |
1a9461d0 CD |
648 | (defun reftex-index-previous (&optional arg) |
649 | "Move to previous selectable item." | |
650 | (interactive "p") | |
651 | (setq reftex-callback-fwd nil) | |
652 | (goto-char (or (previous-single-property-change (point) :data) | |
3666daf6 | 653 | (point))) |
1a9461d0 CD |
654 | (unless (get-text-property (point) :data) |
655 | (goto-char (or (previous-single-property-change (point) :data) | |
3666daf6 | 656 | (point))))) |
1a9461d0 CD |
657 | (defun reftex-index-toggle-follow () |
658 | "Toggle follow (other window follows with context)." | |
659 | (interactive) | |
660 | (setq reftex-last-follow-point -1) | |
661 | (setq reftex-index-follow-mode (not reftex-index-follow-mode))) | |
662 | (defun reftex-index-toggle-context () | |
663 | "Toggle inclusion of label context in *Index* buffer. | |
664 | Label context is only displayed when the labels are there as well." | |
665 | (interactive) | |
666 | (setq reftex-index-include-context (not reftex-index-include-context)) | |
667 | (reftex-index-revert)) | |
668 | (defun reftex-index-view-entry () | |
669 | "View document location in other window." | |
670 | (interactive) | |
671 | (reftex-index-visit-location)) | |
672 | (defun reftex-index-goto-entry-and-hide () | |
673 | "Go to document location in other window. Hide the *Index* window." | |
674 | (interactive) | |
675 | (reftex-index-visit-location 'hide)) | |
676 | (defun reftex-index-goto-entry () | |
677 | "Go to document location in other window. *Index* window stays." | |
678 | (interactive) | |
679 | (reftex-index-visit-location t)) | |
680 | (defun reftex-index-mouse-goto-line-and-hide (ev) | |
681 | "Go to document location in other window. Hide the *Index* window." | |
682 | (interactive "e") | |
683 | (mouse-set-point ev) | |
684 | (reftex-index-visit-location 'hide)) | |
685 | (defun reftex-index-quit () | |
686 | "Hide the *Index* window and do not move point." | |
687 | (interactive) | |
688 | (or (one-window-p) (delete-window)) | |
689 | (switch-to-buffer (marker-buffer reftex-index-return-marker)) | |
690 | (goto-char (or (marker-position reftex-index-return-marker) (point)))) | |
691 | (defun reftex-index-quit-and-kill () | |
692 | "Kill the *Index* buffer." | |
693 | (interactive) | |
694 | (kill-buffer (current-buffer)) | |
695 | (or (one-window-p) (delete-window)) | |
696 | (switch-to-buffer (marker-buffer reftex-index-return-marker)) | |
697 | (goto-char (or (marker-position reftex-index-return-marker) (point)))) | |
698 | (defun reftex-index-goto-toc (&rest ignore) | |
699 | "Switch to the table of contents of the current document. | |
700 | The function will go to the section where the entry at point was defined." | |
701 | (interactive) | |
702 | (if (get-text-property (point) :data) | |
703 | (reftex-index-goto-entry) | |
704 | (switch-to-buffer (marker-buffer reftex-index-return-marker))) | |
705 | (delete-other-windows) | |
706 | (reftex-toc)) | |
707 | (defun reftex-index-rescan (&rest ignore) | |
708 | "Regenerate the *Index* buffer after reparsing file of section at point." | |
709 | (interactive) | |
710 | (let ((index-tag reftex-index-tag)) | |
711 | (if (and reftex-enable-partial-scans | |
3666daf6 CD |
712 | (null current-prefix-arg)) |
713 | (let* ((data (get-text-property (point) :data)) | |
714 | (file (nth 3 data)) | |
715 | (line (+ (count-lines (point-min) (point)) (if (bolp) 1 0)))) | |
716 | (if (not file) | |
717 | (error "Don't know which file to rescan. Try `C-u r'") | |
718 | (switch-to-buffer (reftex-get-file-buffer-force file)) | |
719 | (setq current-prefix-arg '(4)) | |
f3c18bd0 | 720 | (reftex-display-index index-tag nil 'redo line))) |
1a9461d0 CD |
721 | (reftex-index-Rescan)) |
722 | (reftex-kill-temporary-buffers))) | |
723 | (defun reftex-index-Rescan (&rest ignore) | |
724 | "Regenerate the *Index* buffer after reparsing the entire document." | |
725 | (interactive) | |
726 | (let ((index-tag reftex-index-tag) | |
3666daf6 | 727 | (line (+ (count-lines (point-min) (point)) (if (bolp) 1 0)))) |
1a9461d0 CD |
728 | (switch-to-buffer |
729 | (reftex-get-file-buffer-force reftex-last-index-file)) | |
730 | (setq current-prefix-arg '(16)) | |
f3c18bd0 | 731 | (reftex-display-index index-tag nil 'redo line))) |
1a9461d0 CD |
732 | (defun reftex-index-revert (&rest ignore) |
733 | "Regenerate the *Index* from the internal lists. No reparsing os done." | |
734 | (interactive) | |
735 | (let ((buf (current-buffer)) | |
3666daf6 CD |
736 | (index-tag reftex-index-tag) |
737 | (data (get-text-property (point) :data)) | |
738 | (line (+ (count-lines (point-min) (point)) (if (bolp) 1 0)))) | |
1a9461d0 CD |
739 | (switch-to-buffer |
740 | (reftex-get-file-buffer-force reftex-last-index-file)) | |
741 | (reftex-erase-buffer buf) | |
742 | (setq current-prefix-arg nil | |
3666daf6 | 743 | reftex-last-follow-point 1) |
f3c18bd0 | 744 | (reftex-display-index index-tag nil 'redo data line))) |
1a9461d0 CD |
745 | (defun reftex-index-switch-index-tag (&rest ignore) |
746 | "Switch to a different index of the same document." | |
747 | (interactive) | |
748 | (switch-to-buffer | |
749 | (reftex-get-file-buffer-force reftex-last-index-file)) | |
750 | (setq current-prefix-arg nil) | |
f3c18bd0 | 751 | (reftex-display-index nil nil 'redo)) |
1a9461d0 CD |
752 | |
753 | (defun reftex-index-restrict-to-section (&optional force) | |
754 | "Restrict index to entries defined in same document sect. as entry at point." | |
755 | ;; Optional FORCE means, even if point is not on an index entry. | |
756 | (interactive) | |
757 | (let* ((data (get-text-property (point) :data)) | |
3666daf6 CD |
758 | (docstruct (symbol-value reftex-docstruct-symbol)) |
759 | bor eor) | |
1a9461d0 | 760 | (if (and (not data) force) |
3666daf6 | 761 | (setq data (assq 'toc docstruct))) |
1a9461d0 CD |
762 | (when data |
763 | (setq bor (reftex-last-assoc-before-elt 'toc data docstruct) | |
3666daf6 CD |
764 | eor (car (memq (assq 'toc (cdr (memq bor docstruct))) |
765 | docstruct)) | |
766 | reftex-index-restriction-data (list bor eor) | |
767 | reftex-index-restriction-indicator (nth 6 bor) ))) | |
1a9461d0 CD |
768 | (reftex-index-revert)) |
769 | ||
770 | (defun reftex-index-widen (&rest ignore) | |
771 | "Show the unrestricted index (all entries)." | |
772 | (interactive) | |
773 | (setq reftex-index-restriction-indicator nil | |
3666daf6 | 774 | reftex-index-restriction-data nil) |
1a9461d0 CD |
775 | (reftex-index-revert) |
776 | (message "Index widened")) | |
777 | (defun reftex-index-restriction-forward (&rest ignore) | |
778 | "Restrict to previous section. | |
779 | When index is currently unrestricted, restrict it to a section. | |
780 | When index is restricted, select the next section as restriction criterion." | |
781 | (interactive) | |
782 | (let* ((docstruct (symbol-value reftex-docstruct-symbol)) | |
3666daf6 | 783 | (bor (nth 1 reftex-index-restriction-data))) |
1a9461d0 | 784 | (if (or (not bor) |
3666daf6 CD |
785 | (not (eq (car bor) 'toc))) |
786 | (reftex-index-restrict-to-section t) | |
1a9461d0 | 787 | (setq reftex-index-restriction-indicator (nth 6 bor) |
3666daf6 | 788 | reftex-index-restriction-data |
7b07114a | 789 | (list bor |
3666daf6 CD |
790 | (car (memq (assq 'toc (cdr (memq bor docstruct))) |
791 | docstruct)))) | |
1a9461d0 CD |
792 | (reftex-index-revert)))) |
793 | (defun reftex-index-restriction-backward (&rest ignore) | |
794 | "Restrict to next section. | |
795 | When index is currently unrestricted, restrict it to a section. | |
796 | When index is restricted, select the previous section as restriction criterion." | |
797 | (interactive) | |
798 | (let* ((docstruct (symbol-value reftex-docstruct-symbol)) | |
3666daf6 CD |
799 | (eor (car reftex-index-restriction-data)) |
800 | (bor (reftex-last-assoc-before-elt 'toc eor docstruct t))) | |
1a9461d0 | 801 | (if (or (not bor) |
3666daf6 CD |
802 | (not (eq (car bor) 'toc))) |
803 | (reftex-index-restrict-to-section t) | |
1a9461d0 | 804 | (setq reftex-index-restriction-indicator (nth 6 bor) |
3666daf6 CD |
805 | reftex-index-restriction-data |
806 | (list bor eor)) | |
1a9461d0 CD |
807 | (reftex-index-revert)))) |
808 | ||
809 | (defun reftex-index-visit-location (&optional final no-revisit) | |
810 | ;; Visit the tex file corresponding to the index entry on the current line. | |
811 | ;; If FINAL is t, stay there | |
812 | ;; If FINAL is 'hide, hide the *Index* window. | |
813 | ;; Otherwise, move cursor back into *Index* window. | |
814 | ;; NO-REVISIT means don't visit files, just use live biffers. | |
815 | ||
816 | (let* ((data (get-text-property (point) :data)) | |
817 | (index-window (selected-window)) | |
818 | show-window show-buffer match) | |
819 | ||
820 | (unless data (error "Don't know which index entry to visit")) | |
7b07114a | 821 | |
1a9461d0 | 822 | (if (eq (car data) 'index) |
3666daf6 | 823 | (setq match (reftex-index-show-entry data no-revisit))) |
1a9461d0 CD |
824 | |
825 | (setq show-window (selected-window) | |
826 | show-buffer (current-buffer)) | |
827 | ||
828 | (unless match | |
829 | (select-window index-window) | |
830 | (error "Cannot find location")) | |
831 | ||
832 | (select-window index-window) | |
833 | ||
834 | ;; Use the `final' parameter to decide what to do next | |
835 | (cond | |
836 | ((eq final t) | |
837 | (reftex-unhighlight 0) | |
838 | (select-window show-window)) | |
839 | ((eq final 'hide) | |
840 | (reftex-unhighlight 0) | |
841 | (or (one-window-p) (delete-window)) | |
842 | (switch-to-buffer show-buffer)) | |
843 | (t nil)))) | |
844 | ||
845 | (defun reftex-index-analyze-entry (data) | |
846 | ;; This splits the index context so that key, attribute and visual | |
847 | ;; values are accessible individually. | |
848 | (interactive) | |
849 | (let* ((arg (nth 5 data)) | |
3666daf6 CD |
850 | (context (nth 2 data)) |
851 | (sc reftex-index-special-chars) | |
852 | (boa (if (string-match (regexp-quote (concat "{" arg "}")) context) | |
853 | (1+ (match-beginning 0)) | |
854 | (error "Something is wrong here"))) | |
855 | (eoa (1- (match-end 0))) | |
856 | (boactual (if (string-match (concat "[^" (nth 3 sc) "]" (nth 2 sc)) | |
857 | context boa) | |
858 | (1+ (match-beginning 0)) | |
859 | eoa)) | |
860 | (boattr (if (string-match (concat "[^" (nth 3 sc) "]" (nth 1 sc)) | |
861 | context boa) | |
862 | (1+ (match-beginning 0)) | |
863 | boactual)) | |
864 | (pre (substring context 0 boa)) | |
865 | (key (substring context boa boattr)) | |
866 | (attr (substring context boattr boactual)) | |
867 | (actual (substring context boactual eoa)) | |
868 | (post (substring context eoa))) | |
1a9461d0 CD |
869 | (list pre key attr actual post))) |
870 | ||
1a9461d0 CD |
871 | (defun reftex-index-edit () |
872 | "Edit the index entry at point." | |
873 | (interactive) | |
874 | (let* ((data (get-text-property (point) :data)) | |
3666daf6 | 875 | old new) |
1a9461d0 CD |
876 | (unless data (error "Don't know which index entry to edit")) |
877 | (reftex-index-view-entry) | |
878 | (setq old (nth 2 data) new (read-string "Edit: " old)) | |
879 | (reftex-index-change-entry new))) | |
880 | ||
881 | (defun reftex-index-toggle-range-beginning () | |
882 | "Toggle the page range start attribute `|('." | |
883 | (interactive) | |
884 | (let* ((data (get-text-property (point) :data)) | |
3666daf6 CD |
885 | (bor (concat (nth 1 reftex-index-special-chars) "(")) |
886 | new analyze attr) | |
1a9461d0 CD |
887 | (unless data (error "Don't know which index entry to edit")) |
888 | (setq analyze (reftex-index-analyze-entry data) | |
3666daf6 | 889 | attr (nth 2 analyze)) |
1a9461d0 CD |
890 | (setf (nth 2 analyze) (if (string= attr bor) "" bor)) |
891 | (setq new (apply 'concat analyze)) | |
7b07114a | 892 | (reftex-index-change-entry |
1a9461d0 | 893 | new (if (string= (nth 2 analyze) bor) |
3666daf6 CD |
894 | "Entry is now START-OF-PAGE-RANGE" |
895 | "START-OF-PAGE-RANGE canceled")))) | |
1a9461d0 CD |
896 | |
897 | (defun reftex-index-toggle-range-end () | |
898 | "Toggle the page-range-end attribute `|)'." | |
899 | (interactive) | |
900 | (let* ((data (get-text-property (point) :data)) | |
3666daf6 CD |
901 | (eor (concat (nth 1 reftex-index-special-chars) ")")) |
902 | new analyze attr) | |
1a9461d0 CD |
903 | (unless data (error "Don't know which index entry to edit")) |
904 | (setq analyze (reftex-index-analyze-entry data) | |
3666daf6 | 905 | attr (nth 2 analyze)) |
1a9461d0 CD |
906 | (setf (nth 2 analyze) (if (string= attr eor) "" eor)) |
907 | (setq new (apply 'concat analyze)) | |
908 | (reftex-index-change-entry | |
909 | new (if (string= (nth 2 analyze) eor) | |
3666daf6 CD |
910 | "Entry is now END-OF-PAGE-RANGE" |
911 | "END-OF-PAGE-RANGE canceled")))) | |
1a9461d0 CD |
912 | |
913 | (defun reftex-index-edit-key () | |
914 | "Edit the KEY part of the index entry." | |
915 | (interactive) | |
916 | (reftex-index-edit-part nil 1 "" "Key: " t)) | |
917 | ||
918 | (defun reftex-index-edit-attribute (&optional arg) | |
919 | "EDIT the ATTRIBUTE part of the entry. With arg: remove entire ATTRIBUTE." | |
920 | (interactive "P") | |
921 | (reftex-index-edit-part arg 2 (nth 1 reftex-index-special-chars) | |
3666daf6 | 922 | "Attribute: ")) |
1a9461d0 CD |
923 | |
924 | (defun reftex-index-edit-visual (&optional arg) | |
925 | "EDIT the VISUAL part of the entry. With arg: remove entire VISUAL string." | |
926 | (interactive "P") | |
927 | (reftex-index-edit-part arg 3 (nth 2 reftex-index-special-chars) "Visual: ")) | |
928 | ||
929 | (defun reftex-index-edit-part (arg n initial prompt &optional dont-allow-empty) | |
930 | ;; This function does the work for all partial editing commands | |
931 | (let* ((data (get-text-property (point) :data)) | |
3666daf6 | 932 | new analyze opart npart) |
1a9461d0 CD |
933 | (unless data (error "Don't know which index entry to edit")) |
934 | ;; Analyze the whole context string | |
935 | (setq analyze (reftex-index-analyze-entry data) | |
3666daf6 | 936 | opart (nth n analyze)) |
1a9461d0 CD |
937 | (and (> (length opart) 0) (setq opart (substring opart 1))) |
938 | ;; Have the user editing the part | |
939 | (setq npart (if arg "" (read-string (concat prompt initial) opart))) | |
940 | ;; Tests: | |
941 | (cond ((string= npart opart) | |
3666daf6 CD |
942 | (error "Not changed")) |
943 | ((string= npart "") | |
944 | (if dont-allow-empty | |
5181ff9f | 945 | (error "Invalid value") |
3666daf6 CD |
946 | (setf (nth n analyze) npart))) |
947 | (t (setf (nth n analyze) (concat initial npart)))) | |
1a9461d0 CD |
948 | (setq new (apply 'concat analyze)) |
949 | ;; Change the entry and insert the changed version into the index. | |
7b07114a | 950 | (reftex-index-change-entry |
1a9461d0 | 951 | new (if (string= npart "") |
3666daf6 CD |
952 | (format "Deleted: %s" opart) |
953 | (format "New value is: %s" npart))))) | |
1a9461d0 CD |
954 | |
955 | (defun reftex-index-level-down () | |
956 | "Make index entry a subitem of another entry." | |
957 | (interactive) | |
958 | (let* ((data (get-text-property (point) :data)) | |
3666daf6 CD |
959 | (docstruct (symbol-value reftex-docstruct-symbol)) |
960 | old new prefix key) | |
1a9461d0 CD |
961 | (unless data (error "Don't know which index entry to change")) |
962 | (setq old (nth 2 data) | |
3666daf6 | 963 | key (nth 6 data) |
7b07114a CD |
964 | prefix (completing-read |
965 | "Prefix: " | |
966 | (reftex-sublist-nth | |
3666daf6 CD |
967 | docstruct 6 |
968 | (lambda (x) | |
969 | (and (eq (car x) 'index) | |
970 | (string= (nth 1 x) reftex-index-tag))) t))) | |
7b07114a | 971 | (unless (string-match |
3666daf6 CD |
972 | (concat (regexp-quote (car reftex-index-special-chars)) "\\'") |
973 | prefix) | |
1a9461d0 CD |
974 | (setq prefix (concat prefix (car reftex-index-special-chars)))) |
975 | (if (string-match (regexp-quote key) old) | |
3666daf6 | 976 | (setq new (replace-match (concat prefix key) t t old)) |
1a9461d0 CD |
977 | (error "Cannot construct new index key")) |
978 | (reftex-index-change-entry new (format "Added prefix: %s" prefix)))) | |
979 | ||
980 | (defun reftex-index-level-up () | |
981 | "Remove the highest level of a hierarchical index entry." | |
982 | (interactive) | |
983 | (let* ((data (get-text-property (point) :data)) | |
3666daf6 | 984 | old new prefix) |
1a9461d0 CD |
985 | (unless data (error "Don't know which entry to change")) |
986 | (setq old (nth 2 data)) | |
987 | (if (string-match (concat "{\\([^" (nth 0 reftex-index-special-chars) "]*" | |
3666daf6 CD |
988 | "[^" (nth 3 reftex-index-special-chars) "]" |
989 | (regexp-quote (nth 0 reftex-index-special-chars)) | |
990 | "\\)") | |
991 | old) | |
992 | (setq prefix (substring old (match-beginning 1) (match-end 1)) | |
993 | new (concat (substring old 0 (match-beginning 1)) | |
994 | (substring old (match-end 1)))) | |
1a9461d0 CD |
995 | (error "Entry is not a subitem")) |
996 | (reftex-index-change-entry new (format "Removed prefix: %s" prefix)))) | |
997 | ||
998 | (defun reftex-index-kill () | |
999 | "FIXME: Not yet implemented" | |
1000 | (interactive) | |
1001 | (error "This function is currently not implemented")) | |
1002 | ||
1003 | (defun reftex-index-undo () | |
1004 | "FIXME: Not yet implemented" | |
1005 | (interactive) | |
1006 | (error "This function is currently not implemented")) | |
1007 | ||
1008 | (defun reftex-index-change-entry (new &optional message) | |
1009 | ;; Change the full context string of the index entry at point to | |
1010 | ;; NEW. This actually edits the buffer where the entry is defined. | |
7b07114a | 1011 | |
1a9461d0 | 1012 | (let* ((data (get-text-property (point) :data)) |
3666daf6 | 1013 | old beg end info) |
1a9461d0 CD |
1014 | (unless data (error "Cannot change entry")) |
1015 | (reftex-index-view-entry) | |
1016 | (setq beg (match-beginning 0) end (match-end 0)) | |
1017 | (setq old (nth 2 data)) | |
1018 | (and (equal old new) (error "Entry unchanged")) | |
1019 | (save-excursion | |
1020 | (set-buffer (get-file-buffer (nth 3 data))) | |
1021 | (goto-char beg) | |
1022 | (unless (looking-at (regexp-quote old)) | |
3666daf6 | 1023 | (error "This should not happen (reftex-index-change-entry)")) |
1a9461d0 CD |
1024 | (delete-region beg end) |
1025 | (insert new) | |
1026 | (goto-char (1- beg)) | |
1027 | (when (and (re-search-forward (reftex-everything-regexp) nil t) | |
3666daf6 CD |
1028 | (match-end 10) |
1029 | (< (abs (- (match-beginning 10) beg)) (length new)) | |
1030 | (setq info (reftex-index-info-safe buffer-file-name))) | |
1031 | (setcdr data (cdr info)))) | |
1a9461d0 CD |
1032 | (let ((buffer-read-only nil)) |
1033 | (save-excursion | |
3666daf6 CD |
1034 | (reftex-insert-index (list data) reftex-index-tag t |
1035 | "EDITED"))) | |
1a9461d0 | 1036 | (setq reftex-last-follow-point 1) |
5673af85 | 1037 | (and message (message "%s" message)))) |
1a9461d0 CD |
1038 | |
1039 | ;; Index map | |
1040 | (define-key reftex-index-map (if (featurep 'xemacs) [(button2)] [(mouse-2)]) | |
1041 | 'reftex-index-mouse-goto-line-and-hide) | |
a85551d8 | 1042 | (define-key reftex-index-map [follow-link] 'mouse-face) |
1a9461d0 CD |
1043 | |
1044 | (substitute-key-definition | |
1045 | 'next-line 'reftex-index-next reftex-index-map global-map) | |
1046 | (substitute-key-definition | |
1047 | 'previous-line 'reftex-index-previous reftex-index-map global-map) | |
1048 | ||
1049 | (loop for x in | |
1050 | '(("n" . reftex-index-next) | |
3666daf6 CD |
1051 | ("p" . reftex-index-previous) |
1052 | ("?" . reftex-index-show-help) | |
1053 | (" " . reftex-index-view-entry) | |
1054 | ("\C-m" . reftex-index-goto-entry-and-hide) | |
1055 | ("\C-i" . reftex-index-goto-entry) | |
1056 | ("\C-k" . reftex-index-kill) | |
1057 | ("r" . reftex-index-rescan) | |
1058 | ("R" . reftex-index-Rescan) | |
1059 | ("g" . revert-buffer) | |
1060 | ("q" . reftex-index-quit) | |
1061 | ("k" . reftex-index-quit-and-kill) | |
1062 | ("f" . reftex-index-toggle-follow) | |
1063 | ("s" . reftex-index-switch-index-tag) | |
1064 | ("e" . reftex-index-edit) | |
1065 | ("^" . reftex-index-level-up) | |
1066 | ("_" . reftex-index-level-down) | |
1067 | ("}" . reftex-index-restrict-to-section) | |
1068 | ("{" . reftex-index-widen) | |
1069 | (">" . reftex-index-restriction-forward) | |
1070 | ("<" . reftex-index-restriction-backward) | |
1071 | ("(" . reftex-index-toggle-range-beginning) | |
1072 | (")" . reftex-index-toggle-range-end) | |
1073 | ("|" . reftex-index-edit-attribute) | |
1074 | ("@" . reftex-index-edit-visual) | |
1075 | ("*" . reftex-index-edit-key) | |
1076 | ("\C-c=". reftex-index-goto-toc) | |
1077 | ("c" . reftex-index-toggle-context)) | |
1a9461d0 CD |
1078 | do (define-key reftex-index-map (car x) (cdr x))) |
1079 | ||
1080 | (loop for key across "0123456789" do | |
1081 | (define-key reftex-index-map (vector (list key)) 'digit-argument)) | |
1082 | (define-key reftex-index-map "-" 'negative-argument) | |
1083 | ||
1084 | ;; The capital letters and the exclamation mark | |
1085 | (loop for key across (concat "!" reftex-index-section-letters) do | |
1086 | (define-key reftex-index-map (vector (list key)) | |
3666daf6 CD |
1087 | (list 'lambda '() '(interactive) |
1088 | (list 'reftex-index-goto-letter key)))) | |
1a9461d0 CD |
1089 | |
1090 | (defun reftex-index-goto-letter (char) | |
1091 | "Go to the CHAR section in the index." | |
1092 | (let ((pos (point)) | |
3666daf6 | 1093 | (case-fold-search nil)) |
1a9461d0 CD |
1094 | (goto-line 3) |
1095 | (if (re-search-forward (concat "^" (char-to-string char)) nil t) | |
3666daf6 CD |
1096 | (progn |
1097 | (beginning-of-line) | |
1098 | (recenter 0) | |
1099 | (reftex-index-next)) | |
1a9461d0 | 1100 | (goto-char pos) |
7c4d13cc | 1101 | (if (eq char ?!) |
3666daf6 CD |
1102 | (error "This <%s> index does not contain entries sorted before the letters" |
1103 | reftex-index-tag) | |
7b07114a | 1104 | (error "This <%s> index does not contain entries starting with `%c'" |
3666daf6 | 1105 | reftex-index-tag char))))) |
1a9461d0 | 1106 | |
7b07114a | 1107 | (easy-menu-define |
1a9461d0 CD |
1108 | reftex-index-menu reftex-index-map |
1109 | "Menu for Index buffer" | |
1110 | `("Index" | |
7b07114a | 1111 | ["Goto section A-Z" |
1a9461d0 | 1112 | (message "To go to a section, just press any of: !%s" |
3666daf6 | 1113 | reftex-index-section-letters) t] |
1a9461d0 CD |
1114 | ["Show Entry" reftex-index-view-entry t] |
1115 | ["Go To Entry" reftex-index-goto-entry t] | |
1116 | ["Exit & Go To Entry" reftex-index-goto-entry-and-hide t] | |
1117 | ["Table of Contents" reftex-index-goto-toc t] | |
1118 | ["Quit" reftex-index-quit t] | |
1119 | "--" | |
1120 | ("Update" | |
1121 | ["Rebuilt *Index* Buffer" revert-buffer t] | |
1122 | "--" | |
1123 | ["Rescan One File" reftex-index-rescan reftex-enable-partial-scans] | |
1124 | ["Rescan Entire Document" reftex-index-Rescan t]) | |
1125 | ("Restrict" | |
1126 | ["Restrict to section" reftex-index-restrict-to-section t] | |
1127 | ["Widen" reftex-index-widen reftex-index-restriction-indicator] | |
1128 | ["Next Section" reftex-index-restriction-forward | |
1129 | reftex-index-restriction-indicator] | |
1130 | ["Previous Section" reftex-index-restriction-backward | |
1131 | reftex-index-restriction-indicator]) | |
1132 | ("Edit" | |
1133 | ["Edit Entry" reftex-index-edit t] | |
1134 | ["Edit Key" reftex-index-edit-key t] | |
1135 | ["Edit Attribute" reftex-index-edit-attribute t] | |
1136 | ["Edit Visual" reftex-index-edit-visual t] | |
1137 | "--" | |
1138 | ["Add Parentkey" reftex-index-level-down t] | |
1139 | ["Remove Parentkey " reftex-index-level-up t] | |
1140 | "--" | |
1141 | ["Make Start-of-Range" reftex-index-toggle-range-beginning t] | |
1142 | ["Make End-of-Range" reftex-index-toggle-range-end t] | |
1143 | "--" | |
1a9461d0 CD |
1144 | ["Kill Entry" reftex-index-kill nil] |
1145 | "--" | |
1146 | ["Undo" reftex-index-undo nil]) | |
1147 | ("Options" | |
1148 | ["Context" reftex-index-toggle-context :style toggle | |
1149 | :selected reftex-index-include-context] | |
1150 | "--" | |
7b07114a | 1151 | ["Follow Mode" reftex-index-toggle-follow :style toggle |
1a9461d0 CD |
1152 | :selected reftex-index-follow-mode]) |
1153 | "--" | |
1154 | ["Help" reftex-index-show-help t])) | |
1155 | ||
7c4d13cc CD |
1156 | |
1157 | ;;---------------------------------------------------------------------- | |
1158 | ;; The Index Phrases File | |
1159 | ||
1160 | ;; Some constants and variables | |
1161 | (defconst reftex-index-phrases-comment-regexp "^[ \t]*%.*" | |
1162 | "Regular expression to match comment lines in phrases buffer") | |
1163 | (defconst reftex-index-phrases-macrodef-regexp | |
1164 | "^\\(>>>INDEX_MACRO_DEFINITION:\\)[ \t]+\\(\\S-\\)\\( *\t[ \t]*\\)\\([^\t]*[^ \t]\\)\\( *\t[ \t]*\\)\\(\\S-+\\)" | |
1165 | "Regular expression to match macro definition lines the phrases buffer.") | |
1166 | ;(defconst reftex-index-phrases-macrodef-regexp | |
1167 | ; "^\\(>>>INDEX_MACRO_DEFINITION:\\)[ \t]+\\(\\S-\\)\\([ \t]*\\)\\([^\t]*[^ \t]\\)\\([ \t]*\\)\\(nil\\|t\\)[ \t]*$" | |
1168 | ; "Regular expression to match macro definition lines the phrases buffer. | |
1169 | ;This version would allow just spaces as separators.") | |
1170 | (defconst reftex-index-phrases-phrase-regexp1 | |
1171 | "^\\(\\S-?\\)\\(\t\\)\\([^\t\n]*\\S-\\)\\([ \t]*\\)$" | |
1172 | "Regular expression matching phrases which have no separate index key.") | |
1173 | (defconst reftex-index-phrases-phrase-regexp2 | |
1174 | "^\\(\\S-?\\)\\(\t\\)\\([^\t]*\\S-\\)\\(\t[ \t]*\\)\\([^\n\t]*\\S-\\)[ \t]*$" | |
1175 | "Regular expression matching phrases which have a separate index key.") | |
1176 | (defconst reftex-index-phrases-phrase-regexp12 | |
1177 | "^\\(\\S-?\\)\\(\t\\)\\([^\n\t]*\\S-\\)\\(\\(\t[ \t]*\\)\\([^\n\t]*\\S-\\)\\)?[ \t]*$" | |
1178 | "Regular expression matching all types of phrase lines.") | |
1179 | (defvar reftex-index-phrases-macro-data nil | |
1180 | "Alist containing the information taken from the macro definition lines. | |
1181 | This gets refreshed in every phrases command.") | |
1182 | (defvar reftex-index-phrases-files nil | |
1183 | "List of document files relevant for the phrases file.") | |
1184 | ||
1185 | (defvar reftex-index-phrases-font-lock-keywords nil | |
1186 | "Font lock keywords for reftex-index-phrases-mode.") | |
1187 | (defvar reftex-index-phrases-font-lock-defaults nil | |
1188 | "Font lock defaults for reftex-index-phrases-mode.") | |
1189 | (defvar reftex-index-phrases-map (make-sparse-keymap) | |
1190 | "Keymap used for *toc* buffer.") | |
1191 | ||
1192 | ||
1193 | (defun reftex-index-phrase-selection-or-word (arg) | |
1194 | "Add current selection or word at point to the phrases buffer. | |
1195 | When you are in transient-mark-mode and the region is active, the | |
1196 | selection will be used - otherwise the word at point. | |
1197 | You get a chance to edit the entry in the phrases buffer - finish with | |
1198 | `C-c C-c'." | |
1199 | (interactive "P") | |
1200 | (set-marker reftex-index-return-marker (point)) | |
1201 | (reftex-index-selection-or-word arg 'phrase) | |
1202 | (if (eq major-mode 'reftex-index-phrases-mode) | |
5673af85 | 1203 | (message "%s" |
7c4d13cc | 1204 | (substitute-command-keys |
3666daf6 | 1205 | "Return to LaTeX with \\[reftex-index-phrases-save-and-return]")))) |
7c4d13cc CD |
1206 | |
1207 | (defun reftex-index-visit-phrases-buffer () | |
1208 | "Switch to the phrases buffer, initialize if empty." | |
1209 | (interactive) | |
1210 | (reftex-access-scan-info) | |
1211 | (let* ((master (reftex-TeX-master-file)) | |
3666daf6 CD |
1212 | (name (concat (file-name-sans-extension master) |
1213 | reftex-index-phrase-file-extension))) | |
7c4d13cc CD |
1214 | (find-file name) |
1215 | (unless (eq major-mode 'reftex-index-phrases-mode) | |
1216 | (reftex-index-phrases-mode)) | |
1217 | (if (= (buffer-size) 0) | |
3666daf6 | 1218 | (reftex-index-initialize-phrases-buffer master)))) |
7c4d13cc CD |
1219 | |
1220 | (defun reftex-index-initialize-phrases-buffer (&optional master) | |
1221 | "Initialize the phrases buffer by creating the header. | |
1222 | If the buffer is non-empty, delete the old header first." | |
1223 | (interactive) | |
1224 | (let* ((case-fold-search t) | |
3666daf6 CD |
1225 | (default-key (car reftex-index-default-macro)) |
1226 | (default-macro (nth 1 (assoc default-key | |
1227 | reftex-key-to-index-macro-alist))) | |
1228 | (macro-alist | |
1229 | (sort (copy-sequence reftex-index-macro-alist) | |
1230 | (lambda (a b) (equal (car a) default-macro)))) | |
1231 | macro entry key repeat) | |
7b07114a | 1232 | |
7c4d13cc | 1233 | (if master (set (make-local-variable 'TeX-master) |
3666daf6 | 1234 | (file-name-nondirectory master))) |
7c4d13cc CD |
1235 | |
1236 | (when (> (buffer-size) 0) | |
1237 | (goto-char 1) | |
1238 | (set-mark (point)) | |
1239 | (while (re-search-forward reftex-index-phrases-macrodef-regexp nil t) | |
3666daf6 | 1240 | (end-of-line)) |
7c4d13cc CD |
1241 | (beginning-of-line 2) |
1242 | (if (looking-at reftex-index-phrases-comment-regexp) | |
3666daf6 | 1243 | (beginning-of-line 2)) |
7c4d13cc | 1244 | (while (looking-at "^[ \t]*$") |
7b07114a | 1245 | (beginning-of-line 2)) |
7c4d13cc | 1246 | (cond ((fboundp 'zmacs-activate-region) (zmacs-activate-region)) |
3666daf6 | 1247 | ((boundp 'make-active) (setq mark-active t))) |
ce5a3ac0 | 1248 | (if (yes-or-no-p "Delete and rebuild header? ") |
3666daf6 | 1249 | (delete-region (point-min) (point)))) |
7c4d13cc CD |
1250 | |
1251 | ;; Insert the mode line | |
1252 | (insert | |
1253 | (format "%% -*- mode: reftex-index-phrases; TeX-master: \"%s\" -*-\n" | |
3666daf6 | 1254 | (file-name-nondirectory (reftex-index-phrase-tex-master)))) |
7c4d13cc CD |
1255 | ;; Insert the macro definitions |
1256 | (insert "% Key Macro Format Repeat\n") | |
1257 | (insert "%---------------------------------------------------------------------\n") | |
1258 | (while (setq entry (pop macro-alist)) | |
1259 | (setq macro (car entry) | |
3666daf6 CD |
1260 | repeat (nth 7 entry) |
1261 | key (car (delq nil (mapcar (lambda (x) (if (equal (nth 1 x) macro) | |
1262 | (car x) | |
1263 | nil)) | |
1264 | reftex-key-to-index-macro-alist)))) | |
7c4d13cc | 1265 | (insert (format ">>>INDEX_MACRO_DEFINITION:\t%s\t%-20s\t%s\n" |
3666daf6 CD |
1266 | (char-to-string key) (concat macro "{%s}") |
1267 | (if repeat "t" "nil")))) | |
7c4d13cc CD |
1268 | (insert "%---------------------------------------------------------------------\n\n\n"))) |
1269 | ||
1270 | (defvar TeX-master) | |
1271 | (defun reftex-index-phrase-tex-master (&optional dir) | |
1272 | "Return the name of the master file associated with a phrase buffer." | |
1273 | (if (and (boundp 'TeX-master) | |
3666daf6 CD |
1274 | (local-variable-p 'TeX-master (current-buffer)) |
1275 | (stringp TeX-master)) | |
7c4d13cc CD |
1276 | ;; We have a local variable which tells us which file to use |
1277 | (expand-file-name TeX-master dir) | |
1278 | ;; have to guess | |
1279 | (concat (file-name-sans-extension (buffer-file-name)) ".tex"))) | |
1280 | ||
1281 | (defun reftex-index-phrases-save-and-return () | |
1282 | "Return to where the `reftex-index-phrase-selection-or-word' was called." | |
1283 | (interactive) | |
1284 | (save-buffer) | |
1285 | (switch-to-buffer (marker-buffer reftex-index-return-marker)) | |
1286 | (goto-char (or (marker-position reftex-index-return-marker) (point)))) | |
1287 | ||
1288 | ||
1289 | (defvar reftex-index-phrases-menu) | |
7b07114a | 1290 | (defvar reftex-index-phrases-marker) |
7c4d13cc CD |
1291 | (defvar reftex-index-phrases-restrict-file nil) |
1292 | ;;;###autoload | |
1293 | (defun reftex-index-phrases-mode () | |
1294 | "Major mode for managing the Index phrases of a LaTeX document. | |
1295 | This buffer was created with RefTeX. | |
1296 | ||
1297 | To insert new phrases, use | |
1298 | - `C-c \\' in the LaTeX document to copy selection or word | |
1299 | - `\\[reftex-index-new-phrase]' in the phrases buffer. | |
1300 | ||
1301 | To index phrases use one of: | |
1302 | ||
1303 | \\[reftex-index-this-phrase] index current phrase | |
1304 | \\[reftex-index-next-phrase] index next phrase (or N with prefix arg) | |
1305 | \\[reftex-index-all-phrases] index all phrases | |
1306 | \\[reftex-index-remaining-phrases] index current and following phrases | |
1307 | \\[reftex-index-region-phrases] index the phrases in the region | |
1308 | ||
1309 | You can sort the phrases in this buffer with \\[reftex-index-sort-phrases]. | |
1310 | To display information about the phrase at point, use \\[reftex-index-phrases-info]. | |
1311 | ||
1312 | For more information see the RefTeX User Manual. | |
1313 | ||
1314 | Here are all local bindings. | |
1315 | ||
1316 | \\{reftex-index-phrases-map}" | |
1317 | (interactive) | |
1318 | (kill-all-local-variables) | |
1319 | (setq major-mode 'reftex-index-phrases-mode | |
3666daf6 | 1320 | mode-name "Phrases") |
7c4d13cc | 1321 | (use-local-map reftex-index-phrases-map) |
7b07114a | 1322 | (set (make-local-variable 'font-lock-defaults) |
7c4d13cc CD |
1323 | reftex-index-phrases-font-lock-defaults) |
1324 | (easy-menu-add reftex-index-phrases-menu reftex-index-phrases-map) | |
1325 | (set (make-local-variable 'reftex-index-phrases-marker) (make-marker)) | |
7b07114a | 1326 | (run-hooks 'reftex-index-phrases-mode-hook)) |
7c4d13cc CD |
1327 | (add-hook 'reftex-index-phrases-mode-hook 'turn-on-font-lock) |
1328 | ||
1329 | ;; Font Locking stuff | |
1330 | (let ((ss (if (featurep 'xemacs) 'secondary-selection ''secondary-selection))) | |
1331 | (setq reftex-index-phrases-font-lock-keywords | |
7b07114a | 1332 | (list |
3666daf6 CD |
1333 | (cons reftex-index-phrases-comment-regexp 'font-lock-comment-face) |
1334 | (list reftex-index-phrases-macrodef-regexp | |
1335 | '(1 font-lock-type-face) | |
1336 | '(2 font-lock-keyword-face) | |
1337 | (list 3 ss) | |
1338 | '(4 font-lock-function-name-face) | |
1339 | (list 5 ss) | |
1340 | '(6 font-lock-string-face)) | |
1341 | (list reftex-index-phrases-phrase-regexp1 | |
1342 | '(1 font-lock-keyword-face) | |
1343 | (list 2 ss) | |
1344 | '(3 font-lock-string-face) | |
1345 | (list 4 ss)) | |
1346 | (list reftex-index-phrases-phrase-regexp2 | |
1347 | '(1 font-lock-keyword-face) | |
1348 | (list 2 ss) | |
1349 | '(3 font-lock-string-face) | |
1350 | (list 4 ss) | |
1351 | '(5 font-lock-function-name-face)) | |
1352 | (cons "^\t$" ss))) | |
7c4d13cc | 1353 | (setq reftex-index-phrases-font-lock-defaults |
3666daf6 CD |
1354 | '((reftex-index-phrases-font-lock-keywords) |
1355 | nil t nil beginning-of-line)) | |
7b07114a | 1356 | (put 'reftex-index-phrases-mode 'font-lock-defaults |
7c4d13cc CD |
1357 | reftex-index-phrases-font-lock-defaults) ; XEmacs |
1358 | ) | |
1359 | ||
7c4d13cc CD |
1360 | (defun reftex-index-next-phrase (&optional arg) |
1361 | "Index the next ARG phrases in the phrases buffer." | |
1362 | (interactive "p") | |
1363 | (reftex-index-phrases-parse-header t) | |
1364 | (while (> arg 0) | |
1365 | (decf arg) | |
1366 | (end-of-line) | |
1367 | (if (re-search-forward reftex-index-phrases-phrase-regexp12 nil t) | |
3666daf6 CD |
1368 | (progn |
1369 | (goto-char (match-beginning 0)) | |
f3c18bd0 | 1370 | (reftex-index-this-phrase 'slave)) |
7c4d13cc CD |
1371 | (error "No more phrase lines after point")))) |
1372 | ||
f3c18bd0 | 1373 | (defun reftex-index-this-phrase (&optional slave) |
7c4d13cc CD |
1374 | "Index the phrase in the current line. |
1375 | Does a global search and replace in the entire document. At each | |
1376 | match, the user will be asked to confirm the replacement." | |
1377 | (interactive) | |
f3c18bd0 | 1378 | (if (not slave) (reftex-index-phrases-parse-header t)) |
7c4d13cc CD |
1379 | (save-excursion |
1380 | (beginning-of-line) | |
1381 | (cond ((looking-at reftex-index-phrases-comment-regexp) | |
f3c18bd0 | 1382 | (if (not slave) (error "Comment line"))) |
3666daf6 | 1383 | ((looking-at "^[ \t]*$") |
f3c18bd0 | 1384 | (if (not slave) (error "Empty line"))) |
3666daf6 | 1385 | ((looking-at reftex-index-phrases-macrodef-regexp) |
f3c18bd0 | 1386 | (if (not slave) (error "Macro definition line"))) |
3666daf6 CD |
1387 | ((looking-at reftex-index-phrases-phrase-regexp12) |
1388 | ;; This is a phrase | |
1389 | (let* ((char (if (not (equal (match-string 1) "")) | |
1390 | (string-to-char (match-string 1)))) | |
1391 | (phrase (match-string 3)) | |
1392 | (index-key (match-string 6)) | |
1393 | (macro-data (cdr (if (null char) | |
1394 | (car reftex-index-phrases-macro-data) | |
1395 | (assoc char reftex-index-phrases-macro-data)))) | |
1396 | (macro-fmt (car macro-data)) | |
1397 | (repeat (nth 1 macro-data)) | |
1398 | (files | |
1399 | (cond ((and (stringp reftex-index-phrases-restrict-file) | |
1400 | (file-regular-p reftex-index-phrases-restrict-file)) | |
1401 | (list reftex-index-phrases-restrict-file)) | |
1402 | ((stringp reftex-index-phrases-restrict-file) | |
5181ff9f | 1403 | (error "Invalid restriction file %s" |
3666daf6 CD |
1404 | reftex-index-phrases-restrict-file)) |
1405 | (t reftex-index-phrases-files))) | |
1406 | (as-words reftex-index-phrases-search-whole-words)) | |
1407 | (unless macro-data | |
1408 | (error "No macro associated with key %c" char)) | |
1409 | (unwind-protect | |
1410 | (let ((overlay-arrow-string "=>") | |
1411 | (overlay-arrow-position | |
1412 | reftex-index-phrases-marker) | |
1413 | (replace-count 0)) | |
1414 | ;; Show the overlay arrow | |
1415 | (move-marker reftex-index-phrases-marker | |
1416 | (match-beginning 0) (current-buffer)) | |
1417 | ;; Start the query-replace | |
7b07114a CD |
1418 | (reftex-query-index-phrase-globally |
1419 | files phrase macro-fmt | |
3666daf6 | 1420 | index-key repeat as-words) |
7b07114a | 1421 | (message "%s replaced" |
3666daf6 CD |
1422 | (reftex-number replace-count "occurrence")))))) |
1423 | (t (error "Cannot parse this line"))))) | |
7c4d13cc CD |
1424 | |
1425 | (defun reftex-index-all-phrases () | |
1426 | "Index all phrases in the phrases buffer. | |
1427 | Calls `reftex-index-this-phrase' on each line in the buffer." | |
1428 | (interactive) | |
1429 | (reftex-index-region-phrases (point-min) (point-max))) | |
1430 | ||
1431 | (defun reftex-index-remaining-phrases () | |
1432 | "Index all phrases in the phrases buffer. | |
1433 | Calls `reftex-index-this-phrase' on each line ay and below point in | |
1434 | the buffer." | |
1435 | (interactive) | |
1436 | (beginning-of-line) | |
1437 | (reftex-index-region-phrases (point) (point-max))) | |
1438 | ||
1439 | (defun reftex-index-region-phrases (beg end) | |
1440 | "Index all phrases in the phrases buffer. | |
1441 | Calls `reftex-index-this-phrase' on each line in the region." | |
1442 | (interactive "r") | |
1443 | (reftex-index-phrases-parse-header t) | |
1444 | (goto-char beg) | |
1445 | (while (not (or (eobp) | |
3666daf6 | 1446 | (>= (point) end))) |
f3c18bd0 | 1447 | (save-excursion (reftex-index-this-phrase 'slave)) |
7c4d13cc CD |
1448 | (beginning-of-line 2))) |
1449 | ||
1450 | (defun reftex-index-phrases-parse-header (&optional get-files) | |
1451 | "Parse the header of a phrases file to extract the macro definitions. | |
1452 | The definitions get stored in `reftex-index-phrases-macro-data'. | |
1453 | Also switches to the LaTeX document to find out which files belong to | |
1454 | the document and stores the list in `reftex-index-phrases-files'." | |
1455 | (let* ((master (reftex-index-phrase-tex-master)) | |
3666daf6 | 1456 | buf) |
7c4d13cc | 1457 | (if get-files |
3666daf6 CD |
1458 | ;; Get the file list |
1459 | (save-excursion | |
1460 | (setq buf (reftex-get-file-buffer-force master)) | |
1461 | (unless buf (error "Master file %s not found" master)) | |
1462 | (set-buffer buf) | |
1463 | (reftex-access-scan-info) | |
7b07114a | 1464 | (setq reftex-index-phrases-files |
3666daf6 | 1465 | (reftex-all-document-files)))) |
7c4d13cc CD |
1466 | ;; Parse the files header for macro definitions |
1467 | (setq reftex-index-phrases-macro-data nil) | |
1468 | (save-excursion | |
1469 | (goto-char (point-min)) | |
1470 | (while (re-search-forward reftex-index-phrases-macrodef-regexp nil t) | |
3666daf6 CD |
1471 | (push (list |
1472 | (string-to-char (match-string 2)) | |
1473 | (match-string 4) | |
1474 | (equal (match-string 6) "t")) | |
1475 | reftex-index-phrases-macro-data)) | |
7c4d13cc CD |
1476 | ;; Reverse the list, so that the first macro is first |
1477 | (if (null reftex-index-phrases-macro-data) | |
3666daf6 | 1478 | (error "No valid MACRO DEFINITION line in %s file (make sure to use TAB separators)" reftex-index-phrase-file-extension)) |
7b07114a | 1479 | (setq reftex-index-phrases-macro-data |
3666daf6 | 1480 | (nreverse reftex-index-phrases-macro-data)) |
7c4d13cc CD |
1481 | (goto-char (point-min))))) |
1482 | ||
1483 | (defun reftex-index-phrases-apply-to-region (beg end) | |
1484 | "Index all index phrases in the current region. | |
1485 | This works exactly like global indexing from the index phrases buffer, | |
1486 | but operation is restricted to the current region. This is useful if | |
1487 | you need to add/change text in an already indexed document and want to | |
1488 | index the new part without having to go over the unchanged parts again." | |
1489 | (interactive "r") | |
1490 | (let ((win-conf (current-window-configuration)) | |
7b07114a | 1491 | (reftex-index-phrases-restrict-file (buffer-file-name))) |
7c4d13cc CD |
1492 | (save-excursion |
1493 | (save-restriction | |
1494 | (narrow-to-region beg end) | |
1495 | (unwind-protect | |
3666daf6 CD |
1496 | (progn |
1497 | ;; Hide the region highlighting | |
1498 | (cond ((fboundp 'zmacs-deactivate-region) (zmacs-deactivate-region)) | |
1499 | ((fboundp 'deactivate-mark) (deactivate-mark))) | |
1500 | (delete-other-windows) | |
1501 | (reftex-index-visit-phrases-buffer) | |
1502 | (reftex-index-all-phrases)) | |
1503 | (set-window-configuration win-conf)))))) | |
7c4d13cc CD |
1504 | |
1505 | (defun reftex-index-new-phrase (&optional text) | |
1506 | "Open a new line in the phrases buffer, insert TEXT." | |
1507 | (interactive) | |
1508 | (if (and text (stringp text)) | |
1509 | (progn | |
3666daf6 CD |
1510 | ;; Check if the phrase is already in the buffer |
1511 | (setq text (reftex-index-simplify-phrase text)) | |
1512 | (goto-char (point-min)) | |
1513 | (if (re-search-forward | |
7b07114a | 1514 | (concat "^\\(\\S-*\\)\t\\(" (regexp-quote text) |
3666daf6 CD |
1515 | "\\) *[\t\n]") nil t) |
1516 | (progn | |
1517 | (goto-char (match-end 2)) | |
1518 | (error "Phrase is already in phrases buffer"))))) | |
7c4d13cc CD |
1519 | ;; Add the new phrase line after the last in the buffer |
1520 | (goto-char (point-max)) | |
1521 | (if (re-search-backward reftex-index-phrases-phrase-regexp12 nil t) | |
1522 | (end-of-line)) | |
1523 | (if (not (bolp)) | |
1524 | (insert "\n")) | |
1525 | (insert "\t") | |
1526 | (if (and text (stringp text)) | |
1527 | (insert text))) | |
1528 | ||
1529 | (defun reftex-index-find-next-conflict-phrase (&optional arg) | |
1530 | "Find the next a phrase which is has conflicts in the phrase buffer. | |
1531 | The command helps to find possible conflicts in the phrase indexing process. | |
1532 | It searches downward from point for a phrase which is repeated elsewhere | |
1533 | in the buffer, or which is a subphrase of another phrase. If such a | |
1534 | phrase is found, the phrase info is displayed. | |
1535 | To check the whole buffer, start at the beginning and continue by calling | |
1536 | this function repeatedly." | |
1537 | (interactive "P") | |
1538 | (if (catch 'exit | |
3666daf6 CD |
1539 | (while (re-search-forward reftex-index-phrases-phrase-regexp12 nil t) |
1540 | (goto-char (match-beginning 3)) | |
1541 | (let* ((phrase (match-string 3)) | |
1542 | (case-fold-search reftex-index-phrases-case-fold-search) | |
1543 | (re (reftex-index-phrases-find-dup-re phrase t))) | |
7b07114a | 1544 | (if (save-excursion |
3666daf6 CD |
1545 | (goto-char (point-min)) |
1546 | (and (re-search-forward re nil t) | |
1547 | (re-search-forward re nil t))) | |
1548 | (throw 'exit t))))) | |
7c4d13cc | 1549 | (progn |
3666daf6 CD |
1550 | (reftex-index-phrases-info) |
1551 | (message "Phrase with match conflict discovered")) | |
7c4d13cc CD |
1552 | (goto-char (point-max)) |
1553 | (error "No further problematic phrases found"))) | |
1554 | ||
1555 | (defun reftex-index-phrases-info () | |
1556 | "Display information about the phrase at point." | |
1557 | (interactive) | |
1558 | (save-excursion | |
1559 | (beginning-of-line) | |
1560 | (unless (looking-at reftex-index-phrases-phrase-regexp12) | |
1561 | (error "Not a phrase line")) | |
1562 | (save-match-data (reftex-index-phrases-parse-header t)) | |
1563 | (let* ((char (if (not (equal (match-string 1) "")) | |
3666daf6 CD |
1564 | (string-to-char (match-string 1)))) |
1565 | (phrase (match-string 3)) | |
1566 | (index-key (match-string 6)) | |
1567 | (index-keys (split-string | |
1568 | (or index-key phrase) | |
1569 | reftex-index-phrases-logical-or-regexp)) | |
1570 | (macro-data (cdr (if (null char) | |
1571 | (car reftex-index-phrases-macro-data) | |
1572 | (assoc char reftex-index-phrases-macro-data)))) | |
1573 | (macro-fmt (car macro-data)) | |
1574 | (repeat (nth 1 macro-data)) | |
1575 | (as-words reftex-index-phrases-search-whole-words) | |
1576 | (example (reftex-index-make-replace-string | |
1577 | macro-fmt (downcase phrase) (car index-keys) repeat)) | |
1578 | (re (reftex-index-make-phrase-regexp phrase as-words t)) | |
1579 | (re1 (reftex-index-phrases-find-dup-re phrase)) | |
1580 | (re2 (reftex-index-phrases-find-dup-re phrase 'sub)) | |
1581 | superphrases | |
1582 | (nmatches 0) | |
1583 | (ntimes1 0) | |
1584 | (ntimes2 0) | |
1585 | (case-fold-search reftex-index-phrases-case-fold-search) | |
1586 | file files buf) | |
7c4d13cc CD |
1587 | (setq files reftex-index-phrases-files) |
1588 | (save-excursion | |
3666daf6 CD |
1589 | (save-restriction |
1590 | (widen) | |
1591 | (goto-char (point-min)) | |
1592 | (while (re-search-forward re1 nil t) | |
1593 | (incf ntimes1)) | |
1594 | (goto-char (point-min)) | |
1595 | (while (re-search-forward re2 nil t) | |
1596 | (push (cons (count-lines 1 (point)) (match-string 1)) superphrases) | |
1597 | (incf ntimes2)))) | |
7c4d13cc | 1598 | (save-excursion |
3666daf6 CD |
1599 | (while (setq file (pop files)) |
1600 | (setq buf (reftex-get-file-buffer-force file)) | |
1601 | (when buf | |
1602 | (set-buffer buf) | |
1603 | (save-excursion | |
1604 | (save-restriction | |
1605 | (widen) | |
1606 | (goto-char (point-min)) | |
1607 | (let ((case-fold-search reftex-index-phrases-case-fold-search)) | |
1608 | (while (re-search-forward re nil t) | |
1609 | (or (reftex-in-comment) | |
1610 | (incf nmatches))))))))) | |
7c4d13cc | 1611 | (with-output-to-temp-buffer "*Help*" |
3666daf6 CD |
1612 | (princ (format " Phrase: %s\n" phrase)) |
1613 | (princ (format " Macro key: %s\n" char)) | |
1614 | (princ (format " Macro format: %s\n" macro-fmt)) | |
1615 | (princ (format " Repeat: %s\n" repeat)) | |
1616 | (cond | |
1617 | (index-key | |
1618 | (let ((iks index-keys) (cnt 0) ik) | |
1619 | (while (setq ik (pop iks)) | |
1620 | (princ (format "Index entry %d: %s\n" (incf cnt) ik))))) | |
1621 | (repeat | |
1622 | (princ (format " Index entry: %s\n" phrase))) | |
1623 | (t | |
1624 | (princ (format " Index key: <<Given by the match>>\n")))) | |
1625 | (princ (format " Example: %s\n" example)) | |
1626 | (terpri) | |
1627 | (princ (format "Total matches: %s in %s\n" | |
1628 | (reftex-number nmatches "match" "es") | |
1629 | (reftex-number (length reftex-index-phrases-files) | |
1630 | "LaTeX file"))) | |
1631 | (princ (format " Uniqueness: Phrase occurs %s in phrase buffer\n" | |
1632 | (reftex-number ntimes1 "time"))) | |
1633 | (if (> ntimes2 1) | |
1634 | (progn | |
1635 | (princ (format " Superphrases: Phrase matches the following %s in the phrase buffer:\n" | |
1636 | (reftex-number ntimes2 "line"))) | |
7b07114a | 1637 | (mapcar (lambda(x) |
3666daf6 CD |
1638 | (princ (format " Line %4d: %s\n" (car x) (cdr x)))) |
1639 | (nreverse superphrases)))))))) | |
7c4d13cc CD |
1640 | |
1641 | (defun reftex-index-phrases-set-macro-key () | |
1642 | "Change the macro key for the current line. | |
1643 | Prompts for a macro key and insert is at the beginning of the line. | |
1644 | If you reply with SPACE, the macro keyn will be removed, so that the | |
1645 | default macro will be used. If you reply with `RET', just prints | |
1646 | information about the currently selected macro." | |
1647 | (interactive) | |
1648 | (reftex-index-phrases-parse-header) | |
1649 | (save-excursion | |
1650 | (beginning-of-line) | |
1651 | (unless (or (looking-at reftex-index-phrases-phrase-regexp12) | |
3666daf6 | 1652 | (looking-at "\t")) |
7c4d13cc CD |
1653 | (error "This is not a phrase line")) |
1654 | (let* ((nc (reftex-index-select-phrases-macro 0)) | |
3666daf6 CD |
1655 | (macro-data (assoc nc reftex-index-phrases-macro-data)) |
1656 | macro-fmt repeat) | |
7c4d13cc | 1657 | (cond (macro-data) |
3666daf6 CD |
1658 | ((equal nc ?\ ) |
1659 | (setq nc "" | |
1660 | macro-data (car reftex-index-phrases-macro-data))) | |
1661 | ((equal nc ?\C-m) | |
1662 | (setq nc (char-after (point))) | |
1663 | (if (equal nc ?\t) | |
1664 | (setq nc "" | |
1665 | macro-data (car reftex-index-phrases-macro-data)) | |
1666 | (setq macro-data (assoc nc reftex-index-phrases-macro-data)))) | |
1667 | (t (error "No macro associated with %c" nc))) | |
7c4d13cc CD |
1668 | |
1669 | (setq macro-fmt (nth 1 macro-data) | |
3666daf6 | 1670 | repeat (nth 2 macro-data)) |
7c4d13cc | 1671 | (if macro-data |
3666daf6 CD |
1672 | (progn |
1673 | (if (looking-at "[^\t]") (delete-char 1)) | |
1674 | (insert nc) | |
1675 | (message "Line will use %s %s repeat" macro-fmt | |
1676 | (if repeat "with" "without"))) | |
1677 | (error "Abort"))))) | |
7c4d13cc CD |
1678 | |
1679 | (defun reftex-index-sort-phrases (&optional chars-first) | |
1680 | "Sort the phrases lines in the buffer alphabetically. | |
1681 | Normally, this looks only at the phrases. With a prefix arg CHARS-FIRST, | |
1682 | it first compares the macro identifying chars and then the phrases." | |
1683 | (interactive "P") | |
1684 | ;; Remember the current line, so that we can return | |
1685 | (let ((line (buffer-substring (progn (beginning-of-line) (point)) | |
3666daf6 CD |
1686 | (progn (end-of-line) (point)))) |
1687 | beg end) | |
7c4d13cc CD |
1688 | (goto-char (point-min)) |
1689 | ;; Find first and last phrase line in buffer | |
7b07114a | 1690 | (setq beg |
3666daf6 CD |
1691 | (and (re-search-forward reftex-index-phrases-phrase-regexp12 nil t) |
1692 | (match-beginning 0))) | |
7c4d13cc CD |
1693 | (goto-char (point-max)) |
1694 | (setq end (re-search-backward reftex-index-phrases-phrase-regexp12 nil t)) | |
1695 | (if end (setq end (progn (goto-char end) (end-of-line) (point)))) | |
1696 | ;; Take the lines, sort them and re-insert. | |
1697 | (if (and beg end) | |
3666daf6 CD |
1698 | (progn |
1699 | (message "Sorting lines...") | |
1700 | (let* ((lines (split-string (buffer-substring beg end) "\n")) | |
1701 | (lines1 (sort lines 'reftex-compare-phrase-lines))) | |
1702 | (message "Sorting lines...done") | |
1703 | (let ((inhibit-quit t)) ;; make sure we do not loose lines | |
1704 | (delete-region beg end) | |
1705 | (insert (mapconcat 'identity lines1 "\n")))) | |
1706 | (goto-char (point-max)) | |
1707 | (re-search-backward (concat "^" (regexp-quote line) "$") nil t)) | |
7c4d13cc CD |
1708 | (error "Cannot find phrases lines to sort")))) |
1709 | ||
1710 | (defvar chars-first) | |
1711 | (defun reftex-compare-phrase-lines (a b) | |
1712 | "The comparison function used for sorting." | |
1713 | (let (ca cb pa pb c-p p-p) | |
1714 | (if (string-match reftex-index-phrases-phrase-regexp12 a) | |
3666daf6 CD |
1715 | (progn |
1716 | ;; Extract macro char and phrase-or-key for a | |
7b07114a CD |
1717 | (setq ca (match-string 1 a) |
1718 | pa (downcase | |
3666daf6 CD |
1719 | (or (and reftex-index-phrases-sort-prefers-entry |
1720 | (match-string 6 a)) | |
1721 | (match-string 3 a)))) | |
1722 | (if (string-match reftex-index-phrases-phrase-regexp12 b) | |
1723 | (progn | |
1724 | ;; Extract macro char and phrase-or-key for b | |
7b07114a | 1725 | (setq cb (match-string 1 b) |
3666daf6 CD |
1726 | pb (downcase |
1727 | (or (and reftex-index-phrases-sort-prefers-entry | |
1728 | (match-string 6 b)) | |
1729 | (match-string 3 b)))) | |
1730 | (setq c-p (string< ca cb) | |
1731 | p-p (string< pa pb)) | |
1732 | ;; Do the right comparison, based on the value of `chars-first' | |
7b07114a | 1733 | ;; `chars-first' is bound locally in the calling function |
3666daf6 CD |
1734 | (if chars-first |
1735 | (if (string= ca cb) p-p c-p) | |
1736 | (if (string= pa pb) c-p p-p))))) | |
7c4d13cc CD |
1737 | ;; If line a does not match, the answer we return determines |
1738 | ;; if non-matching lines are collected at the beginning. | |
1739 | ;; When we return t here, non-matching lines form | |
1740 | ;; block separators for searches. | |
1741 | (not reftex-index-phrases-sort-in-blocks)))) | |
1742 | ||
1743 | (defvar reftex-index-phrases-menu) | |
7b07114a | 1744 | (defun reftex-index-make-phrase-regexp (phrase &optional |
3666daf6 | 1745 | as-words allow-newline) |
7c4d13cc CD |
1746 | "Return a regexp matching PHRASE, even if distributed over lines. |
1747 | With optional arg AS-WORDS, require word boundary at beginning and end. | |
1748 | With optional arg ALLOW-NEWLINE, allow single newline between words." | |
1749 | (let* ((words (split-string phrase)) | |
3666daf6 CD |
1750 | (space-re (if allow-newline |
1751 | "\\([ \t]*\\(\n[ \t]*\\)?\\|[ \t]\\)" | |
1752 | "\\([ \t]+\\)"))) | |
7c4d13cc | 1753 | (concat (if (and as-words (string-match "\\`\\w" (car words))) |
f3c18bd0 | 1754 | "\\(\\<\\|[`']\\)" "") |
7b07114a | 1755 | (mapconcat (lambda (w) (regexp-quote |
f3c18bd0 CD |
1756 | (if reftex-index-phrases-case-fold-search |
1757 | (downcase w) | |
1758 | w))) | |
3666daf6 | 1759 | words space-re) |
7b07114a | 1760 | (if (and as-words |
3666daf6 | 1761 | (string-match "\\w\\'" (nth (1- (length words)) words))) |
f3c18bd0 | 1762 | "\\(\\>\\|'\\)" "")))) |
7c4d13cc CD |
1763 | |
1764 | (defun reftex-index-simplify-phrase (phrase) | |
1765 | "Make phrase single spaces and single line." | |
1766 | (mapconcat 'identity (split-string phrase) " ")) | |
1767 | ||
1768 | (defun reftex-index-phrases-find-dup-re (phrase &optional sub) | |
1769 | "Return a regexp which matches variations of PHRASE (with additional space). | |
1770 | When SUB ins non-nil, the regexp will also match when PHRASE is a subphrase | |
1771 | of another phrase. The regexp works lonly in the phrase buffer." | |
1772 | (concat (if sub "^\\S-?\t\\([^\t\n]*" "^\\S-?\t") | |
3666daf6 CD |
1773 | (mapconcat 'regexp-quote (split-string phrase) " +") |
1774 | (if sub "[^\t\n]*\\)\\([\t\n]\\|$\\)" " *\\([\t\n]\\|$\\)"))) | |
7c4d13cc CD |
1775 | |
1776 | (defun reftex-index-make-replace-string (macro-fmt match index-key | |
3666daf6 | 1777 | &optional repeat mathp) |
7c4d13cc CD |
1778 | "Return the string which can be used as replacement. |
1779 | Treats the logical `and' for index phrases." | |
1780 | (let ((index-keys (split-string (or index-key match) | |
3666daf6 | 1781 | reftex-index-phrases-logical-and-regexp))) |
7c4d13cc | 1782 | (concat |
7b07114a CD |
1783 | (mapconcat (lambda (x) |
1784 | (format macro-fmt | |
3666daf6 CD |
1785 | (format (if mathp reftex-index-math-format "%s") x))) |
1786 | index-keys "") | |
7c4d13cc CD |
1787 | (if repeat (reftex-index-simplify-phrase match) "")))) |
1788 | ||
1789 | (defun reftex-query-index-phrase-globally (files &rest args) | |
1790 | "Call `reftex-query-index-phrase' for all files in FILES." | |
1791 | (let ((win-conf (current-window-configuration)) | |
3666daf6 | 1792 | (file)) |
7c4d13cc CD |
1793 | (unless files (error "No files")) |
1794 | (unwind-protect | |
3666daf6 | 1795 | (progn |
7b07114a | 1796 | (switch-to-buffer-other-window (reftex-get-file-buffer-force |
3666daf6 CD |
1797 | (car files))) |
1798 | (catch 'no-more-files | |
1799 | (while (setq file (pop files)) | |
1800 | (switch-to-buffer (reftex-get-file-buffer-force file)) | |
1801 | (save-excursion | |
1802 | (save-restriction | |
1803 | (unless (stringp reftex-index-phrases-restrict-file) | |
1804 | (widen)) | |
1805 | (goto-char (point-min)) | |
1806 | (apply 'reftex-query-index-phrase args)))))) | |
7c4d13cc CD |
1807 | (reftex-unhighlight 0) |
1808 | (set-window-configuration win-conf)))) | |
1809 | ||
1810 | (defconst reftex-index-phrases-help | |
1811 | " Keys for query-index search | |
1812 | =========================== | |
1813 | y Replace this match | |
1814 | n Skip this match | |
1815 | ! Replace this and all further matches in this file | |
1816 | q / Q Skip match, start next file / start next phrase | |
1817 | o Use a different indexing macro for this match | |
1818 | 1 - 9 Select one of the multiple phrases | |
1819 | e Edit the replacement text | |
1820 | C-r Recursive edit. | |
1821 | s / S Save this buffer / Save all document buffers | |
1822 | C-g Abort" | |
1823 | "The help string for indexing phrases.") | |
1824 | ||
1825 | (defvar replace-count) | |
1826 | (defun reftex-query-index-phrase (phrase macro-fmt &optional | |
3666daf6 | 1827 | index-key repeat as-words) |
7c4d13cc CD |
1828 | "Search through buffer for PHRASE, and offer to replace it with an indexed |
1829 | version. The index version is derived by applying `format' with MACRO-FMT | |
1830 | to INDEX-KEY or PHRASE. When REPEAT is non-nil, the PHRASE is inserted | |
1831 | again after the macro. | |
1832 | AS-WORDS means, the search for PHRASE should require word boundaries at | |
1833 | both ends." | |
1834 | (let* ((re (reftex-index-make-phrase-regexp phrase as-words 'allow-newline)) | |
3666daf6 | 1835 | (case-fold-search reftex-index-phrases-case-fold-search) |
7b07114a | 1836 | (index-keys (split-string |
3666daf6 CD |
1837 | (or index-key phrase) |
1838 | reftex-index-phrases-logical-or-regexp)) | |
1839 | (nkeys (length index-keys)) | |
1840 | (ckey (nth 0 index-keys)) | |
7b07114a CD |
1841 | (all-yes nil) |
1842 | match rpl char (beg (make-marker)) (end (make-marker)) mathp) | |
1843 | (move-marker beg 1) | |
1844 | (move-marker end 1) | |
7c4d13cc | 1845 | (unwind-protect |
3666daf6 CD |
1846 | (while (re-search-forward re nil t) |
1847 | (catch 'next-match | |
f3c18bd0 CD |
1848 | (if (reftex-in-comment) |
1849 | (throw 'next-match nil)) | |
3666daf6 CD |
1850 | (if (and (fboundp reftex-index-verify-function) |
1851 | (not (funcall reftex-index-verify-function))) | |
1852 | (throw 'next-match nil)) | |
1853 | (setq match (match-string 0)) | |
1854 | (setq mathp | |
1855 | (save-match-data | |
1856 | (condition-case nil (texmathp) (error nil)))) | |
7b07114a CD |
1857 | (setq beg (move-marker beg (match-beginning 0)) |
1858 | end (move-marker end (match-end 0))) | |
3666daf6 CD |
1859 | (if (and reftex-index-phrases-skip-indexed-matches |
1860 | (save-match-data | |
1861 | (reftex-index-phrase-match-is-indexed beg | |
1862 | end))) | |
1863 | (throw 'next-match nil)) | |
1864 | (reftex-highlight 0 (match-beginning 0) (match-end 0)) | |
7b07114a | 1865 | (setq rpl |
3666daf6 CD |
1866 | (save-match-data |
1867 | (reftex-index-make-replace-string | |
1868 | macro-fmt (match-string 0) ckey repeat mathp))) | |
7b07114a | 1869 | (while |
3666daf6 CD |
1870 | (not |
1871 | (catch 'loop | |
1872 | (message "REPLACE: %s? (yn!qoe%s?)" | |
1873 | rpl | |
7b07114a | 1874 | (if (> nkeys 1) |
3666daf6 CD |
1875 | (concat "1-" (int-to-string nkeys)) |
1876 | "")) | |
1877 | (setq char (if all-yes ?y (read-char-exclusive))) | |
1878 | (cond ((member char '(?y ?Y ?\ )) | |
1879 | ;; Yes! | |
1880 | (replace-match rpl t t) | |
1881 | (incf replace-count) | |
1882 | ;; See if we should insert newlines to shorten lines | |
1883 | (and reftex-index-phrases-wrap-long-lines | |
1884 | (reftex-index-phrases-fixup-line beg end)) | |
1885 | (throw 'loop t)) | |
1886 | ((member char '(?n ?N ?\C-h ?\C-?));; FIXME: DEL | |
1887 | ;; No | |
1888 | (throw 'loop t)) | |
1889 | ((equal char ?!) | |
1890 | ;; Yes for all in this buffer | |
1891 | (setq all-yes t)) | |
1892 | ((equal char ?q) | |
1893 | ;; Stop this one in this file | |
1894 | (goto-char (point-max)) | |
1895 | (throw 'loop t)) | |
1896 | ((equal char ?Q) | |
1897 | ;; Stop this one | |
1898 | (throw 'no-more-files t)) | |
1899 | ((equal char ?s) | |
1900 | (save-buffer)) | |
1901 | ((equal char ?S) | |
1902 | (reftex-save-all-document-buffers)) | |
1903 | ((equal char ?\C-g) | |
1904 | (keyboard-quit)) | |
1905 | ((member char '(?o ?O)) | |
1906 | ;; Select a differnt macro | |
1907 | (let* ((nc (reftex-index-select-phrases-macro 2)) | |
7b07114a | 1908 | (macro-data |
3666daf6 CD |
1909 | (cdr (assoc nc reftex-index-phrases-macro-data))) |
1910 | (macro-fmt (car macro-data)) | |
1911 | (repeat (nth 1 macro-data))) | |
1912 | (if macro-data | |
1913 | (setq rpl (save-match-data | |
1914 | (reftex-index-make-replace-string | |
1915 | macro-fmt match | |
1916 | ckey repeat mathp))) | |
1917 | (ding)))) | |
1918 | ((equal char ?\?) | |
1919 | ;; Help | |
1920 | (with-output-to-temp-buffer "*Help*" | |
1921 | (princ reftex-index-phrases-help))) | |
1922 | ((equal char ?\C-r) | |
1923 | ;; Recursive edit | |
1924 | (save-match-data | |
1925 | (save-excursion | |
5673af85 | 1926 | (message "%s" |
3666daf6 CD |
1927 | (substitute-command-keys |
1928 | "Recursive edit. Resume with \\[exit-recursive-edit]")) | |
1929 | (recursive-edit)))) | |
1930 | ((equal char ?e) | |
1931 | (setq rpl (read-string "Edit: " rpl))) | |
1932 | ((equal char ?0) | |
1933 | (setq ckey (or index-key phrase) | |
1934 | rpl (save-match-data | |
1935 | (reftex-index-make-replace-string | |
1936 | macro-fmt match ckey repeat mathp)))) | |
1937 | ((and (> char ?0) | |
1938 | (<= char (+ ?0 nkeys))) | |
1939 | (setq ckey (nth (1- (- char ?0)) index-keys) | |
1940 | rpl (save-match-data | |
1941 | (reftex-index-make-replace-string | |
1942 | macro-fmt match ckey repeat mathp)))) | |
1943 | (t (ding))) | |
1944 | nil))))) | |
7c4d13cc | 1945 | (message "") |
7b07114a CD |
1946 | (move-marker beg nil) |
1947 | (move-marker end nil) | |
7c4d13cc CD |
1948 | (setq all-yes nil) |
1949 | (reftex-unhighlight 0)))) | |
1950 | ||
1951 | (defun reftex-index-phrase-match-is-indexed (beg end) | |
f3c18bd0 | 1952 | ;; Check if match is in an argument of an index macro, or if an |
3666daf6 | 1953 | ;; index macro is directly attached to the match. |
7c4d13cc CD |
1954 | (save-excursion |
1955 | (goto-char end) | |
3666daf6 | 1956 | (let* ((all-macros (reftex-what-macro t)) |
7b07114a | 1957 | ; (this-macro (car (car all-macros))) |
3666daf6 CD |
1958 | (before-macro |
1959 | (and (> beg 2) | |
1960 | (goto-char (1- beg)) | |
1961 | (memq (char-after (point)) '(?\] ?\})) | |
1962 | (car (reftex-what-macro 1)))) | |
1963 | (after-macro | |
1964 | (and (goto-char end) | |
1965 | (looking-at "\\(\\\\[a-zA-Z]+\\*?\\)[[{]") | |
1966 | (match-string 1))) | |
1967 | macro) | |
1968 | (or (catch 'matched | |
1969 | (while (setq macro (pop all-macros)) | |
1970 | (if (member (car macro) reftex-macros-with-index) | |
1971 | (throw 'matched t))) | |
1972 | nil) | |
1973 | (and before-macro | |
1974 | (member before-macro reftex-macros-with-index)) | |
1975 | (and after-macro | |
1976 | (member after-macro reftex-macros-with-index)))))) | |
db95369b | 1977 | |
7c4d13cc CD |
1978 | (defun reftex-index-phrases-fixup-line (beg end) |
1979 | "Insert newlines before BEG and/or after END to shorten line." | |
1980 | (let (bol eol space1 space2) | |
1981 | (save-excursion | |
1982 | ;; Find line boundaries and possible line breaks near BEG and END | |
1983 | (beginning-of-line) | |
1984 | (setq bol (point)) | |
1985 | (end-of-line) | |
1986 | (setq eol (point)) | |
1987 | (goto-char beg) | |
1988 | (skip-chars-backward "^ \n") | |
1989 | (if (and (equal (preceding-char) ?\ ) | |
3666daf6 CD |
1990 | (string-match "\\S-" (buffer-substring bol (point)))) |
1991 | (setq space1 (1- (point)))) | |
7c4d13cc CD |
1992 | (goto-char end) |
1993 | (skip-chars-forward "^ \n") | |
1994 | (if (and (equal (following-char) ?\ ) | |
3666daf6 CD |
1995 | (string-match "\\S-" (buffer-substring (point) eol))) |
1996 | (setq space2 (point))) | |
7c4d13cc CD |
1997 | ;; Now check what we have and insert the newlines |
1998 | (if (<= (- eol bol) fill-column) | |
3666daf6 CD |
1999 | ;; Line is already short |
2000 | nil | |
2001 | (cond | |
2002 | ((and (not space1) (not space2))) ; No spaces available | |
2003 | ((not space2) ; Do space1 | |
2004 | (reftex-index-phrases-replace-space space1)) | |
2005 | ((not space1) ; Do space2 | |
2006 | (reftex-index-phrases-replace-space space2)) | |
2007 | (t ; We have both spaces | |
2008 | (let ((l1 (- space1 bol)) | |
2009 | (l2 (- space2 space1)) | |
2010 | (l3 (- eol space2))) | |
2011 | (if (> l2 fill-column) | |
2012 | ;; The central part alone is more than one line | |
2013 | (progn | |
2014 | (reftex-index-phrases-replace-space space1) | |
2015 | (reftex-index-phrases-replace-space space2)) | |
2016 | (if (> (+ l1 l2) fill-column) | |
2017 | ;; Need to split beginning | |
2018 | (reftex-index-phrases-replace-space space1)) | |
2019 | (if (> (+ l2 l3) fill-column) | |
2020 | ;; Need to split end | |
2021 | (reftex-index-phrases-replace-space space2)))))))))) | |
7c4d13cc CD |
2022 | |
2023 | (defun reftex-index-phrases-replace-space (pos) | |
2024 | "If there is a space at POS, replace it with a newline char. | |
2025 | Does not do a save-excursion." | |
2026 | (when (equal (char-after pos) ?\ ) | |
2027 | (goto-char pos) | |
2028 | (delete-char 1) | |
2029 | (insert "\n"))) | |
2030 | ||
2031 | (defun reftex-index-select-phrases-macro (&optional delay) | |
2032 | "Offer a list of possible index macros and have the user select one." | |
2033 | (let* ((prompt (concat "Select macro: [" | |
3666daf6 CD |
2034 | (mapconcat (lambda (x) (char-to-string (car x))) |
2035 | reftex-index-phrases-macro-data "") | |
2036 | "] ")) | |
2037 | (help (concat "Select an indexing macro\n========================\n" | |
2038 | (mapconcat (lambda (x) | |
2039 | (format " [%c] %s" | |
2040 | (car x) (nth 1 x))) | |
2041 | reftex-index-phrases-macro-data "\n")))) | |
7c4d13cc CD |
2042 | (reftex-select-with-char prompt help delay))) |
2043 | ||
2044 | ;; Keybindings and Menu for phrases buffer | |
2045 | ||
2046 | (loop for x in | |
2047 | '(("\C-c\C-c" . reftex-index-phrases-save-and-return) | |
3666daf6 CD |
2048 | ("\C-c\C-x" . reftex-index-this-phrase) |
2049 | ("\C-c\C-f" . reftex-index-next-phrase) | |
2050 | ("\C-c\C-r" . reftex-index-region-phrases) | |
2051 | ("\C-c\C-a" . reftex-index-all-phrases) | |
2052 | ("\C-c\C-d" . reftex-index-remaining-phrases) | |
2053 | ("\C-c\C-s" . reftex-index-sort-phrases) | |
2054 | ("\C-c\C-n" . reftex-index-new-phrase) | |
2055 | ("\C-c\C-m" . reftex-index-phrases-set-macro-key) | |
2056 | ("\C-c\C-i" . reftex-index-phrases-info) | |
2057 | ("\C-c\C-t" . reftex-index-find-next-conflict-phrase) | |
2058 | ("\C-i" . self-insert-command)) | |
7c4d13cc CD |
2059 | do (define-key reftex-index-phrases-map (car x) (cdr x))) |
2060 | ||
7b07114a | 2061 | (easy-menu-define |
7c4d13cc CD |
2062 | reftex-index-phrases-menu reftex-index-phrases-map |
2063 | "Menu for Phrases buffer" | |
2064 | '("Phrases" | |
2065 | ["New Phrase" reftex-index-new-phrase t] | |
2066 | ["Set Phrase Macro" reftex-index-phrases-set-macro-key t] | |
2067 | ["Recreate File Header" reftex-index-initialize-phrases-buffer t] | |
2068 | "--" | |
2069 | ("Sort Phrases" | |
2070 | ["Sort" reftex-index-sort-phrases t] | |
2071 | "--" | |
2072 | "Sort Options" | |
2073 | ["by Search Phrase" (setq reftex-index-phrases-sort-prefers-entry nil) | |
2074 | :style radio :selected (not reftex-index-phrases-sort-prefers-entry)] | |
2075 | ["by Index Entry" (setq reftex-index-phrases-sort-prefers-entry t) | |
2076 | :style radio :selected reftex-index-phrases-sort-prefers-entry] | |
2077 | ["in Blocks" (setq reftex-index-phrases-sort-in-blocks | |
3666daf6 | 2078 | (not reftex-index-phrases-sort-in-blocks)) |
7c4d13cc CD |
2079 | :style toggle :selected reftex-index-phrases-sort-in-blocks]) |
2080 | ["Describe Phrase" reftex-index-phrases-info t] | |
2081 | ["Next Phrase Conflict" reftex-index-find-next-conflict-phrase t] | |
2082 | "--" | |
2083 | ("Find and Index in Document" | |
2084 | ["Current Phrase" reftex-index-this-phrase t] | |
2085 | ["Next Phrase" reftex-index-next-phrase t] | |
2086 | ["Current and Following" reftex-index-remaining-phrases t] | |
2087 | ["Region Phrases" reftex-index-region-phrases t] | |
2088 | ["All Phrases" reftex-index-all-phrases t] | |
2089 | "--" | |
2090 | "Options" | |
2091 | ["Match Whole Words" (setq reftex-index-phrases-search-whole-words | |
3666daf6 | 2092 | (not reftex-index-phrases-search-whole-words)) |
7c4d13cc CD |
2093 | :style toggle :selected reftex-index-phrases-search-whole-words] |
2094 | ["Case Sensitive Search" (setq reftex-index-phrases-case-fold-search | |
3666daf6 | 2095 | (not reftex-index-phrases-case-fold-search)) |
7c4d13cc | 2096 | :style toggle :selected (not |
3666daf6 | 2097 | reftex-index-phrases-case-fold-search)] |
7c4d13cc | 2098 | ["Wrap Long Lines" (setq reftex-index-phrases-wrap-long-lines |
3666daf6 | 2099 | (not reftex-index-phrases-wrap-long-lines)) |
7c4d13cc CD |
2100 | :style toggle :selected reftex-index-phrases-wrap-long-lines] |
2101 | ["Skip Indexed Matches" (setq reftex-index-phrases-skip-indexed-matches | |
3666daf6 | 2102 | (not reftex-index-phrases-skip-indexed-matches)) |
7c4d13cc CD |
2103 | :style toggle :selected reftex-index-phrases-skip-indexed-matches]) |
2104 | "--" | |
2105 | ["Save and Return" reftex-index-phrases-save-and-return t])) | |
2106 | ||
2107 | ||
ab5796a9 | 2108 | ;;; arch-tag: 4b2362af-c156-42c1-8932-ea2823e205c1 |
1a9461d0 | 2109 | ;;; reftex-index.el ends here |