reftex-global.el 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  1. ;;; reftex-global.el --- operations on entire documents with RefTeX
  2. ;; Copyright (C) 1997-2012 Free Software Foundation, Inc.
  3. ;; Author: Carsten Dominik <dominik@science.uva.nl>
  4. ;; Maintainer: auctex-devel@gnu.org
  5. ;; Version: 4.31
  6. ;; Package: reftex
  7. ;; This file is part of GNU Emacs.
  8. ;; GNU Emacs is free software: you can redistribute it and/or modify
  9. ;; it under the terms of the GNU General Public License as published by
  10. ;; the Free Software Foundation, either version 3 of the License, or
  11. ;; (at your option) any later version.
  12. ;; GNU Emacs is distributed in the hope that it will be useful,
  13. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. ;; GNU General Public License for more details.
  16. ;; You should have received a copy of the GNU General Public License
  17. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
  18. ;;; Commentary:
  19. ;;; Code:
  20. (eval-when-compile (require 'cl))
  21. (provide 'reftex-global)
  22. (require 'reftex)
  23. ;;;
  24. (defun reftex-create-tags-file ()
  25. "Create TAGS file by running `etags' on the current document.
  26. The TAGS file is also immediately visited with `visit-tags-table'."
  27. (interactive)
  28. (reftex-access-scan-info current-prefix-arg)
  29. (let* ((master (reftex-TeX-master-file))
  30. (files (reftex-all-document-files))
  31. (cmd (format "etags %s" (mapconcat 'shell-quote-argument
  32. files " "))))
  33. (with-current-buffer (reftex-get-file-buffer-force master)
  34. (message "Running etags to create TAGS file...")
  35. (shell-command cmd)
  36. (visit-tags-table "TAGS"))))
  37. ;; History of grep commands.
  38. (defvar reftex-grep-history nil)
  39. (defvar reftex-grep-command "grep -n "
  40. "Last grep command used in \\[reftex-grep-document]; default for next grep.")
  41. (defun reftex-grep-document (grep-cmd)
  42. "Run grep query through all files related to this document.
  43. With prefix arg, force to rescan document.
  44. No active TAGS table is required."
  45. (interactive
  46. (list (read-from-minibuffer "Run grep on document (like this): "
  47. reftex-grep-command nil nil
  48. 'reftex-grep-history)))
  49. (reftex-access-scan-info current-prefix-arg)
  50. (let* ((files (reftex-all-document-files t))
  51. (cmd (format
  52. "%s %s" grep-cmd
  53. (mapconcat 'identity files " "))))
  54. (grep cmd)))
  55. (defun reftex-search-document (&optional regexp)
  56. "Regexp search through all files of the current document.
  57. Starts always in the master file. Stops when a match is found.
  58. To continue searching for next match, use command \\[tags-loop-continue].
  59. No active TAGS table is required."
  60. (interactive)
  61. (let ((default (reftex-this-word)))
  62. (unless regexp
  63. (setq regexp (read-string (format "Search regexp in document [%s]: "
  64. default))))
  65. (if (string= regexp "") (setq regexp (regexp-quote default)))
  66. (reftex-access-scan-info current-prefix-arg)
  67. (tags-search regexp (list 'reftex-all-document-files))))
  68. (defun reftex-query-replace-document (&optional from to delimited)
  69. "Do `query-replace-regexp' of FROM with TO over the entire document.
  70. Third arg DELIMITED (prefix arg) means replace only word-delimited matches.
  71. If you exit (\\[keyboard-quit], RET or q), you can resume the query replace
  72. with the command \\[tags-loop-continue].
  73. No active TAGS table is required."
  74. (interactive)
  75. (let ((default (reftex-this-word)))
  76. (unless from
  77. (setq from (read-string (format "Replace regexp in document [%s]: "
  78. default)))
  79. (if (string= from "") (setq from (regexp-quote default))))
  80. (unless to
  81. (setq to (read-string (format "Replace regexp %s with: " from))))
  82. (reftex-access-scan-info current-prefix-arg)
  83. (tags-query-replace from to (or delimited current-prefix-arg)
  84. (list 'reftex-all-document-files))))
  85. (defvar TeX-master)
  86. (defvar isearch-next-buffer-function)
  87. (defun reftex-find-duplicate-labels ()
  88. "Produce a list of all duplicate labels in the document."
  89. (interactive)
  90. ;; Rescan the document to make sure
  91. (reftex-access-scan-info t)
  92. (let ((master (reftex-TeX-master-file))
  93. (cnt 0)
  94. (dlist
  95. (mapcar
  96. (lambda (x)
  97. (let (x1)
  98. (cond
  99. ((memq (car x)
  100. '(toc bof eof bib thebib label-numbers xr xr-doc
  101. master-dir file-error bibview-cache appendix
  102. is-multi index))
  103. nil)
  104. (t
  105. (setq x1 (reftex-all-assoc-string
  106. (car x) (symbol-value reftex-docstruct-symbol)))
  107. (if (< 1 (length x1))
  108. (append (list (car x))
  109. (mapcar (lambda(x)
  110. (abbreviate-file-name (nth 3 x)))
  111. x1))
  112. (list nil))))))
  113. (reftex-uniquify-by-car (symbol-value reftex-docstruct-symbol)))))
  114. (setq dlist (reftex-uniquify-by-car dlist))
  115. (if (null dlist) (error "No duplicate labels in document"))
  116. (switch-to-buffer-other-window "*Duplicate Labels*")
  117. (set (make-local-variable 'TeX-master) master)
  118. (erase-buffer)
  119. (insert " MULTIPLE LABELS IN CURRENT DOCUMENT:\n")
  120. (insert
  121. " Move point to label and type `r' to run a query-replace on the label\n"
  122. " and its references. Type `q' to exit this buffer.\n\n")
  123. (insert " LABEL FILE\n")
  124. (insert " -------------------------------------------------------------\n")
  125. (use-local-map (make-sparse-keymap))
  126. (local-set-key [?q] (lambda () "Kill this buffer." (interactive)
  127. (kill-buffer (current-buffer)) (delete-window)))
  128. (local-set-key [?r] 'reftex-change-label)
  129. (while dlist
  130. (when (and (car (car dlist))
  131. (cdr (car dlist)))
  132. (incf cnt)
  133. (insert (mapconcat 'identity (car dlist) "\n ") "\n"))
  134. (pop dlist))
  135. (goto-char (point-min))
  136. (when (= cnt 0)
  137. (kill-buffer (current-buffer))
  138. (delete-window)
  139. (message "Document does not contain duplicate labels."))))
  140. (defun reftex-change-label (&optional from to)
  141. "Run `query-replace-regexp' of FROM with TO in all macro arguments.
  142. Works on the entire multifile document.
  143. If you exit (\\[keyboard-quit], RET or q), you can resume the query replace
  144. with the command \\[tags-loop-continue].
  145. No active TAGS table is required."
  146. (interactive)
  147. (let ((default (reftex-this-word "-a-zA-Z0-9_*.:")))
  148. (unless from
  149. (setq from (read-string (format "Replace label globally [%s]: "
  150. default))))
  151. (if (string= from "") (setq from default))
  152. (unless to
  153. (setq to (read-string (format "Replace label %s with: "
  154. from))))
  155. (reftex-query-replace-document
  156. (concat "{" (regexp-quote from) "}")
  157. (format "{%s}" to))))
  158. (defun reftex-renumber-simple-labels ()
  159. "Renumber all simple labels in the document to make them sequentially.
  160. Simple labels are the ones created by RefTeX, consisting only of the
  161. prefix and a number. After the command completes, all these labels will
  162. have sequential numbers throughout the document. Any references to
  163. the labels will be changed as well. For this, RefTeX looks at the
  164. arguments of any macros which either start or end in the string `ref'.
  165. This command should be used with care, in particular in multifile
  166. documents. You should not use it if another document refers to this
  167. one with the `xr' package."
  168. (interactive)
  169. ;; Rescan the entire document
  170. (reftex-access-scan-info 1)
  171. ;; Get some insurance
  172. (if (and (reftex-is-multi)
  173. (not (yes-or-no-p "Replacing all simple labels in multiple files is risky. Continue? ")))
  174. (error "Abort"))
  175. ;; Make the translation list
  176. (let* ((re-core (concat "\\("
  177. (mapconcat 'cdr reftex-typekey-to-prefix-alist "\\|")
  178. "\\)"))
  179. (label-re (concat "\\`" re-core "\\([0-9]+\\)\\'"))
  180. (search-re (concat "[{,]\\(" re-core "\\([0-9]+\\)\\)[,}]"))
  181. (error-fmt "Undefined label or reference %s. Ignore and continue? ")
  182. (label-numbers-alist (mapcar (lambda (x) (cons (cdr x) 0))
  183. reftex-typekey-to-prefix-alist))
  184. (files (reftex-all-document-files))
  185. (list (symbol-value reftex-docstruct-symbol))
  186. translate-alist n entry label new-label nr-cell changed-sequence)
  187. (while (setq entry (pop list))
  188. (when (and (stringp (car entry))
  189. (string-match label-re (car entry)))
  190. (setq label (car entry)
  191. nr-cell (assoc (match-string 1 (car entry))
  192. label-numbers-alist))
  193. (if (assoc label translate-alist)
  194. (error "Duplicate label %s" label))
  195. (setq new-label (concat (match-string 1 (car entry))
  196. (int-to-string (incf (cdr nr-cell)))))
  197. (push (cons label new-label) translate-alist)
  198. (or (string= label new-label) (setq changed-sequence t))))
  199. (unless changed-sequence
  200. (error "Simple labels are already in correct sequence"))
  201. (reftex-ensure-write-access (reftex-all-document-files))
  202. ;; Save all document buffers before this operation
  203. (reftex-save-all-document-buffers)
  204. ;; First test to check for errors.
  205. (setq n (reftex-translate
  206. files search-re translate-alist error-fmt 'test))
  207. ;; Now the real thing.
  208. (if (yes-or-no-p
  209. (format "Replace %d items at %d places in %d files? "
  210. (length translate-alist) n (length files)))
  211. (progn
  212. (let ((inhibit-quit t)) ;; Do not disturb...
  213. (reftex-translate
  214. files search-re translate-alist error-fmt nil)
  215. (setq quit-flag nil))
  216. (if (and (reftex-is-multi)
  217. (yes-or-no-p "Save entire document? "))
  218. (reftex-save-all-document-buffers))
  219. ;; Rescan again...
  220. (reftex-access-scan-info 1)
  221. (message "Done replacing simple labels."))
  222. (message "No replacements done"))))
  223. (defun reftex-translate (files search-re translate-alist error-fmt test)
  224. ;; In FILES, look for SEARCH-RE and replace match 1 of it with
  225. ;; its association in TRANSLATE-ALIST.
  226. ;; If we do not find an association and TEST is non-nil, query
  227. ;; to ignore the problematic string.
  228. ;; If TEST is nil, it is ignored without query.
  229. ;; Return the number of replacements.
  230. (let ((n 0) file label match-data buf macro pos cell)
  231. (while (setq file (pop files))
  232. (setq buf (reftex-get-file-buffer-force file))
  233. (unless buf
  234. (error "No such file %s" file))
  235. (set-buffer buf)
  236. (save-excursion
  237. (save-restriction
  238. (widen)
  239. (goto-char (point-min))
  240. (while (re-search-forward search-re nil t)
  241. (backward-char)
  242. (save-excursion
  243. (setq label (reftex-match-string 1)
  244. cell (assoc label translate-alist)
  245. match-data (match-data)
  246. macro (reftex-what-macro 1)
  247. pos (cdr macro))
  248. (goto-char (or pos (point)))
  249. (when (and macro
  250. (or (looking-at "\\\\ref")
  251. (looking-at "\\\\[a-zA-Z]*ref\\(range\\)?[^a-zA-Z]")
  252. (looking-at "\\\\ref[a-zA-Z]*[^a-zA-Z]")
  253. (looking-at (format
  254. reftex-find-label-regexp-format
  255. (regexp-quote label)))))
  256. ;; OK, we should replace it.
  257. (set-match-data match-data)
  258. (cond
  259. ((and test (not cell))
  260. ;; We've got a problem
  261. (unwind-protect
  262. (progn
  263. (reftex-highlight 1 (match-beginning 0) (match-end 0))
  264. (ding)
  265. (or (y-or-n-p (format error-fmt label))
  266. (error "Abort")))
  267. (reftex-unhighlight 1)))
  268. ((and test cell)
  269. (incf n))
  270. ((and (not test) cell)
  271. ;; Replace
  272. (goto-char (match-beginning 1))
  273. (delete-region (match-beginning 1) (match-end 1))
  274. (insert (cdr cell)))
  275. (t nil))))))))
  276. n))
  277. (defun reftex-save-all-document-buffers ()
  278. "Save all documents associated with the current document.
  279. The function is useful after a global action like replacing or renumbering
  280. labels."
  281. (interactive)
  282. (let ((files (reftex-all-document-files))
  283. file buffer)
  284. (save-current-buffer
  285. (while (setq file (pop files))
  286. (setq buffer (reftex-get-buffer-visiting file))
  287. (when buffer
  288. (set-buffer buffer)
  289. (save-buffer))))))
  290. (defun reftex-ensure-write-access (files)
  291. "Make sure we have write access to all files in FILES.
  292. Also checks if buffers visiting the files are in read-only mode."
  293. (let (file buf)
  294. (while (setq file (pop files))
  295. (unless (file-exists-p file)
  296. (ding)
  297. (or (y-or-n-p (format "No such file %s. Continue? " file))
  298. (error "Abort")))
  299. (unless (file-writable-p file)
  300. (ding)
  301. (or (y-or-n-p (format "No write access to %s. Continue? " file))
  302. (error "Abort")))
  303. (when (and (setq buf (reftex-get-buffer-visiting file))
  304. (with-current-buffer buf
  305. buffer-read-only))
  306. (ding)
  307. (or (y-or-n-p (format "Buffer %s is read-only. Continue? "
  308. (buffer-name buf)))
  309. (error "Abort"))))))
  310. ;;; Multi-file RefTeX Isearch
  311. ;; `reftex-isearch-wrap-function', `reftex-isearch-push-state-function',
  312. ;; `reftex-isearch-pop-state-function', `reftex-isearch-isearch-search'
  313. ;; functions remain here only for backward-compatibility with Emacs 22
  314. ;; and are obsolete since Emacs 23 that supports a single function
  315. ;; variable `multi-isearch-next-buffer-function'.
  316. (defun reftex-isearch-wrap-function ()
  317. (if (not isearch-word)
  318. (switch-to-buffer
  319. (funcall isearch-next-buffer-function (current-buffer) t)))
  320. (goto-char (if isearch-forward (point-min) (point-max))))
  321. (defun reftex-isearch-push-state-function ()
  322. `(lambda (cmd)
  323. (reftex-isearch-pop-state-function cmd ,(current-buffer))))
  324. (defun reftex-isearch-pop-state-function (cmd buffer)
  325. (switch-to-buffer buffer))
  326. (defun reftex-isearch-isearch-search (string bound noerror)
  327. (let ((nxt-buff nil)
  328. (search-fun
  329. (cond
  330. (isearch-word
  331. (if isearch-forward 'word-search-forward 'word-search-backward))
  332. (isearch-regexp
  333. (if isearch-forward 're-search-forward 're-search-backward))
  334. (t
  335. (if isearch-forward 'search-forward 'search-backward)))))
  336. (or
  337. (funcall search-fun string bound noerror)
  338. (unless bound
  339. (condition-case nil
  340. (when isearch-next-buffer-function
  341. (while (not (funcall search-fun string bound noerror))
  342. (cond
  343. (isearch-forward
  344. (setq nxt-buff
  345. (funcall isearch-next-buffer-function
  346. (current-buffer)))
  347. (if (not nxt-buff)
  348. (progn
  349. (error "Wrap forward"))
  350. (switch-to-buffer nxt-buff)
  351. (goto-char (point-min))))
  352. (t
  353. (setq nxt-buff
  354. (funcall isearch-next-buffer-function
  355. (current-buffer)))
  356. (if (not nxt-buff)
  357. (progn
  358. (error "Wrap backward"))
  359. (switch-to-buffer nxt-buff)
  360. (goto-char (point-max))))))
  361. (point))
  362. (error nil))))))
  363. ;; This function is called when isearch reaches the end of a
  364. ;; buffer. For reftex what we want to do is not wrap to the
  365. ;; beginning, but switch to the next buffer in the logical order of
  366. ;; the document. This function looks through list of files in the
  367. ;; document (reftex-all-document-files), searches for the current
  368. ;; buffer and switches to the next/previous one in the logical order
  369. ;; of the document. If WRAPP is true then wrap the search to the
  370. ;; beginning/end of the file list, depending of the search direction.
  371. (defun reftex-isearch-switch-to-next-file (crt-buf &optional wrapp)
  372. (reftex-access-scan-info)
  373. (let ((cb (buffer-file-name crt-buf))
  374. (flist (reftex-all-document-files)))
  375. (when flist
  376. (if wrapp
  377. (unless isearch-forward
  378. (setq flist (last flist)))
  379. (unless isearch-forward
  380. (setq flist (reverse flist)))
  381. (while (not (string= (car flist) cb))
  382. (setq flist (cdr flist)))
  383. (setq flist (cdr flist)))
  384. (when flist
  385. (find-file-noselect (car flist))))))
  386. ;;;###autoload
  387. (defun reftex-isearch-minor-mode (&optional arg)
  388. "When on, isearch searches the whole document, not only the current file.
  389. This minor mode allows isearch to search through all the files of
  390. the current TeX document.
  391. With no argument, this command toggles
  392. `reftex-isearch-minor-mode'. With a prefix argument ARG, turn
  393. `reftex-isearch-minor-mode' on if ARG is positive, otherwise turn it off."
  394. (interactive "P")
  395. (let ((old-reftex-isearch-minor-mode reftex-isearch-minor-mode))
  396. (setq reftex-isearch-minor-mode
  397. (not (or (and (null arg) reftex-isearch-minor-mode)
  398. (<= (prefix-numeric-value arg) 0))))
  399. (unless (eq reftex-isearch-minor-mode old-reftex-isearch-minor-mode)
  400. (if reftex-isearch-minor-mode
  401. (progn
  402. (dolist (crt-buf (buffer-list))
  403. (with-current-buffer crt-buf
  404. (when reftex-mode
  405. (if (boundp 'multi-isearch-next-buffer-function)
  406. (set (make-local-variable 'multi-isearch-next-buffer-function)
  407. 'reftex-isearch-switch-to-next-file)
  408. (set (make-local-variable 'isearch-wrap-function)
  409. 'reftex-isearch-wrap-function)
  410. (set (make-local-variable 'isearch-search-fun-function)
  411. (lambda () 'reftex-isearch-isearch-search))
  412. (set (make-local-variable 'isearch-push-state-function)
  413. 'reftex-isearch-push-state-function)
  414. (set (make-local-variable 'isearch-next-buffer-function)
  415. 'reftex-isearch-switch-to-next-file))
  416. (setq reftex-isearch-minor-mode t))))
  417. (add-hook 'reftex-mode-hook 'reftex-isearch-minor-mode))
  418. (dolist (crt-buf (buffer-list))
  419. (with-current-buffer crt-buf
  420. (when reftex-mode
  421. (if (boundp 'multi-isearch-next-buffer-function)
  422. (kill-local-variable 'multi-isearch-next-buffer-function)
  423. (kill-local-variable 'isearch-wrap-function)
  424. (kill-local-variable 'isearch-search-fun-function)
  425. (kill-local-variable 'isearch-push-state-function)
  426. (kill-local-variable 'isearch-next-buffer-function))
  427. (setq reftex-isearch-minor-mode nil))))
  428. (remove-hook 'reftex-mode-hook 'reftex-isearch-minor-mode)))
  429. ;; Force modeline redisplay.
  430. (set-buffer-modified-p (buffer-modified-p))))
  431. (add-minor-mode 'reftex-isearch-minor-mode "/I" nil nil
  432. 'reftex-isearch-minor-mode)
  433. ;;; reftex-global.el ends here