comparison lisp/textmodes/reftex-index.el @ 26910:489a5439b988

* reftex.el (reftex-compile-variables): respect new structure of `reftex-index-macro' (reftex-compile-variables): Use the changed structure of `reftex-label-alist'. * reftex-vars.el (reftex-index-math-format, (reftex-toc-max-level): New option. reftex-index-phrases-search-whole-words, reftex-index-phrases-case-fold-search, reftex-index-phrases-skip-indexed-matches, reftex-index-phrases-wrap-long-lines, reftex-index-phrases-sort-prefers-entry, reftex-index-phrases-sort-in-blocks): New options. (reftex-index-macros): Option structure changed. (reftex-index-macros-builtin): Added `repeat' item to each entry. (reftex-label-alist): Additional item in each entry to specify if the environment should be listed in the TOC. (eval-when-compile (require 'cl)) added. * reftex-index.el (reftex-index-selection-or-word): No longer deals with "repeat". (reftex-index): "repeat property in `reftex-index-macro-alist' is now used. (reftex-index-phrases-comment-regexp, reftex-index-phrases-macrodef-regexp, reftex-index-phrases-phrase-regexp1, reftex-index-phrases-phrase-regexp2, reftex-index-phrases-phrase-regexp12, reftex-index-phrases-help): New constants. (reftex-index-phrases-macro-data, reftex-index-phrases-files, reftex-index-phrases-font-lock-keywords, reftex-index-phrases-font-lock-defaults, reftex-index-phrases-map, reftex-index-phrases-restrict-file): New variables. (reftex-index-phrase-selection-or-word, reftex-index-visit-phrases-buffer, reftex-index-initialize-phrases-buffer, reftex-index-phrases-save-and-return, reftex-index-phrases-mode, reftex-index-next-phrase, reftex-index-this-phrase, reftex-index-all-phrases, reftex-index-region-phrases, reftex-index-phrases-parse-header, reftex-index-phrases-toggle-restricted, reftex-index-new-phrase, reftex-index-find-next-conflict-phrase, reftex-index-phrases-info, reftex-index-phrases-set-macro-key, reftex-index-sort-phrases, reftex-compare-phrase-lines, reftex-index-make-phrase-regexp, reftex-index-simplify-phrase, reftex-index-phrases-find-dup-re, reftex-index-make-replace-string, reftex-query-index-phrase-globally, reftex-query-index-phrase, reftex-index-phrase-match-is-indexed, reftex-index-phrases-fixup-line, reftex-index-phrases-replace-space, reftex-index-select-phrases-macro): New functions. (reftex-index-globalize, reftex-index-globally): functions removed (eval-when-compile (require 'cl)) added. * reftex-toc.el (reftex-toc-mode): Create new indicator for max level. (reftex-toc-max-level-indicator): New variable. (reftex-toc-max-level): New command. (reftex-toc-map): New keybinding `t'. (reftex-toc-help): Constant updated. (eval-when-compile (require 'cl)) added. * reftex-ref.el (reftex-offer-label-menu): Prefix to `t' command key can change `reftex-toc-max-level' (eval-when-compile (require 'cl)) added. * reftex-sel (reftex-insert-docstruct): Respect `reftex-toc-max-level' (eval-when-compile (require 'cl)) added. * reftex-auc.el (eval-when-compile (require 'cl)) added. * reftex-vcr.el (eval-when-compile (require 'cl)) added. * reftex-cite.el (reftex-citep, reftex-citet): New commands. (reftex-citation, reftex-do-citation, reftex-figure-out-cite-format): Additional argument FORMAT-KEY to preselect a citation format. (eval-when-compile (require 'cl)) added. * reftex-parse.el (reftex-context-substring): Optional parameter to-end (reftex-section-info): Deal with environment matches. (eval-when-compile (require 'cl)) added. * reftex-global.el (eval-when-compile (require 'cl)) added.
author Carsten Dominik <dominik@science.uva.nl>
date Wed, 15 Dec 1999 17:02:38 +0000
parents 7ed67319c5aa
children 083669ed376a
comparison
equal deleted inserted replaced
26909:5a2ef05e2490 26910:489a5439b988
1 ;;; reftex-index.el - Index support with RefTeX 1 ;;; reftex-index.el - Index support with RefTeX
2 ;;; Version: 4.6 2 ;;; Version: 4.9
3 ;;; 3 ;;;
4 ;;; See main file reftex.el for licensing information 4 ;;; See main file reftex.el for licensing information
5 5
6 (eval-when-compile (require 'cl))
6 (provide 'reftex-index) 7 (provide 'reftex-index)
7 (require 'reftex) 8 (require 'reftex)
8 ;;; 9 ;;;
9 10
10 (defvar mark-active) 11 (defvar mark-active)
11 (defvar zmacs-regions) 12 (defvar zmacs-regions)
12 (defvar transient-mark-mode) 13 (defvar transient-mark-mode)
13 (defun reftex-index-selection-or-word (&optional arg) 14 (defun reftex-index-selection-or-word (&optional arg phrase)
14 "Put selection or the word near point into the default index macro. 15 "Put selection or the word near point into the default index macro.
15 This uses the information in `reftex-index-default-macro' to make an index 16 This uses the information in `reftex-index-default-macro' to make an index
16 entry. The phrase indexed is the current selection or the word near point. 17 entry. The phrase indexed is the current selection or the word near point.
17 When called with one `C-u' prefix, let the user have a chance to edit the 18 When called with one `C-u' prefix, let the user have a chance to edit the
18 index entry. When called with 2 `C-u' as prefix, also ask for the index 19 index entry. When called with 2 `C-u' as prefix, also ask for the index
35 (save-excursion 36 (save-excursion
36 (skip-syntax-forward "w\\") (point)))) 37 (skip-syntax-forward "w\\") (point))))
37 (sel (buffer-substring beg end)) 38 (sel (buffer-substring beg end))
38 (mathp (condition-case nil (texmathp) (error nil))) 39 (mathp (condition-case nil (texmathp) (error nil)))
39 (current-prefix-arg nil) ; we want to call reftex-index without prefix. 40 (current-prefix-arg nil) ; we want to call reftex-index without prefix.
40 key def-char def-tag full-entry repeat-word) 41 key def-char def-tag full-entry)
41 42
42 (if (equal sel "") 43 (if phrase
43 ;; Nothing selecte, no word, so use full reftex-index command 44 (progn
44 (reftex-index) 45 (reftex-index-visit-phrases-buffer)
45 ;; OK, we have something to index here. 46 (reftex-index-new-phrase sel))
46 ;; Add the dollars when necessary 47
47 (setq key (if mathp 48 (if (equal sel "")
48 (format reftex-index-math-format sel) 49 ;; Nothing selected, no word, so use full reftex-index command
49 sel)) 50 (reftex-index)
50 ;; Get info from `reftex-index-default-macro' 51 ;; OK, we have something to index here.
51 (setq def-char (if use-default (car reftex-index-default-macro))) 52 ;; Add the dollars when necessary
52 (setq def-tag (if use-default (nth 1 reftex-index-default-macro))) 53 (setq key (if mathp
53 ;; Does the user want to edit the entry? 54 (format reftex-index-math-format sel)
54 (setq full-entry (if arg 55 sel))
55 (reftex-index-complete-key 56 ;; Get info from `reftex-index-default-macro'
56 def-tag nil (cons key 0)) 57 (setq def-char (if use-default (car reftex-index-default-macro)))
57 key)) 58 (setq def-tag (if use-default (nth 1 reftex-index-default-macro)))
58 ;; Do we neet to repeat the word outside the macro? 59 ;; Does the user want to edit the entry?
59 (setq repeat-word (if use-default 60 (setq full-entry (if arg
60 (nth 2 reftex-index-default-macro) 61 (reftex-index-complete-key
61 (y-or-n-p "Repeat phrase outside macro? "))) 62 def-tag nil (cons key 0))
62 ;; Delete what is in the buffer and make the index entry 63 key))
63 (delete-region beg end) 64 ;; Delete what is in the buffer and make the index entry
64 (reftex-index def-char full-entry def-tag (if repeat-word sel nil))))) 65 (delete-region beg end)
65 66 (reftex-index def-char full-entry def-tag sel)))))
66 (defun reftex-index (&optional char key tag postfix no-insert) 67
68 (defun reftex-index (&optional char key tag sel no-insert)
67 "Query for an index macro and insert it along with its argments. 69 "Query for an index macro and insert it along with its argments.
68 The index macros available are those defined in `reftex-index-macro' or 70 The index macros available are those defined in `reftex-index-macro' or
69 by a call to `reftex-add-index-macros', typically from an AUCTeX style file. 71 by a call to `reftex-add-index-macros', typically from an AUCTeX style file.
70 RefteX provides completion for the index tag and the index key, and 72 RefteX provides completion for the index tag and the index key, and
71 will prompt for other arguments." 73 will prompt for other arguments."
86 (ntag (nth 1 entry)) 88 (ntag (nth 1 entry))
87 (tag (or tag (nth 1 entry))) 89 (tag (or tag (nth 1 entry)))
88 (nargs (nth 4 entry)) 90 (nargs (nth 4 entry))
89 (nindex (nth 5 entry)) 91 (nindex (nth 5 entry))
90 (opt-args (nth 6 entry)) 92 (opt-args (nth 6 entry))
93 (repeat (nth 7 entry))
91 opt tag1 value) 94 opt tag1 value)
92 95
93 ;; Get the supported arguments 96 ;; Get the supported arguments
94 (if (stringp tag) 97 (if (stringp tag)
95 (setq tag1 tag) 98 (setq tag1 tag)
109 (int-to-string i) 112 (int-to-string i)
110 (if opt " (optional)" "") 113 (if opt " (optional)" "")
111 ": "))))) 114 ": ")))))
112 (unless (and opt (string= value "")) 115 (unless (and opt (string= value ""))
113 (insert (if opt "[" "{") value (if opt "]" "}")))) 116 (insert (if opt "[" "{") value (if opt "]" "}"))))
114 (and (stringp postfix) (insert postfix)) 117 (and repeat (stringp sel) (insert sel))
115 (and key reftex-plug-into-AUCTeX (fboundp 'LaTeX-add-index-entries) 118 (and key reftex-plug-into-AUCTeX (fboundp 'LaTeX-add-index-entries)
116 (LaTeX-add-index-entries key)) 119 (LaTeX-add-index-entries key))
117 (reftex-index-update-taglist tag1) 120 (reftex-index-update-taglist tag1)
118 (reftex-notice-new))) 121 (reftex-notice-new)))
119 122
234 ;; add NEWTAG to the list of available index tags. 237 ;; add NEWTAG to the list of available index tags.
235 (let ((cell (assoc 'index-tags (symbol-value reftex-docstruct-symbol)))) 238 (let ((cell (assoc 'index-tags (symbol-value reftex-docstruct-symbol))))
236 (and newtag (cdr cell) (not (member newtag (cdr cell))) 239 (and newtag (cdr cell) (not (member newtag (cdr cell)))
237 (push newtag (cdr cell))))) 240 (push newtag (cdr cell)))))
238 241
239 (defvar reftex-last-index-file)
240 (defun reftex-index-globally (&optional data call-file)
241 "Index a word with a global search and replace.
242 This works very much like `reftex-query-replace-document', but the
243 defaults for the search and replace strings are derived from
244 local context.
245 When there is an index entry, we try to index similar words. The word
246 to search for is either a word in direct contact with the index macro
247 (like `\\index{WORD}WORD' or `WORD\\index{WORD}') or the index key.
248 The replacement text is the index macro with all its arguments and the
249 attached word.
250 When there is no index entry at point, we search for the word near point
251 and propose to index it like this: `\\index{word}word'.
252 You get a chance to edit the search and replacement strings.
253 DATA can be a docstruct entry describing an index entry, and then the
254 defaults will be derived from it.
255 CALL-FILE may be the file from where to call the global search command."
256 (interactive)
257 (let* ((call-file (cond (call-file call-file)
258 (reftex-mode (buffer-file-name))
259 ((eq major-mode 'reftex-index-mode)
260 reftex-last-index-file)
261 (t (error "Need a call file here"))))
262 (pos (point))
263 (data (cond
264 (data data)
265 ((and reftex-mode
266 (save-excursion
267 (forward-char 20)
268 (re-search-backward reftex-everything-regexp nil t)
269 (< (count-lines (min pos (point)) (max pos (point)))
270 2)))
271 (reftex-index-info (buffer-file-name)))
272 (t nil)))
273 (ksep (car reftex-index-special-chars))
274 (words-include-escapes t)
275 (case-replace nil)
276 (case-fold-search t)
277 word rpl start analyze-list pre key attr actual post)
278
279 ;; Find the word and construct the replacement string
280 (if (and data (eq (car data) 'index))
281 ;; OK, we have an index entry
282 (progn
283 (setq analyze-list (reftex-index-analyze-entry data)
284 pre (car analyze-list)
285 key (nth 1 analyze-list)
286 attr (nth 2 analyze-list)
287 actual (nth 3 analyze-list)
288 post (nth 4 analyze-list))
289 (when (string-match (concat "\\<\\(\\sw+\\)" reftex-index-re) pre)
290 (setq word (match-string 1 pre)
291 pre (concat "<<<1>>>" (substring pre (match-end 1)))
292 rpl (concat pre key attr actual post)))
293 (when (string-match "}\\(\\sw+\\)\\>[^}]*\\'" post)
294 (setq word (match-string 1 post)
295 post (concat (substring post 0 (match-beginning 1))
296 "<<<1>>>")
297 rpl (concat pre key attr actual post)))
298 (when (and (not word) key)
299 (if (string-match (concat ".*" (regexp-quote ksep)) key)
300 (setq word (substring key (match-end 0)))
301 (setq word key))
302 (setq rpl (concat pre key attr actual post))))
303 ;; No index entry, just use local word.
304 (setq word (save-excursion
305 (buffer-substring-no-properties
306 (progn (skip-syntax-backward "w") (point))
307 (progn (skip-syntax-forward "w") (point))))
308 rpl (concat "\\index{" word "}<<<1>>>")))
309 ;; Quote what is necessary
310 (setq word (regexp-quote (downcase word)))
311 (setq start 0)
312 (while (setq start (string-match "\\\\" rpl start))
313 (setq rpl (replace-match "\\\\" t t rpl)
314 start (+ 2 start)))
315 ;; We used <<<1>>> instead of \1 to avoid the quoting. Fix this now.
316 (if (string-match "<<<1>>>" rpl)
317 (setq rpl (replace-match "\\1" t t rpl)))
318
319 ;; Give the user a chance to edit the strings
320 (setq word (read-string "Search: "
321 (if word (format "\\<\\(%s\\)\\>" word)))
322 rpl (read-string "Replace with: " rpl))
323
324 ;; Execute the command
325 (save-excursion
326 (switch-to-buffer (get-file-buffer call-file))
327 (condition-case nil
328 (reftex-query-replace-document word rpl)
329 (error nil)))))
330
331 (defvar reftex-index-map (make-sparse-keymap) 242 (defvar reftex-index-map (make-sparse-keymap)
332 "Keymap used for *Index* buffers.") 243 "Keymap used for *Index* buffers.")
333 244
334 (defvar reftex-index-menu) 245 (defvar reftex-index-menu)
335 246
390 e / C-k Edit/Kill the entry. 301 e / C-k Edit/Kill the entry.
391 * | @ Edit specific part of entry: [*]key [|]attribute [@]visual 302 * | @ Edit specific part of entry: [*]key [|]attribute [@]visual
392 With prefix: kill that part. 303 With prefix: kill that part.
393 ( ) Toggle entry's beginning/end of page range property. 304 ( ) Toggle entry's beginning/end of page range property.
394 _ ^ Add/Remove parent key (to make this item a subitem). 305 _ ^ Add/Remove parent key (to make this item a subitem).
395 & Index the same word everywhere in the document.
396 } / { Restrict Index to a single document section / Widen. 306 } / { Restrict Index to a single document section / Widen.
397 < / > When restricted, move restriction to previous/next section.") 307 < / > When restricted, move restriction to previous/next section.")
398 308
399 (defun reftex-index-show-entry (data &optional no-revisit) 309 (defun reftex-index-show-entry (data &optional no-revisit)
400 ;; Find an index entry associated with DATA and display it highlighted 310 ;; Find an index entry associated with DATA and display it highlighted
916 (attr (substring context boattr boactual)) 826 (attr (substring context boattr boactual))
917 (actual (substring context boactual eoa)) 827 (actual (substring context boactual eoa))
918 (post (substring context eoa))) 828 (post (substring context eoa)))
919 (list pre key attr actual post))) 829 (list pre key attr actual post)))
920 830
921 (defun reftex-index-globalize (&optional arg)
922 "Globalize the current index entry.
923 This starts a global search and replace to index the same word
924 at other places in the document. After this function completes, you
925 need to rescan the document with `r' or `C-u r' in order to get the
926 entries into the index buffer.
927 Defaults for the search and replace strings are derived from
928 the current entry. See the command `reftex-index-globally'."
929 (interactive)
930 (let* ((data (get-text-property (point) :data))
931 (buf (current-buffer)))
932 (unless data
933 (error "No index entry at point"))
934 (reftex-index-globally data)
935 (switch-to-buffer buf)))
936
937 (defun reftex-index-edit () 831 (defun reftex-index-edit ()
938 "Edit the index entry at point." 832 "Edit the index entry at point."
939 (interactive) 833 (interactive)
940 (let* ((data (get-text-property (point) :data)) 834 (let* ((data (get-text-property (point) :data))
941 old new) 835 old new)
962 856
963 (defun reftex-index-toggle-range-end () 857 (defun reftex-index-toggle-range-end ()
964 "Toggle the page-range-end attribute `|)'." 858 "Toggle the page-range-end attribute `|)'."
965 (interactive) 859 (interactive)
966 (let* ((data (get-text-property (point) :data)) 860 (let* ((data (get-text-property (point) :data))
967 (eor (concat (nth 1 reftex-index-special-chars) "(")) 861 (eor (concat (nth 1 reftex-index-special-chars) ")"))
968 new analyze attr) 862 new analyze attr)
969 (unless data (error "Don't know which index entry to edit")) 863 (unless data (error "Don't know which index entry to edit"))
970 (setq analyze (reftex-index-analyze-entry data) 864 (setq analyze (reftex-index-analyze-entry data)
971 attr (nth 2 analyze)) 865 attr (nth 2 analyze))
972 (setf (nth 2 analyze) (if (string= attr eor) "" eor)) 866 (setf (nth 2 analyze) (if (string= attr eor) "" eor))
1136 ("(" . reftex-index-toggle-range-beginning) 1030 ("(" . reftex-index-toggle-range-beginning)
1137 (")" . reftex-index-toggle-range-end) 1031 (")" . reftex-index-toggle-range-end)
1138 ("|" . reftex-index-edit-attribute) 1032 ("|" . reftex-index-edit-attribute)
1139 ("@" . reftex-index-edit-visual) 1033 ("@" . reftex-index-edit-visual)
1140 ("*" . reftex-index-edit-key) 1034 ("*" . reftex-index-edit-key)
1141 ("&" . reftex-index-globalize)
1142 ("\C-c=". reftex-index-goto-toc) 1035 ("\C-c=". reftex-index-goto-toc)
1143 ("c" . reftex-index-toggle-context)) 1036 ("c" . reftex-index-toggle-context))
1144 do (define-key reftex-index-map (car x) (cdr x))) 1037 do (define-key reftex-index-map (car x) (cdr x)))
1145 1038
1146 (loop for key across "0123456789" do 1039 (loop for key across "0123456789" do
1162 (progn 1055 (progn
1163 (beginning-of-line) 1056 (beginning-of-line)
1164 (recenter 0) 1057 (recenter 0)
1165 (reftex-index-next)) 1058 (reftex-index-next))
1166 (goto-char pos) 1059 (goto-char pos)
1167 (error "This <%s> index does not contain entries starting with `%c'" 1060 (if (eq char ?!)
1168 reftex-index-tag char)))) 1061 (error "This <%s> index does not contain entries sorted before the letters"
1062 reftex-index-tag)
1063 (error "This <%s> index does not contain entries starting with `%c'"
1064 reftex-index-tag char)))))
1169 1065
1170 (easy-menu-define 1066 (easy-menu-define
1171 reftex-index-menu reftex-index-map 1067 reftex-index-menu reftex-index-map
1172 "Menu for Index buffer" 1068 "Menu for Index buffer"
1173 `("Index" 1069 `("Index"
1202 ["Remove Parentkey " reftex-index-level-up t] 1098 ["Remove Parentkey " reftex-index-level-up t]
1203 "--" 1099 "--"
1204 ["Make Start-of-Range" reftex-index-toggle-range-beginning t] 1100 ["Make Start-of-Range" reftex-index-toggle-range-beginning t]
1205 ["Make End-of-Range" reftex-index-toggle-range-end t] 1101 ["Make End-of-Range" reftex-index-toggle-range-end t]
1206 "--" 1102 "--"
1207 ["Globalize" reftex-index-globalize t]
1208 ["Kill Entry" reftex-index-kill nil] 1103 ["Kill Entry" reftex-index-kill nil]
1209 "--" 1104 "--"
1210 ["Undo" reftex-index-undo nil]) 1105 ["Undo" reftex-index-undo nil])
1211 ("Options" 1106 ("Options"
1212 ["Context" reftex-index-toggle-context :style toggle 1107 ["Context" reftex-index-toggle-context :style toggle
1215 ["Follow Mode" reftex-index-toggle-follow :style toggle 1110 ["Follow Mode" reftex-index-toggle-follow :style toggle
1216 :selected reftex-index-follow-mode]) 1111 :selected reftex-index-follow-mode])
1217 "--" 1112 "--"
1218 ["Help" reftex-index-show-help t])) 1113 ["Help" reftex-index-show-help t]))
1219 1114
1115
1116 ;;----------------------------------------------------------------------
1117 ;; The Index Phrases File
1118
1119 ;; Some constants and variables
1120 (defconst reftex-index-phrases-comment-regexp "^[ \t]*%.*"
1121 "Regular expression to match comment lines in phrases buffer")
1122 (defconst reftex-index-phrases-macrodef-regexp
1123 "^\\(>>>INDEX_MACRO_DEFINITION:\\)[ \t]+\\(\\S-\\)\\( *\t[ \t]*\\)\\([^\t]*[^ \t]\\)\\( *\t[ \t]*\\)\\(\\S-+\\)"
1124 "Regular expression to match macro definition lines the phrases buffer.")
1125 ;(defconst reftex-index-phrases-macrodef-regexp
1126 ; "^\\(>>>INDEX_MACRO_DEFINITION:\\)[ \t]+\\(\\S-\\)\\([ \t]*\\)\\([^\t]*[^ \t]\\)\\([ \t]*\\)\\(nil\\|t\\)[ \t]*$"
1127 ; "Regular expression to match macro definition lines the phrases buffer.
1128 ;This version would allow just spaces as separators.")
1129 (defconst reftex-index-phrases-phrase-regexp1
1130 "^\\(\\S-?\\)\\(\t\\)\\([^\t\n]*\\S-\\)\\([ \t]*\\)$"
1131 "Regular expression matching phrases which have no separate index key.")
1132 (defconst reftex-index-phrases-phrase-regexp2
1133 "^\\(\\S-?\\)\\(\t\\)\\([^\t]*\\S-\\)\\(\t[ \t]*\\)\\([^\n\t]*\\S-\\)[ \t]*$"
1134 "Regular expression matching phrases which have a separate index key.")
1135 (defconst reftex-index-phrases-phrase-regexp12
1136 "^\\(\\S-?\\)\\(\t\\)\\([^\n\t]*\\S-\\)\\(\\(\t[ \t]*\\)\\([^\n\t]*\\S-\\)\\)?[ \t]*$"
1137 "Regular expression matching all types of phrase lines.")
1138 (defvar reftex-index-phrases-macro-data nil
1139 "Alist containing the information taken from the macro definition lines.
1140 This gets refreshed in every phrases command.")
1141 (defvar reftex-index-phrases-files nil
1142 "List of document files relevant for the phrases file.")
1143
1144 (defvar reftex-index-phrases-font-lock-keywords nil
1145 "Font lock keywords for reftex-index-phrases-mode.")
1146 (defvar reftex-index-phrases-font-lock-defaults nil
1147 "Font lock defaults for reftex-index-phrases-mode.")
1148 (defvar reftex-index-phrases-map (make-sparse-keymap)
1149 "Keymap used for *toc* buffer.")
1150
1151
1152 (defun reftex-index-phrase-selection-or-word (arg)
1153 "Add current selection or word at point to the phrases buffer.
1154 When you are in transient-mark-mode and the region is active, the
1155 selection will be used - otherwise the word at point.
1156 You get a chance to edit the entry in the phrases buffer - finish with
1157 `C-c C-c'."
1158 (interactive "P")
1159 (set-marker reftex-index-return-marker (point))
1160 (reftex-index-selection-or-word arg 'phrase)
1161 (if (eq major-mode 'reftex-index-phrases-mode)
1162 (message
1163 (substitute-command-keys
1164 "Return to LaTeX with \\[reftex-index-phrases-save-and-return]"))))
1165
1166 (defun reftex-index-visit-phrases-buffer ()
1167 "Switch to the phrases buffer, initialize if empty."
1168 (interactive)
1169 (reftex-access-scan-info)
1170 (let* ((master (reftex-TeX-master-file))
1171 (name (concat (file-name-sans-extension master) ".rip")))
1172 (find-file name)
1173 (unless (eq major-mode 'reftex-index-phrases-mode)
1174 (reftex-index-phrases-mode))
1175 (if (= (buffer-size) 0)
1176 (reftex-index-initialize-phrases-buffer master))))
1177
1178 (defun reftex-index-initialize-phrases-buffer (&optional master)
1179 "Initialize the phrases buffer by creating the header.
1180 If the buffer is non-empty, delete the old header first."
1181 (interactive)
1182 (let* ((case-fold-search t)
1183 (default-key (car reftex-index-default-macro))
1184 (default-macro (nth 1 (assoc default-key
1185 reftex-key-to-index-macro-alist)))
1186 (macro-alist
1187 (sort (copy-sequence reftex-index-macro-alist)
1188 (lambda (a b) (equal (car a) default-macro))))
1189 macro entry key repeat)
1190
1191 (if master (set (make-local-variable 'TeX-master)
1192 (file-name-nondirectory master)))
1193
1194 (when (> (buffer-size) 0)
1195 (goto-char 1)
1196 (set-mark (point))
1197 (while (re-search-forward reftex-index-phrases-macrodef-regexp nil t)
1198 (end-of-line))
1199 (beginning-of-line 2)
1200 (if (looking-at reftex-index-phrases-comment-regexp)
1201 (beginning-of-line 2))
1202 (while (looking-at "^[ \t]*$")
1203 (beginning-of-line 2))
1204 (cond ((fboundp 'zmacs-activate-region) (zmacs-activate-region))
1205 ((boundp 'make-active) (setq mark-active t)))
1206 (if (yes-or-no-p "Delete and rebuilt header ")
1207 (delete-region (point-min) (point))))
1208
1209 ;; Insert the mode line
1210 (insert
1211 (format "%% -*- mode: reftex-index-phrases; TeX-master: \"%s\" -*-\n"
1212 (file-name-nondirectory (reftex-index-phrase-tex-master))))
1213 ;; Insert the macro definitions
1214 (insert "% Key Macro Format Repeat\n")
1215 (insert "%---------------------------------------------------------------------\n")
1216 (while (setq entry (pop macro-alist))
1217 (setq macro (car entry)
1218 repeat (nth 7 entry)
1219 key (car (delq nil (mapcar (lambda (x) (if (equal (nth 1 x) macro)
1220 (car x)
1221 nil))
1222 reftex-key-to-index-macro-alist))))
1223 (insert (format ">>>INDEX_MACRO_DEFINITION:\t%s\t%-20s\t%s\n"
1224 (char-to-string key) (concat macro "{%s}")
1225 (if repeat "t" "nil"))))
1226 (insert "%---------------------------------------------------------------------\n\n\n")))
1227
1228 (defvar TeX-master)
1229 (defun reftex-index-phrase-tex-master (&optional dir)
1230 "Return the name of the master file associated with a phrase buffer."
1231 (if (and (boundp 'TeX-master)
1232 (local-variable-p 'TeX-master (current-buffer))
1233 (stringp TeX-master))
1234 ;; We have a local variable which tells us which file to use
1235 (expand-file-name TeX-master dir)
1236 ;; have to guess
1237 (concat (file-name-sans-extension (buffer-file-name)) ".tex")))
1238
1239 (defun reftex-index-phrases-save-and-return ()
1240 "Return to where the `reftex-index-phrase-selection-or-word' was called."
1241 (interactive)
1242 (save-buffer)
1243 (switch-to-buffer (marker-buffer reftex-index-return-marker))
1244 (goto-char (or (marker-position reftex-index-return-marker) (point))))
1245
1246
1247 (defvar reftex-index-phrases-menu)
1248 (defvar reftex-index-phrases-restrict-file nil)
1249 ;;;###autoload
1250 (defun reftex-index-phrases-mode ()
1251 "Major mode for managing the Index phrases of a LaTeX document.
1252 This buffer was created with RefTeX.
1253
1254 To insert new phrases, use
1255 - `C-c \\' in the LaTeX document to copy selection or word
1256 - `\\[reftex-index-new-phrase]' in the phrases buffer.
1257
1258 To index phrases use one of:
1259
1260 \\[reftex-index-this-phrase] index current phrase
1261 \\[reftex-index-next-phrase] index next phrase (or N with prefix arg)
1262 \\[reftex-index-all-phrases] index all phrases
1263 \\[reftex-index-remaining-phrases] index current and following phrases
1264 \\[reftex-index-region-phrases] index the phrases in the region
1265
1266 You can sort the phrases in this buffer with \\[reftex-index-sort-phrases].
1267 To display information about the phrase at point, use \\[reftex-index-phrases-info].
1268
1269 For more information see the RefTeX User Manual.
1270
1271 Here are all local bindings.
1272
1273 \\{reftex-index-phrases-map}"
1274 (interactive)
1275 (kill-all-local-variables)
1276 (setq major-mode 'reftex-index-phrases-mode
1277 mode-name "Phrases")
1278 (use-local-map reftex-index-phrases-map)
1279 (set (make-local-variable 'font-lock-defaults)
1280 reftex-index-phrases-font-lock-defaults)
1281 (easy-menu-add reftex-index-phrases-menu reftex-index-phrases-map)
1282 (set (make-local-variable 'reftex-index-phrases-marker) (make-marker))
1283 (run-hooks 'reftex-index-phrases-mode-hook))
1284 (add-hook 'reftex-index-phrases-mode-hook 'turn-on-font-lock)
1285
1286 ;; Font Locking stuff
1287 (let ((ss (if (featurep 'xemacs) 'secondary-selection ''secondary-selection)))
1288 (setq reftex-index-phrases-font-lock-keywords
1289 (list
1290 (cons reftex-index-phrases-comment-regexp 'font-lock-comment-face)
1291 (list reftex-index-phrases-macrodef-regexp
1292 '(1 font-lock-type-face)
1293 '(2 font-lock-keyword-face)
1294 (list 3 ss)
1295 '(4 font-lock-function-name-face)
1296 (list 5 ss)
1297 '(6 font-lock-string-face))
1298 (list reftex-index-phrases-phrase-regexp1
1299 '(1 font-lock-keyword-face)
1300 (list 2 ss)
1301 '(3 font-lock-string-face)
1302 (list 4 ss))
1303 (list reftex-index-phrases-phrase-regexp2
1304 '(1 font-lock-keyword-face)
1305 (list 2 ss)
1306 '(3 font-lock-string-face)
1307 (list 4 ss)
1308 '(5 font-lock-function-name-face))
1309 (cons "^\t$" ss)))
1310 (setq reftex-index-phrases-font-lock-defaults
1311 '((reftex-index-phrases-font-lock-keywords)
1312 nil t nil beginning-of-line))
1313 (put 'reftex-index-phrases-mode 'font-lock-defaults
1314 reftex-index-phrases-font-lock-defaults) ; XEmacs
1315 )
1316
1317 (defvar reftex-index-phrases-marker)
1318 (defun reftex-index-next-phrase (&optional arg)
1319 "Index the next ARG phrases in the phrases buffer."
1320 (interactive "p")
1321 (reftex-index-phrases-parse-header t)
1322 (while (> arg 0)
1323 (decf arg)
1324 (end-of-line)
1325 (if (re-search-forward reftex-index-phrases-phrase-regexp12 nil t)
1326 (progn
1327 (goto-char (match-beginning 0))
1328 (reftex-index-this-phrase))
1329 (error "No more phrase lines after point"))))
1330
1331 (defun reftex-index-this-phrase ()
1332 "Index the phrase in the current line.
1333 Does a global search and replace in the entire document. At each
1334 match, the user will be asked to confirm the replacement."
1335 (interactive)
1336 (if (interactive-p) (reftex-index-phrases-parse-header t))
1337 (save-excursion
1338 (beginning-of-line)
1339 (cond ((looking-at reftex-index-phrases-comment-regexp)
1340 (if (interactive-p) (error "Comment line")))
1341 ((looking-at "^[ \t]*$")
1342 (if (interactive-p) (error "Empty line")))
1343 ((looking-at reftex-index-phrases-macrodef-regexp)
1344 (if (interactive-p) (error "Macro definition line")))
1345 ((looking-at reftex-index-phrases-phrase-regexp12)
1346 ;; This is a phrase
1347 (let* ((char (if (not (equal (match-string 1) ""))
1348 (string-to-char (match-string 1))))
1349 (phrase (match-string 3))
1350 (index-key (match-string 6))
1351 (macro-data (cdr (if (null char)
1352 (car reftex-index-phrases-macro-data)
1353 (assoc char reftex-index-phrases-macro-data))))
1354 (macro-fmt (car macro-data))
1355 (repeat (nth 1 macro-data))
1356 (files
1357 (cond ((and (stringp reftex-index-phrases-restrict-file)
1358 (file-regular-p reftex-index-phrases-restrict-file))
1359 (list reftex-index-phrases-restrict-file))
1360 ((stringp reftex-index-phrases-restrict-file)
1361 (error "Illegal restriction file %s"
1362 reftex-index-phrases-restrict-file))
1363 (t reftex-index-phrases-files)))
1364 (as-words reftex-index-phrases-search-whole-words))
1365 (unless macro-data
1366 (error "No macro associated with key %c" char))
1367 (unwind-protect
1368 (let ((overlay-arrow-string "=>")
1369 (overlay-arrow-position
1370 reftex-index-phrases-marker)
1371 (replace-count 0))
1372 ;; Show the overlay arrow
1373 (move-marker reftex-index-phrases-marker
1374 (match-beginning 0) (current-buffer))
1375 ;; Start the query-replace
1376 (reftex-query-index-phrase-globally
1377 files phrase macro-fmt
1378 index-key repeat as-words)
1379 (message "%s replaced"
1380 (reftex-number replace-count "occurrence"))))))
1381 (t (error "Cannot parse this line")))))
1382
1383 (defun reftex-index-all-phrases ()
1384 "Index all phrases in the phrases buffer.
1385 Calls `reftex-index-this-phrase' on each line in the buffer."
1386 (interactive)
1387 (reftex-index-region-phrases (point-min) (point-max)))
1388
1389 (defun reftex-index-remaining-phrases ()
1390 "Index all phrases in the phrases buffer.
1391 Calls `reftex-index-this-phrase' on each line ay and below point in
1392 the buffer."
1393 (interactive)
1394 (beginning-of-line)
1395 (reftex-index-region-phrases (point) (point-max)))
1396
1397 (defun reftex-index-region-phrases (beg end)
1398 "Index all phrases in the phrases buffer.
1399 Calls `reftex-index-this-phrase' on each line in the region."
1400 (interactive "r")
1401 (reftex-index-phrases-parse-header t)
1402 (goto-char beg)
1403 (while (not (or (eobp)
1404 (>= (point) end)))
1405 (save-excursion (reftex-index-this-phrase))
1406 (beginning-of-line 2)))
1407
1408 (defun reftex-index-phrases-parse-header (&optional get-files)
1409 "Parse the header of a phrases file to extract the macro definitions.
1410 The definitions get stored in `reftex-index-phrases-macro-data'.
1411 Also switches to the LaTeX document to find out which files belong to
1412 the document and stores the list in `reftex-index-phrases-files'."
1413 (let* ((master (reftex-index-phrase-tex-master))
1414 buf)
1415 (if get-files
1416 ;; Get the file list
1417 (save-excursion
1418 (setq buf (reftex-get-file-buffer-force master))
1419 (unless buf (error "Master file %s not found" master))
1420 (set-buffer buf)
1421 (reftex-access-scan-info)
1422 (setq reftex-index-phrases-files
1423 (reftex-all-document-files))))
1424 ;; Parse the files header for macro definitions
1425 (setq reftex-index-phrases-macro-data nil)
1426 (save-excursion
1427 (goto-char (point-min))
1428 (while (re-search-forward reftex-index-phrases-macrodef-regexp nil t)
1429 (push (list
1430 (string-to-char (match-string 2))
1431 (match-string 4)
1432 (equal (match-string 6) "t"))
1433 reftex-index-phrases-macro-data))
1434 ;; Reverse the list, so that the first macro is first
1435 (if (null reftex-index-phrases-macro-data)
1436 (error "No valid MACRO DEFINITION line in .rip file (make sure to use TAB separators)"))
1437 (setq reftex-index-phrases-macro-data
1438 (nreverse reftex-index-phrases-macro-data))
1439 (goto-char (point-min)))))
1440
1441 (defun reftex-index-phrases-apply-to-region (beg end)
1442 "Index all index phrases in the current region.
1443 This works exactly like global indexing from the index phrases buffer,
1444 but operation is restricted to the current region. This is useful if
1445 you need to add/change text in an already indexed document and want to
1446 index the new part without having to go over the unchanged parts again."
1447 (interactive "r")
1448 (let ((win-conf (current-window-configuration))
1449 (reftex-index-phrases-restrict-file (buffer-file-name)))
1450 (save-excursion
1451 (save-restriction
1452 (narrow-to-region beg end)
1453 (unwind-protect
1454 (progn
1455 ;; Hide the region highlighting
1456 (cond ((fboundp 'zmacs-deactivate-region) (zmacs-deactivate-region))
1457 ((fboundp 'deactivate-mark) (deactivate-mark)))
1458 (delete-other-windows)
1459 (reftex-index-visit-phrases-buffer)
1460 (reftex-index-all-phrases))
1461 (set-window-configuration win-conf))))))
1462
1463 (defun reftex-index-new-phrase (&optional text)
1464 "Open a new line in the phrases buffer, insert TEXT."
1465 (interactive)
1466 (if (and text (stringp text))
1467 (progn
1468 ;; Check if the phrase is already in the buffer
1469 (setq text (reftex-index-simplify-phrase text))
1470 (goto-char (point-min))
1471 (if (re-search-forward
1472 (concat "^\\(\\S-*\\)\t\\(" (regexp-quote text)
1473 "\\) *[\t\n]") nil t)
1474 (progn
1475 (goto-char (match-end 2))
1476 (error "Phrase is already in phrases buffer")))))
1477 ;; Add the new phrase line after the last in the buffer
1478 (goto-char (point-max))
1479 (if (re-search-backward reftex-index-phrases-phrase-regexp12 nil t)
1480 (end-of-line))
1481 (if (not (bolp))
1482 (insert "\n"))
1483 (insert "\t")
1484 (if (and text (stringp text))
1485 (insert text)))
1486
1487 (defun reftex-index-find-next-conflict-phrase (&optional arg)
1488 "Find the next a phrase which is has conflicts in the phrase buffer.
1489 The command helps to find possible conflicts in the phrase indexing process.
1490 It searches downward from point for a phrase which is repeated elsewhere
1491 in the buffer, or which is a subphrase of another phrase. If such a
1492 phrase is found, the phrase info is displayed.
1493 To check the whole buffer, start at the beginning and continue by calling
1494 this function repeatedly."
1495 (interactive "P")
1496 (if (catch 'exit
1497 (while (re-search-forward reftex-index-phrases-phrase-regexp12 nil t)
1498 (goto-char (match-beginning 3))
1499 (let* ((phrase (match-string 3))
1500 (case-fold-search reftex-index-phrases-case-fold-search)
1501 (re (reftex-index-phrases-find-dup-re phrase t)))
1502 (if (save-excursion
1503 (goto-char (point-min))
1504 (and (re-search-forward re nil t)
1505 (re-search-forward re nil t)))
1506 (throw 'exit t)))))
1507 (progn
1508 (reftex-index-phrases-info)
1509 (message "Phrase with match conflict discovered"))
1510 (goto-char (point-max))
1511 (error "No further problematic phrases found")))
1512
1513 (defun reftex-index-phrases-info ()
1514 "Display information about the phrase at point."
1515 (interactive)
1516 (save-excursion
1517 (beginning-of-line)
1518 (unless (looking-at reftex-index-phrases-phrase-regexp12)
1519 (error "Not a phrase line"))
1520 (save-match-data (reftex-index-phrases-parse-header t))
1521 (let* ((char (if (not (equal (match-string 1) ""))
1522 (string-to-char (match-string 1))))
1523 (phrase (match-string 3))
1524 (index-key (match-string 6))
1525 (index-keys (split-string
1526 (or index-key phrase)
1527 reftex-index-phrases-logical-or-regexp))
1528 (macro-data (cdr (if (null char)
1529 (car reftex-index-phrases-macro-data)
1530 (assoc char reftex-index-phrases-macro-data))))
1531 (macro-fmt (car macro-data))
1532 (repeat (nth 1 macro-data))
1533 (as-words reftex-index-phrases-search-whole-words)
1534 (example (reftex-index-make-replace-string
1535 macro-fmt (downcase phrase) (car index-keys) repeat))
1536 (re (reftex-index-make-phrase-regexp phrase as-words t))
1537 (re1 (reftex-index-phrases-find-dup-re phrase))
1538 (re2 (reftex-index-phrases-find-dup-re phrase 'sub))
1539 superphrases
1540 (nmatches 0)
1541 (ntimes1 0)
1542 (ntimes2 0)
1543 (case-fold-search reftex-index-phrases-case-fold-search)
1544 file files buf)
1545 (setq files reftex-index-phrases-files)
1546 (save-excursion
1547 (save-restriction
1548 (widen)
1549 (goto-char (point-min))
1550 (while (re-search-forward re1 nil t)
1551 (incf ntimes1))
1552 (goto-char (point-min))
1553 (while (re-search-forward re2 nil t)
1554 (push (cons (count-lines 1 (point)) (match-string 1)) superphrases)
1555 (incf ntimes2))))
1556 (save-excursion
1557 (while (setq file (pop files))
1558 (setq buf (reftex-get-file-buffer-force file))
1559 (when buf
1560 (set-buffer buf)
1561 (save-excursion
1562 (save-restriction
1563 (widen)
1564 (goto-char (point-min))
1565 (let ((case-fold-search reftex-index-phrases-case-fold-search))
1566 (while (re-search-forward re nil t)
1567 (or (reftex-in-comment)
1568 (incf nmatches)))))))))
1569 (with-output-to-temp-buffer "*Help*"
1570 (princ (format " Phrase: %s\n" phrase))
1571 (princ (format " Macro key: %s\n" char))
1572 (princ (format " Macro format: %s\n" macro-fmt))
1573 (princ (format " Repeat: %s\n" repeat))
1574 (cond
1575 (index-key
1576 (let ((iks index-keys) (cnt 0) ik)
1577 (while (setq ik (pop iks))
1578 (princ (format "Index entry %d: %s\n" (incf cnt) ik)))))
1579 (repeat
1580 (princ (format " Index entry: %s\n" phrase)))
1581 (t
1582 (princ (format " Index key: <<Given by the match>>\n"))))
1583 (princ (format " Example: %s\n" example))
1584 (terpri)
1585 (princ (format "Total matches: %s in %s\n"
1586 (reftex-number nmatches "match" "es")
1587 (reftex-number (length reftex-index-phrases-files)
1588 "LaTeX file")))
1589 (princ (format " Uniqueness: Phrase occurs %s in phrase buffer\n"
1590 (reftex-number ntimes1 "time")))
1591 (if (> ntimes2 1)
1592 (progn
1593 (princ (format " Superphrases: Phrase matches the following %s in the phrase buffer:\n"
1594 (reftex-number ntimes2 "line")))
1595 (mapcar (lambda(x)
1596 (princ (format " Line %4d: %s\n" (car x) (cdr x))))
1597 (nreverse superphrases))))))))
1598
1599 (defun reftex-index-phrases-set-macro-key ()
1600 "Change the macro key for the current line.
1601 Prompts for a macro key and insert is at the beginning of the line.
1602 If you reply with SPACE, the macro keyn will be removed, so that the
1603 default macro will be used. If you reply with `RET', just prints
1604 information about the currently selected macro."
1605 (interactive)
1606 (reftex-index-phrases-parse-header)
1607 (save-excursion
1608 (beginning-of-line)
1609 (unless (or (looking-at reftex-index-phrases-phrase-regexp12)
1610 (looking-at "\t"))
1611 (error "This is not a phrase line"))
1612 (let* ((nc (reftex-index-select-phrases-macro 0))
1613 (macro-data (assoc nc reftex-index-phrases-macro-data))
1614 macro-fmt repeat)
1615 (cond (macro-data)
1616 ((equal nc ?\ )
1617 (setq nc ""
1618 macro-data (car reftex-index-phrases-macro-data)))
1619 ((equal nc ?\C-m)
1620 (setq nc (char-after (point)))
1621 (if (equal nc ?\t)
1622 (setq nc ""
1623 macro-data (car reftex-index-phrases-macro-data))
1624 (setq macro-data (assoc nc reftex-index-phrases-macro-data))))
1625 (t (error "No macro associated with %c" nc)))
1626
1627 (setq macro-fmt (nth 1 macro-data)
1628 repeat (nth 2 macro-data))
1629 (if macro-data
1630 (progn
1631 (if (looking-at "[^\t]") (delete-char 1))
1632 (insert nc)
1633 (message "Line will use %s %s repeat" macro-fmt
1634 (if repeat "with" "without")))
1635 (error "Abort")))))
1636
1637 (defun reftex-index-sort-phrases (&optional chars-first)
1638 "Sort the phrases lines in the buffer alphabetically.
1639 Normally, this looks only at the phrases. With a prefix arg CHARS-FIRST,
1640 it first compares the macro identifying chars and then the phrases."
1641 (interactive "P")
1642 ;; Remember the current line, so that we can return
1643 (let ((line (buffer-substring (progn (beginning-of-line) (point))
1644 (progn (end-of-line) (point))))
1645 beg end)
1646 (goto-char (point-min))
1647 ;; Find first and last phrase line in buffer
1648 (setq beg
1649 (and (re-search-forward reftex-index-phrases-phrase-regexp12 nil t)
1650 (match-beginning 0)))
1651 (goto-char (point-max))
1652 (setq end (re-search-backward reftex-index-phrases-phrase-regexp12 nil t))
1653 (if end (setq end (progn (goto-char end) (end-of-line) (point))))
1654 ;; Take the lines, sort them and re-insert.
1655 (if (and beg end)
1656 (progn
1657 (message "Sorting lines...")
1658 (let* ((lines (split-string (buffer-substring beg end) "\n"))
1659 (lines1 (sort lines 'reftex-compare-phrase-lines)))
1660 (message "Sorting lines...done")
1661 (let ((inhibit-quit t)) ;; make sure we do not loose lines
1662 (delete-region beg end)
1663 (insert (mapconcat 'identity lines1 "\n"))))
1664 (goto-char (point-max))
1665 (re-search-backward (concat "^" (regexp-quote line) "$") nil t))
1666 (error "Cannot find phrases lines to sort"))))
1667
1668 (defvar chars-first)
1669 (defun reftex-compare-phrase-lines (a b)
1670 "The comparison function used for sorting."
1671 (let (ca cb pa pb c-p p-p)
1672 (if (string-match reftex-index-phrases-phrase-regexp12 a)
1673 (progn
1674 ;; Extract macro char and phrase-or-key for a
1675 (setq ca (match-string 1 a)
1676 pa (downcase
1677 (or (and reftex-index-phrases-sort-prefers-entry
1678 (match-string 6 a))
1679 (match-string 3 a))))
1680 (if (string-match reftex-index-phrases-phrase-regexp12 b)
1681 (progn
1682 ;; Extract macro char and phrase-or-key for b
1683 (setq cb (match-string 1 b)
1684 pb (downcase
1685 (or (and reftex-index-phrases-sort-prefers-entry
1686 (match-string 6 b))
1687 (match-string 3 b))))
1688 (setq c-p (string< ca cb)
1689 p-p (string< pa pb))
1690 ;; Do the right comparison, based on the value of `chars-first'
1691 ;; `chars-first' is bound locally in the calling function
1692 (if chars-first
1693 (if (string= ca cb) p-p c-p)
1694 (if (string= pa pb) c-p p-p)))))
1695 ;; If line a does not match, the answer we return determines
1696 ;; if non-matching lines are collected at the beginning.
1697 ;; When we return t here, non-matching lines form
1698 ;; block separators for searches.
1699 (not reftex-index-phrases-sort-in-blocks))))
1700
1701 (defvar reftex-index-phrases-menu)
1702 (defun reftex-index-make-phrase-regexp (phrase &optional
1703 as-words allow-newline)
1704 "Return a regexp matching PHRASE, even if distributed over lines.
1705 With optional arg AS-WORDS, require word boundary at beginning and end.
1706 With optional arg ALLOW-NEWLINE, allow single newline between words."
1707 (let* ((words (split-string phrase))
1708 (space-re (if allow-newline
1709 "\\([ \t]*\\(\n[ \t]*\\)?\\|[ \t]\\)"
1710 "\\([ \t]+\\)")))
1711 (concat (if (and as-words (string-match "\\`\\w" (car words)))
1712 "\\<" "")
1713 (mapconcat (lambda (w) (regexp-quote (downcase w)))
1714 words space-re)
1715 (if (and as-words
1716 (string-match "\\w\\'" (nth (1- (length words)) words)))
1717 "\\>" ""))))
1718
1719 (defun reftex-index-simplify-phrase (phrase)
1720 "Make phrase single spaces and single line."
1721 (mapconcat 'identity (split-string phrase) " "))
1722
1723 (defun reftex-index-phrases-find-dup-re (phrase &optional sub)
1724 "Return a regexp which matches variations of PHRASE (with additional space).
1725 When SUB ins non-nil, the regexp will also match when PHRASE is a subphrase
1726 of another phrase. The regexp works lonly in the phrase buffer."
1727 (concat (if sub "^\\S-?\t\\([^\t\n]*" "^\\S-?\t")
1728 (mapconcat 'regexp-quote (split-string phrase) " +")
1729 (if sub "[^\t\n]*\\)\\([\t\n]\\|$\\)" " *\\([\t\n]\\|$\\)")))
1730
1731 (defun reftex-index-make-replace-string (macro-fmt match index-key
1732 &optional repeat mathp)
1733 "Return the string which can be used as replacement.
1734 Treats the logical `and' for index phrases."
1735 (let ((index-keys (split-string (or index-key match)
1736 reftex-index-phrases-logical-and-regexp)))
1737 (concat
1738 (mapconcat (lambda (x)
1739 (format macro-fmt
1740 (format (if mathp reftex-index-math-format "%s") x)))
1741 index-keys "")
1742 (if repeat (reftex-index-simplify-phrase match) ""))))
1743
1744 (defun reftex-query-index-phrase-globally (files &rest args)
1745 "Call `reftex-query-index-phrase' for all files in FILES."
1746 (let ((win-conf (current-window-configuration))
1747 (file))
1748 (unless files (error "No files"))
1749 (unwind-protect
1750 (progn
1751 (switch-to-buffer-other-window (reftex-get-file-buffer-force
1752 (car files)))
1753 (catch 'no-more-files
1754 (while (setq file (pop files))
1755 (switch-to-buffer (reftex-get-file-buffer-force file))
1756 (save-excursion
1757 (save-restriction
1758 (unless (stringp reftex-index-phrases-restrict-file)
1759 (widen))
1760 (goto-char (point-min))
1761 (apply 'reftex-query-index-phrase args))))))
1762 (reftex-unhighlight 0)
1763 (set-window-configuration win-conf))))
1764
1765 (defconst reftex-index-phrases-help
1766 " Keys for query-index search
1767 ===========================
1768 y Replace this match
1769 n Skip this match
1770 ! Replace this and all further matches in this file
1771 q / Q Skip match, start next file / start next phrase
1772 o Use a different indexing macro for this match
1773 1 - 9 Select one of the multiple phrases
1774 e Edit the replacement text
1775 C-r Recursive edit.
1776 s / S Save this buffer / Save all document buffers
1777 C-g Abort"
1778 "The help string for indexing phrases.")
1779
1780 (defvar replace-count)
1781 (defun reftex-query-index-phrase (phrase macro-fmt &optional
1782 index-key repeat as-words)
1783 "Search through buffer for PHRASE, and offer to replace it with an indexed
1784 version. The index version is derived by applying `format' with MACRO-FMT
1785 to INDEX-KEY or PHRASE. When REPEAT is non-nil, the PHRASE is inserted
1786 again after the macro.
1787 AS-WORDS means, the search for PHRASE should require word boundaries at
1788 both ends."
1789 (let* ((re (reftex-index-make-phrase-regexp phrase as-words 'allow-newline))
1790 (case-fold-search reftex-index-phrases-case-fold-search)
1791 (index-keys (split-string
1792 (or index-key phrase)
1793 reftex-index-phrases-logical-or-regexp))
1794 (nkeys (length index-keys))
1795 (ckey (nth 0 index-keys))
1796 (all-yes nil)
1797 match rpl char beg end mathp)
1798 (unwind-protect
1799 (while (re-search-forward re nil t)
1800 (catch 'next-match
1801 (setq match (match-string 0))
1802 (setq mathp
1803 (save-match-data
1804 (condition-case nil (texmathp) (error nil))))
1805 (setq beg (car (match-data))
1806 end (nth 1 (match-data)))
1807 (if (and reftex-index-phrases-skip-indexed-matches
1808 (save-match-data
1809 (reftex-index-phrase-match-is-indexed beg
1810 end)))
1811 (throw 'next-match nil))
1812 (reftex-highlight 0 (match-beginning 0) (match-end 0))
1813 (setq rpl
1814 (save-match-data
1815 (reftex-index-make-replace-string
1816 macro-fmt (match-string 0) ckey repeat mathp)))
1817 (while
1818 (not
1819 (catch 'loop
1820 (message "REPLACE: %s? (yn!qoe%s?)"
1821 rpl
1822 (if (> nkeys 1)
1823 (concat "1-" (int-to-string nkeys))
1824 ""))
1825 (setq char (if all-yes ?y (read-char-exclusive)))
1826 (cond ((member char '(?y ?Y ?\ ))
1827 ;; Yes!
1828 (replace-match rpl t t)
1829 (incf replace-count)
1830 ;; See if we should insert newlines to shorten lines
1831 (and reftex-index-phrases-wrap-long-lines
1832 (reftex-index-phrases-fixup-line beg end))
1833 (throw 'loop t))
1834 ((member char '(?n ?N ?\C-h ?\C-?));; FIXME: DEL
1835 ;; No
1836 (throw 'loop t))
1837 ((equal char ?!)
1838 ;; Yes for all in this buffer
1839 (setq all-yes t))
1840 ((equal char ?q)
1841 ;; Stop this one in this file
1842 (goto-char (point-max))
1843 (throw 'loop t))
1844 ((equal char ?Q)
1845 ;; Stop this one
1846 (throw 'no-more-files t))
1847 ((equal char ?s)
1848 (save-buffer))
1849 ((equal char ?S)
1850 (reftex-save-all-document-buffers))
1851 ((equal char ?\C-g)
1852 (keyboard-quit))
1853 ((member char '(?o ?O))
1854 ;; Select a differnt macro
1855 (let* ((nc (reftex-index-select-phrases-macro 2))
1856 (macro-data
1857 (cdr (assoc nc reftex-index-phrases-macro-data)))
1858 (macro-fmt (car macro-data))
1859 (repeat (nth 1 macro-data)))
1860 (if macro-data
1861 (setq rpl (save-match-data
1862 (reftex-index-make-replace-string
1863 macro-fmt match
1864 ckey repeat mathp)))
1865 (ding))))
1866 ((equal char ?\?)
1867 ;; Help
1868 (with-output-to-temp-buffer "*Help*"
1869 (princ reftex-index-phrases-help)))
1870 ((equal char ?\C-r)
1871 ;; Recursive edit
1872 (save-match-data
1873 (save-excursion
1874 (message
1875 (substitute-command-keys
1876 "Recursive edit. Resume with \\[exit-recursive-edit]"))
1877 (recursive-edit))))
1878 ((equal char ?e)
1879 (setq rpl (read-string "Edit: " rpl)))
1880 ((equal char ?0)
1881 (setq ckey (or index-key phrase)
1882 rpl (save-match-data
1883 (reftex-index-make-replace-string
1884 macro-fmt match ckey repeat mathp))))
1885 ((and (> char ?0)
1886 (<= char (+ ?0 nkeys)))
1887 (setq ckey (nth (1- (- char ?0)) index-keys)
1888 rpl (save-match-data
1889 (reftex-index-make-replace-string
1890 macro-fmt match ckey repeat mathp))))
1891 (t (ding)))
1892 nil)))))
1893 (message "")
1894 (setq all-yes nil)
1895 (reftex-unhighlight 0))))
1896
1897 (defun reftex-index-phrase-match-is-indexed (beg end)
1898 (save-excursion
1899 (goto-char end)
1900 (let* ((this-macro (car (reftex-what-macro 1)))
1901 (before-char (char-before beg))
1902 (after-char (char-after end))
1903 (before-macro
1904 (and (> beg 2)
1905 (goto-char (1- beg))
1906 (memq (char-after (point)) '(?\] ?\}))
1907 (car (reftex-what-macro 1))))
1908 (after-macro
1909 (and (goto-char end)
1910 (looking-at "\\(\\\\[a-zA-Z]+\\*?\\)[[{]")
1911 (match-string 1))))
1912 (or (and this-macro
1913 (member before-char '(?\{ ?\[))
1914 (member after-char '(?\} ?\]))
1915 (member this-macro reftex-macros-with-index))
1916 (and before-macro
1917 (member before-macro reftex-macros-with-index))
1918 (and after-macro
1919 (member after-macro reftex-macros-with-index))))))
1920
1921
1922 (defun reftex-index-phrases-fixup-line (beg end)
1923 "Insert newlines before BEG and/or after END to shorten line."
1924 (let (bol eol space1 space2)
1925 (save-excursion
1926 ;; Find line boundaries and possible line breaks near BEG and END
1927 (beginning-of-line)
1928 (setq bol (point))
1929 (end-of-line)
1930 (setq eol (point))
1931 (goto-char beg)
1932 (skip-chars-backward "^ \n")
1933 (if (and (equal (preceding-char) ?\ )
1934 (string-match "\\S-" (buffer-substring bol (point))))
1935 (setq space1 (1- (point))))
1936 (goto-char end)
1937 (skip-chars-forward "^ \n")
1938 (if (and (equal (following-char) ?\ )
1939 (string-match "\\S-" (buffer-substring (point) eol)))
1940 (setq space2 (point)))
1941 ;; Now check what we have and insert the newlines
1942 (if (<= (- eol bol) fill-column)
1943 ;; Line is already short
1944 nil
1945 (cond
1946 ((and (not space1) (not space2))) ; No spaces available
1947 ((not space2) ; Do space1
1948 (reftex-index-phrases-replace-space space1))
1949 ((not space1) ; Do space2
1950 (reftex-index-phrases-replace-space space2))
1951 (t ; We have both spaces
1952 (let ((l1 (- space1 bol))
1953 (l2 (- space2 space1))
1954 (l3 (- eol space2)))
1955 (if (> l2 fill-column)
1956 ;; The central part alone is more than one line
1957 (progn
1958 (reftex-index-phrases-replace-space space1)
1959 (reftex-index-phrases-replace-space space2))
1960 (if (> (+ l1 l2) fill-column)
1961 ;; Need to split beginning
1962 (reftex-index-phrases-replace-space space1))
1963 (if (> (+ l2 l3) fill-column)
1964 ;; Need to split end
1965 (reftex-index-phrases-replace-space space2))))))))))
1966
1967 (defun reftex-index-phrases-replace-space (pos)
1968 "If there is a space at POS, replace it with a newline char.
1969 Does not do a save-excursion."
1970 (when (equal (char-after pos) ?\ )
1971 (goto-char pos)
1972 (delete-char 1)
1973 (insert "\n")))
1974
1975 (defun reftex-index-select-phrases-macro (&optional delay)
1976 "Offer a list of possible index macros and have the user select one."
1977 (let* ((prompt (concat "Select macro: ["
1978 (mapconcat (lambda (x) (char-to-string (car x)))
1979 reftex-index-phrases-macro-data "")
1980 "] "))
1981 (help (concat "Select an indexing macro\n========================\n"
1982 (mapconcat (lambda (x)
1983 (format " [%c] %s"
1984 (car x) (nth 1 x)))
1985 reftex-index-phrases-macro-data "\n"))))
1986 (reftex-select-with-char prompt help delay)))
1987
1988 ;; Keybindings and Menu for phrases buffer
1989
1990 (loop for x in
1991 '(("\C-c\C-c" . reftex-index-phrases-save-and-return)
1992 ("\C-c\C-x" . reftex-index-this-phrase)
1993 ("\C-c\C-f" . reftex-index-next-phrase)
1994 ("\C-c\C-r" . reftex-index-region-phrases)
1995 ("\C-c\C-a" . reftex-index-all-phrases)
1996 ("\C-c\C-d" . reftex-index-remaining-phrases)
1997 ("\C-c\C-s" . reftex-index-sort-phrases)
1998 ("\C-c\C-n" . reftex-index-new-phrase)
1999 ("\C-c\C-m" . reftex-index-phrases-set-macro-key)
2000 ("\C-c\C-i" . reftex-index-phrases-info)
2001 ("\C-c\C-t" . reftex-index-find-next-conflict-phrase)
2002 ("\C-i" . self-insert-command))
2003 do (define-key reftex-index-phrases-map (car x) (cdr x)))
2004
2005 (easy-menu-define
2006 reftex-index-phrases-menu reftex-index-phrases-map
2007 "Menu for Phrases buffer"
2008 '("Phrases"
2009 ["New Phrase" reftex-index-new-phrase t]
2010 ["Set Phrase Macro" reftex-index-phrases-set-macro-key t]
2011 ["Recreate File Header" reftex-index-initialize-phrases-buffer t]
2012 "--"
2013 ("Sort Phrases"
2014 ["Sort" reftex-index-sort-phrases t]
2015 "--"
2016 "Sort Options"
2017 ["by Search Phrase" (setq reftex-index-phrases-sort-prefers-entry nil)
2018 :style radio :selected (not reftex-index-phrases-sort-prefers-entry)]
2019 ["by Index Entry" (setq reftex-index-phrases-sort-prefers-entry t)
2020 :style radio :selected reftex-index-phrases-sort-prefers-entry]
2021 ["in Blocks" (setq reftex-index-phrases-sort-in-blocks
2022 (not reftex-index-phrases-sort-in-blocks))
2023 :style toggle :selected reftex-index-phrases-sort-in-blocks])
2024 ["Describe Phrase" reftex-index-phrases-info t]
2025 ["Next Phrase Conflict" reftex-index-find-next-conflict-phrase t]
2026 "--"
2027 ("Find and Index in Document"
2028 ["Current Phrase" reftex-index-this-phrase t]
2029 ["Next Phrase" reftex-index-next-phrase t]
2030 ["Current and Following" reftex-index-remaining-phrases t]
2031 ["Region Phrases" reftex-index-region-phrases t]
2032 ["All Phrases" reftex-index-all-phrases t]
2033 "--"
2034 "Options"
2035 ["Match Whole Words" (setq reftex-index-phrases-search-whole-words
2036 (not reftex-index-phrases-search-whole-words))
2037 :style toggle :selected reftex-index-phrases-search-whole-words]
2038 ["Case Sensitive Search" (setq reftex-index-phrases-case-fold-search
2039 (not reftex-index-phrases-case-fold-search))
2040 :style toggle :selected (not
2041 reftex-index-phrases-case-fold-search)]
2042 ["Wrap Long Lines" (setq reftex-index-phrases-wrap-long-lines
2043 (not reftex-index-phrases-wrap-long-lines))
2044 :style toggle :selected reftex-index-phrases-wrap-long-lines]
2045 ["Skip Indexed Matches" (setq reftex-index-phrases-skip-indexed-matches
2046 (not reftex-index-phrases-skip-indexed-matches))
2047 :style toggle :selected reftex-index-phrases-skip-indexed-matches])
2048 "--"
2049 ["Save and Return" reftex-index-phrases-save-and-return t]))
2050
2051
1220 ;;; reftex-index.el ends here 2052 ;;; reftex-index.el ends here