summaryrefslogtreecommitdiff
path: root/lisp/textmodes/reftex.el
blob: be9b23677cb011499984398722629d9987e9bf60 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
;;; reftex.el --- minor mode for doing \label, \ref, \cite, \index in LaTeX
;; Copyright (C) 1997-2000, 2003-2021 Free Software Foundation, Inc.

;; Author: Carsten Dominik <dominik@science.uva.nl>
;; Maintainer: auctex-devel@gnu.org
;; Keywords: tex

;; This file is part of GNU Emacs.

;; GNU Emacs is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.

;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.

;;; Commentary:

;; RefTeX is a minor mode with distinct support for \ref, \label, \cite,
;; and \index commands in (multi-file) LaTeX documents.
;; - A table of contents provides easy access to any part of a document.
;; - Labels are created semi-automatically.
;; - Definition context of labels is provided when creating a reference.
;; - Citations are simplified with efficient database lookup.
;; - Text phrases can be collected in a file, for later global indexing.
;; - The index preview buffer helps to check and edit index entries.
;;
;; There is an extensive Texinfo document describing RefTeX in detail.
;; One way to view this documentation is `M-x reftex-info RET'.
;;
;; The documentation in various formats is also available at
;;
;;     https://www.gnu.org/software/auctex/manual/reftex.index.html
;;
;; RefTeX is bundled with Emacs and available as a plug-in package for
;; XEmacs 21.x.  If you need to install it yourself, you can find a
;; distribution at
;;
;;    https://www.gnu.org/software/auctex/reftex.html
;;
;; RefTeX was written by Carsten Dominik <dominik@science.uva.nl> with
;; contributions from Stephen Eglen.  It is currently maintained by
;; the AUCTeX project.

;;; Code:

(eval-when-compile (require 'cl-lib))
(require 'easymenu)

(defvar reftex-tables-dirty t
  "Flag showing if tables need to be re-computed.")

(eval-and-compile
  (defun reftex-set-dirty (symbol value)
    (setq reftex-tables-dirty t)
    (set symbol value)))


;; Configuration variables
(require 'reftex-vars)


;;; Autoloads to ensure loading of support files when necessary
(require 'reftex-loaddefs)

;; We autoload tons of functions from these files, but some have
;; a single function that needs to be globally autoloaded.
;; The alternative is to use a Makefile rule + distinct autoload
;; cookie (eg ;;;###reftex-autoload) for internal autoloads,
;; as eg calendar/ does.  But that seemed like overkill for 4 functions.

;;;###autoload(autoload 'reftex-citation "reftex-cite" nil t)
;;;###autoload(autoload 'reftex-all-document-files "reftex-parse")
;;;###autoload(autoload 'reftex-isearch-minor-mode "reftex-global" nil t)
;;;###autoload(autoload 'reftex-index-phrases-mode "reftex-index" nil t)

;; Generated functions.
(autoload 'reftex-varioref-vref "reftex-ref"
  "Make a varioref reference." t)
(autoload 'reftex-fancyref-fref "reftex-ref"
  "Make a fancyref \\fref reference." t)
(autoload 'reftex-fancyref-Fref "reftex-ref"
  "Make a fancyref \\Fref reference." t)

;;; =========================================================================
;;;
;;; Define the formal stuff for a minor mode named RefTeX.
;;;

(defconst reftex-version emacs-version
  "Version string for RefTeX.")

(defvar reftex-mode-map
  (let ((map (make-sparse-keymap)))
    ;; The default bindings in the mode map.
    (define-key map "\C-c=" 'reftex-toc)
    (define-key map "\C-c-" 'reftex-toc-recenter)
    (define-key map "\C-c(" 'reftex-label)
    (define-key map "\C-c)" 'reftex-reference)
    (define-key map "\C-c[" 'reftex-citation)
    (define-key map "\C-c<" 'reftex-index)
    (define-key map "\C-c>" 'reftex-display-index)
    (define-key map "\C-c/" 'reftex-index-selection-or-word)
    (define-key map "\C-c\\" 'reftex-index-phrase-selection-or-word)
    (define-key map "\C-c|" 'reftex-index-visit-phrases-buffer)
    (define-key map "\C-c&" 'reftex-view-crossref)

    ;; Bind `reftex-mouse-view-crossref' only when the key is still free
    (if (featurep 'xemacs)
        (unless (key-binding [(shift button2)])
          (define-key map [(shift button2)] 'reftex-mouse-view-crossref))
      (unless (key-binding [(shift mouse-2)])
        (define-key map [(shift mouse-2)] 'reftex-mouse-view-crossref)))

    ;; For most of these commands there are already bindings in place.
    ;; Setting `reftex-extra-bindings' really is only there to spare users
    ;; the hassle of defining bindings in the user space themselves.  This
    ;; is why they violate the key binding recommendations.
    (when reftex-extra-bindings
      (define-key map "\C-ct" 'reftex-toc)
      (define-key map "\C-cl" 'reftex-label)
      (define-key map "\C-cr" 'reftex-reference)
      (define-key map "\C-cc" 'reftex-citation)
      (define-key map "\C-cv" 'reftex-view-crossref)
      (define-key map "\C-cg" 'reftex-grep-document)
      (define-key map "\C-cs" 'reftex-search-document))

    map)
  "Keymap for RefTeX mode.")

(defvar reftex-mode-menu nil)
(defvar reftex-syntax-table nil)
(defvar reftex-syntax-table-for-bib nil)

(defun reftex--prepare-syntax-tables ()
  (setq reftex-syntax-table (copy-syntax-table))
  (modify-syntax-entry ?\( "." reftex-syntax-table)
  (modify-syntax-entry ?\) "." reftex-syntax-table)

  (setq reftex-syntax-table-for-bib (copy-syntax-table))
  (modify-syntax-entry ?\' "." reftex-syntax-table-for-bib)
  (modify-syntax-entry ?\" "." reftex-syntax-table-for-bib)
  (modify-syntax-entry ?\[ "." reftex-syntax-table-for-bib)
  (modify-syntax-entry ?\] "." reftex-syntax-table-for-bib)
  (modify-syntax-entry ?\( "." reftex-syntax-table-for-bib)
  (modify-syntax-entry ?\) "." reftex-syntax-table-for-bib))

(unless (and reftex-syntax-table reftex-syntax-table-for-bib)
  (reftex--prepare-syntax-tables))

;; The following definitions are out of place, but I need them here
;; to make the compilation of reftex-mode not complain.
(defvar reftex-auto-view-crossref-timer nil
  "The timer used for auto-view-crossref.")
(defvar reftex-toc-auto-recenter-timer nil
  "The idle timer used to recenter the toc window.")

;;;###autoload
(defun turn-on-reftex ()
  "Turn on RefTeX mode."
  (reftex-mode t))

(put 'reftex-mode :included '(memq major-mode '(latex-mode tex-mode)))
(put 'reftex-mode :menu-tag "RefTeX Mode")
;;;###autoload
(define-minor-mode reftex-mode
  "Minor mode with distinct support for \\label, \\ref and \\cite in LaTeX.

\\<reftex-mode-map>A Table of Contents of the entire (multifile) document with browsing
capabilities is available with `\\[reftex-toc]'.

Labels can be created with `\\[reftex-label]' and referenced with `\\[reftex-reference]'.
When referencing, you get a menu with all labels of a given type and
context of the label definition.  The selected label is inserted as a
\\ref macro.

Citations can be made with `\\[reftex-citation]' which will use a regular expression
to pull out a *formatted* list of articles from your BibTeX
database.  The selected citation is inserted as a \\cite macro.

Index entries can be made with `\\[reftex-index-selection-or-word]' which indexes the word at point
or the current selection.  More general index entries are created with
`\\[reftex-index]'.  `\\[reftex-display-index]' displays the compiled index.

Most command have help available on the fly.  This help is accessed by
pressing `?' to any prompt mentioning this feature.

Extensive documentation about RefTeX is available in Info format.
You can view this information with `\\[reftex-info]'.

\\{reftex-mode-map}
Under X, these and other functions will also be available as `Ref' menu
on the menu bar.

------------------------------------------------------------------------------"
  :lighter " Ref" :keymap reftex-mode-map
  (if reftex-mode
      (progn
        ;; Mode was turned on
        (when (featurep 'xemacs)
          (easy-menu-add reftex-mode-menu))
        (and reftex-plug-into-AUCTeX
             (reftex-plug-into-AUCTeX))
        (unless (get 'reftex-auto-view-crossref 'initialized)
          (and reftex-auto-view-crossref
               (reftex-toggle-auto-view-crossref))
          (put 'reftex-auto-view-crossref 'initialized t))
        (unless (get 'reftex-auto-recenter-toc 'initialized)
          (and (eq reftex-auto-recenter-toc t)
               (reftex-toggle-auto-toc-recenter))
          (put 'reftex-auto-recenter-toc 'initialized t))

        ;; Prepare the special syntax tables.
	(reftex--prepare-syntax-tables)

        (run-hooks 'reftex-mode-hook))
    ;; Mode was turned off
    (when (featurep 'xemacs)
      (easy-menu-remove reftex-mode-menu))))

(defvar reftex-docstruct-symbol)
(defun reftex-kill-buffer-hook ()
  "Save RefTeX's parse file for this buffer if the information has changed."
  ;; Save the parsing information if it was modified.
  ;; This function should be installed in `kill-buffer-hook'.
  ;; We are careful to make sure nothing goes wrong in this function.
  (when (and (boundp 'reftex-mode)  reftex-mode
             (boundp 'reftex-save-parse-info)  reftex-save-parse-info
             (boundp 'reftex-docstruct-symbol)  reftex-docstruct-symbol
             (symbol-value reftex-docstruct-symbol)
             (get reftex-docstruct-symbol 'modified))
    ;; Write the file.
    (condition-case nil
        (reftex-access-parse-file 'write)
      (error nil))))

(defun reftex-kill-emacs-hook ()
  "Call `reftex-kill-buffer-hook' on all buffers."
  ;; This function should be installed in `kill-emacs-hook'.
  (save-excursion
    (mapcar (lambda (buf)
              (set-buffer buf)
              (reftex-kill-buffer-hook))
            (buffer-list))))

;;; =========================================================================
;;;
;;; Silence warnings about variables in other packages.
(defvar TeX-master)
(defvar LaTeX-section-hook)
(defvar LaTeX-label-function)
(defvar tex-main-file)
(defvar outline-minor-mode)
(defvar font-lock-mode)
(defvar font-lock-keywords)
(defvar font-lock-fontify-region-function)

;;; =========================================================================
;;;
;;; Multibuffer Variables
;;;
;; Technical notes: These work as follows: We keep just one list
;; of labels for each master file - this can save a lot of memory.
;; `reftex-master-index-list' is an alist which connects the true file name
;; of each master file with the symbols holding the information on that
;; document.  Each buffer has local variables which point to these symbols.

;; List of variables which handle the multifile stuff.
;; This list is used to tie, untie, and reset these symbols.
(defconst reftex-multifile-symbols
  '(reftex-docstruct-symbol))

;; Alist connecting master file names with the corresponding lisp symbols.
(defvar reftex-master-index-list nil)

;; Last index used for a master file.
(defvar reftex-multifile-index 0)

;; Variable holding the symbol with the label list of the document.
(defvar reftex-docstruct-symbol nil)
(make-variable-buffer-local 'reftex-docstruct-symbol)

(defun reftex-next-multifile-index ()
  ;; Return the next free index for multifile symbols.
  (cl-incf reftex-multifile-index))

(defun reftex-tie-multifile-symbols ()
  "Tie the buffer-local symbols to globals connected with the master file.
If the symbols for the current master file do not exist, they are created."
  (let* ((master (file-truename (reftex-TeX-master-file)))
         (index (assoc master reftex-master-index-list))
         (symlist reftex-multifile-symbols)
         symbol symname newflag)
    ;; Find the correct index.
    (if index
        ;; Symbols do exist
        (setq index (cdr index))
      ;; Get a new index and add info to the alist.
      (setq index (reftex-next-multifile-index)
            newflag t)
      (push (cons master index) reftex-master-index-list))

    ;; Get/create symbols and tie them.
    (while symlist
      (setq symbol (car symlist)
            symlist (cdr symlist)
            symname (symbol-name symbol))
      (set symbol (intern (concat symname "-" (int-to-string index))))
      (put (symbol-value symbol) :master-index index)
      ;; Initialize if new symbols.
      (when newflag
        (set (symbol-value symbol) nil)
        (put (symbol-value symbol) 'reftex-index-macros-style '(default))
	(put (symbol-value symbol) 'reftex-ref-style-list
	     reftex-ref-style-default-list)))

    ;; Return t if the symbols did already exist, nil when we've made them.
    (not newflag)))

(defun reftex-untie-multifile-symbols ()
  "Remove ties from multifile symbols, so that next use makes new ones."
  (let ((symlist reftex-multifile-symbols)
        (symbol nil))
    (while symlist
      (setq symbol  (car symlist)
            symlist (cdr symlist))
      (set symbol nil))))

(defun reftex-TeX-master-file ()
  ;; Return the name of the master file associated with the current buffer.
  ;; When AUCTeX is loaded, we will use it's more sophisticated method.
  ;; We also support the default TeX and LaTeX modes by checking for a
  ;; variable tex-main-file.
  (let
      ((master
        (cond
	 ;; Test if we're in a subfile using the subfiles document
	 ;; class, e.g., \documentclass[main.tex]{subfiles}.  It's
	 ;; argument is the main file, however it's not really the
	 ;; master file in `TeX-master-file' or `tex-main-file's
	 ;; sense.  It should be used for references but not for
	 ;; compilation, thus subfiles use a setting of
	 ;; `TeX-master'/`tex-main-file' being themselves.
	 ((save-excursion
            (goto-char (point-min))
            (re-search-forward
             "^[[:space:]]*\\\\documentclass\\[\\([^]]+\\)\\]{subfiles}"
             nil t))
          (match-string-no-properties 1))
         ;; AUCTeX is loaded.  Use its mechanism.
         ((fboundp 'TeX-master-file)
          (condition-case nil
              (TeX-master-file t)
            (error (buffer-file-name))))
         ;; Emacs LaTeX mode
         ((fboundp 'tex-main-file) (tex-main-file))
         ;; Check the `TeX-master' variable.
         ((boundp 'TeX-master)
          (cond
           ((eq TeX-master t)
            (buffer-file-name))
           ((eq TeX-master 'shared)
            (setq TeX-master (read-file-name "Master file: "
                                             nil nil t nil)))
           (TeX-master)
           (t
            (setq TeX-master (read-file-name "Master file: "
                                             nil nil t nil)))))
         ;; Check the `tex-main-file' variable.
         ((boundp 'tex-main-file)
          ;; This is the variable from the default TeX modes.
          (cond
           ((stringp tex-main-file)
            ;; ok, this must be it
            tex-main-file)
           (t
            ;; In this case, the buffer is its own master.
            (buffer-file-name))))
         ;; We know nothing about master file.  Assume this is a
         ;; master file.
         (t
          (buffer-file-name)))))
    (cond
     ((null master)
      (error "Need a filename for this buffer, please save it first"))
     ((or (file-exists-p (concat master ".tex"))
          (reftex-get-buffer-visiting (concat master ".tex")))
      ;; Ahh, an extra .tex was missing...
      (setq master (concat master ".tex")))
     ((or (file-exists-p master)
          (reftex-get-buffer-visiting master))
      ;; We either see the file, or have a buffer on it.  OK.
      )
     (t
      ;; Use buffer file name.
      (setq master (buffer-file-name))))
    (expand-file-name master)))

(defun reftex-is-multi ()
  ;; Tell if this is a multifile document.  When not sure, say yes.
  (let ((entry (assq 'is-multi (symbol-value reftex-docstruct-symbol))))
    (if entry
        (nth 1 entry)
      t)))

(defun reftex-set-cite-format (value)
  "Set the document-local value of `reftex-cite-format'.
When such a value exists, it overwrites the setting given with
`reftex-cite-format'.  See the documentation of `reftex-cite-format'
for possible values.  This function should be used from AUCTeX style files."
  (unless reftex-docstruct-symbol
    (reftex-tie-multifile-symbols))
  (when (and reftex-docstruct-symbol
             (symbolp reftex-docstruct-symbol))
    (put reftex-docstruct-symbol 'reftex-cite-format value)))

(defun reftex-get-cite-format ()
  ;; Return the current citation format.  Either the document-local value in
  ;; reftex-cite-format-symbol, or the global value in reftex-cite-format.
  (if (and reftex-docstruct-symbol
           (symbolp reftex-docstruct-symbol)
           (get reftex-docstruct-symbol 'reftex-cite-format))
      (get reftex-docstruct-symbol 'reftex-cite-format)
    reftex-cite-format))

(defun reftex-add-index-macros (entry-list)
  "Add index macro descriptions to `reftex-index-macros-style'.
The format of ENTRY-LIST is exactly like `reftex-index-macros'.  See there
for details.
This function makes it possible to support RefTeX from AUCTeX style files.
The entries in ENTRY-LIST will be processed after the user settings in
`reftex-index-entries', and before the defaults.  Any changes made to
`reftex-index-macros-style' will raise a flag to the effect that
the label information is recompiled on next use."
  (unless reftex-docstruct-symbol
    (reftex-tie-multifile-symbols))
  (when (and reftex-docstruct-symbol
             (symbolp reftex-docstruct-symbol))
    (let ((list (get reftex-docstruct-symbol 'reftex-index-macros-style))
          entry changed)
      (while entry-list
        (setq entry (pop entry-list))
        ;; When it is a symbol, remove all other symbols
        (and (symbolp entry)
             (not (memq entry list))
             (setq list (reftex-remove-symbols-from-list list)))
        ;; Add to list unless already member
        (unless (member entry list)
          (setq reftex-tables-dirty t
                changed t)
          (push entry list)))
      (when changed
        (put reftex-docstruct-symbol 'reftex-index-macros-style list)))))

(defun reftex-ref-style-activate (style)
  "Activate the referencing style STYLE."
  (reftex-ref-style-toggle style 'activate))

(defun reftex-ref-style-toggle (style &optional action)
  "Activate or deactivate the referencing style STYLE.
With the optional argument ACTION a certain action can be forced.
The symbol `activate' will activate the style and `deactivate'
will deactivate it."
  (unless reftex-docstruct-symbol
    (reftex-tie-multifile-symbols))
  (when (and reftex-docstruct-symbol
             (symbolp reftex-docstruct-symbol))
    (let ((list (get reftex-docstruct-symbol 'reftex-ref-style-list))
          changed)
      (cond ((eq action 'activate)
	     (unless (member style list)
	       (setq reftex-tables-dirty t
		     changed t)
               (setq list (append list (list style)))))
	    ((eq action 'deactivate)
	     (when (member style list)
	       (setq reftex-tables-dirty t
		     changed t)
	       (setq list (delete style list))))
	    (t
	     (if (member style list)
		 (delete style list)
	       (setq list (append list (list style))))
	     (setq reftex-tables-dirty t
		   changed t)))
      (when changed
        (put reftex-docstruct-symbol 'reftex-ref-style-list list)))))

(defun reftex-ref-style-list ()
  "Return the list of referencing styles to be active at the moment."
  ;; Initialize the value of `reftex-ref-style-list' and tie it to the
  ;; docstruct symbol if necessary.
  (unless reftex-docstruct-symbol
    (reftex-tie-multifile-symbols))
  (if (and reftex-docstruct-symbol
           (symbolp reftex-docstruct-symbol)
           (get reftex-docstruct-symbol 'reftex-ref-style-list))
      (get reftex-docstruct-symbol 'reftex-ref-style-list)
    reftex-ref-style-default-list))

;;; =========================================================================
;;;
;;; Functions to compile the tables, reset the mode etc.

;; The following constants are derived from `reftex-label-alist'.

;; Prompt used for label type queries directed to the user.
(defvar reftex-type-query-prompt nil)

;; Help string for label type queries.
(defvar reftex-type-query-help nil)

;; Alist relating label type to reference format.
(defvar reftex-typekey-to-format-alist nil)

;; Alist relating label type to label prefix.
(defvar reftex-typekey-to-prefix-alist nil)

;; Alist relating environments or macros to label type and context regexp.
(defvar reftex-env-or-mac-alist nil)

;; List of special environment parser functions
(defvar reftex-special-env-parsers nil)

;; List of macros carrying a label.
(defvar reftex-label-mac-list nil)

;; List of environments carrying a label.
(defvar reftex-label-env-list nil)

;; List of all typekey letters in use.
(defvar reftex-typekey-list nil)

;; Alist relating magic words to a label type.
(defvar reftex-words-to-typekey-alist nil)
;; Alist relating label prefixes to a label type.
(defvar reftex-prefix-to-typekey-alist nil)

;; The last list-of-labels entry used in a reference.
(defvar reftex-last-used-reference (list nil nil nil nil))

;; Alist relating index macros to other info.
(defvar reftex-key-to-index-macro-alist nil)
;; Prompt for index macro queries
(defvar reftex-query-index-macro-prompt nil)
;; Help string for index macro queries
(defvar reftex-query-index-macro-help nil)

;; The message when follow-mode is suspended
(defvar reftex-no-follow-message
  "No follow-mode into unvisited file.  Press SPC to visit it.")
(defvar reftex-no-info-message
  "%s: info not available, use `\\[reftex-view-crossref]' to get it.")

;; Global variables used for communication between functions.
(defvar reftex-default-context-position nil)
(defvar reftex-location-start nil)
(defvar reftex-call-back-to-this-buffer nil)
(defvar reftex-select-return-marker (make-marker))
(defvar reftex-active-toc nil)
(defvar reftex-tex-path nil)
(defvar reftex-bib-path nil)
(defvar reftex-select-marked nil)
(defvar reftex-last-follow-point nil)
(defvar reftex-latex-syntax-table nil)
(defvar reftex-prefix nil)
(defvar reftex-section-levels-all nil)
(defvar reftex-buffers-with-changed-invisibility nil)
(defvar reftex-callback-fwd t)
(defvar reftex-last-toc-master nil
  "Stores the name of the tex file that `reftex-toc' was last run on.")
;; Marker for return point from recursive edit
(defvar reftex-recursive-edit-marker (make-marker))

;; List of buffers created temporarily for lookup, which should be killed.
(defvar reftex-buffers-to-kill nil)

;; Regexp to find anything.
(defvar reftex-section-regexp nil)
(defvar reftex-section-or-include-regexp nil)
(defvar reftex-index-macro-regexp nil)
(defvar reftex-index-level-re nil)
(defvar reftex-index-key-end-re nil)
(defvar reftex-find-index-entry-regexp-format nil)
(defvar reftex-everything-regexp nil)
(defvar reftex-everything-regexp-no-index nil)
(defvar reftex-index-re nil)
(defvar reftex-find-citation-regexp-format
  "\\\\\\([a-zA-Z]*cite[*a-zA-Z]*\\*?\\|bibentry\\)\\(\\[[^]]*\\]\\|{[^}]*}\\)*{\\([^}]*,\\)?\\(%s\\)[},]")
(defvar reftex-find-reference-format
  "\\\\\\(ref[a-zA-Z]*\\|[a-zA-Z]*ref\\(range\\)?\\)\\*?\\(\\[[^]]*\\]\\|{[^}]*}\\)*{\\(%s\\)}")
(defvar reftex-macros-with-labels nil)
(defvar reftex-macros-with-index nil)
(defvar reftex-index-macro-alist nil)
(defvar reftex-find-label-regexp-format nil)
(defvar reftex-find-label-regexp-format2 nil)

;; Constants for making RefTeX open to Texinfo hooking
(defvar reftex-section-pre-regexp "\\\\")
;; Including `\' as a character to be matched at the end of the regexp
;; will allow stuff like \begin{foo}\label{bar} to be matched.  This
;; will make the parser to advance one char too much.  Therefore
;; `reftex-parse-from-file' will step one char back if a section is
;; found.
(defvar reftex-section-post-regexp "\\*?\\(\\[[^]]*\\]\\)?[[{ \t\r\n\\]")
(defvar reftex-section-info-function 'reftex-section-info)

(defvar reftex-memory nil
  "Memorizes old variable values to indicate changes in these variables.")

;; A list of all variables in the cache.
;; The cache is used to save the compiled versions of some variables.
(defconst reftex-cache-variables
  '(reftex-memory ;; This MUST ALWAYS be the first!

    ;; Outline
    reftex-section-levels-all

    ;; Labels
    reftex-env-or-mac-alist
    reftex-special-env-parsers
    reftex-macros-with-labels
    reftex-label-mac-list
    reftex-label-env-list
    reftex-typekey-list
    reftex-typekey-to-format-alist
    reftex-typekey-to-prefix-alist
    reftex-words-to-typekey-alist
    reftex-prefix-to-typekey-alist
    reftex-type-query-prompt
    reftex-type-query-help

    ;; Index
    reftex-index-macro-alist
    reftex-macros-with-index
    reftex-query-index-macro-prompt
    reftex-query-index-macro-help
    reftex-key-to-index-macro-alist

    ;; Regular expressions
    reftex-section-regexp
    reftex-section-or-include-regexp
    reftex-index-re
    reftex-everything-regexp
    reftex-everything-regexp-no-index
    reftex-find-label-regexp-format
    reftex-find-label-regexp-format2
    reftex-find-index-entry-regexp-format
))

(defun reftex-ensure-compiled-variables ()
  ;; Recompile the label alist when necessary
  (let* ((mem reftex-memory)
         (cache (get reftex-docstruct-symbol 'reftex-cache))
         (cmem  (car cache))
         (alist reftex-label-alist)
         (levels (get reftex-docstruct-symbol 'reftex-section-levels))
         (style (get reftex-docstruct-symbol 'reftex-label-alist-style))
         (default reftex-default-label-alist-entries)
         (index reftex-index-macros)
         (istyle (get reftex-docstruct-symbol 'reftex-index-macros-style)))
    (cond
     (reftex-tables-dirty (reftex-compile-variables))
     ((and (eq alist   (nth 0 mem))
           (eq levels  (nth 1 mem))
           (eq style   (nth 2 mem))
           (eq default (nth 3 mem))
           (eq index   (nth 4 mem))
           (eq istyle  (nth 5 mem))))  ;; everything is OK
     ((and (eq alist   (nth 0 cmem))
           (eq levels  (nth 1 cmem))
           (eq style   (nth 2 cmem))
           (eq default (nth 2 cmem))
           (eq index   (nth 4 cmem))
           (eq istyle  (nth 5 cmem)))
      ;; restore the cache
      (message "Restoring cache")
      (mapcar (lambda (sym) (set sym (pop cache))) reftex-cache-variables))
     (t (reftex-compile-variables)))))

(defun reftex-reset-mode ()
  "Reset RefTeX Mode.
This will re-compile the configuration information and remove all
current scanning information and the parse file to enforce a rescan
on next use."
  (interactive)

  ;; Reset the file search path variables
  (dolist (prop '(status master-dir recursive-path rec-type))
    (put 'reftex-tex-path prop nil)
    (put 'reftex-bib-path prop nil))

  ;; Kill temporary buffers associated with RefTeX - just in case they
  ;; were not cleaned up properly
  (save-excursion
    (let ((buffer-list '("*RefTeX Help*" "*RefTeX Select*"
                         "*Duplicate Labels*" "*toc*" " *RefTeX-scratch*"))
          buf)
      (while (setq buf (pop buffer-list))
        (if (get-buffer buf)
            (kill-buffer buf))))
    (reftex-erase-all-selection-and-index-buffers))

  ;; Make sure the current document will be rescanned soon.
  (reftex-reset-scanning-information)

  ;; Remove any parse info file
  (reftex-access-parse-file 'kill)

  ;; Plug functions into AUCTeX if the user option says so.
  (and reftex-plug-into-AUCTeX
       (reftex-plug-into-AUCTeX))

  (reftex-compile-variables))

;;;###autoload
(defun reftex-reset-scanning-information ()
  "Reset the symbols containing information from buffer scanning.
This enforces rescanning the buffer on next use."
  (if (string= reftex-last-toc-master (reftex-TeX-master-file))
      (reftex-erase-buffer "*toc*"))
  (let ((symlist reftex-multifile-symbols)
        symbol)
    (while symlist
      (setq symbol (car symlist)
            symlist (cdr symlist))
      (if (and (symbolp (symbol-value symbol))
               (not (null (symbol-value symbol))))
          (set (symbol-value symbol) nil)))))

(defun reftex-erase-all-selection-and-index-buffers ()
  ;; Remove all selection buffers associated with current document.
  (mapc
   (lambda (type)
     (reftex-erase-buffer (reftex-make-selection-buffer-name type)))
   reftex-typekey-list)
  ;; Kill all index buffers
  (mapc
   (lambda (tag)
     (reftex-kill-buffer (reftex-make-index-buffer-name tag)))
   (cdr (assoc 'index-tags (symbol-value reftex-docstruct-symbol)))))

(defun reftex-compile-variables ()
  ;; Compile the information in reftex-label-alist & Co.

  (message "Compiling label environment definitions...")

  ;; Update AUCTeX style information
  (when (and (featurep 'tex-site) (fboundp 'TeX-update-style))
    (condition-case nil (TeX-update-style) (error nil)))

  ;; Record that we have done this, and what we have used.
  (setq reftex-tables-dirty nil)
  (setq reftex-memory
        (list reftex-label-alist
              (get reftex-docstruct-symbol 'reftex-section-levels)
              (get reftex-docstruct-symbol 'reftex-label-alist-style)
              reftex-default-label-alist-entries
              reftex-index-macros
              (get reftex-docstruct-symbol 'reftex-index-macros-style)))

  ;; Compile information in reftex-label-alist
  (let ((all (reftex-uniquify-by-car
              (reftex-splice-symbols-into-list
               (append reftex-label-alist
                       (get reftex-docstruct-symbol
                            'reftex-label-alist-style)
                       reftex-default-label-alist-entries)
               reftex-label-alist-builtin)
              '(nil)))
        (all-index (reftex-uniquify-by-car
                    (reftex-splice-symbols-into-list
                     (append reftex-index-macros
                             (get reftex-docstruct-symbol
                                  'reftex-index-macros-style)
                             '(default))
                     reftex-index-macros-builtin)))
        entry env-or-mac typekeychar typekey prefix context word
        fmt reffmt labelfmt wordlist qh-list macros-with-labels
        nargs nlabel opt-args cell sum i
        macro verify repeat nindex tag key toc-level toc-levels)

    (setq reftex-words-to-typekey-alist nil
          reftex-prefix-to-typekey-alist
          '(("sec:" . "s") ("cha:" . "s") ("chap:" . "s"))
          reftex-typekey-list nil
          reftex-typekey-to-format-alist nil
          reftex-typekey-to-prefix-alist nil
          reftex-env-or-mac-alist nil
          reftex-label-env-list nil
          reftex-label-mac-list nil)
    (while all
      (catch 'next-entry
        (setq entry (car all)
              env-or-mac (car entry)
              entry (cdr entry)
              all (cdr all))
        (if (null env-or-mac)
            (setq env-or-mac ""))
        (if (stringp (car entry))
            ;; This is before version 2.00 - convert entry to new format
            ;; This is just to keep old users happy
            (setq entry (cons (string-to-char (car entry))
                              (cons (concat (car entry) ":")
                                    (cdr entry)))))
        (setq typekeychar (nth 0 entry)
              typekey (if typekeychar (char-to-string typekeychar) nil)
              prefix (nth 1 entry)
              fmt (nth 2 entry)
              context (nth 3 entry)
              wordlist (nth 4 entry)
              toc-level (nth 5 entry))
        (if (stringp wordlist)
            ;; This is before version 2.04 - convert to new format
            (setq wordlist (nthcdr 4 entry)))

        (if (and (stringp fmt)
                 (string-match "@" fmt))
            ;; Special syntax for specifying a label format
            (setq fmt (split-string fmt "@+"))
          (setq fmt (list "\\label{%s}" fmt)))
        (setq labelfmt (car fmt)
              reffmt (nth 1 fmt))
        ;; Note a new typekey
        (if typekey
            (cl-pushnew typekey reftex-typekey-list :test #'equal))
        (if (and typekey prefix
                 (not (assoc prefix reftex-prefix-to-typekey-alist)))
            (cl-pushnew (cons prefix typekey) reftex-prefix-to-typekey-alist
                        :test #'equal))
        (if (and typekey prefix
                 (not (assoc typekey reftex-typekey-to-prefix-alist)))
            (cl-pushnew (cons typekey prefix) reftex-typekey-to-prefix-alist
                        :test #'equal))
        ;; Check if this is a macro or environment
        (cond
         ((symbolp env-or-mac)
          ;; A special parser function
          (unless (fboundp env-or-mac)
            (message "Warning: %s does not seem to be a valid function"
                     env-or-mac))
          (setq nargs nil nlabel nil opt-args nil)
          (cl-pushnew env-or-mac reftex-special-env-parsers)
          (setq env-or-mac (symbol-name env-or-mac)))
         ((string-match "\\`\\\\" env-or-mac)
          ;; It's a macro
          (let ((result (reftex-parse-args env-or-mac)))
            (setq env-or-mac (or (cl-first result) env-or-mac)
                  nargs (cl-second result)
                  nlabel (cl-third result)
                  opt-args (cl-fourth result))
            (if nlabel (cl-pushnew env-or-mac macros-with-labels :test #'equal)))
          (if typekey (cl-pushnew env-or-mac reftex-label-mac-list :test #'equal)))
         (t
          ;; It's an environment
          (setq nargs nil nlabel nil opt-args nil)
          (cond ((string= env-or-mac "any"))
                ((string= env-or-mac ""))
                ((string= env-or-mac "section"))
                (t
                 (cl-pushnew env-or-mac reftex-label-env-list :test #'equal)
                 (if toc-level
                     (let ((string (format "begin{%s}" env-or-mac)))
                       (or (assoc string toc-levels)
                           (push (cons string toc-level) toc-levels))))))))
        ;; Translate some special context cases
        (when (assq context reftex-default-context-regexps)
          (setq context
                (format
                 (cdr (assq context reftex-default-context-regexps))
                 (regexp-quote env-or-mac))))
        ;; See if this is the first format for this typekey
        (and reffmt
             (not (assoc typekey reftex-typekey-to-format-alist))
             (push (cons typekey reffmt) reftex-typekey-to-format-alist))
        ;; See if this is the first definition for this env-or-mac
        (and (not (string= env-or-mac "any"))
             (not (string= env-or-mac ""))
             (not (assoc env-or-mac reftex-env-or-mac-alist))
             (push (list env-or-mac typekey context labelfmt
                         nargs nlabel opt-args)
                   reftex-env-or-mac-alist))
        ;; Are the magic words regular expressions?  Quote normal words.
        (if (eq (car wordlist) 'regexp)
            (setq wordlist (cdr wordlist))
          (setq wordlist (mapcar 'regexp-quote wordlist)))
        ;; Remember the first association of each word.
        (while (stringp (setq word (pop wordlist)))
          (or (assoc word reftex-words-to-typekey-alist)
              (push (cons word typekey) reftex-words-to-typekey-alist)))
        (cond
         ((string= "" env-or-mac) nil)
         ((setq cell (assoc typekey qh-list))
          (push env-or-mac (cdr cell)))
         (typekey
          (push (list typekey env-or-mac) qh-list)))))

    (setq reftex-typekey-to-prefix-alist
          (nreverse reftex-typekey-to-prefix-alist))

    ;; Prepare the typekey query prompt and help string.
    (setq qh-list
          (sort qh-list
                (lambda (x1 x2)
                  (string< (downcase (car x1)) (downcase (car x2))))))
    (setq reftex-type-query-prompt
          (concat "Label type: ["
                  (mapconcat (lambda(x) (format "%s" (car x)))
                             qh-list "")
                  "]"))
    ;; In the help string, we need to wrap lines...
    (setq reftex-type-query-help
          (concat
           "SELECT A LABEL TYPE:\n--------------------\n"
           (mapconcat
            (lambda(x)
              (setq sum 0)
              (format " [%s]   %s"
                      (car x)
                      (mapconcat (lambda(env)
                                   (setq sum (+ sum (length env)))
                                   (if (< sum 60)
                                       env
                                     (setq sum 0)
                                     (concat "\n       " env)))
                                 (cdr x) " ")))
            qh-list "\n")))

    ;; Convert magic words to regular expressions.  We make regular expressions
    ;; which allow for some chars from the ref format to be in the buffer.
    ;; These characters will be seen and removed.
    (setq reftex-words-to-typekey-alist
          (mapcar
           (lambda (x)
             (setq word (car x)
                   typekey (cdr x)
                   fmt (cdr (assoc typekey reftex-typekey-to-format-alist)))
             (setq word (concat "\\W\\(" word "[ \t\n\r]*\\)\\("))
             (setq i 0)
             (while (and (< i 10)   ; maximum number of format chars allowed
                         (< i (length fmt))
                         (not (member (aref fmt i) '(?%))))
               (setq word (concat word "\\|" (regexp-quote
                                              (substring fmt 0 (1+ i)))))
               (cl-incf i))
             (cons (concat word "\\)\\=") typekey))
           (nreverse reftex-words-to-typekey-alist)))

    ;; Parse the index macros
    (setq reftex-index-macro-alist nil
          reftex-key-to-index-macro-alist nil
          reftex-macros-with-index nil)
    (while all-index
      (setq entry (car all-index)
            macro (car entry)
            tag (nth 1 entry)
            key (nth 2 entry)
            prefix (or (nth 3 entry) "")
            verify (nth 4 entry)
            ;; For repeat, we need to be compatible with older code
            ;; This information used to be given only for the default macro,
            ;; but later we required to have it for *every* index macro
            repeat (cond ((> (length entry) 5) (nth 5 entry))
                         ((and (eq key (car reftex-index-default-macro))
                               (> (length reftex-index-default-macro) 2))
                          ;; User has old setting - respect it
                          (nth 2 reftex-index-default-macro))
                         (t t))
            all-index (cdr all-index))
      (let ((result (reftex-parse-args macro)))
        (setq macro (or (cl-first result) macro)
              nargs (cl-second result)
              nindex (cl-third result)
              opt-args (cl-fourth result))
        (unless (member macro reftex-macros-with-index)
          ;;           0     1    2      3     4     5       6        7
          (push (list macro tag prefix verify nargs nindex opt-args repeat)
                reftex-index-macro-alist)
          (or (assoc key reftex-key-to-index-macro-alist)
              (push (list key macro) reftex-key-to-index-macro-alist))
          (push macro reftex-macros-with-index))))
    ;; Make the prompt and help string for index macros query
    (setq reftex-key-to-index-macro-alist
          (sort reftex-key-to-index-macro-alist
                (lambda (a b) (< (downcase (car a)) (downcase (car b))))))
    (setq reftex-query-index-macro-prompt
          (concat "Index macro: ["
                  (mapconcat (lambda (x) (char-to-string (car x)))
                             reftex-key-to-index-macro-alist "")
                  "]"))
    (setq i 0
          reftex-query-index-macro-help
          (concat
           "SELECT A MACRO:\n---------------\n"
           (mapconcat
            (lambda(x)
              (format "[%c] %-20.20s%s" (car x) (nth 1 x)
                      (if (= 0 (mod (cl-incf i) 3)) "\n" "")))
            reftex-key-to-index-macro-alist "")))

    ;; Make the full list of section levels
    (setq reftex-section-levels-all
          (append toc-levels
                  (get reftex-docstruct-symbol 'reftex-section-levels)
                  reftex-section-levels))

    ;; Calculate the regular expressions
    (let* (
;          (wbol "\\(\\`\\|[\n\r]\\)[ \t]*")
           (wbol "\\(^\\)%?[ \t]*") ; Need to keep the empty group because
                                    ; match numbers are hard coded
           (label-re (concat "\\(?:"
			     (mapconcat 'identity reftex-label-regexps "\\|")
			     "\\)"))
           (include-re (concat wbol
                               "\\\\\\("
                               (mapconcat 'identity
                                          reftex-include-file-commands "\\|")
                               "\\)[{ \t]+\\([^} \t\n\r]+\\)"))
           (section-re
            (concat wbol reftex-section-pre-regexp "\\("
                    (mapconcat (lambda (x) (regexp-quote (car x)))
                               reftex-section-levels-all "\\|")
                    "\\)" reftex-section-post-regexp))
           (appendix-re (concat wbol "\\(\\\\appendix\\)"))
           (macro-re
            (if macros-with-labels
                (concat "\\("
                        (mapconcat 'regexp-quote macros-with-labels "\\|")
                        "\\)[[{]")
              ""))
           (index-re
            (concat "\\("
                    (mapconcat 'regexp-quote reftex-macros-with-index "\\|")
                    "\\)[[{]"))
           (find-index-re-format
            (concat "\\("
                    (mapconcat 'regexp-quote reftex-macros-with-index "\\|")
                    "\\)\\([[{][^]}]*[]}]\\)*[[{]\\(%s\\)[]}]"))
           (find-label-re-format
            (concat "\\("
		    "label[[:space:]]*=[[:space:]]*"
		    "\\|"
                    (mapconcat 'regexp-quote (append '("\\label")
                                                     macros-with-labels) "\\|")
                    "\\)\\([[{][^]}]*[]}]\\)*[[{]\\(%s\\)[]}]"))
           (index-level-re
            (regexp-quote (nth 0 reftex-index-special-chars)))
           (index-key-end-re ;; ^]- not allowed
            (concat "[^" (nth 3 reftex-index-special-chars) "]"
                    "[" (nth 1 reftex-index-special-chars)
                    (nth 2 reftex-index-special-chars) "]"))
           )
      (setq reftex-section-regexp section-re
            reftex-section-or-include-regexp
            (concat section-re "\\|" include-re)
            reftex-everything-regexp
            (concat label-re "\\|" section-re "\\|" include-re
                    "\\|" appendix-re
                    "\\|" index-re
                    (if macros-with-labels "\\|" "") macro-re)
            reftex-everything-regexp-no-index
            (concat label-re "\\|" section-re "\\|" include-re
                    "\\|" appendix-re
                    "\\|" "\\(\\\\6\\\\3\\\\1\\)" ; This is unlikely to match
                    (if macros-with-labels "\\|" "") macro-re)
            reftex-index-re index-re
            reftex-index-level-re index-level-re
            reftex-index-key-end-re index-key-end-re
            reftex-macros-with-labels macros-with-labels
            reftex-find-index-entry-regexp-format find-index-re-format
            reftex-find-label-regexp-format find-label-re-format
            reftex-find-label-regexp-format2
            "\\([]} \t\n\r]\\)\\([[{]\\)\\(%s\\)[]}]")
      (message "Compiling label environment definitions...done")))
  (put reftex-docstruct-symbol 'reftex-cache
       (mapcar 'symbol-value reftex-cache-variables)))

(defun reftex-parse-args (macro)
  ;; Return a list of macro name, nargs, arg-nr which is label and a list of
  ;; optional argument indices.
  (if (string-match "[[{]\\*?[]}]" macro)
      (progn
        (let ((must-match (substring macro 0 (match-beginning 0)))
              (args (substring macro (match-beginning 0)))
              opt-list nlabel (cnt 0))
          (while (string-match "\\`[[{]\\(\\*\\)?[]}]" args)
            (cl-incf cnt)
            (when (eq ?\[ (string-to-char args))
              (push cnt opt-list))
            (when (and (match-end 1)
                       (not nlabel))
              (setq nlabel cnt))
            (setq args (substring args (match-end 0))))
          (list must-match cnt nlabel opt-list)))
    nil))

;;; =========================================================================
;;;
;;; Accessing the parse information

(defun reftex-access-scan-info (&optional rescan file)
  "Ensure access to the scanning info for the current file."
  ;; When the multifile symbols are not yet tied,
  ;; tie them.  When they are empty or RESCAN is non-nil, scan the document.
  ;; But, when RESCAN is -1, don't rescan even if docstruct is empty.
  ;; When FILE is non-nil, parse only from that file.

  ;; Error out in a buffer without a file.
  (if (and reftex-mode
	   (not (buffer-file-name)))
      (error "RefTeX works only in buffers visiting a file"))

  ;; Make sure we have the symbols tied
  (if (eq reftex-docstruct-symbol nil)
      ;; Symbols are not yet tied: Tie them.
      (reftex-tie-multifile-symbols))

  (reftex-ensure-compiled-variables)

  (when (or (null (symbol-value reftex-docstruct-symbol))
            (member rescan '(t 1 (4) (16))))
    ;; The docstruct will change: Remove selection buffers.
    (save-excursion
      (reftex-erase-buffer "*toc*")
      (reftex-erase-all-selection-and-index-buffers)))

  (if (and (null (symbol-value reftex-docstruct-symbol))
           (not (member rescan '(t 1 (4) (16))))
           reftex-save-parse-info)
      ;; Try to read the stuff from a file
      (reftex-access-parse-file 'read))

  (cond
   ((equal rescan -1))  ;; We are not allowed to scan.
   ((not (symbol-value reftex-docstruct-symbol))
    ;; Scan the whole document
    (reftex-do-parse 1 file))
   ((member rescan '(t 1 (4) (16)))
    ;; Scan whatever was required by the caller.
    (reftex-do-parse rescan file))))

(defun reftex-scanning-info-available-p ()
  "Is the scanning info about the current document available?"
  (unless reftex-docstruct-symbol
    (reftex-tie-multifile-symbols))
  (and (symbolp reftex-docstruct-symbol)
       (symbol-value reftex-docstruct-symbol)
       t))

(defun reftex-silence-toc-markers (list n)
  ;; Set all toc markers in the first N entries in list to nil
  (while (and list (> (cl-decf n) -1))
    (and (eq (car (car list)) 'toc)
         (markerp (nth 4 (car list)))
         (set-marker (nth 4 (car list)) nil))
    (pop list)))

(defun reftex-access-parse-file (action)
  "Perform ACTION on the parse file (the .rel file).
Valid actions are: readable, restore, read, kill, write."
  (let* ((list (symbol-value reftex-docstruct-symbol))
         (docstruct-symbol reftex-docstruct-symbol)
         (master (reftex-TeX-master-file))
         (enable-local-variables nil)
         (file (if (string-match "\\.[a-zA-Z]+\\'" master)
                   (concat (substring master 0 (match-beginning 0))
                           reftex-parse-file-extension)
                 (concat master reftex-parse-file-extension))))
    (cond
     ((eq action 'readable)
      (file-readable-p file))
     ((eq action 'restore)
      (put reftex-docstruct-symbol 'modified nil)
      (if (eq reftex-docstruct-symbol nil)
          ;; Symbols are not yet tied: Tie them.
          (reftex-tie-multifile-symbols))
      (if (file-exists-p file)
          ;; load the file and return t for success
          (condition-case nil
              (progn (load-file file) t)
            (error (set reftex-docstruct-symbol nil)
                   (error "Error while loading file %s" file)))
        ;; Throw an exception if the file does not exist
        (error "No restore file %s" file)))
     ((eq action 'read)
      (put reftex-docstruct-symbol 'modified nil)
      (if (file-exists-p file)
          ;; load the file and return t for success
          (condition-case nil
              (progn
                (load-file file)
                (reftex-check-parse-consistency)
                t)
            (error (message "Error while restoring file %s" file)
                   (set reftex-docstruct-symbol nil)
                   nil))
        ;; return nil for failure, but no exception
        nil))
     ((eq action 'kill)
      ;; Remove the file
      (when (and (file-exists-p file) (file-writable-p file))
        (message "Unlinking file %s" file)
        (delete-file file)))
     (t
      (put docstruct-symbol 'modified nil)
      (save-excursion
        (if (file-writable-p file)
            (with-temp-file file
              (message "Writing parse file %s" (abbreviate-file-name file))
              (insert (format ";; RefTeX parse info file\n"))
              (insert (format ";; File: %s\n" master))
              (insert (format ";; User: %s (%s)\n\n"
                              (user-login-name) (user-full-name)))
              (insert "(set reftex-docstruct-symbol '(\n\n")
              (let ((standard-output (current-buffer)))
                (mapc
                 (lambda (x)
                   (cond ((eq (car x) 'toc)
                          ;; A toc entry. Do not save the marker.
                          ;; Save the markers  position at position 8
                          (print (list 'toc "toc" (nth 2 x) (nth 3 x)
                                       nil (nth 5 x) (nth 6 x) (nth 7 x)
                                       (or (and (markerp (nth 4 x))
                                                (marker-position (nth 4 x)))
                                           (nth 8 x)))))
                         ((and (not (eq t reftex-support-index))
                               (eq (car x) 'index))
                          ;; Don't save index entries
                          )
                         (t (print x))))
                 list))
              (insert "))\n\n"))
          (error "Cannot write to file %s" file)))
      t))))

(defun reftex-check-parse-consistency ()
  ;; Check if parse file is consistent, throw an error if not.

  ;; Check if the master is the same: when moving a document, this will see it.
  (let* ((real-master (reftex-TeX-master-file))
         (parsed-master
          (nth 1 (assq 'bof (symbol-value reftex-docstruct-symbol)))))
    (unless (string= (file-truename real-master) (file-truename parsed-master))
      (message "Master file name in load file is different: %s versus %s"
               parsed-master real-master)
      (error "Master file name error")))

  ;; Check for the existence of all document files
;;;  (let* ((all (symbol-value reftex-docstruct-symbol)))
;;;    (while all
;;;      (when (and (eq (car (car all)) 'bof)
;;;              (not (file-regular-p (nth 1 (car all)))))
;;;     (message "File %s in saved parse info not available" (cdr (car all)))
;;;     (error "File not found"))
;;;      (setq all (cdr all))))
  )

(defun reftex-select-external-document (xr-alist xr-index)
  ;; Return index of an external document.
  (let* ((len (length xr-alist)) (highest (1- (+ ?0 len)))
         (prompt (format "[%c-%c] Select    TAB: Read prefix with completion"
                         ?0 highest))
         key prefix)
    (cond
     ((= len 1)
      (message "No external documents available")
      (ding) (sit-for 1) 0)
     ((= len 2)
      (- 1 xr-index))
     (t
      (save-excursion
        (let* ((length (apply 'max (mapcar
                                    (lambda(x) (length (car x))) xr-alist)))
               (fmt (format " [%%c]  %%-%ds  %%s\n" length))
               (n (1- ?0)))
          (setq key
                (reftex-select-with-char
                 prompt
                 (concat
                  "SELECT EXTERNAL DOCUMENT\n------------------------\n"
                  (mapconcat
                   (lambda (x)
                     (format fmt (cl-incf n) (or (car x) "")
                             (abbreviate-file-name (cdr x))))
                   xr-alist ""))
                 nil t))
          (cond
           ((and (>= key ?0) (<= key highest)) (- key ?0))
           ((= key ?\C-i)
            (setq prefix (completing-read "Prefix: " xr-alist nil t))
            (- len (length (memq (assoc prefix xr-alist) xr-alist))))
           (t (error "Invalid document selection [%c]" key)))))))))

;;; =========================================================================
;;;
;;; Finding files

(defun reftex-locate-file (file type master-dir &optional die)
  "Find FILE of type TYPE in MASTER-DIR or on the path associated with TYPE.
If the file does not have any of the valid extensions for TYPE,
try first the default extension and only then the naked file name.
When DIE is non-nil, throw an error if file not found."
  (let* ((rec-values (if reftex-search-unrecursed-path-first '(nil t) '(t)))
         (extensions (cdr (assoc type reftex-file-extensions)))
         (def-ext (car extensions))
         (ext-re (concat "\\("
                         (mapconcat 'regexp-quote extensions "\\|")
                         "\\)\\'"))
         (files (if (string-match ext-re file)
                    (cons file nil)
		  (if reftex-try-all-extensions
		      (append (mapcar (lambda (x) (concat file x))
				      extensions)
			      (list file))
		    (list (concat file def-ext) file))))
         path old-path file1 f fs)
    (cond
     ((file-name-absolute-p file)
      (while (setq f (pop files))
	(if (file-regular-p f)
	    (setq file1 f files nil))))
     ((and reftex-use-external-file-finders
           (assoc type reftex-external-file-finders))
      (setq file1 (reftex-find-file-externally file type master-dir)))
     (t
      (while (and (null file1) rec-values)
        (setq path (reftex-access-search-path
                    type (pop rec-values) master-dir file))
	(setq fs files)
	(while (and (null file1) (setq f (pop fs)))
	  (when (or (null old-path)
		    (not (eq old-path path)))
	    (setq old-path path
		  path (cons master-dir path))
	    (setq file1 (reftex-find-file-on-path f path master-dir)))))))
    (cond (file1 file1)
          (die (error "No such file: %s" file) nil)
          (t (message "No such file: %s (ignored)" file) nil))))

(defun reftex-find-file-externally (file type &optional master-dir)
  ;; Use external program to find FILE.
  ;; The program is taken from `reftex-external-file-finders'.
  ;; Interpret relative path definitions starting from MASTER-DIR.
  (let ((default-directory (or master-dir default-directory))
        (prg (cdr (assoc type reftex-external-file-finders)))
        out)
    (if (string-match "%f" prg)
        (setq prg (replace-match file t t prg)))
    (setq out (apply 'reftex-process-string (split-string prg)))
    (if (string-match "[ \t\n]+\\'" out)     ; chomp
        (setq out (replace-match "" nil nil out)))
    (cond ((equal out "") nil)
          ((file-regular-p out) (expand-file-name out master-dir))
          (t nil))))

(defun reftex-process-string (program &rest args)
  "Execute PROGRAM with arguments ARGS and return its STDOUT as a string."
  (let ((calling-dir default-directory))  ; remember default directory
    (with-output-to-string
      (with-current-buffer standard-output
        (let ((default-directory calling-dir)) ; set default directory
          (apply 'call-process program nil '(t nil) nil args))))))

(defun reftex-access-search-path (type &optional recurse master-dir file)
  ;; Access path from environment variables.  TYPE is either "tex" or "bib".
  ;; When RECURSE is t, expand path elements ending in `//' recursively.
  ;; Relative path elements are left as they are.  However, relative recursive
  ;; elements are expanded with MASTER-DIR as default directory.
  ;; The expanded path is cached for the next search.
  ;; FILE is just for the progress message.
  ;; Returns the derived path.
  (let* ((pathvar (intern (concat "reftex-" type "-path"))))
    (when (null (get pathvar 'status))
      ;; Get basic path
      (set pathvar
           (reftex-uniquify
            (reftex-parse-colon-path
             (mapconcat
              (lambda(x)
                (if (string-match "^!" x)
                    (apply 'reftex-process-string
                           (split-string (substring x 1)))
                  (or (getenv x) x)))
              ;; For consistency, the next line should look like this:
              ;;  (cdr (assoc type reftex-path-environment))
              ;; However, historically we have separate options for the
              ;; environment variables, so we have to do this:
              (symbol-value (intern (concat "reftex-" type
                                            "path-environment-variables")))
              path-separator))))
      (put pathvar 'status 'split)
      ;; Check if we have recursive elements
      (let ((path (symbol-value pathvar)) dir rec)
        (while (setq dir (pop path))
          (when (string= (substring dir -2) "//")
            (if (file-name-absolute-p dir)
                (setq rec (or rec 'absolute))
              (setq rec 'relative))))
        (put pathvar 'rec-type rec)))

    (if recurse
        ;; Return the recursive expansion of the path
        (cond
         ((not (get pathvar 'rec-type))
          ;; Path does not contain recursive elements - use simple path
          (symbol-value pathvar))
         ((or (not (get pathvar 'recursive-path))
              (and (eq (get pathvar 'rec-type) 'relative)
                   (not (equal master-dir (get pathvar 'master-dir)))))
          ;; Either: We don't have a recursive expansion yet.
          ;; or:     Relative recursive path elements need to be expanded
          ;;         relative to new default directory
          (message "Expanding search path to find %s file: %s ..." type file)
          (put pathvar 'recursive-path
               (reftex-expand-path (symbol-value pathvar) master-dir))
          (put pathvar 'master-dir master-dir)
          (get pathvar 'recursive-path))
         (t
          ;; Recursive path computed earlier is still OK.
          (get pathvar 'recursive-path)))
      ;; The simple path was requested
      (symbol-value pathvar))))

(defun reftex-find-file-on-path (file path &optional def-dir)
  ;; Find FILE along the directory list PATH.
  ;; DEF-DIR is the default directory for expanding relative path elements.
  (catch 'exit
    (when (file-name-absolute-p file)
      (if (file-regular-p file)
          (throw 'exit file)
        (throw 'exit nil)))
    (let* ((thepath path) file1 dir)
      (while (setq dir (pop thepath))
        (when (string= (substring dir -2) "//")
          (setq dir (substring dir 0 -1)))
        (setq file1 (expand-file-name file (expand-file-name dir def-dir)))
        (if (file-regular-p file1)
            (throw 'exit file1)))
      ;; No such file
      nil)))

(defun reftex-parse-colon-path (path)
  ;; Like parse-colon-parse, but // or /~ are left alone.
  ;; Trailing ! or !! will be converted into `//' (emTeX convention)
  (mapcar
   (lambda (dir)
     (if (string-match "\\(//+\\|/*!+\\)\\'" dir)
         (setq dir (replace-match "//" t t dir)))
     (file-name-as-directory dir))
   (delete "" (split-string path (concat path-separator "+")))))

(defun reftex-expand-path (path &optional default-dir)
  ;; Expand parts of path ending in `//' recursively into directory list.
  ;; Relative recursive path elements are expanded relative to DEFAULT-DIR.
  (let (path1 dir recursive)
    (while (setq dir (pop path))
      (if (setq recursive (string= (substring dir -2) "//"))
          (setq dir (substring dir 0 -1)))
      (if (and recursive
               (not (file-name-absolute-p dir)))
          (setq dir (expand-file-name dir default-dir)))
      (if recursive
          ;; Expand recursively
          (setq path1 (append (reftex-recursive-directory-list dir) path1))
        ;; Keep unchanged
        (push dir path1)))
    (nreverse path1)))

(defun reftex-recursive-directory-list (dir)
  ;; Return a list of all directories below DIR, including DIR itself
  (let ((path (list dir)) path1 file files)
    (while (setq dir (pop path))
      (when (file-directory-p dir)
        (setq files (nreverse (directory-files dir t "[^.]")))
        (while (setq file (pop files))
          (if (file-directory-p file)
              (push (file-name-as-directory file) path)))
        (push dir path1)))
    path1))

;;; =========================================================================
;;;
;;; Some generally useful functions

(defun reftex-typekey-check (typekey conf-variable &optional n)
  ;; Check if CONF-VARIABLE is true or contains TYPEKEY
  (and n (setq conf-variable (nth n conf-variable)))
  (or (eq conf-variable t)
      (and (stringp conf-variable)
           (let ((case-fold-search nil))
             (string-match (concat "[" conf-variable "]") typekey)))))

(defun reftex-check-recursive-edit ()
  ;; Check if we are already in a recursive edit.  Abort with helpful
  ;; message if so.
  (if (marker-position reftex-recursive-edit-marker)
      (error
       (substitute-command-keys
        "In unfinished selection process. Finish, or abort with \\[abort-recursive-edit]"))))

(defun reftex-in-comment ()
  "Return non-nil if point is in a comment."
  (save-excursion
    (save-match-data
      (let ((pos (point)))
	(beginning-of-line)
	(re-search-forward
	 (or comment-start-skip
	     ;; The parser may open files in fundamental mode if
	     ;; `reftex-initialize-temporary-buffers' is nil, so here
	     ;; is a default suitable for plain TeX and LaTeX.
	     "\\(\\(^\\|[^\\\n]\\)\\(\\\\\\\\\\)*\\)\\(%+[ \t]*\\)")
	 pos t)))))

(defun reftex-no-props (string)
  ;; Return STRING with all text properties removed
  (and (stringp string)
       (set-text-properties 0 (length string) nil string))
  string)

(defun reftex-match-string (n)
  ;; Match string without properties
  (when (match-beginning n)
    (buffer-substring-no-properties (match-beginning n) (match-end n))))

(defun reftex-region-active-p ()
  "Should we operate on an active region?"
  (if (fboundp 'use-region-p)
      (use-region-p)
    ;; For XEmacs.
    (region-active-p)))

(defun reftex-kill-buffer (buffer)
  ;; Kill buffer if it exists.
  (and (setq buffer (get-buffer buffer))
       (kill-buffer buffer)))

(defun reftex-erase-buffer (&optional buffer)
  ;; Erase BUFFER if it exists.  BUFFER defaults to current buffer.
  ;; This even erases read-only buffers.
  (cond
   ((null buffer)
    ;; erase current buffer
    (let ((buffer-read-only nil)) (erase-buffer)))
   ((setq buffer (get-buffer buffer))
    ;; buffer exists
    (with-current-buffer buffer
      (let ((inhibit-read-only t)) (erase-buffer))))))

(defun reftex-this-word (&optional class)
  ;; Grab the word around point.
  (setq class (or class "-a-zA-Z0-9:_/.*;|"))
  (save-excursion
    (buffer-substring-no-properties
     (progn (skip-chars-backward class) (point))
     (progn (skip-chars-forward  class) (point)))))

(defun reftex-number (n unit &optional ending)
  (if (and (integerp n) (stringp unit))
      (format "%d %s%s" n unit (if (= n 1) "" (or ending "s")))
    ""))

(defun reftex-all-assq (key list)
  ;; Return a list of all associations of KEY in LIST.  Comparison with eq.
  (let (rtn)
    (while (setq list (memq (assq key list) list))
      (push (car list) rtn)
      (pop list))
    (nreverse rtn)))

(defun reftex-all-assoc-string (key list)
  ;; Return a list of all associations of KEY in LIST.  Comparison with string=.
  (let (rtn)
    (while list
      (if (string= (car (car list)) key)
          (push (car list) rtn))
      (pop list))
    (nreverse rtn)))

(defun reftex-last-assoc-before-elt (key elt list &optional exclusive)
  ;; Find the last association of KEY in LIST before or at ELT
  ;; ELT is found in LIST with equal, not eq.
  ;; Returns nil when either KEY or elt are not found in LIST.
  ;; When EXCLUSIVE is non-nil, ELT cannot be the return value.
  ;; On success, returns the association.
  (let* ((elt (car (member elt list))) (ex (not exclusive)) ass last-ass)
    (while (and (setq ass (assoc key list))
                (setq list (memq ass list))
                (or ex (not (eq elt (car list))))
                (memq elt list))
      (setq last-ass ass
            list (cdr list)))
    last-ass))

(defun reftex-sublist-nth (list nth predicate &optional completion)
  ;; Make a list of the NTH elements of all members of LIST which
  ;; fulfill PREDICATE.
  ;; When COMPLETION is non-nil, make all elements of the resulting
  ;; list also a list, so that the result can be used for completion.
  (let (rtn)
    (while list
      (if (funcall predicate (car list))
          (push (if completion
                    (list (nth nth (car list)))
                  (nth nth (car list)))
                rtn))
      (setq list (cdr list)))
    (nreverse rtn)))

(defun reftex-make-selection-buffer-name (type &optional index)
  ;; Make unique name for a selection buffer.
  (format " *RefTeX[%s][%d]*"
          type (or index (get reftex-docstruct-symbol :master-index) 0)))

(defun reftex-make-index-buffer-name (tag &optional cnt)
  ;; Make unique name for an index buffer.
  (format "*Index[%s][%d]*"
          tag (or cnt (get reftex-docstruct-symbol :master-index) 0)))

(defun reftex-truncate (string ncols &optional ellipses padding)
  ;; Truncate STRING to NCOLS characters.
  ;; When PADDING is non-nil, and string is shorter than NCOLS, fill with
  ;; white space to NCOLS characters.  When ELLIPSES is non-nil and the
  ;; string needs to be truncated, replace last 3 characters by dots.
  (setq string
        (if (<= (length string) ncols)
            string
          (if ellipses
              (concat (substring string 0 (- ncols 3)) "...")
            (substring string 0 ncols))))
  (if padding
      (format (format "%%-%ds" ncols) string)
    string))

(defun reftex-nearest-match (regexp &optional max-length)
  ;; Find the nearest match of REGEXP.  Set the match data.
  ;; If POS is given, calculate distances relative to it.
  ;; Return nil if there is no match.
  (let ((pos (point))
        (dist (or max-length (length regexp)))
        match1 match2 match)
    (goto-char (min (+ pos dist) (point-max)))
    (when (re-search-backward regexp nil t)
      (setq match1 (match-data)))
    (goto-char (max (- pos dist) (point-min)))
    (when (re-search-forward regexp nil t)
      (setq match2 (match-data)))
    (goto-char pos)
    (setq match
          (cond
           ((not match1) match2)
           ((not match2) match1)
           ((< (abs (- pos (car match1))) (abs (- pos (car match2)))) match1)
           (t match2)))
    (if match (progn (set-match-data match) t) nil)))

(defun reftex-auto-mode-alist ()
  ;; Return an `auto-mode-alist' with only the .gz (etc) thingies.
  ;; Stolen from gnus nnheader.
  (let ((alist auto-mode-alist)
        out)
    (while alist
      (when (listp (cdr (car alist)))
        (push (car alist) out))
      (pop alist))
    (nreverse out)))

(defun reftex-window-height ()
  (if (fboundp 'window-displayed-height)
      (window-displayed-height)
    (window-height)))

(defun reftex-enlarge-to-fit (buf2 &optional keep-current)
  ;; Enlarge other window displaying buffer to show whole buffer if possible.
  ;; If KEEP-CURRENT in non-nil, current buffer must remain visible.
  (let* ((win1 (selected-window))
         (buf1 (current-buffer))
         (win2 (get-buffer-window buf2))) ;; Only on current frame.
    (when win2
      (select-window win2)
      (unless (and (pos-visible-in-window-p (point-min))
                   (pos-visible-in-window-p (point-max)))
        (enlarge-window (1+ (- (count-lines (point-min) (point-max))
                               (reftex-window-height))))))
    (cond
     ((window-live-p win1) (select-window win1))
     (keep-current
      ;; we must have the old buffer!
      (switch-to-buffer-other-window buf1)
      (shrink-window (- (window-height) window-min-height))))))

(defun reftex-select-with-char (prompt help-string &optional delay-time scroll)
  ;; Offer to select something with PROMPT and, after DELAY-TIME seconds,
  ;; also with HELP-STRING.
  ;; When SCROLL is non-nil, use SPC and DEL to scroll help window.
  (let ((char ?\?))
    (save-window-excursion
      (catch 'exit
        (message "%s   (?=Help)" prompt)
        (when (or (sit-for (or delay-time 0))
                  (= ?\? (setq char (read-char-exclusive))))
          (reftex-kill-buffer "*RefTeX Select*")
          (switch-to-buffer-other-window "*RefTeX Select*")
          (insert help-string)
          (goto-char 1)
          (unless (and (pos-visible-in-window-p (point-min))
                       (pos-visible-in-window-p (point-max)))
            (enlarge-window (1+ (- (count-lines (point-min) (point-max))
                                   (reftex-window-height)))))
          (setq truncate-lines t))
        (if (and (pos-visible-in-window-p (point-min))
                 (pos-visible-in-window-p (point-max)))
            nil
          (setq prompt (concat prompt (if scroll "   (SPC/DEL=Scroll)" ""))))
        (message "%s" prompt)
        (and (equal char ?\?) (setq char (read-char-exclusive)))
        (while t
          (cond ((equal char ?\C-g) (keyboard-quit))
                ((equal char ?\?))
                ((and scroll (equal char ?\ ))
                 (condition-case nil (scroll-up) (error nil))
                 (message "%s" prompt))
                ((and scroll (equal char ?\C-? ))
                 (condition-case nil (scroll-down) (error nil))
                 (message "%s" prompt))
                (t (message "")
		   (reftex-kill-buffer "*RefTeX Select*")
                   (throw 'exit char)))
          (setq char (read-char-exclusive)))))))


(defun reftex-make-regexp-allow-for-ctrl-m (string)
  ;; convert STRING into a regexp, allowing ^M for \n and vice versa
  (let ((start -2))
    (setq string (regexp-quote string))
    (while (setq start (string-match "[\n\r]" string (+ 3 start)))
      (setq string (replace-match "[\n\r]" nil t string)))
    string))

(defun reftex-get-buffer-visiting (file)
  ;; return a buffer visiting FILE
  (cond
   ((boundp 'find-file-compare-truenames) ; XEmacs
    (let ((find-file-compare-truenames t))
      (get-file-buffer file)))
   ((fboundp 'find-buffer-visiting)       ; Emacs
    (find-buffer-visiting file))
   (t (error "This should not happen (reftex-get-buffer-visiting)"))))

;; Define `current-message' for compatibility with XEmacs prior to 20.4
(defvar message-stack)
(if (and (featurep 'xemacs)
         (not (fboundp 'current-message)))
    (defun current-message (&optional _frame)
      (cdr (car message-stack))))

(defun reftex-visited-files (list)
  ;; Takes a list of filenames and returns the buffers of those already visited
  (delq nil (mapcar (lambda (x) (if (reftex-get-buffer-visiting x) x nil))
                    list)))

(defun reftex-get-file-buffer-force (file &optional mark-to-kill)
  ;; Return a buffer visiting file.  Make one, if necessary.
  ;; If neither such a buffer nor the file exist, return nil.
  ;; If MARK-TO-KILL is t and there is no live buffer, visit the file with
  ;; initializations according to `reftex-initialize-temporary-buffers',
  ;; and mark the buffer to be killed after use.

  (let ((buf (reftex-get-buffer-visiting file)))

    (cond (buf
           ;; We have it already as a buffer - just return it
           buf)

          ((file-readable-p file)
           ;; At least there is such a file and we can read it.

           (if (or (not mark-to-kill)
                   (eq t reftex-initialize-temporary-buffers))

               ;; Visit the file with full magic
               (setq buf (find-file-noselect file))

             ;; Else: Visit the file just briefly, without or
             ;;       with limited Magic

             ;; The magic goes away
             (cl-letf ((format-alist nil)
                       (auto-mode-alist (reftex-auto-mode-alist))
                       ((default-value 'major-mode) 'fundamental-mode)
                       (enable-local-variables nil)
                       (after-insert-file-functions nil))
               (setq buf (find-file-noselect file)))

             ;; Is there a hook to run?
             (when (listp reftex-initialize-temporary-buffers)
               (with-current-buffer buf
                 (run-hooks 'reftex-initialize-temporary-buffers))))

           ;; Let's see if we got a license to kill :-|
           (and mark-to-kill
                (cl-pushnew buf reftex-buffers-to-kill))

           ;; Return the new buffer
           buf)

          ;; If no such file exists, return nil
          (t nil))))

(defun reftex-kill-temporary-buffers (&optional buffer)
  ;; Kill all buffers in the list reftex-kill-temporary-buffers.
  (cond
   (buffer
    (when (member buffer reftex-buffers-to-kill)
      (kill-buffer buffer)
      (setq reftex-buffers-to-kill
            (delete buffer reftex-buffers-to-kill))))
   (t
    (while (setq buffer (pop reftex-buffers-to-kill))
      (when (bufferp buffer)
        (and (buffer-modified-p buffer)
             (y-or-n-p (format "Save file %s? "
                               (buffer-file-name buffer)))
             (with-current-buffer buffer
               (save-buffer)))
        (kill-buffer buffer))
      (pop reftex-buffers-to-kill)))))

(defun reftex-splice-symbols-into-list (list alist)
  ;; Splice the association in ALIST of any symbols in LIST into the list.
  ;; Return new list.
  (let (rtn tmp)
    (while list
      (while (and (not (null (car list)))  ;; keep list elements nil
                  (symbolp (car list)))
        (setq tmp (car list))
        (cond
         ((assoc tmp alist)
          (setq list (append (nth 2 (assoc tmp alist)) (cdr list))))
         (t
          (error "Cannot treat symbol %s in reftex-label-alist"
                 (symbol-name tmp)))))
      (push (pop list) rtn))
    (nreverse rtn)))

(defun reftex-remove-symbols-from-list (list)
  ;; Remove all symbols from list
  (let (rtn)
    (while list
      (unless (symbolp (car list))
        (push (car list) rtn))
      (setq list (cdr list)))
    (nreverse rtn)))

(defun reftex-uniquify (list &optional sort)
  ;; Return a list of all strings in LIST, but each only once, keeping order
  ;; unless SORT is set (faster!).
  (setq list (copy-sequence list))
  (if sort
      (progn
	(setq list (sort list 'string<))
	(let ((p list))
	  (while (cdr p)
	    (if (string= (car p) (car (cdr p)))
		(setcdr p (cdr (cdr p)))
	      (setq p (cdr p)))))
	list)
    (let ((p list) lst elt)
      ;; push all sublists into lst in reverse(!) order
      (while p
	(push p lst)
	(setq p (cdr p)))
      ;; sort all sublists
      (setq lst (sort lst (lambda (x1 x2) (string< (car x1) (car x2)))))
      (while (cdr lst)
	(setq elt (car (car lst)))
	;; for equal elements in the sorted sublist, replace the
	;; last(!) original list member with nil
	(when (string= elt (car (cadr lst)))
	  (setcar (pop lst) nil)
	  (while (and (cdr lst) (string= elt (car (cadr lst))))
	    (setcar (pop lst) nil)))
	(pop lst)))
    ;; weed out all nils and return.
    (delq nil list)))

(defun reftex-uniquify-by-car (alist &optional keep-list sort)
  ;; Return a list of all elements in ALIST, but each car only once.
  ;; Elements of KEEP-LIST are not removed even if duplicate.
  ;; The order is kept unless SORT is set (faster!).
  (setq keep-list (sort (copy-sequence keep-list) #'string<)
	alist (copy-sequence alist))
  (if sort
      (let (lst elt)
	(setq alist (sort alist (lambda(a b) (string< (car a) (car b)))))
	(setq lst alist)
	(while (cdr lst)
	  (setq elt (car (car lst)))
	  (when (string= elt (car (cadr lst)))
	    (while (and keep-list (string< (car keep-list) elt))
	      (pop keep-list))
	    (if (and keep-list (string= elt (car keep-list)))
		(progn
		  (pop lst)
		  (while (and (cdr lst)
			      (string= elt (car (cadr lst))))
		    (pop lst)))
	      (setcdr lst (cdr (cdr lst)))
	      (while (and (cdr lst)
			  (string= elt (car (cadr lst))))
		(setcdr lst (cdr (cdr lst))))))
	  (pop lst))
	alist)
    (let ((p alist) lst elt)
      (while p
	(push p lst)
	(setq p (cdr p)))
      (setq lst (sort lst (lambda(a b) (string< (car (car a))
						(car (car b))))))
      (while (cdr lst)
	(setq elt (car (car (car lst))))
	(when (string= elt (car (car (cadr lst))))
	  (while (and keep-list (string< (car keep-list) elt))
	    (pop keep-list))
	  (if (and keep-list (string= elt (car keep-list)))
	      (progn
		(pop lst)
		(while (and (cdr lst)
			    (string= elt (car (car (cadr lst)))))
		  (pop lst)))
	    (setcar (pop lst) nil)
	    (while (and (cdr lst)
			(string= elt (car (car (cadr lst)))))
	      (setcar (pop lst) nil))))
	(pop lst)))
    (delq nil alist)))

(defun reftex-remove-if (predicate list)
  "Nondestructively remove all items from LIST which satisfy PREDICATE."
  (let (result)
    (dolist (elt list (nreverse result))
      (unless (funcall predicate elt)
	(push elt result)))))

(defun reftex-abbreviate-title (string)
  (reftex-convert-string string "[-~ \t\n\r,;]" nil t t
                         5 40 nil 1 " " (nth 5 reftex-derive-label-parameters)))

(defun reftex-convert-string (string split-re invalid-re dot keep-fp
                                     nwords maxchar invalid abbrev sep
                                     ignore-words &optional downcase)
  "Convert a string (a sentence) to something shorter.
SPLIT-RE     is the regular expression used to split the string into words.
INVALID-RE   matches characters which are invalid in the final string.
DOT          t means add dots to abbreviated words.
KEEP-FP      t means to keep a final punctuation when applicable.
NWORDS       Number of words to use.
MAXCHAR      Maximum number of characters in the final string.
INVALID      nil: Throw away any words containing stuff matched with INVALID-RE.
             t:   Throw away only the matched part, not the whole word.
ABBREV       nil: Never abbreviate words.
             t:   Always abbreviate words (see `reftex-abbrev-parameters').
             not t and not nil: Abbreviate words if necessary to shorten
                                string below MAXCHAR.
SEP          String separating different words in the output string.
IGNORE-WORDS List of words which should be removed from the string."

  (let* ((words0 (split-string string (or split-re "[ \t\n\r]")))
         (reftex-label-illegal-re (or invalid-re "\000"))
         (abbrev-re (concat
                     "\\`\\("
                     (make-string (nth 0 reftex-abbrev-parameters) ?.)
                     "[" (nth 2 reftex-abbrev-parameters) "]*"
                     "\\)"
                     "[" (nth 3 reftex-abbrev-parameters) "]"
                     (make-string (1- (nth 1 reftex-abbrev-parameters)) ?.)))
         words word)

    ;; Remove words from the ignore list or with funny characters
    (while (setq word (pop words0))
      (if downcase (setq word (downcase word)))
      (cond
       ((member (downcase word) ignore-words))
       ((string-match reftex-label-illegal-re word)
        (when invalid
          (while (string-match reftex-label-illegal-re word)
            (setq word (replace-match "" nil nil word)))
          (push word words)))
       (t
        (push word words))))
    (setq words (nreverse words))

    ;; Restrict number of words
    (if (> (length words) nwords)
        (setcdr (nthcdr (1- nwords) words) nil))

    ;; First, try to use all words
    (setq string (mapconcat 'identity words sep))

    ;; Abbreviate words if enforced by user settings or string length
    (if (or (eq t abbrev)
            (and abbrev
                 (> (length string) maxchar)))
        (setq words
              (mapcar
               (lambda (w) (if (string-match abbrev-re w)
                               (if dot
                                   (concat (match-string 1 w) ".")
                                 (match-string 1 w))
                             w))
               words)
              string (mapconcat 'identity words sep)))

    ;; Shorten if still to long
    (setq string
          (if (> (length string) maxchar)
              (substring string 0 maxchar)
            string))

    ;; Delete the final punctuation, if any
    (if (and (not keep-fp) (string-match "\\s.+\\'" string))
        (setq string (replace-match "" nil nil string)))
    string))

(defun reftex-nicify-text (text)
  ;; Make TEXT nice for inclusion as context into label menu.
  ;; 1. remove line breaks and extra white space
  (while (string-match "[\n\r\t]\\|[ \t][ \t]+" text)
    (setq text (replace-match " " nil t text)))
  ;; 2. cut before the next `\end{' or `\item' or `\\'
  (if (string-match "\\(\\\\end{\\|\\\\item\\|\\\\\\\\\\).*" text)
      (setq text (replace-match "" nil t text)))
  ;; 3. kill the embedded label
  (if (string-match "\\\\label{[^}]*}" text)
      (setq text (replace-match "" nil t text)))
  ;; 4. remove leading garbage
  (if (string-match "\\`[ }]+" text)
      (setq text (replace-match "" nil t text)))
  ;; 5. limit length
  (cond
   ((> (length text) 100) (substring text 0 100))
   ((= (length text) 0) (make-string 1 ?\ ))
   (t text)))


;;; =========================================================================
;;;
;;; Fontification and Highlighting

(defun reftex-use-fonts ()
  ;; Return t if we can and want to use fonts.
  (and ; window-system
       reftex-use-fonts
       (featurep 'font-lock)))

(defun reftex-refontify ()
  ;; Return t if we need to refontify context
  (and (reftex-use-fonts)
       (or (eq t reftex-refontify-context)
           (and (eq 1 reftex-refontify-context)
                ;; Test of we use the font-lock version of x-symbol
                (and (featurep 'x-symbol-tex) (not (boundp 'x-symbol-mode)))))))

(defvar font-lock-defaults-computed)
(defun reftex-fontify-select-label-buffer (parent-buffer)
  ;; Fontify the `*RefTeX Select*' buffer.  Buffer is temporarily renamed to
  ;; start with none-SPC char, because Font-Lock otherwise refuses operation.
  (run-hook-with-args 'reftex-pre-refontification-functions
                      parent-buffer 'reftex-ref)
  (let* ((oldname (buffer-name))
         (newname (concat "Fontify-me-" oldname)))
    (unwind-protect
        (progn
          ;; Rename buffer temporarily to start w/o space (because of font-lock)
          (rename-buffer newname t)
          (cond
           ((fboundp 'font-lock-default-fontify-region)
            ;; Good: we have the indirection functions
            (set (make-local-variable 'font-lock-fontify-region-function)
                 'reftex-select-font-lock-fontify-region)
            (let ((major-mode 'latex-mode))
              (font-lock-mode 1)))
           ((fboundp 'font-lock-set-defaults-1)
            ;; Looks like the XEmacs font-lock stuff.
            ;; FIXME: this is still kind of a hack, but it works.
            (set (make-local-variable 'font-lock-keywords) nil)
            (let ((major-mode 'latex-mode)
                  (font-lock-defaults-computed nil))
              (font-lock-set-defaults-1)
              (reftex-select-font-lock-fontify-region (point-min) (point-max))))
           (t
            ;; Oops?
            (message "Sorry: cannot refontify RefTeX Select buffer."))))
      (rename-buffer oldname))))

(defun reftex-select-font-lock-fontify-region (beg end &optional _loudly)
  ;; Fontify a region, but only lines starting with a dot.
  (let ((func (if (fboundp 'font-lock-default-fontify-region)
                  'font-lock-default-fontify-region
                'font-lock-fontify-region))
        beg1 end1)
    (goto-char beg)
    (while (re-search-forward "^\\." end t)
      (setq beg1 (point) end1 (progn (skip-chars-forward "^\n") (point)))
      (funcall func beg1 end1 nil)
      (goto-char end1))))

(defun reftex-select-font-lock-unfontify (&rest _ignore) t)

(defun reftex-verified-face (&rest faces)
  ;; Return the first valid face in FACES, or nil if none is valid.
  ;; Also, when finding a nil element in FACES, return nil.  This
  ;; function is just a safety net to catch name changes of builtin
  ;; fonts. Currently it is only used for reftex-label-face.
  (let (face)
    (catch 'exit
      (while (setq face (pop faces))
        (if (featurep 'xemacs)
            (if (find-face face) (throw 'exit face))
          (if (facep face) (throw 'exit face)))))))

;; Highlighting uses overlays.  For XEmacs, we use extends.
(defalias 'reftex-make-overlay
  (if (featurep 'xemacs) 'make-extent 'make-overlay))
(defalias 'reftex-overlay-put
  (if (featurep 'xemacs) 'set-extent-property 'overlay-put))
(defalias 'reftex-move-overlay
  (if (featurep 'xemacs) 'set-extent-endpoints 'move-overlay))
(defalias 'reftex-delete-overlay
  (if (featurep 'xemacs) 'detach-extent 'delete-overlay))

;; We keep a vector with several different overlays to do our highlighting.
(defvar reftex-highlight-overlays [nil nil nil])

;; Initialize the overlays
(aset reftex-highlight-overlays 0 (reftex-make-overlay 1 1))
(reftex-overlay-put (aref reftex-highlight-overlays 0)
             'face 'highlight)
(aset reftex-highlight-overlays 1 (reftex-make-overlay 1 1))
(reftex-overlay-put (aref reftex-highlight-overlays 1)
             'face reftex-cursor-selected-face)
(aset reftex-highlight-overlays 2 (reftex-make-overlay 1 1))
(reftex-overlay-put (aref reftex-highlight-overlays 2)
             'face reftex-cursor-selected-face)

;; Two functions for activating and deactivation highlight overlays
(defun reftex-highlight (index begin end &optional buffer)
  "Highlight a region with overlay INDEX."
  (reftex-move-overlay (aref reftex-highlight-overlays index)
                begin end (or buffer (current-buffer))))
(defun reftex-unhighlight (index)
  "Detach overlay INDEX."
  (reftex-delete-overlay (aref reftex-highlight-overlays index)))

(defun reftex-highlight-shall-die ()
  ;; Function used in pre-command-hook to remove highlights.
  (remove-hook 'pre-command-hook 'reftex-highlight-shall-die)
  (reftex-unhighlight 0))

;;; =========================================================================
;;;
;;; Keybindings

(defvar bibtex-mode-map)

;; Bind `reftex-view-crossref-from-bibtex' in BibTeX mode map
(eval-after-load
 "bibtex"
 '(define-key bibtex-mode-map "\C-c&" 'reftex-view-crossref-from-bibtex))

;;; =========================================================================
;;;
;;; Menu

;; Define a menu for the menu bar if Emacs is running under X

(defvar reftex-isearch-minor-mode nil)
(make-variable-buffer-local 'reftex-isearch-minor-mode)

(easy-menu-define reftex-mode-menu reftex-mode-map
 "Menu used in RefTeX mode"
 `("Ref"
   ["Table of Contents"       reftex-toc t]
   ["Recenter TOC"            reftex-toc-recenter t]
   "--"
   ["\\label"                 reftex-label t]
   ["\\ref"                   reftex-reference t]
   ["\\cite"                  reftex-citation t]
   ("\\index"
    ["\\index"                    reftex-index t]
    ["\\index{THIS}"              reftex-index-selection-or-word t]
    "--"
    ["Add THIS to Index Phrases"  reftex-index-phrase-selection-or-word t]
    ["Visit Phrase Buffer"        reftex-index-visit-phrases-buffer t]
    ["Apply Phrases to Region"    reftex-index-phrases-apply-to-region t]
    "--"
    ["Display the Index"          reftex-display-index t])
   "--"
   ["View Crossref"           reftex-view-crossref t]
   "--"
   ("Parse Document"
    ["One File"               reftex-parse-one reftex-enable-partial-scans]
    ["Entire Document"        reftex-parse-all t]
    ["Save to File"           (reftex-access-parse-file 'write)
     (> (length (symbol-value reftex-docstruct-symbol)) 0)]
    ["Restore from File"      (reftex-access-parse-file 'restore) t])
   ("Global Actions"
    ["Search Whole Document"  reftex-search-document t]
    ["Search Again"           tags-loop-continue t]
    ["Replace in Document"    reftex-query-replace-document t]
    ["Grep on Document"       reftex-grep-document t]
    "--"
    ["Goto Label"             reftex-goto-label t]
    ["Find Duplicate Labels"  reftex-find-duplicate-labels t]
    ["Change Label and Refs"  reftex-change-label t]
    ["Renumber Simple Labels" reftex-renumber-simple-labels t]
    "--"
    ["Create BibTeX File"     reftex-create-bibtex-file t]
    "--"
    ["Create TAGS File"       reftex-create-tags-file t]
    "--"
    ["Save Document"          reftex-save-all-document-buffers t])
   "--"
   ("Options"
    "PARSER"
    ["Partial Scans"
     (setq reftex-enable-partial-scans (not reftex-enable-partial-scans))
     :style toggle :selected reftex-enable-partial-scans]
    ["Auto-Save Parse Info"
     (setq reftex-save-parse-info (not reftex-save-parse-info))
     :style toggle :selected reftex-save-parse-info]
    "--"
    "TOC RECENTER"
    ["Automatic Recenter" reftex-toggle-auto-toc-recenter
     :style toggle :selected reftex-toc-auto-recenter-timer]
    "--"
    "CROSSREF INFO"
    ["Automatic Info" reftex-toggle-auto-view-crossref
     :style toggle :selected reftex-auto-view-crossref-timer]
    ["...in Echo Area" (setq reftex-auto-view-crossref t)
     :style radio :selected (eq reftex-auto-view-crossref t)]
    ["...in Other Window" (setq reftex-auto-view-crossref 'window)
     :style radio :selected (eq reftex-auto-view-crossref 'window)]
    "--"
    "MISC"
    ["AUCTeX Interface" reftex-toggle-plug-into-AUCTeX
     :style toggle :selected reftex-plug-into-AUCTeX]
    ["isearch whole document" reftex-isearch-minor-mode
     :style toggle :selected reftex-isearch-minor-mode])
   ("Reference Style"
    ,@(let (list item)
	(dolist (elt reftex-ref-style-alist)
	  (setq elt (car elt)
		item (vector
		      elt
		      `(reftex-ref-style-toggle ,elt)
		      :style 'toggle
		      :selected `(member ,elt (reftex-ref-style-list))))
	  (unless (member item list)
            (setq list (append list (list item)))))
	list))
   ("Citation Style"
    ,@(mapcar
       (lambda (x)
         (vector
          (capitalize (symbol-name (car x)))
          (list 'reftex-set-cite-format (list 'quote (car x)))
          :style 'radio :selected
          (list 'eq (list 'reftex-get-cite-format) (list 'quote (car x)))))
       reftex-cite-format-builtin)
    "--"
    "Sort Database Matches"
    ["Not" (setq reftex-sort-bibtex-matches nil)
     :style radio :selected (eq reftex-sort-bibtex-matches nil)]
    ["by Author" (setq reftex-sort-bibtex-matches 'author)
     :style radio :selected (eq reftex-sort-bibtex-matches 'author)]
    ["by Year" (setq reftex-sort-bibtex-matches 'year)
     :style radio :selected (eq reftex-sort-bibtex-matches 'year)]
    ["by Year, reversed" (setq reftex-sort-bibtex-matches 'reverse-year)
     :style radio :selected (eq reftex-sort-bibtex-matches 'reverse-year)])
   ("Index Style"
    ,@(mapcar
       (lambda (x)
         (vector
          (capitalize (symbol-name (car x)))
          (list 'reftex-add-index-macros (list 'list (list 'quote (car x))))
          :style 'radio :selected
          (list 'memq (list 'quote (car x))
                (list 'get 'reftex-docstruct-symbol
                      (list 'quote 'reftex-index-macros-style)))))
       reftex-index-macros-builtin))
   "--"
    ["Reset RefTeX Mode"       reftex-reset-mode t]
   "--"
   ("Customize"
    ["Browse RefTeX Group" reftex-customize t]
    "--"
    ["Build Full Customize Menu" reftex-create-customize-menu
     (fboundp 'customize-menu-create)])
   ("Documentation"
    ["Info" reftex-info t]
    ["Commentary" reftex-show-commentary t])))

(defun reftex-customize ()
  "Call the customize function with reftex as argument."
  (interactive)
  (customize-browse 'reftex))

(defun reftex-create-customize-menu ()
  "Create a full customization menu for RefTeX, insert it into the menu."
  (interactive)
  (if (fboundp 'customize-menu-create)
      (progn
        (easy-menu-change
         '("Ref") "Customize"
         `(["Browse RefTeX group" reftex-customize t]
           "--"
           ,(customize-menu-create 'reftex)
           ["Set" Custom-set t]
           ["Save" Custom-save t]
           ["Reset to Current" Custom-reset-current t]
           ["Reset to Saved" Custom-reset-saved t]
           ["Reset to Standard Settings" Custom-reset-standard t]))
        (message "\"Ref\"-menu now contains full customization menu"))
    (error "Cannot expand menu (outdated version of cus-edit.el)")))


;;; Misc

(defun reftex-show-commentary ()
  "Use the finder to view the file documentation from `reftex.el'."
  (interactive)
  (finder-commentary "reftex.el"))

(defun reftex-info (&optional node)
  "Read documentation for RefTeX in the info system.
With optional NODE, go directly to that node."
  (interactive)
  (info (format "(reftex)%s" (or node ""))))

(defun reftex-report-bug ()
  "Report a bug in RefTeX.

Don't hesitate to report any problems or inaccurate documentation.

If you don't have setup sending mail from (X)Emacs, please copy the
output buffer into your mail program, as it gives us important
information about your RefTeX version and configuration."
  (interactive)
  (require 'reporter)
  (defvar reporter-prompt-for-summary-p)
  (let ((reporter-prompt-for-summary-p "Bug report subject: "))
    (reporter-submit-bug-report
     "bug-auctex@gnu.org, bug-gnu-emacs@gnu.org"
     reftex-version
     (list 'window-system
	   'reftex-plug-into-AUCTeX)
     nil nil
     "Remember to cover the basics, that is, what you expected to happen and
what in fact did happen.

Check if the bug is reproducible with an up-to-date version of
RefTeX available from https://www.gnu.org/software/auctex/.

If the bug is triggered by a specific (La)TeX file, you should try
to produce a minimal sample file showing the problem and include it
in your report.

Your bug report will be posted to the AUCTeX bug reporting list.
------------------------------------------------------------------------")))

;;; Install the kill-buffer and kill-emacs hooks ------------------------------

(add-hook 'kill-buffer-hook 'reftex-kill-buffer-hook)
(unless noninteractive
  (add-hook 'kill-emacs-hook  'reftex-kill-emacs-hook))

;;; Run Hook ------------------------------------------------------------------

(run-hooks 'reftex-load-hook)

;;; That's it! ----------------------------------------------------------------

(setq reftex-tables-dirty t)  ; in case this file is evaluated by hand

(provide 'reftex)

;;; reftex.el ends here