aboutsummaryrefslogtreecommitdiffhomepage
path: root/twelf/twelf-old.el
blob: 62763ba4a0d168c20c2429c3cd5231ebc51bd04e (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
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
;; twelf-old.el  Port of old Twelf Emacs mode
;;
;; Author: Frank Pfenning
;;	   Adapted for Proof General by David Aspinall <David.Aspinall@ed.ac.uk>
;;
;; $Id$
;;
;;

;; FIXME: have copied over directly!

;;; Modes and utilities for Twelf programming.  This package supports (1)
;;; editing Twelf source files with reasonable indentation, (2) managing
;;; configurations of Twelf source files, including TAGS tables, (3)
;;; communication with an inferior Twelf server to type-check and execute
;;; declarations and queries, (4) interaction with an inferior Twelf process
;;; in SML.
;;;
;;; For documentation, type C-h m in Twelf mode, or see the function
;;; twelf-mode below
;;;
;;; Author: Frank Pfenning
;;; Thu Oct 7 19:48:50 1993 (1.0 created)
;;; Fri Jan 6 09:06:38 1995 (2.0 major revision)
;;; Tue Jun 16 15:49:31 1998 (3.0 major revision)
;;;
;;;======================================================================
;;; For the `.emacs' file (copied from init.el)
;;;======================================================================
;;;
;;; ;; Tell Emacs where the Twelf libraries are.
;;; (setq load-path
;;;       (cons "/afs/cs/project/twelf/research/twelf/emacs" load-path))
;;;
;;; ;; Autoload libraries when Twelf-related major modes are started.
;;; (autoload 'twelf-mode "twelf" "Major mode for editing Twelf source." t)
;;; (autoload 'twelf-server "twelf" "Run an inferior Twelf server." t)
;;; (autoload 'twelf-sml "twelf" "Run an inferior Twelf-SML process." t)
;;;
;;; ;; Switch buffers to Twelf mode based on filename extension,
;;; ;; which is one of .elf, .quy, .thm, or .cfg.
;;; (setq auto-mode-alist
;;;       (cons '("\\.elf$" . twelf-mode)
;;;	    (cons '("\\.quy$" . twelf-mode)
;;;		  (cons '("\\.thm$" . twelf-mode)
;;;			(cons '("\\.cfg$" . twelf-mode)
;;;			      auto-mode-alist)))))
;;;
;;; ;; Default Twelf server program location
;;; (setq twelf-server-program
;;;       "/afs/cs/project/twelf/research/twelf/bin/twelf-server")
;;;
;;; ;; Default Twelf SML program location
;;; (setq twelf-sml-program
;;;       "/afs/cs/project/twelf/misc/smlnj/bin/sml-cm")
;;;
;;; ;; Default documentation location (in info format)
;;; (setq twelf-info-file
;;;       "/afs/cs/project/twelf/research/twelf/doc/info/twelf.info")
;;;
;;; ;; Automatically highlight Twelf sources using font-lock
;;; (add-hook 'twelf-mode-hook 'twelf-font-fontify-buffer)
;;;
;;;======================================================================
;;; Command Summary
;;;======================================================================
;;;
;;; Quick summary of Twelf mode, generated from C-h b:
;;;
;;; --- Editing Commands ---
;;; TAB          twelf-indent-line
;;; DEL          backward-delete-char-untabify
;;; M-C-q        twelf-indent-decl
;;;
;;; --- Type Checking ---
;;; C-c C-c      twelf-save-check-config
;;; C-c C-s      twelf-save-check-file
;;; C-c C-d      twelf-check-declaration
;;; C-c c        twelf-type-const
;;; C-c C-u      twelf-server-display
;;;
;;; --- Error Tracking ---
;;; C-c `        twelf-next-error
;;; C-c =        twelf-goto-error
;;;
;;; --- Syntax Highlighting ---
;;; C-c C-l      twelf-font-fontify-decl
;;; C-c l        twelf-font-fontify-buffer
;;;
;;; --- Server State ---
;;; C-c <        twelf-set
;;; C-c >        twelf-get
;;; C-c C-i      twelf-server-interrupt
;;; M-x twelf-server
;;; M-x twelf-server-configure
;;; M-x twelf-server-quit
;;; M-x twelf-server-restart
;;; M-x twelf-server-send-command
;;;
;;; --- Timers ---
;;; M-x twelf-timers-reset
;;; M-x twelf-timers-show
;;; M-x twelf-timers-check
;;;
;;; --- Tags (standard Emacs etags package) ---
;;; M-x twelf-tag
;;; M-.          find-tag (standard binding)
;;; C-x 4 .      find-tag-other-window (standard binding)
;;; C-c q        tags-query-replace (Twelf mode binding)
;;; C-c s        tags-search (Twelf mode binding)
;;; M-,          tags-loop-continue (standard binding)
;;;              visit-tags-table, list-tags, tags-apropos
;;;
;;; --- Communication with inferior Twelf-SML process (not Twelf Server) ---
;;; M-x twelf-sml
;;; C-c C-e      twelf-sml-send-query
;;; C-c C-r      twelf-sml-send-region
;;; C-c RET      twelf-sml-send-newline
;;; C-c ;        twelf-sml-send-semicolon
;;; C-c d        twelf-sml-cd
;;; M-x twelf-sml-quit
;;;
;;; --- Variables ---
;;; twelf-indent        amount of indentation for nested Twelf expressions
;;;
;;;======================================================================
;;; Some Terminology
;;;======================================================================
;;;
;;; Twelf Server --- an inferior process that services requests to type-check,
;;; load, or execute declarations and queries.  It is usually attached to the
;;; buffer *twelf-server*.  Requests are generated by Emacs from user commands,
;;; or may be typed directly into the Twelf server buffer.
;;;
;;; Current configuration --- A configuration is an ordered list of
;;; Twelf source files in dependency order.  It is usually initialized
;;; and maintained in a file sources.cfg.  The current configuration is
;;; also the bases for the TAGS file created by twelf-tags.  This allows
;;; quick jumping to declaration sites for constants, or to apply
;;; searches or replacements to all files in a configuration.
;;;
;;; Current Twelf declaration --- When checking individual declarations
;;; Emacs must extract it from the current buffer and then send it to
;;; the server.  This is necessarily based on a heuristic, since Emacs
;;; does not know enough in order to parse Twelf source properly in all
;;; cases, but it knows the syntax for comments, Twelf identifiers, and
;;; matching delimiters.  Search for the end or beginning of a
;;; declaration is always limited by double blank lines in order to be
;;; more robust (in case a period is missing at the end of a
;;; declaration).  If the point falls between declarations, the
;;; declaration after the point is considered current.
;;;
;;; Twelf-SML --- During development or debugging of the Twelf
;;; implementation itself it is often useful to interact with SML, the
;;; language in which Twelf is implementated, rather than using an Twelf
;;; server.  This is an inferior SML process which may run a Twelf
;;; query interpreter.
;;;
;;;======================================================================
;;; Change Log
;;;======================================================================
;;;
;;; Thu Jun  3 14:51:35 1993 -fp
;;; Added variable display-elf-queries.  If T (default) redisplays Elf
;;; buffer after a query has been sent.  Delays one second after sending
;;; the query which is rather arbitrary.
;;; Wed Jun 30 19:57:58 1993
;;; - Error messages in the format line0.col0-line1.col1 can now be parsed.
;;; - Error from std_in, either interactive or through elf-send-query
;;;   can now be tracked.
;;; - Added simple directory tracking and function elf-cd, bound to C-c d.
;;; - improved filename completion in Elf mode under Lucid Emacs.
;;; - replaced tail recursion in elf-indent-line by a while loop.
;;; - changed elf-input-filter to ignore one character inputs.
;;; - elf-error-marker is now updated on every interactive input or send.
;;; - added commands elf-send-newline, bound to C-c RET
;;;   and elf-send-semicolon, bound to C-c ;.
;;;   These are useful when sending queries from a buffer with examples.
;;; Fri Sep  3 15:02:10 1993
;;; Changed definition of elf-current-paragraph so that it recognizes
;;; individual declarations within a traditional ``paragraph'' (separated
;;; by blank lines).
;;; Fri Oct 22 10:05:08 1993
;;; Changed elf-send-query to ensure that the Elf process expects a query
;;; If the Elf process is at the SML prompt, it starts a top level.
;;; If the Elf process is waiting after printing an answer substitution,
;;; it sends a RET.
;;; This is based on a heuristic analysis of the contents of the Elf buffer.
;;; Fri Dec 16 15:27:14 1994
;;; Changed elf-error-marker to elf-error-pos, since it moved in undesirable
;;; ways in Emacs 19.
;;; Fri Jan  6 09:06:54 1995
;;; Major revision: incorporating elf-server.el and elf-tag.el
;;; Thu Jan 12 14:31:36 1995
;;; Finished major revision (version 2.0)
;;; Sat Jun 13 12:14:34 1998
;;; Renamed to Twelf and incorporated menus from elf-menu.el
;;; Major revision for Twelf 1.2 release
;;; Q: Improve tagging for %keyword declarations?
;;; Thu Jun 25 08:52:41 1998
;;; Finished major revision (version 3.0)
;;; Fri Oct  2 11:06:15 1998
;;; Added NT Emacs bug workaround

(require 'comint)
(require 'easymenu)

;;;----------------------------------------------------------------------
;;; User visible variables
;;;----------------------------------------------------------------------

(defvar twelf-indent 3
  "*Indent for Twelf expressions.")

(defvar twelf-infix-regexp ":\\|\\<->\\>\\|\\<<-\\>\\|\\<=\\>"
  "*Regular expression to match Twelf infix operators.
Match must exclude surrounding whitespace.  This is used for indentation.")

(defvar twelf-server-program "twelf-server"
  "*Default Twelf server program.")

(defvar twelf-info-file "twelf.info"
  "*Default info file for Twelf.")

(defvar twelf-server-display-commands nil
  "*If non-nil, the Twelf server buffer will be displayed after each command.
Normally, the Twelf server buffer is displayed only after some selected
commands or if a command is given a prefix argument.")

(defvar twelf-highlight-range-function 'twelf-highlight-range-zmacs
  "*Function which highlights the range analyzed by the server.
This is called for certain commands which apply to a subterm at point.
You may want to change this for FSF Emacs, XEmacs and/or highlight packages.")

(defvar twelf-focus-function 'twelf-focus-noop
  "*Function which focusses on the current declaration or query.
This is called for certain commands which pick out (a part of) a declaration
or query.  You may want to change this for FSF Emacs, XEmacs and/or highlight
packages.")

(defvar twelf-server-echo-commands t
  "*If nil, Twelf server commands will not be echoed in the Twelf server buffer.")

(defvar twelf-save-silently nil
  "*If non-nil, modified buffers are saved without confirmation
before `twelf-check-config' if they belong to the current configuration.")

(defvar twelf-server-timeout 5
  "*Number of seconds before the server is considered delinquent.
This is unsupported in some versions of Emacs.")

(defvar twelf-sml-program "twelf-sml"
  "*Default Twelf-SML program.")

(defvar twelf-sml-args '()
  "*Arguments to Twelf-SML program.")

(defvar twelf-sml-display-queries t
  "*If nil, the Twelf-SML buffer will not be selected after a query.")

(defvar twelf-mode-hook '()
  "List of hook functions to run when switching to Twelf mode.")

(defvar twelf-server-mode-hook '()
  "List of hook functions to run when switching to Twelf Server mode.")

(defvar twelf-config-mode-hook '()
  "List of hook functions to run when switching to Twelf Config minor mode.")

(defvar twelf-sml-mode-hook '()
  "List of hook functions for Twelf-SML mode.")

(defvar twelf-to-twelf-sml-mode '()
  "List of hook functions for 2Twelf-SML minor mode.")

(defvar twelf-config-mode nil
  "Non-NIL means the Twelf Config minor mode is in effect.")

;;;----------------------------------------------------------------------
;;; Internal variables
;;;----------------------------------------------------------------------

(defvar *twelf-server-buffer-name* "*twelf-server*"
  "The default name for the Twelf server buffer.")

(defvar *twelf-server-buffer* nil
  "The buffer with the Twelf server if one exists.")

(defvar *twelf-server-process-name* "twelf-server"
  "Name of the Twelf server process.")

(defvar *twelf-config-buffer* nil
  "The current Twelf configuration buffer if one exists.")

(defvar *twelf-config-time* nil
  "The modification time of Twelf configuration file when read by the server.")

(defvar *twelf-config-list* nil
  "The reversely ordered list with files in the current Twelf configuration.")

(defvar *twelf-server-last-process-mark* 0
  "The process mark before the last command in the Twelf server buffer.")

(defvar *twelf-last-region-sent* nil
  "Contains a list (BUFFER START END) identifying the last region sent
to the Twelf server or Twelf-SML process for error tracking.
If nil, then the last input was interactive.
If t, then the last input was interactive, but has already been copied
to the end of the Twelf-SML buffer.")

(defvar *twelf-last-input-buffer* nil
  "Last buffer to which input was sent.
This is used by the error message parser.")

(defvar *twelf-error-pos* 0
  "Last error position in the server buffer.")

(defconst *twelf-read-functions*
  '((nat . twelf-read-nat)
    (bool . twelf-read-bool)
    (limit . twelf-read-limit)
    (strategy . twelf-read-strategy))
  "Association between Twelf parameter types and their Emacs read functions.")

(defconst *twelf-parm-table*
  '(("chatter" . nat)
    ("doubleCheck" . bool)
    ("Print.implicit" . bool)
    ("Print.depth" . limit)
    ("Print.length" . limit)
    ("Print.indent" . nat)
    ("Print.width" . nat)
    ("Prover.strategy" . strategy)
    ("Prover.maxSplit" . nat)
    ("Prover.maxRecurse" . nat))
  "Association between Twelf parameters and their types.")

(defvar twelf-chatter 3
  "Chatter level in current Twelf server.
Maintained to present reasonable menus.")

;(defvar twelf-trace 0
;  "Trace level in current Twelf server.
;Maintained to present reasonable menus.")

(defvar twelf-double-check "false"
  "Current value of doubleCheck Twelf parameter.")

(defvar twelf-print-implicit "false"
  "Current value of Print.implicit Twelf parameter.")

(defconst *twelf-track-parms*
  '(("chatter" . twelf-chatter)
    ;("trace" . twelf-trace)
    ("doubleCheck" . twelf-double-check)
    ("Print.implicit" . twelf-print-implicit))
  "Association between Twelf parameters and Emacs tracking variables.")

;;;----------------------------------------------------------------------
;;; Basic key bindings
;;;----------------------------------------------------------------------

(defun install-basic-twelf-keybindings (map)
  "General key bindings for Twelf and Twelf Server modes."
  ;; Additional tag keybindings
  (define-key map "\C-cq" 'tags-query-replace)
  (define-key map "\C-cs" 'tags-search)
  ;; Server state
  (define-key map "\C-c<" 'twelf-set)
  (define-key map "\C-c>" 'twelf-get)
  ;; Error handling
  (define-key map "\C-c`" 'twelf-next-error)
  (define-key map "\C-c=" 'twelf-goto-error)
  ;; Proper indentation
  (define-key map "\e\C-q" 'twelf-indent-decl)
  (define-key map "\t" 'twelf-indent-line)
  (define-key map "\177" 'backward-delete-char-untabify)
  ;; Info documentation
  (define-key map "\C-c\C-h" 'twelf-info)
  )

;;;----------------------------------------------------------------------
;;; Twelf mode
;;; This mode should be used for files with Twelf declarations,
;;; usually *.elf, *.quy, or *.thm, and Twelf configuration files *.cfg
;;;----------------------------------------------------------------------

(defun install-twelf-keybindings (map)
  "Install the key bindings for the Twelf mode."
  (define-key map "\C-cl" 'twelf-font-fontify-buffer) ;autoload twelf-font
  (define-key map "\C-c\C-l" 'twelf-font-fontify-decl) ;autoload twelf-font
  (define-key map "\C-c\C-i" 'twelf-server-interrupt)
  (define-key map "\C-c\C-u" 'twelf-server-display)
  (define-key map "\C-cc" 'twelf-type-const)
  ;(define-key map "\C-ce" 'twelf-expected-type-at-point)
  ;(define-key map "\C-cp" 'twelf-type-at-point)
  ;(define-key map "\C-c." 'twelf-complete)
  ;(define-key map "\C-c?" 'twelf-completions-at-point)
  (define-key map "\C-c\C-d" 'twelf-check-declaration)
  (define-key map "\C-c\C-s" 'twelf-save-check-file)
  (define-key map "\C-c\C-c" 'twelf-save-check-config)
  )

(defvar twelf-mode-map nil
  "The keymap used in Twelf mode.")

(cond ((not twelf-mode-map)
       (setq twelf-mode-map (make-sparse-keymap))
       (install-basic-twelf-keybindings twelf-mode-map)
       (install-twelf-keybindings twelf-mode-map)))

;;;----------------------------------------------------------------------
;;; General editing and indentation
;;;----------------------------------------------------------------------

(defvar twelf-mode-syntax-table nil
  "The syntax table used in Twelf mode.")

(defun set-twelf-syntax (char entry)
  (modify-syntax-entry char entry twelf-mode-syntax-table))
(defun set-word (char) (set-twelf-syntax char "w   "))
(defun set-symbol (char) (set-twelf-syntax char "_   "))

(defun map-string (func string)
  (if (string= "" string)
      ()
    (funcall func (string-to-char string))
    (map-string func (substring string 1))))

(if twelf-mode-syntax-table
    ()
  (setq twelf-mode-syntax-table (make-syntax-table))
  ;; A-Z and a-z are already word constituents
  ;; For fontification, it would be better if _ and ' were word constituents
  (map-string 'set-word "!&$^+/<=>?@~|#*`;,-0123456789\\") ; word constituents
  (map-string 'set-symbol "_'")         ; symbol constituents
  ;; Delimited comments are %{ }%, see 1234 below.
  (set-twelf-syntax ?\ "    ")            ; whitespace
  (set-twelf-syntax ?\t "    ")           ; whitespace
  (set-twelf-syntax ?% "< 14")            ; comment begin
  (set-twelf-syntax ?\n ">   ")           ; comment end
  (set-twelf-syntax ?: ".   ")            ; punctuation
  (set-twelf-syntax ?. ".   ")            ; punctuation
  (set-twelf-syntax ?\( "()  ")           ; open delimiter
  (set-twelf-syntax ?\) ")(  ")           ; close delimiter
  (set-twelf-syntax ?\[ "(]  ")           ; open delimiter
  (set-twelf-syntax ?\] ")[  ")           ; close delimiter
  (set-twelf-syntax ?\{ "(}2 ")           ; open delimiter
  (set-twelf-syntax ?\} "){ 3")           ; close delimiter
  ;; Actually, strings are illegal but we include:
  (set-twelf-syntax ?\" "\"   ")          ; string quote
  ;; \ is not an escape, but a word constituent (see above)
  ;;(set-twelf-syntax ?\\ "/   ")         ; escape
  )

(defconst *whitespace* " \t\n\f"
  "Whitespace characters to be skipped by various operations.")

(defconst *twelf-comment-start* (concat "%[%{" *whitespace* "]")
  "Regular expression to match the start of a Twelf comment.")

(defconst *twelf-id-chars* "a-z!&$^+/<=>?@~|#*`;,\\-\\\\A-Z_0-9'"
  "Characters that constitute Twelf identifiers.")

(defun skip-twelf-comments-and-whitespace ()
  "Skip Twelf comments (single-line or balanced delimited) and white space."
  (skip-chars-forward *whitespace*)
  (while (looking-at *twelf-comment-start*)
    (cond ((looking-at "%{")		; delimited comment
	   (condition-case nil (forward-sexp 1)
	     (error (goto-char (point-max))))
	   (or (eobp) (forward-char 1)))
	  (t				; single-line comment
	   (end-of-line 1)))
    (skip-chars-forward *whitespace*)))

(defun twelf-end-of-par (&optional limit)
  "Skip to presumed end of current Twelf declaration.
Moves to next period or blank line (whichever comes first)
and returns t if period is found, nil otherwise.
Skips over comments (single-line or balanced delimited).
Optional argument LIMIT specifies limit of search for period."
  (if (not limit)
      (save-excursion
	(forward-paragraph 1)
	(setq limit (point))))
  (while (and (not (looking-at "\\."))
	      (< (point) limit))
    (skip-chars-forward "^.%" limit)
    (cond ((looking-at *twelf-comment-start*)
	   (skip-twelf-comments-and-whitespace))
	  ((looking-at "%")
	   (forward-char 1))))
  (cond ((looking-at "\\.")
	 (forward-char 1)
	 t)
	(t ;; stopped at limit
	 nil)))

(defun twelf-current-decl ()
  "Returns list (START END COMPLETE) for current Twelf declaration.
This should be the declaration or query under or just before
point within the nearest enclosing blank lines.
If declaration ends in `.' then COMPLETE is t, otherwise nil."
  (let (par-start par-end complete)
    (save-excursion
      ;; Skip backwards if between declarations
      (if (or (eobp) (looking-at (concat "[" *whitespace* "]")))
	  (skip-chars-backward (concat *whitespace* ".")))
      (setq par-end (point))
      ;; Move forward from beginning of decl until last
      ;; declaration before par-end is found.
      (if (not (bobp)) (backward-paragraph 1))
      (setq par-start (point))
      (while (and (twelf-end-of-par par-end)
		  (< (point) par-end))
	(setq par-start (point)))
      ;; Now par-start is at end of preceding declaration or query.
      (goto-char par-start)
      (skip-twelf-comments-and-whitespace)
      (setq par-start (point))
      ;; Skip to period or consective blank lines
      (setq complete (twelf-end-of-par))
      (setq par-end (point)))
    (list par-start par-end complete)))

(defun twelf-mark-decl ()
  "Marks current Twelf declaration and moves point to its beginning."
  (interactive)
  (let* ((par (twelf-current-decl))
	 (par-start (nth 0 par))
	 (par-end (nth 1 par)))
    (push-mark par-end)
    (goto-char par-start)))

(defun twelf-indent-decl ()
  "Indent each line of the current Twelf declaration."
  (interactive)
  (let* ((par (twelf-current-decl))
	 (par-start (nth 0 par))
	 (par-end (nth 1 par)))
    (goto-char par-start)
    (twelf-indent-lines (count-lines par-start par-end))))

(defun twelf-indent-region (from to)
  "Indent each line of the region as Twelf code."
  (interactive "r")
  (cond ((< from to)
	 (goto-char from)
	 (twelf-indent-lines (count-lines from to)))
	((> from to)
	 (goto-char to)
	 (twelf-indent-lines (count-lines to from)))
	(t nil)))

(defun twelf-indent-lines (n)
  "Indent N lines starting at point."
  (interactive "p")
  (while (> n 0)
    (twelf-indent-line)
    (forward-line 1)
    (setq n (1- n))))

(defun twelf-comment-indent ()
  "Calculates the proper Twelf comment column.
Currently does not deal specially with pragmas."
  (cond ((looking-at "%%%")
	 0)
	((looking-at "%[%{]")
	 (car (twelf-calculate-indent)))
	(t
	 (skip-chars-backward " \t")
	 (max (if (bolp) 0 (1+ (current-column))) comment-column))))

(defun looked-at ()
  "Returns the last string matched against.
Beware of intervening, even unsuccessful matches."
  (buffer-substring (match-beginning 0) (match-end 0)))

(defun twelf-indent-line ()
  "Indent current line as Twelf code.
This recognizes comments, matching delimiters, and standard infix operators."
  (interactive)
  (let ((old-point (point)))
    (beginning-of-line)
    (let* ((indent-info (twelf-calculate-indent))
	   (indent-column (nth 0 indent-info))
	   (indent-type (nth 1 indent-info))
	   (indent-string (nth 2 indent-info)))
      (skip-chars-forward " \t")        ; skip whitespace
      (let ((fwdskip (- old-point (point))))
	(cond ((looking-at "%%%")
	       (twelf-indent-line-to 0 fwdskip)) ; %%% comment at column 0
	      ((looking-at "%[%{]")     ; delimited or %% comment
	       (twelf-indent-line-to indent-column fwdskip))
	      ((looking-at *twelf-comment-start*)    ; indent single-line comment
	       (indent-for-comment)
	       (forward-char -1))
	      ((looking-at "%")		; %keyword declaration
	       (twelf-indent-line-to indent-column fwdskip))
	      ((looking-at twelf-infix-regexp) ; looking at infix operator
	       (if (string= indent-string (looked-at))
		   ;; indent string is the same as the one we are looking at
		   (twelf-indent-line-to indent-column fwdskip)
		 (twelf-indent-line-to (+ indent-column twelf-indent) fwdskip)))
	      ((eq indent-type 'delimiter) ; indent after delimiter
	       (twelf-indent-line-to (+ indent-column twelf-indent) fwdskip))
	      ((eq indent-type 'limit)  ; no delimiter or infix found.
	       (twelf-indent-line-to indent-column fwdskip))
	      ((eq indent-type 'infix)
	       (twelf-indent-line-to (+ indent-column twelf-indent) fwdskip)))))))

(defun twelf-indent-line-to (indent fwdskip)
  "Indent current line to INDENT then skipping to FWDSKIP if positive.
Assumes point is on the first non-whitespace character of the line."
  (let ((text-start (point))
	(shift-amount (- indent (current-column))))
    (if (= shift-amount 0)
	nil
      (beginning-of-line)
      (delete-region (point) text-start)
      (indent-to indent))
    (if (> fwdskip 0)
	(forward-char fwdskip))))

(defun twelf-calculate-indent ()
  "Calculate the indentation and return a list (INDENT INDENT-TYPE STRING).
INDENT is a natural number,
INDENT-TYPE is 'DELIMITER, 'INFIX, or 'LIMIT, and
STRING is the delimiter, infix operator, or the empty string, respectively."
  (save-excursion
    (let* ((par (twelf-current-decl))
	   (par-start (nth 0 par))
	   (par-end (nth 1 par))
	   (par-complete (nth 2 par))
	   (limit (cond ((> par-start (point)) (point))
			((and (> (point) par-end) par-complete) par-end)
			(t par-start))))
      (twelf-dsb limit))))

(defun twelf-dsb (limit)
  "Scan backwards from point to find opening delimiter or infix operator.
This currently does not deal with comments or mis-matched delimiters.
Argument LIMIT specifies bound for backwards search."
  (let ((result nil)
	(lparens 0) (lbraces 0) (lbrackets 0))
    (while (not result)
      (if (or (= lparens 1) (= lbraces 1) (= lbrackets 1))
	  (setq result (list (current-column) 'delimiter (looked-at)))
	(if (re-search-backward (concat "[][{}()]\\|" twelf-infix-regexp)
				limit 'limit) ; return 'LIMIT if limit reached
	    (let ((found (looked-at)))
	      (cond
	       ((string= found "(") (setq lparens (1+ lparens)))
	       ((string= found ")") (setq lparens (1- lparens)))
	       ((string= found "{") (setq lbraces (1+ lbraces)))
	       ((string= found "}") (setq lbraces (1- lbraces)))
	       ((string= found "[") (setq lbrackets (1+ lbrackets)))
	       ((string= found "]") (setq lbrackets (1- lbrackets)))
	       (t;; otherwise, we are looking at an infix operator
		(if (and (= lparens 0) (= lbraces 0) (= lbrackets 0))
		    (setq result (list (current-column) 'infix found))
		  nil))))               ; embedded - skip
	  (setq result (list 0 'limit ""))))) ; reached the limit, no indent
    result))

(defun twelf-mode-variables ()
  "Set up local variables for Twelf mode."
  (set-syntax-table twelf-mode-syntax-table)
  ;; Paragraphs are separated by blank lines or ^L.
  (make-local-variable 'paragraph-start)
  (setq paragraph-start "^[ \t\f]*$")
  (make-local-variable 'paragraph-separate)
  (setq paragraph-separate paragraph-start)
  (make-local-variable 'indent-line-function)
  (setq indent-line-function 'twelf-indent-line)
  (make-local-variable 'comment-start)
  (setq comment-start "%")
  (make-local-variable 'comment-start-skip)
  (setq comment-start-skip "%+{?[ \t]*")
  (make-local-variable 'comment-end)
  (setq comment-end "")
  (make-local-variable 'comment-column)
  (setq comment-column 40)
  ;; (make-local-variable 'parse-sexp-ignore-comments)
  ;; (setq parse-sexp-ignore-comments t)
  )

(defun twelf-mode ()
  "Major mode for editing Twelf code.
Tab indents for Twelf code.
Delete converts tabs to spaces as it moves back.
M-C-q indents all lines in current Twelf declaration.

Twelf mode also provides commands to maintain groups of Twelf source
files (configurations) and communicate with an Twelf server which
processes declarations.  It also supports quick jumps to the (presumed)
source of error message that may arise during parsing or type-checking.

Customisation: Entry to this mode runs the hooks on twelf-mode-hook.
See also the hints for the .emacs file given below.

Mode map
========
\\{twelf-mode-map}
\\<twelf-mode-map>
Overview
========

The basic architecture is that Emacs sends commands to an Twelf server
which runs as an inferior process, usually in the buffer *twelf-server*.
Emacs in turn interprets or displays the replies from the Twelf server.
Since a typical Twelf application comprises several files, Emacs
maintains a configuration in a file, usally called sources.cfg.  This
file contains a list of files, each on a separate line, in dependency
order.  The `%' character starts a comment line.  A configuration is
established with the command \\[twelf-server-configure].

A new file is switched to Twelf mode if a file has extension `.elf',
`.quy', `.thm' or `.cfg' and the `auto-mode-alist' is set correctly (see
init.el).

The files in the current configuration can be checked in sequence with
\\[twelf-save-check-config], the current file with
\\[twelf-save-check-file], individual declarations with
\\[twelf-check-declaration].  These, like many other commands, take an
optional prefix arguments which means to display the Twelf server buffer
after the processing of the configuration, file, or declaration.  If an
error should arise during these or related operations a message is
issued both in the server buffer and Emacs, and the command
\\[twelf-next-error] visits the presumed source of the type error in a
separate buffer.

Summary of most common commands:
 M-x twelf-save-check-config \\[twelf-save-check-config]  save, check & load configuration
 M-x twelf-save-check-file   \\[twelf-save-check-file]  save, check & load current file
 M-x twelf-check-declaration \\[twelf-check-declaration]  type-check declaration at point
 M-x twelf-server-display    \\[twelf-server-display]  display Twelf server buffer

It is important to remember that the commands to save and check
a file or check a declaration may change the state of the global
signature maintained in Twelf.  After a number of changes it is usually
a good idea to return to a clean slate with \\[twelf-save-check-config].

Individual Commands
===================

Configurations, Files and Declarations

  twelf-save-check-config                   \\[twelf-save-check-config]
   Save its modified buffers and then check the current Twelf configuration.
   With prefix argument also displays Twelf server buffer.
   If necessary, this will start up an Twelf server process.

  twelf-save-check-file                     \\[twelf-save-check-file]
   Save buffer and then check it by giving a command to the Twelf server.
   With prefix argument also displays Twelf server buffer.

  twelf-check-declaration                   \\[twelf-check-declaration]
   Send the current declaration to the Twelf server process for checking.
   With prefix argument, subsequently display Twelf server buffer.

Subterm at Point

  twelf-type-const                          \\[twelf-type-const]
   Display the type of the constant before point.
   Note that the type of the constant will be `absolute' rather than the
   type of the particular instance of the constant.

Error Tracking

  twelf-next-error                          \\[twelf-next-error]
   Find the next error by parsing the Twelf server or Twelf-SML buffer.

  twelf-goto-error                          \\[twelf-goto-error]
   Go to the error reported on the current line or below.

Server State

  twelf-set PARM VALUE                      \\[twelf-set]
   Sets the Twelf server parameter PARM to VALUE.
   Prompts for PARM when called interactively, using completion for legal
   parameters.

  twelf-get PARM                            \\[twelf-get]
   Print the current value the Twelf server parameter PARM.

  twelf-server-interrupt                    \\[twelf-server-interrupt]
   Interrupt the Twelf server-process.

  twelf-server                              \\[twelf-server]
   Start a Twelf server process in a buffer named *twelf-server*.

  twelf-server-configure                    \\[twelf-server-configure]
   Set the current configuration of the Twelf server.

  twelf-reset                               \\[twelf-reset]
   Reset the global signature in the Twelf server process.

  twelf-server-quit                         \\[twelf-server-quit]
   Kill the Twelf server process.

  twelf-server-restart                      \\[twelf-server-restart]
   Restarts server and re-initializes configuration.
   This is primarily useful during debugging of the Twelf server code or
   if the Twelf server is hopelessly wedged.

  twelf-server-send-command                 \\[twelf-server-send-command]
   Send arbitrary string to Twelf server.

Tags (for other, M-x apropos tags or see `etags' documentation)

  twelf-tag                                 \\[twelf-tag]
   Create tags file TAGS for current configuration.
   If current configuration is names CONFIGx, tags file will be named TAGx.
   Errors are displayed in the Twelf server buffer.

Timers

  twelf-timers-reset			    \\[twelf-timers-reset]
   Reset Twelf timers.

  twelf-timers-show                         \\[twelf-timers-show]
   Show and reset Twelf timers.

  twelf-timers-check                        \\[twelf-timers-check]
   Show, but do not reset Twelf timers.

Editing

  twelf-indent-decl                         \\[twelf-indent-decl]
   Indent each line in current declaration as Twelf code.

  twelf-indent-region                       \\[twelf-indent-region]
   Indent each line of the region as Twelf code.

Minor Modes
===========

An associated minor modes is 2Twelf-SML (toggled with
twelf-to-twelf-sml-mode).  This means that we assume communication
is an inferior Twelf-SML process and not a Twelf server.

Related Major Modes
===================

Related major modes are Twelf Server (for the Twelf server buffer) and
Twelf-SML (for an inferior Twelf-SML process).  Both modes are based on
the standard Emacs comint package and inherit keybindings for retrieving
preceding input.

Customization
=============

The following variables may be of general utility.

 twelf-indent          amount of indentation for nested Twelf expressions
 twelf-mode-hook       hook to run when entering Twelf mode
 twelf-server-program  full pathname of Twelf server program
 twelf-server-mode-hook  hook to run when entering Twelf server mode
 twelf-info-file       name of Twelf info file with documentation

The following is a typical section of a .emacs initialization file
which can be found in the file init.el.

(setq load-path (cons \"/afs/cs/project/twelf/research/twelf/emacs\" load-path))

(autoload 'twelf-mode \"twelf\" \"Major mode for editing Twelf source.\" t)
(autoload 'twelf-server \"twelf\" \"Run an inferior Twelf server.\" t)
(autoload 'twelf-sml \"twelf\" \"Run an inferior Twelf-SML process.\" t)

(setq auto-mode-alist
      (cons '(\"\\.elf$\" . twelf-mode)
	    (cons '(\"\\.quy$\" . twelf-mode)
		  (cons '(\"\\.thm$\" . twelf-mode)
			(cons '(\"\\.cfg$\" . twelf-mode)
			      auto-mode-alist)))))

(setq twelf-server-program
      \"/afs/cs/project/twelf/research/twelf/bin/twelf-server\")

(setq twelf-sml-program
      \"/afs/cs/project/twelf/misc/smlnj/bin/sml-cm\")

(setq twelf-info-file
      \"/afs/cs/project/twelf/research/twelf/doc/info/twelf.info\")
"
  (interactive)
  (kill-all-local-variables)
  (twelf-mode-variables)
  (use-local-map twelf-mode-map)
  (setq major-mode 'twelf-mode)
  (setq mode-name "Twelf")
  (twelf-config-mode-check)
  (twelf-add-menu)			; add Twelf menu to menubar
  ;; disable twelf-add-to-config-check: require explicit add-file
  ;; (twelf-add-to-config-check)
  (run-hooks 'twelf-mode-hook))

;;;----------------------------------------------------------------------
;;; Reading info file
;;;----------------------------------------------------------------------

(defun twelf-info (&optional file)
  "Enter Info, starting with the Twelf node
Optional argument FILE specifies the info file.

In interactive use, a prefix arguments directs this command to
read a file name from the minibuffer."
  (interactive (if current-prefix-arg
		   (list (read-file-name "Info file name: " nil nil t))))
  (info (or file twelf-info-file)))

;;;----------------------------------------------------------------------
;;; Error message parsing
;;;----------------------------------------------------------------------

(defconst twelf-error-regexp
  "^.+:[-0-9.:]+.* \\(Error\\|Warning\\):"
  "Regexp for matching Twelf error.")

(defconst twelf-error-fields-regexp
   "^[-=? \t]*\\(.+\\):\
\\([0-9]+\\)\\(\\.\\([0-9]+\\)\\)?\\(-\\([0-9]+\\)\\(\\.\\([0-9]+\\)\\)?\\)?\
.+\\(Error\\|Warning\\):"
   "Regexp to extract fields of Twelf error.")

(defconst twelf-error-decl-regexp
  "^[-=? \t]*\\(.+\\)::\\([^ \t\n]+\\) "
  "Regexp to extract filename and identifier from declaration error.")

(defun looked-at-nth (n)
  (let ((b (match-beginning n))
	(e (match-end n)))
    (if (or (null b) (null e)) nil
      (buffer-substring (match-beginning n) (match-end n)))))

(defun looked-at-nth-int (n)
  (let ((str (looked-at-nth n)))
    (if (null str) nil
      (string-to-number str))))

(defun twelf-error-parser (pt)
  "Standard parser for Twelf errors.
Returns a 5-element list (FILE START-LINE START-COL END-LINE END-COL)
or (\"Local\" START-CHAR NIL END-CHAR NIL)."
  (save-excursion
    (goto-char pt)
    (re-search-forward twelf-error-fields-regexp)
    (list (looked-at-nth 1)		; file or "Local" or "stdIn"
	  (looked-at-nth-int 2)		; start line or char
	  (looked-at-nth-int 4)		; start column, if given, else nil
	  (looked-at-nth-int 6)		; end line, if given, else nil or char
	  (looked-at-nth-int 8)		; end column, if given, else nil
	  )))

(defun twelf-error-decl (pos)
  "Determines if the error is identified only by its declaration."
  (save-excursion
    (goto-char pos)
    (looking-at twelf-error-decl-regexp)))

(defun twelf-mark-relative (line0 col0 line1 col1)
  "Mark error region if location is given relative to a buffer position."
  (if (not (= line0 1))
      (forward-line (1- line0)))
  ;; work around bug: from stdIn, first line is off by one.
  (forward-char (if (not (= line0 1)) (1- col0) (1- (1- col0))))
  ;; select region, if non-empty
  (cond ((not (null line1))
	 (push-mark (point))
	 (cond ((not (= line1 line0))
		(forward-line (- line1 line0))
		(forward-char (1- col1)))
	       (t (forward-char (- col1 col0))))
	 (exchange-point-and-mark)
	 (funcall twelf-highlight-range-function (point) (mark)))))

(defun twelf-mark-absolute (line0 col0 line1 col1)
  "Mark error region if location is given as absolute buffer position."
  (cond ((and line0 col0 line1 col1)	; line0.col0-line1.col1 range
	 (goto-line line0)
	 ;; don't use move-to-column since <tab> is 1 char to lexer
	 (forward-char (1- col0))
	 ;; select region, if non-empty
	 (push-mark (point))
	 (goto-line line1)
	 (forward-char (1- col1))
	 (exchange-point-and-mark)
	 (funcall twelf-highlight-range-function (point) (mark)))
	((and (null col0) (null col1))	; char0-char1 range
	 (goto-char line0)
	 (push-mark (point))
	 (goto-char line1)
	 (exchange-point-and-mark)
	 (funcall twelf-highlight-range-function (point) (mark)))
	((and line0 col0)		; beginning line0.col0
	 (goto-line line0)
	 (forward-char (1- col0)))
	(line0				; beginning char0
	 (goto-char line0))
	(t (error "Unrecognized format for error location"))))

(defun twelf-find-decl (filename id)
  "In FILENAME find probable declaration of ID."
  (if (not (file-readable-p filename))
      (error "Cannot read file %s" filename)
    (switch-to-buffer-other-window (find-file-noselect filename))
    (goto-char (point-min))
    (let ((done nil)
	  decl-id)
      (while (not done)
	(setq decl-id (twelf-next-decl filename *twelf-last-input-buffer*))
	(if (not decl-id)
	    (error "Declaration of %s not found in file %s." id filename)
	  (setq done (string= decl-id id))
	  (if (not done) (twelf-end-of-par)))))))

(defun twelf-next-error ()
  "Find the next error by parsing the Twelf server or Twelf-SML buffer.
Move the error message on the top line of the window;
put the cursor at the beginning of the error source. If the
error message specifies a range, the mark is placed at the end."
  (interactive)
  (let ((case-fold-search nil)
	(twelf-buffer (or *twelf-last-input-buffer*
			(error "Cannot determine process buffer with last input")))
	error-begin)
    (pop-to-buffer twelf-buffer)
    (goto-char *twelf-error-pos*)   ; go to last error
    (if (not (re-search-forward twelf-error-regexp (point-max) t))
	(error "No error message found.")
      (setq error-begin (match-beginning 0))
      (setq *twelf-error-pos* (point))
      (set-window-start (get-buffer-window twelf-buffer)
			(save-excursion (beginning-of-line) (point)))
      (if (twelf-error-decl error-begin)
	  (twelf-find-decl (looked-at-nth 1) (looked-at-nth 2))
	(let* ((parse (twelf-error-parser error-begin))
	       (file (nth 0 parse))
	       (line0 (nth 1 parse))
	       (col0 (nth 2 parse))
	       (line1 (nth 3 parse))
	       (col1 (nth 4 parse)))
	  (cond ((equal file "stdIn")
		 ;; Error came from direct input
		 (cond ((null *twelf-last-region-sent*)
			;; from last interactive input in the Twelf buffer
			(goto-char (point-max))
			(comint-previous-input 1)
			(setq *twelf-last-region-sent* t)
			(goto-char (process-mark
				    (get-buffer-process twelf-buffer)))
			(twelf-mark-relative line0 col0 line1 col1))
		       ((eq *twelf-last-region-sent* t)
			;; from the waiting input in the Twelf buffer
			(goto-char (process-mark
				    (get-buffer-process twelf-buffer)))
			(twelf-mark-relative line0 col0 line1 col1))
		       (t
			;; from a region sent from some buffer
			(let ((buf (nth 0 *twelf-last-region-sent*))
			      (start (nth 1 *twelf-last-region-sent*)))
			  (switch-to-buffer-other-window buf)
			  (goto-char start)
			  (twelf-mark-relative line0 col0 line1 col1)))))
		((equal file "Local")
		 ;; Error came from local input, usually to a server process
		 ;; in this case the address relative, and expressed in
		 ;; characters, rather than lines.
		 (let ((local-buffer (nth 0 *twelf-last-region-sent*))
		       ;; Local characters seem to be off by two
		       (char0 (+ (nth 1 *twelf-last-region-sent*) (- line0 2)))
		       (char1 (+ (nth 1 *twelf-last-region-sent*) (- line1 2))))
		   (switch-to-buffer-other-window local-buffer)
		   (goto-char char1)
		   (push-mark)
		   (goto-char char0)
		   (exchange-point-and-mark)))
		((file-readable-p file)
		 ;; Error came from a source file
		 (switch-to-buffer-other-window (find-file-noselect file))
		 (twelf-mark-absolute line0 col0 line1 col1))
		(t
		 (error (concat "Can't read file " file)))))))))

(defun twelf-goto-error ()
  "Go to the error reported on the current line or below.
Also updates the error cursor to the current line."
  (interactive)
  (pop-to-buffer (or *twelf-last-input-buffer*
		     (error "Cannot determine process buffer with last input")))
  (beginning-of-line)
  (setq *twelf-error-pos* (point))
  (twelf-next-error))

;;;----------------------------------------------------------------------
;;; NT Emacs bug workaround
;;;----------------------------------------------------------------------

(defun twelf-convert-standard-filename (filename)
  "Convert FILENAME to form appropriate for Twelf Server of current OS."
  (cond ((eq system-type 'windows-nt)
	 (while (string-match "/" filename)
	   (setq filename (replace-match "\\" t t filename)))
	 filename)
	(t (convert-standard-filename filename))))

;;;----------------------------------------------------------------------
;;; Communication with Twelf server
;;;----------------------------------------------------------------------

(defun string-member (x l)
  (if (null l) nil
    (or (string-equal x (car l)) (string-member x (cdr l)))))

;(defun twelf-add-to-config-check ()
;  "Ask if current file should be added to the current Twelf configuration."
;  (let ((file-name (buffer-file-name)))
;    (if (and (not (string-member file-name *twelf-config-list*))
;             (not (null *twelf-config-buffer*))
;             (yes-or-no-p "Add to the current configuration? "))
;        (twelf-server-add-file file-name))))

(defun twelf-config-proceed-p (file-name)
  "Ask if to proceed if FILE-NAME is not in current configuration."
  (if (and (not (string-member file-name *twelf-config-list*))
	   (not (yes-or-no-p "File not in current configuration.  Save? ")))
      nil
    t))

(defun twelf-save-if-config (buffer)
  "Ask if BUFFER should be saved if in the current configuration.
Always save if the variable `twelf-save-silently' is non-nil."
  (let ((file-name (buffer-file-name buffer)))
    (if (and (buffer-modified-p buffer)
	     file-name
	     (string-member file-name *twelf-config-list*))
	(if twelf-save-silently
	    (save-buffer)
	  (pop-to-buffer buffer)
	  (if (yes-or-no-p (concat "Save " file-name "? "))
	      (save-buffer))))))

(defun twelf-config-save-some-buffers ()
  "Cycle through all buffers and save those in the current configuration."
  (mapcar 'twelf-save-if-config (buffer-list)))

(defun twelf-save-check-config (&optional displayp)
  "Save its modified buffers and then check the current Twelf configuration.
With prefix argument also displays Twelf server buffer.
If necessary, this will start up an Twelf server process."
  (interactive "P")
  (let ((current-file-name (buffer-file-name)))
    (cond ((and current-file-name
		(not buffer-read-only)
		(buffer-modified-p)
		(twelf-config-proceed-p current-file-name))
	   (save-buffer)))
    (save-excursion
      (twelf-config-save-some-buffers))
    (twelf-check-config displayp)))

(defun twelf-check-config (&optional displayp)
  "Check the current Twelf configuration.
With prefix argument also displays Twelf server buffer.
If necessary, this will start up an Twelf server process."
  (interactive "P")
  (if (not *twelf-config-buffer*)
      (call-interactively 'twelf-server-configure))
  (twelf-server-sync-config)
  (twelf-focus nil nil)
  (twelf-server-send-command "Config.load")
  (twelf-server-wait displayp))

(defun twelf-save-check-file (&optional displayp)
  "Save buffer and then check it by giving a command to the Twelf server.
In Twelf Config minor mode, it reconfigures the server.
With prefix argument also displays Twelf server buffer."
  (interactive "P")
  (save-buffer)
  (if twelf-config-mode
      (twelf-server-configure (buffer-file-name) "Server OK: Reconfigured")
    (let* ((save-file (buffer-file-name))
	   (check-file (file-relative-name save-file (twelf-config-directory)))
	   (check-file-os (twelf-convert-standard-filename check-file)))
      (twelf-server-sync-config)
      (twelf-focus nil nil)
      (twelf-server-send-command (concat "loadFile " check-file-os))
      (twelf-server-wait displayp))))

(defun twelf-buffer-substring (start end)
  "The substring of the current buffer between START and END.
The location is recorded for purposes of error parsing."
  (setq *twelf-last-region-sent* (list (current-buffer) start end))
  (buffer-substring start end))

(defun twelf-buffer-substring-dot (start end)
  "The substring of the current buffer between START and END plus
an end-of-input marker, `%.'.  The location of the input is recorded
for purposes of error parsing."
  (concat (twelf-buffer-substring start end) "%."))

(defun twelf-check-declaration (&optional displayp)
  "Send the current declaration to the Twelf server process for checking.
With prefix argument also displays Twelf server buffer."
  (interactive "P")
  (let* ((par (twelf-current-decl))
	 (par-start (nth 0 par))
	 (par-end (nth 1 par))
	 (decl (twelf-buffer-substring-dot par-start par-end)))
    (twelf-focus par-start par-end)
    (twelf-server-send-command (concat "readDecl\n" decl))
    (twelf-server-wait displayp)))

;(defun twelf-highlight-range (par-start par-end &optional offset)
;  "Set point and mark to encompass the range analyzed by the Twelf server."
;  (let* ((range (twelf-parse-range))
;         (range-start (nth 0 range))
;         (range-end (nth 1 range))
;         (offset (if (null offset) 0 offset)))
;    (if (and (integerp range-start) (integerp range-end))
;        (progn (goto-char (+ (- (+ par-start range-end) 2) offset))
;               (push-mark (- (+ par-start range-start) 2))
;	       (funcall twelf-highlight-range-function (point) (mark))))))

(defun twelf-highlight-range-zmacs (start end)
  "Highlight range as zmacs region.  Assumes point and mark are set.
Does nothing if function zmacs-activate-region is undefined."
  (if (fboundp 'zmacs-activate-region)
      (zmacs-activate-region)))

(defun twelf-focus (&optional start end)
  "Focus on region between START and END as current declaration or query.  If
START and END are nil, then no focus exists.  This intermediary just calls
the appropriate function."
  (funcall twelf-focus-function start end))

(defun twelf-focus-noop (start end)
  "This default focus function does nothing."
  ())

;; Not yet available in Twelf 1.2 -fp

;(defun twelf-type-at-point ()
;  "Display the type of the subterm at the point in the current Twelf decl.

;The subterm at point is the smallest subterm whose printed representation
;begins to the left of point and extends up to or beyond point.  After this and
;similar commands applicable to subterms, the current region (between mark and
;point) is set to encompass precisely the selected subterm.  In XEmacs,
;it will thus be highlighted under many circumstances.  In other versions
;of Emacs \\[exchange-point-and-mark] will indicate the extent of the region.

;The type computed for the subterm at point takes contextual information into
;account.  For example, if the subterm at point is a constant with implicit
;arguments, the type displayed will be the instance of the constant (unlike
;M-x twelf-type-const (\\[twelf-type-const]), which yields the absolute type of a constant)."

;  (interactive)
;  (let* ((par (twelf-current-decl))
;         (par-start (nth 0 par))
;         (par-end (nth 1 par))
;         (decl (twelf-buffer-substring-dot par-start par-end)))
;    (twelf-focus par-start par-end)
;    (twelf-server-send-command
;     (concat "type-at "
;             (twelf-current-syncat) " "
;             (int-to-string (+ (- (point) par-start) 2)) "\n"
;             decl))
;    (twelf-server-wait t)
;    (twelf-highlight-range par-start par-end)))

;(defun twelf-expected-type-at-point ()
;  "Display the type expected at the point in the current declaration.

;This replaces the subterm at point by an underscore _ and determines
;the type that _ would have to have for the whole declaration to be valid.
;This is useful for debugging in places where inconsistent type constraints
;have arisen.  Error messages may be given, but will not be correctly
;interpreted by Emacs, since the string sent to the server may be different
;from the declaration in the buffer.

;For a definition of the subterm at point, see function twelf-type-at-point."
;  (interactive)
;  (let* ((par (twelf-current-decl))
;         (par-start (nth 0 par))
;         (par-end (nth 1 par))
;         (par-initial-end nil)
;         (par-final-start nil)
;         modified-decl)
;    ;; (exp-present (not (looking-at (concat "[" *whitespace* "]"))))
;    (backward-sexp 1)
;    (setq par-initial-end (point))
;    (forward-sexp 1)
;    (setq par-final-start (point))
;    (setq modified-decl
;          (concat (twelf-buffer-substring par-start par-initial-end)
;                  "_" (twelf-buffer-substring-dot par-final-start par-end)))
;    ;; Error messages here are not accurate.  Nontheless:
;    (setq *twelf-last-region-sent* (list (current-buffer) par-start par-end))
;    (twelf-focus par-start par-end)
;    (twelf-server-send-command
;     (concat "type-at "
;             (twelf-current-syncat) " "
;             (int-to-string (1+ (+ (- par-initial-end par-start) 2))) "\n"
;             modified-decl))
;    (twelf-server-wait t)
;    (twelf-highlight-range par-start par-end
;			 (1- (- par-final-start par-initial-end)))))

;(defun twelf-parse-range ()
;  "Parse a range as returned by the Twelf server and return as a list."
;  (save-window-excursion
;    (let ((twelf-server-buffer (twelf-get-server-buffer)))
;      (set-buffer twelf-server-buffer)
;      (goto-char *twelf-server-last-process-mark*)
;      ;; We are now at the beginning of the output
;      (re-search-forward "^\\[\\([0-9]+\\),\\([0-9]+\\))")
;      (list (looked-at-nth-int 1) (looked-at-nth-int 2)))))

(defun twelf-type-const ()
  "Display the type of the constant before point.
Note that the type of the constant will be `absolute' rather than the
type of the particular instance of the constant."
  (interactive)
  (let ((previous-point (point)))
    (skip-chars-backward *whitespace* (point-min))
    (skip-chars-forward *twelf-id-chars* (point-max))
    (let ((end-of-id (point)))
      (skip-chars-backward *twelf-id-chars* (point-min))
      (let ((c (if (= (point) end-of-id)
		   ;; we didn't move.  this should eventually become a
		   ;; completing-read
		   (read-string "Constant: ")
		 (buffer-substring (point) end-of-id))))
	(twelf-server-send-command (concat "decl " c))
	(twelf-server-wait t)             ; Wait for and display reply
	(goto-char previous-point)))))

;; Unused? -fp
;(defun twelf-backwards-parse-arglist ()
;  "Parse an argument list template as returned by the server."
;  (save-window-excursion
;    (let ((twelf-server-buffer (twelf-get-server-buffer)))
;      (set-buffer twelf-server-buffer)
;      (goto-char *twelf-server-last-process-mark*)
;      ;; Should be right at the beginning of the output.
;      ;; (re-search-forward "^arglist") ;
;      ;; (beginning-of-line 2)
;      (let ((arglist-begin (point)))
;        (skip-chars-forward "^." (point-max))
;        (buffer-substring arglist-begin (point))))))

;; Not yet ported to Twelf 1.2
;(defun twelf-show-region-in-window (start end)
;  "Change window parameters so it precisely shows the given region."
;  (enlarge-window (- (max (count-lines start end) window-min-height)
;                     (window-height)))
;  (set-window-start (selected-window) start))

;(defun twelf-show-menu ()
;  "Display the Twelf server buffer to show menu of possible completions."
;  (let ((old-buffer (current-buffer))
;        (twelf-server-buffer (twelf-get-server-buffer))
;        region-start region-end)
;    (switch-to-buffer-other-window twelf-server-buffer)
;    (goto-char *twelf-server-last-process-mark*)
;    (if (re-search-forward "-\\.$" (point-max) t)
;        (progn
;          (forward-char 1)
;          (setq region-start (point))
;          (if (re-search-forward "^-\\." (point-max) t)
;              (setq region-end (point))
;            (error "List of alternatives not terminated by -.")))
;      (error "No alternatives found."))
;    (twelf-show-region-in-window region-start region-end)
;    (switch-to-buffer-other-window old-buffer)))

;(defun twelf-completions-at-point ()
;  "List the possible completions of the term at point based on type information.

;The possible completions are numbered, and the function twelf-complete
;(\\[twelf-complete]) can be used subsequently to replace the term at point with
;one of the alternatives.

;Above the display of the alternatives, the type of the subterm at
;point is shown, since it is this type which is the basis for listing
;the possible completions.

;In the list alternatives, a variable X free in the remaining declaration
;is printed ^X, and a bound variable x may be printed as !x.  These marks
;are intended to aid in the understanding of the alternatives, but
;must be removed in case the alternative is copied literally into the
;input declaration (as, for example, with the \\[twelf-complete] command)."
;  (interactive)
;  (let* ((par (twelf-current-decl))
;         (par-start (nth 0 par))
;         (par-end (nth 1 par))
;         (decl (twelf-buffer-substring-dot par-start par-end)))
;    (twelf-focus par-start par-end)
;    (twelf-server-send-command
;     (concat "complete-at "
;             (twelf-current-syncat) " "
;             (int-to-string (+ (- (point) par-start) 2)) "\n"
;             decl))
;    (twelf-server-wait nil)
;    (twelf-highlight-range par-start par-end)
;    (twelf-show-menu)))

;(defun twelf-complete (n)
;  "Pick the alternative N from among possible completions.
;This replaces the current region with the given pattern.
;The list of completions must be generated with the command
;twelf-completions-at-point (\\[twelf-completions-at-point])."
;  (interactive "NAlternative: ")
;  (let (start completion)
;    (save-excursion
;      (set-buffer (twelf-get-server-buffer))
;      (goto-char *twelf-server-last-process-mark*)
;      (if (not (re-search-forward (concat "^" (int-to-string n) "\\. ")
;                                  (point-max) t))
;          (error "No alternative %d found in Twelf server buffer." n))
;      (setq start (point))
;      (if (not (search-forward " ::" (point-max) t))
;          (error "List of completions not well-formed."))
;      (backward-char 3)
;      (setq completion (buffer-substring start (point))))
;    (delete-region (point) (mark))
;    (insert "(" completion ")")
;    (twelf-show-menu)))

;;;----------------------------------------------------------------------
;;; Twelf server mode (major mode)
;;; This is for the buffer with the Twelf server process, to facilitate
;;; direct interaction (which should rarely be necessary)
;;;----------------------------------------------------------------------

(defvar twelf-server-mode-map nil
  "The keymap used in twelf-server mode.")

(cond ((not twelf-server-mode-map)
       (setq twelf-server-mode-map (copy-keymap comint-mode-map))
       (install-basic-twelf-keybindings twelf-server-mode-map)
       ;; C-c C-c is bound to twelf-save-check config in Twelf mode
       (define-key twelf-server-mode-map "\C-c\C-c" 'twelf-save-check-config)
       ;; Bind the function shadowed by the previous definition to C-c C-i
       (define-key twelf-server-mode-map "\C-c\C-i" 'comint-interrupt-subjob)
       ))

(defconst twelf-server-cd-regexp "^\\s *OS\\.chDir\\s *\\(.*\\)"
  "Regular expression used to match cd commands in Twelf server buffer.")

(defun looked-at-string (string n)
  "Substring of STRING consisting of Nth match."
  (substring string (match-beginning n) (match-end n)))

(defun twelf-server-directory-tracker (input)
  "Checks input for cd commands and changes default directory in buffer.
As a side effect, it resets *twelf-error-pos* and *twelf-last-region-sent*
to indicate interactive input.  Used as comint-input-filter-function in Twelf
server buffer."
  (if (twelf-input-filter input)
      (setq *twelf-last-region-sent* nil))
  (setq *twelf-last-input-buffer* (current-buffer))
  (setq *twelf-error-pos* (marker-position (process-mark (twelf-server-process))))
  (cond ((string-match twelf-server-cd-regexp input)
	 (let ((expanded-dir (expand-dir (looked-at-string input 1))))
	   (setq default-directory expanded-dir)
	   (pwd)))
	((string-match "^set\\s +chatter\\s +\\([0-9]\\)+" input)
	 (setq twelf-chatter (string-to-number (looked-at-string input 1))))
	;;((string-match "^set\\s +trace\\s +\\([0-9]\\)+" input)
	;; (setq twelf-trace (string-to-number (looked-at-string input 1))))
	((string-match "^set\\s-+\\(\\S-+\\)\\s-+\\(\\w+\\)" input)
	 (if (assoc (looked-at-string input 1) *twelf-track-parms*)
	     (set (cdr (assoc (looked-at-string input 1) *twelf-track-parms*))
		  (looked-at-string input 2))))))

(defun twelf-input-filter (input)
  "Function to filter strings before they are saved in input history.
We filter out all whitespace and anything shorter than two characters."
  (and (not (string-match "\\`\\s *\\'" input))
       (> (length input) 1)))

(defun twelf-server-mode ()
  "Major mode for interacting with an inferior Twelf server process.
Runs twelf-server-mode-hook.

The following commands are available:
\\{twelf-server-mode-map}"
  (interactive)
  (kill-all-local-variables)
  ;; Initialize comint parameters
  (comint-mode)
  (setq comint-prompt-regexp "^") ;; no prompt
  (setq comint-input-filter 'twelf-input-filter)
  ;;changed for XEmacs 19.16
  ;;(setq comint-input-sentinel 'twelf-server-directory-tracker)
  (add-hook 'comint-input-filter-functions 'twelf-server-directory-tracker
	    nil t)
  (twelf-mode-variables)
  ;; For sequencing through error messages:
  (make-local-variable '*twelf-error-pos*)
  (setq *twelf-error-pos* (point-max))
  ;; Set mode and keymap
  (setq major-mode 'twelf-server-mode)
  (setq mode-name "Twelf Server")
  (setq mode-line-process '(": %s"))
  (use-local-map twelf-server-mode-map)
  (twelf-server-add-menu)		; add Twelf Server menu
  ;; Run user specified hooks, if any
  (run-hooks 'twelf-server-mode-hook))

;;;----------------------------------------------------------------------
;;; Functions to support use of the Twelf server
;;;----------------------------------------------------------------------

(defun twelf-parse-config ()
  "Starting at point, parse a configuration file."
  (let ((filelist nil))
    (skip-chars-forward *whitespace*)
    (while (not (eobp))                 ; end of buffer?
      (cond ((looking-at "%")           ; comment through end of line
	     (end-of-line))
	    (t (let ((begin-point (point))) ; parse filename starting at point
		 (skip-chars-forward (concat "^" *whitespace*))
		 (let* ((file-name (buffer-substring begin-point (point)))
			(absolute-file-name
			 (expand-file-name file-name default-directory)))
		   (if (file-readable-p absolute-file-name)
		       (setq filelist (cons absolute-file-name filelist))
		     (error "File %s not readable." file-name))))))
      (skip-chars-forward *whitespace*))
    filelist))

(defun twelf-server-read-config ()
  "Read the configuration and initialize *twelf-config-list*."
  (if (or (not (bufferp *twelf-config-buffer*))
	  (null (buffer-name *twelf-config-buffer*)))
      (error "No current configuration buffer"))
  (set-buffer *twelf-config-buffer*)
  (goto-char (point-min))
  (twelf-parse-config))

(defun twelf-server-sync-config ()
  "Synchronize the configuration file, buffer, and Twelf server."
  (if (or (not (bufferp *twelf-config-buffer*))
	  (null (buffer-name *twelf-config-buffer*)))
      (error "No current configuration buffer"))
  (if (and twelf-config-mode
	   (not (equal *twelf-config-buffer* (current-buffer)))
	   (yes-or-no-p "Buffer is different from current configuration, reconfigure server? "))
      (twelf-server-configure (buffer-file-name (current-buffer))
			      "Server OK: Reconfigured"))
  (save-excursion
    (set-buffer *twelf-config-buffer*)
    (if (buffer-modified-p *twelf-config-buffer*)
	(progn
	  (display-buffer *twelf-config-buffer*)
	  (if (yes-or-no-p "Config buffer has changed, save new version? ")
	      (save-buffer)
	    (message "Checking old configuration"))))
    (if (not (verify-visited-file-modtime *twelf-config-buffer*))
	(if (yes-or-no-p "Config file has changed, read new contents? ")
	    (revert-buffer t t)))
    (if (not (equal (visited-file-modtime) *twelf-config-time*))
	(progn
	  (display-buffer *twelf-config-buffer*)
	  (if (yes-or-no-p "Config file has changed, reconfigure server? ")
	      (twelf-server-configure (buffer-file-name *twelf-config-buffer*)
				    "Server OK: Configured")
	    (if (not (yes-or-no-p "Ask next time? "))
		(setq *twelf-config-time* (visited-file-modtime))))))))

(defun twelf-get-server-buffer (&optional createp)
  "Get the current Twelf server buffer.
Optional argument CREATEP indicates if the buffer should be
created if it doesn't exist."
  (if (and (bufferp *twelf-server-buffer*)
	   (not (null (buffer-name *twelf-server-buffer*))))
      *twelf-server-buffer*
    (if createp
	(let ((twelf-server-buffer
	       (get-buffer-create *twelf-server-buffer-name*)))
	  (save-window-excursion
	    (set-buffer twelf-server-buffer)
	    (twelf-server-mode)
	    (setq *twelf-server-buffer* twelf-server-buffer))
	  twelf-server-buffer)
      (error "No Twelf server buffer"))))

(defun twelf-init-variables ()
  "Initialize variables that track Twelf server state."
  (setq twelf-chatter 3)
  ;;(setq twelf-trace 0)
  (setq twelf-double-check "false")
  (setq twelf-print-implicit "false"))

(defun twelf-server (&optional program)
  "Start an Twelf server process in a buffer named *twelf-server*.
Any previously existing process is deleted after confirmation.
Optional argument PROGRAM defaults to the value of the variable
twelf-server-program.
This locally re-binds `twelf-server-timeout' to 15 secs."
  (interactive)
  (let* ((default-program (if (null program) twelf-server-program program))
	 (default-dir (file-name-directory default-program))
	 (program (expand-file-name
		   (if (null program)
		       (read-file-name (concat "Twelf server: (default "
					       (file-name-nondirectory
						default-program)
					       ") ")
				       default-dir
				       default-program
				       t)
		     program)))
	 ;; longer timeout during startup
	 (twelf-server-timeout 15))
    ;; We save the program name as the default for the next time a server is
    ;; started in this session.
    (setq twelf-server-program program))
  (save-window-excursion
    (let* ((twelf-server-buffer (twelf-get-server-buffer t))
	   (twelf-server-process (get-buffer-process twelf-server-buffer)))
      (set-buffer twelf-server-buffer)
      (if (not (null twelf-server-process))
	  (if (yes-or-no-p "Kill current server process? ")
	      (delete-process twelf-server-process)
	    (error "Twelf Server restart aborted")))
      (goto-char (point-max))
      (setq *twelf-server-last-process-mark* (point))
      ;; initialize variables
      (twelf-init-variables)
      (start-process *twelf-server-process-name*
		     twelf-server-buffer
		     twelf-server-program)
      (twelf-server-wait)
      (twelf-server-process))))

(defun twelf-server-process (&optional buffer)
  "Return the twelf server process, starting one if none exists."
  (let* ((twelf-server-buffer (if (null buffer) (twelf-get-server-buffer t)
			      buffer))
	 (twelf-server-process (get-buffer-process twelf-server-buffer)))
      (if (not (null twelf-server-process))
	  twelf-server-process
	  (twelf-server))))

(defun twelf-server-display (&optional selectp)
  "Display Twelf server buffer, moving to the end of output.
With prefix argument also selects the Twelf server buffer."
  (interactive "P")
  (display-server-buffer)
  (if selectp (pop-to-buffer (twelf-get-server-buffer))))

(defun display-server-buffer (&optional buffer)
  "Display the Twelf server buffer so that the end of output is visible."
  (let* ((twelf-server-buffer (if (null buffer) (twelf-get-server-buffer)
			      buffer))
	 (_ (set-buffer twelf-server-buffer))
	 (twelf-server-process (twelf-server-process twelf-server-buffer))
	 (proc-mark (process-mark twelf-server-process))
	 (_ (display-buffer twelf-server-buffer))
	 (twelf-server-window (get-buffer-window twelf-server-buffer)))
    (if (not (pos-visible-in-window-p proc-mark twelf-server-window))
	(progn
	  (push-mark proc-mark)
	  (set-window-point twelf-server-window proc-mark)))
    (sit-for 0)))

(defun twelf-server-send-command (command)
  "Send a string COMMAND to the Twelf server."
  (interactive "sCommand: ")
  (let* ((input (concat command "\n"))
	 (twelf-server-buffer (twelf-get-server-buffer))
	 (twelf-server-process (twelf-server-process twelf-server-buffer)))
    (if twelf-server-echo-commands
	(let ((previous-buffer (current-buffer)))
	  (if twelf-server-display-commands
	      (display-server-buffer twelf-server-buffer))
	  (set-buffer twelf-server-buffer)
	  (goto-char (point-max))
	  (insert input)
	  (set-marker (process-mark twelf-server-process) (point-max))
	  (setq *twelf-error-pos* (point-max))
	  (set-buffer previous-buffer)))
    (setq *twelf-last-input-buffer* twelf-server-buffer)
    (setq *twelf-server-last-process-mark*
	  (marker-position (process-mark twelf-server-process)))
    (comint-send-string twelf-server-process input)))

(defun twelf-accept-process-output (process timeout)
  "Incompatibility workaround for versions of accept-process-output.
In case the function accepts no TIMEOUT argument, we wait potentially
forever (until the user aborts, typically with \\[keyboard-quit])."
  (condition-case nil			; do not keep track of error message
      (accept-process-output process timeout)
    (wrong-number-of-arguments
     (accept-process-output process))))

(defun twelf-server-wait (&optional displayp ok-message abort-message)
  "Wait for server acknowledgment and beep if error occurred.
If optional argument DISPLAYP is non-NIL, or if an error occurred, the
Twelf server buffer is displayed.  Optional second and third arguments
OK-MESSAGE and ABORT-MESSAGE are the strings to show upon successful
completion or abort of the server which default to \"Server OK\" and
\"Server ABORT\"."
  (let* ((chunk-count 0)
	 (last-point *twelf-server-last-process-mark*)
	 (previous-buffer (current-buffer))
	 (previous-match-data (match-data))
	 (twelf-server-buffer (twelf-get-server-buffer))
	 (twelf-server-process (get-buffer-process twelf-server-buffer)))
    (unwind-protect
	(catch 'done
	  (set-buffer twelf-server-buffer)
	  (while t
	    (goto-char last-point)
	    (if (re-search-forward "\\(%% OK %%\n\\)\\|\\(%% ABORT %%\n\\)"
				   (point-max) 'limit)
		(cond ((match-beginning 1)
		       (if displayp
			   (display-server-buffer twelf-server-buffer))
		       (message (or ok-message "Server OK"))
		       (throw 'done nil))
		      ((match-beginning 2)
		       (display-server-buffer twelf-server-buffer)
		       (error (or abort-message "Server ABORT"))
		       (throw 'done nil)))
	      (cond ((or (not (twelf-accept-process-output
			       twelf-server-process twelf-server-timeout))
			 (= last-point (point)))
		     (display-server-buffer twelf-server-buffer)
		     (message "Server TIMEOUT, continuing Emacs")
		     (throw 'done nil))
		    (t (setq chunk-count (+ chunk-count 1))
		       (if (= (mod chunk-count 10) 0)
			   (message (make-string (/ chunk-count 10) ?#)))
		       (sit-for 0))))))
      (store-match-data previous-match-data)
      (set-buffer previous-buffer))))

(defun twelf-server-quit ()
  "Kill the Twelf server process."
  (interactive)
  (twelf-server-send-command "OS.exit"))

(defun twelf-server-interrupt ()
  "Interrupt the Twelf server process."
  (interactive)
  (interrupt-process (twelf-server-process)))

(defun twelf-reset ()
  "Reset the global signature of Twelf maintained by the server."
  (interactive)
  (twelf-server-send-command "reset"))

(defun twelf-config-directory ()
  "Returns directory with current Twelf server configuration."
  (let ((config-file (buffer-file-name *twelf-config-buffer*)))
    (file-name-directory config-file)))

;(defun relativize-file-name (filename dir)
;  "Relativize FILENAME with respect to DIR, if possible."
;  (if (string= dir (file-name-directory filename))
;      (file-name-nondirectory filename)
;    filename))

(defun twelf-server-configure (config-file &optional ok-message)
  "Initializes the Twelf server configuration from CONFIG-FILE.
A configuration file is a list of relative file names in
dependency order.  Lines starting with % are treated as comments.
Starts a Twelf servers if necessary."
  (interactive
   (list (if twelf-config-mode (buffer-file-name)
	   (expand-file-name
	    (read-file-name "Visit config file: (default sources.cfg) "
			    default-directory
			    (concat default-directory "sources.cfg")
			    nil ; don't require match for now
			    )))))
  (let* ((config-file (if (file-directory-p config-file)
			  (concat config-file "sources.cfg")
			config-file))
	 (config-file-os (twelf-convert-standard-filename config-file))
	 (config-dir (file-name-directory config-file))
	 (config-dir-os (twelf-convert-standard-filename config-dir))
	 (config-buffer (set-buffer (or (get-file-buffer config-file)
					(find-file-noselect config-file))))
	 config-list)
    (setq *twelf-config-buffer* config-buffer)
    (if (and (not (verify-visited-file-modtime (get-file-buffer config-file)))
	     (yes-or-no-p "Config file has changed, read new contents? "))
	(revert-buffer t t))
    (setq config-list (twelf-server-read-config))
    (twelf-server-process)                ; Start process if necessary
    (let* ((_ (set-buffer (twelf-get-server-buffer)))
	   (cd-command
	    (if (equal default-directory config-dir)
		nil
	      (setq default-directory config-dir)
	      (concat "OS.chDir " config-dir-os)))
	   (_ (set-buffer config-buffer)))
      (cond ((not (null cd-command))
	     (twelf-server-send-command cd-command)
	     (twelf-server-wait nil ""
				"Server ABORT: Could not change directory")))
      (twelf-server-send-command
       (concat "Config.read " config-file-os))
      (twelf-server-wait nil (or ok-message "Server OK")
		       "Server ABORT: Could not be configured")
      ;; *twelf-config-buffer* should still be current buffer here
      (setq *twelf-config-time* (visited-file-modtime))
      (setq *twelf-config-list* config-list))))

;(defun twelf-server-add-file (filename)
;  "Adds a file to the current configuration."
;  (interactive
;   (list (expand-file-name
;          (read-file-name "File to add: " (twelf-config-directory)))))
;  (let ((relative-file (file-relative-name filename (twelf-config-directory)))
;	temp-time)
;    (save-excursion
;      (set-buffer *twelf-config-buffer*)
;      (goto-char (point-max))
;      (if (not (= (point) (point-min)))
;          (progn
;            (backward-char 1)
;            (if (looking-at "\n")
;                (forward-char 1)
;              (forward-char 1)
;              (insert "\n"))))
;      (insert (concat relative-file "\n"))
;      (save-buffer)
;      (setq temp-time (visited-file-modtime)))
;    (twelf-server-send-command
;     (concat "Config.read " (buffer-file-name *twelf-config-buffer*)))
;    (twelf-server-wait nil "" "Server ABORT: File could not be added to configuration")
;    (setq *twelf-config-list* (cons filename *twelf-config-list*))
;    (setq *twelf-config-time* temp-time)))

(defun natp (x)
  "Checks if X is an integer greater or equal to 0."
  (and (integerp x) (>= x 0)))

(defun twelf-read-nat ()
  "Reads a natural number from the minibuffer."
  (let ((num nil))
    (while (not (natp num))
      (setq num (read-from-minibuffer "Number: " (if num (prin1-to-string num))
				      nil t t))
      (if (not (natp num)) (beep)))
    num))

(defun twelf-read-bool ()
  "Read a boolean in mini-buffer."
  (completing-read "Boolean: "
		   '(("true" . true) ("false" . false))
		   nil t))

(defun twelf-read-limit ()
  "Read a limit (* or natural number) in mini-buffer."
  (let ((input (read-string "Limit (* or nat): ")))
    (if (equal input "*")
	input
      (let ((n (string-to-number input)))
	(if (and (integerp n) (> n 0))
	    n
	  (error "Number must be non-negative integer"))))))

(defun twelf-read-strategy ()
  "Read a strategy in mini-buffer."
  (completing-read "Strategy: "
		   '(("FRS" . "FRS") ("RFS" . "RFS"))
		   nil t))

(defun twelf-read-value (argtype)
  "Call the read function appropriate for ARGTYPE and return result."
  (funcall (cdr (assoc argtype *twelf-read-functions*))))

(defun twelf-set (parm value)
  "Sets the Twelf parameter PARM to VALUE.
When called interactively, prompts for parameter and value, supporting
completion."
  (interactive
   (let* ((parm (completing-read
		 "Parameter: " *twelf-parm-table* nil t))
	  (argtype (cdr (assoc parm *twelf-parm-table*)))
	  (value (twelf-read-value argtype)))
     (list parm value)))
  (track-parm parm value)		; track, if necessary
  (twelf-server-send-command (concat "set " parm " " value)))

(defun twelf-set-parm (parm)
  "Prompts for and set the value of Twelf parameter PARM.
Used in menus."
  (let* ((argtype (cdr (assoc parm *twelf-parm-table*)))
	 (value (and argtype (twelf-read-value argtype))))
    (if (null argtype)
	(error "Unknown parameter")
      (twelf-set parm value))))

(defun track-parm (parm value)
  "Tracks Twelf parameter values in Emacs."
  (if (assoc parm *twelf-track-parms*)
      (set (cdr (assoc parm *twelf-track-parms*)) value)))

(defun twelf-toggle-double-check ()
  "Toggles doubleCheck parameter of Twelf."
  (let ((value (if (string-equal twelf-double-check "false")
		   "true" "false")))
    (twelf-set "doubleCheck" value)))

(defun twelf-toggle-print-implicit ()
  "Toggles Print.implicit parameter of Twelf."
  (let ((value (if (string-equal twelf-print-implicit "false")
		   "true" "false")))
    (twelf-set "Print.implicit" value)))

(defun twelf-get (parm)
  "Prints the value of the Twelf parameter PARM.
When called interactively, promts for parameter, supporting completion."
  (interactive (list (completing-read "Parameter: " *twelf-parm-table* nil t)))
  (twelf-server-send-command (concat "get " parm))
  (twelf-server-wait)
  (save-window-excursion
    (let ((twelf-server-buffer (twelf-get-server-buffer)))
      (set-buffer twelf-server-buffer)
      (goto-char *twelf-server-last-process-mark*)
      ;; We are now at the beginning of the output
      (end-of-line 1)
      (message (buffer-substring *twelf-server-last-process-mark* (point))))))

(defun twelf-timers-reset ()
  "Reset the Twelf timers."
  (interactive)
  (twelf-server-send-command "Timers.reset"))

(defun twelf-timers-show ()
  "Show and reset the Twelf timers."
  (interactive)
  (twelf-server-send-command "Timers.show")
  (twelf-server-wait t))

(defun twelf-timers-check ()
  "Show the Twelf timers without resetting them."
  (interactive)
  (twelf-server-send-command "Timers.show")
  (twelf-server-wait t))

(defun twelf-server-restart ()
  "Restarts server and re-initializes configuration.
This is primarily useful during debugging of the Twelf server code or
if the Twelf server is hopelessly wedged."
  (interactive)
  (twelf-server twelf-server-program)
  (twelf-server-configure (if *twelf-config-buffer*
			    (buffer-file-name *twelf-config-buffer*)
			  "sources.cfg")
			"Server configured, now checking...")
  (twelf-check-config))

;;;----------------------------------------------------------------------
;;; Twelf Config minor mode
;;;----------------------------------------------------------------------

(defun twelf-config-mode (&optional prefix)
  "Toggles minor mode for Twelf configuration files.
This affects \\<twelf-mode-map>
 twelf-server-configure (\\[twelf-server-configure])
 twelf-save-check-config (\\[twelf-save-check-config])
"
  (interactive "P")
  (make-local-variable 'twelf-config-mode)
  (cond ((not (assq 'twelf-config-mode minor-mode-alist))
	 (setq minor-mode-alist
	       (cons '(twelf-config-mode " Config") minor-mode-alist))))
  (cond ((or (not twelf-config-mode) prefix)
	 (setq twelf-config-mode t)
	 (run-hooks 'twelf-config-mode-hook))
	(t (setq twelf-config-mode t))))

(defun twelf-config-mode-check (&optional buffer)
  "Switch on the Twelf Config minor mode if the ends in `.cfg'."
  (if (string-match "\\.cfg$" (buffer-file-name (or buffer (current-buffer))))
      (twelf-config-mode t)))

;;;----------------------------------------------------------------------
;;; Support for creating a TAGS file for current Twelf server configuration
;;;----------------------------------------------------------------------

(defun twelf-tag (&optional tags-filename)
  "Create tags file for current configuration.
If the current configuration is sources.cfg, the tags file is TAGS.
If current configuration is named FILE.cfg, tags file will be named FILE.tag
Errors are displayed in the Twelf server buffer.
Optional argument TAGS-FILENAME specifies alternative filename."
  (interactive)
  (twelf-server-sync-config)
  (let* ((error-buffer (twelf-get-server-buffer))
	 (config-filename (buffer-file-name *twelf-config-buffer*))
	 (tags-file
	  (or tags-filename
	      (if (string-equal "sources.cfg"
				(file-name-nondirectory config-filename))
		  (concat (file-name-directory config-filename "TAGS"))
		(concat (file-name-sans-extension config-filename)
			".tag")))))
    (save-excursion
      (set-buffer error-buffer)
      (goto-char (point-max))
      (insert "Tagging configuration " config-filename " in file " tags-file "\n"))
    (set-buffer *twelf-config-buffer*)
    (twelf-tag-files (rev-relativize *twelf-config-list* default-directory)
		   tags-file error-buffer)
    (if (get-buffer-process error-buffer)
	(set-marker (process-mark (get-buffer-process error-buffer))
		    (point-max)))))

(defun twelf-tag-files (filelist &optional tags-filename error-buffer)
  "Create tags file for FILELIST, routing errors to buffer *tags-errors*.
Optional argument TAGS-FILENAME specifies alternative filename (default: TAGS),
optional argument ERROR-BUFFER specifies alternative buffer for error message
(default: *tags-errors*)."
  (let* ((tags-filename (or tags-filename "TAGS"))
	 (tags-buffer (find-file-noselect tags-filename))
	 (error-buffer (or error-buffer (new-temp-buffer "*tags-errors*"))))
    (save-excursion
      (set-buffer tags-buffer)
      (if (equal (point-min) (point-max))
	  nil
	;;(pop-to-buffer tags-buffer)
	;;(if (yes-or-no-p "Delete current tags information? ")
	(delete-region (point-min) (point-max))
	;;)
	))
    (switch-to-buffer-other-window error-buffer)
    (while (not (null filelist))
      (twelf-tag-file (car filelist) tags-buffer error-buffer)
      (setq filelist (cdr filelist)))
    (save-excursion
      (set-buffer tags-buffer)
      (save-buffer))))

(defun twelf-tag-file (filename tags-buffer error-buffer)
  "Deposit tag information for FILENAME in TAGS-BUFFER, errors in ERROR-BUFFER."
  (let ((src-buffer (find-file-noselect filename))
	file-start file-end end-of-id tag-string)
    (save-excursion
      (set-buffer tags-buffer)
      (goto-char (point-max))
      (insert "\f\n" filename ",0\n")
      (setq file-start (point))
      (save-excursion
	(set-buffer src-buffer)
	(goto-char (point-min))
	(while (twelf-next-decl filename error-buffer)
	  (setq end-of-id (point))
	  (beginning-of-line 1)
	  (setq tag-string
		(concat (buffer-substring (point) end-of-id)
			"\C-?" (current-line-absolute) "," (point) "\n"))
	  (goto-char end-of-id)
	  (if (not (twelf-end-of-par))
	      (let ((error-line (current-line-absolute)))
		(save-excursion
		  (set-buffer error-buffer)
		  (goto-char (point-max))
		  (insert filename ":" (int-to-string error-line)
			  " Warning: missing period\n"))))
	  (save-excursion
	    (set-buffer tags-buffer)
	    (insert tag-string))))
      (setq file-end (point-max))
      (goto-char (- file-start 2))
      (delete-char 1)
      (insert (int-to-string (- file-end file-start)))
      (goto-char (point-max)))))

(defun twelf-next-decl (filename error-buffer)
  "Set point after the identifier of the next declaration.
Return the declared identifier or `nil' if none was found.
FILENAME and ERROR-BUFFER are used if something appears wrong."
  (let ((id nil)
	end-of-id
	beg-of-id)
    (skip-twelf-comments-and-whitespace)
    (while (and (not id) (not (eobp)))
      (setq beg-of-id (point))
      (if (zerop (skip-chars-forward *twelf-id-chars*))
	  ;; Not looking at id: skip ahead
	  (skip-ahead filename (current-line-absolute) "No identifier"
		      error-buffer)
	(setq end-of-id (point))
	(skip-twelf-comments-and-whitespace)
	(if (not (looking-at ":"))
	    ;; Not looking at valid decl: skip ahead
	    (skip-ahead filename (current-line-absolute end-of-id) "No colon"
			error-buffer)
	  (goto-char end-of-id)
	  (setq id (buffer-substring beg-of-id end-of-id))))
      (skip-twelf-comments-and-whitespace))
    id))

(defun skip-ahead (filename line message error-buffer)
  "Skip ahead when syntactic error was found.
A parsable error message constited from FILENAME, LINE, and MESSAGE is
deposited in ERROR-BUFFER."
  (if error-buffer
      (save-excursion
	(set-buffer error-buffer)
	(goto-char (point-max))
	(insert filename ":" (int-to-string line) " Warning: " message "\n")
	(setq *twelf-error-pos* (point))))
  (twelf-end-of-par))

(defun current-line-absolute (&optional char-pos)
  "Return line number of CHAR-POS (default: point) in current buffer.
Ignores any possible buffer restrictions."
  (1+ (count-lines 1 (or char-pos (point)))))

(defun new-temp-buffer (&optional name)
  "Create or delete contents of buffer named \"*temp*\" and return it.
Optional argument NAME specified an alternative name."
  (if (not name) (setq name "*temp*"))
  (if (get-buffer name)
      (save-excursion
	(set-buffer name)
	(delete-region (point-min) (point-max))
	(get-buffer name))
    (get-buffer-create name)))

(defun rev-relativize (filelist dir)
  "Reverse and relativize FILELIST with respect to DIR."
  (let ((newlist nil))
    (while (not (null filelist))
      (setq newlist
	    (cons (file-relative-name (car filelist) dir) newlist))
      (setq filelist (cdr filelist)))
    newlist))


;;;----------------------------------------------------------------------
;;; Twelf-SML mode
;;;----------------------------------------------------------------------

(defvar twelf-sml-mode-map nil
  "The keymap used in Twelf-SML mode.")

(cond ((not twelf-sml-mode-map)
       ;;(setq twelf-sml-mode-map (full-copy-sparse-keymap comint-mode-map))
       ;; fixed for Emacs 19.25.  -fp Thu Oct 27 09:08:44 1994
       (setq twelf-sml-mode-map (copy-keymap comint-mode-map))
       (install-basic-twelf-keybindings twelf-sml-mode-map)
       ))

(defconst twelf-sml-prompt-regexp "^\\- \\|^\\?\\- ")

(defun expand-dir (dir)
  "Expand argument and check that it is a directory."
  (let ((expanded-dir (file-name-as-directory (expand-file-name dir))))
    (if (not (file-directory-p expanded-dir))
	(error "%s is not a directory" dir))
    expanded-dir))

(defun twelf-sml-cd (dir)
  "Make DIR become the Twelf-SML process' buffer's default directory and
furthermore issue an appropriate command to the inferior Twelf-SML process."
  (interactive "DChange default directory: ")
  (let ((expanded-dir (expand-dir dir)))
    (save-excursion
      (set-buffer (twelf-sml-process-buffer))
      (setq default-directory expanded-dir)
      (comint-simple-send (twelf-sml-process) (concat "Twelf.OS.chDir \"" expanded-dir "\";")))
    ;;(pwd)
    ))

(defconst twelf-sml-cd-regexp "^\\s *cd\\s *\"\\([^\"]*\\)\""
  "Regular expression used to match cd commands in Twelf-SML buffer.")

(defun twelf-sml-directory-tracker (input)
  "Checks input for cd commands and changes default directory in buffer.
As a side-effect, it sets *twelf-last-region-sent* to NIL to indicate interactive
input.  As a second side-effect, it resets the *twelf-error-pos*.
Used as comint-input-sentinel in Twelf-SML buffer."
  (if (twelf-input-filter input)
      (setq *twelf-last-region-sent* nil))
  (setq *twelf-last-input-buffer* (current-buffer))
  (setq *twelf-error-pos* (marker-position (process-mark (twelf-sml-process))))
  (cond ((string-match twelf-sml-cd-regexp input)
	 (let ((expanded-dir (expand-dir (substring input
						    (match-beginning 1)
						    (match-end 1)))))
	   (setq default-directory expanded-dir)
	   (pwd)))))

(defun twelf-sml-mode ()
  "Major mode for interacting with an inferior Twelf-SML process.

The following commands are available:
\\{twelf-sml-mode-map}

An Twelf-SML process can be started with \\[twelf-sml].

Customisation: Entry to this mode runs the hooks on twelf-sml-mode-hook.

You can send queries to the inferior Twelf-SML process from other buffers.

Commands:
Return after the end of the process' output sends the text from the
    end of process to point.
Return before the end of the process' output copies the current line
    to the end of the process' output, and sends it.
Delete converts tabs to spaces as it moves back.
Tab indents for Twelf; with argument, shifts rest
    of expression rigidly with the current line.
C-M-q does Tab on each line starting within following expression.
Paragraphs are separated only by blank lines.  % start single comments,
delimited comments are enclosed in %{...}%.
If you accidentally suspend your process, use \\[comint-continue-subjob]
to continue it."
  (interactive)
  (kill-all-local-variables)
  (comint-mode)
  (setq comint-prompt-regexp twelf-sml-prompt-regexp)
  (setq comint-input-filter 'twelf-input-filter)
  ;; changed for XEmacs 19.16 Sat Jun 13 11:28:53 1998
  (add-hook 'comint-input-filter-functions 'twelf-sml-directory-tracker
	    nil t)
  (twelf-mode-variables)

  ;; For sequencing through error messages:
  (make-local-variable '*twelf-error-pos*)
  (setq *twelf-error-pos* (point-max))
  ;; Workaround for problem with Lucid Emacs version of comint.el:
  ;; must exclude double quotes " and must include $ and # in filenames.
  (make-local-variable 'comint-match-partial-pathname-chars)
  (setq comint-match-partial-pathname-chars
	"^][<>{}()!^&*\\|?`'\" \t\n\r\b")

  (setq major-mode 'twelf-sml-mode)
  (setq mode-name "Twelf-SML")
  (setq mode-line-process '(": %s"))
  (use-local-map twelf-sml-mode-map)

  (run-hooks 'twelf-sml-mode-hook))

(defun twelf-sml (&optional cmd)
  "Run an inferior Twelf-SML process in a buffer *twelf-sml*.
If there is a process already running in *twelf-sml*, just
switch to that buffer.  With argument, allows you to change the program
which defaults to the value of twelf-sml-program.  Runs the hooks from
twelf-sml-mode-hook (after the comint-mode-hook is run).

Type \\[describe-mode] in the process buffer for a list of commands."
  (interactive (list (and current-prefix-arg
			  (read-string "Run Twelf-SML: " twelf-sml-program))))
  (let ((cmd (or cmd twelf-sml-program)))
    (cond ((not (comint-check-proc (twelf-sml-process-buffer)))
	   ;; process does not already exist
	   (set-buffer (apply 'make-comint "twelf-sml" cmd nil twelf-sml-args))
	   ;; in case we are using SML mode (for error tracking)
	   (if (boundp 'sml-buffer)
	       (set 'sml-buffer (twelf-sml-process-buffer)))
	   (twelf-sml-mode))))
  (switch-to-buffer (twelf-sml-process-buffer)))

(defun switch-to-twelf-sml (eob-p)
  "Switch to the Twelf-SML process buffer.
With argument, positions cursor at end of buffer."
  (interactive "P")
  (if (twelf-sml-process-buffer)
      (pop-to-buffer (twelf-sml-process-buffer))
      (error "No current process buffer. "))
  (cond (eob-p
	 (push-mark)
	 (goto-char (point-max)))))

(defun display-twelf-sml-buffer (&optional buffer)
  "Display the Twelf-SML buffer so that the end of output is visible."
  ;; Accept output from Twelf-SML process
  (sit-for 1)
  (let* ((twelf-sml-buffer (if (null buffer) (twelf-sml-process-buffer)
		       buffer))
	 (_ (set-buffer twelf-sml-buffer))
	 (twelf-sml-process (twelf-sml-process))
	 (proc-mark (process-mark twelf-sml-process))
	 (_ (display-buffer twelf-sml-buffer))
	 (twelf-sml-window (get-buffer-window twelf-sml-buffer)))
    (if (not (pos-visible-in-window-p proc-mark twelf-sml-window))
	(progn
	  (push-mark proc-mark)
	  (set-window-point twelf-sml-window proc-mark)))))

(defun twelf-sml-send-string (string)
  "Send the given string to the Twelf-SML process."
  (setq *twelf-last-input-buffer* (twelf-sml-process-buffer))
  (comint-send-string (twelf-sml-process) string))

(defun twelf-sml-send-region (start end &optional and-go)
  "Send the current region to the inferior Twelf-SML process.
Prefix argument means switch-to-twelf-sml afterwards.
If the region is short, it is sent directly, via COMINT-SEND-REGION."
  (interactive "r\nP")
  (if (> start end)
      (twelf-sml-send-region end start and-go)
    ;; (setq twelf-sml-last-region-sent (list (current-buffer) start end))
    (let ((cur-buffer (current-buffer))
	  (twelf-sml-buffer (twelf-sml-process-buffer)))
      (switch-to-buffer twelf-sml-buffer)
      ;; (setq sml-error-pos (marker-position (process-mark (twelf-sml-process))))
      (setq *twelf-last-input-buffer* twelf-sml-buffer)
      (switch-to-buffer cur-buffer))
    (comint-send-region (twelf-sml-process) start end)
    (if (not (string= (buffer-substring (1- end) end) "\n"))
	(comint-send-string (twelf-sml-process) "\n"))
    ;; Next two lines mess up when an Twelf error occurs, since the
    ;; newline is not read and later messes up counting.
    ;; (if (not and-go)
    ;;  (comint-send-string (twelf-sml-process) "\n"))
    (if and-go (switch-to-twelf-sml t)
      (if twelf-sml-display-queries (display-twelf-sml-buffer)))))

(defun twelf-sml-send-query (&optional and-go)
  "Send the current declaration to the inferior Twelf-SML process as a query.
Prefix argument means switch-to-twelf-sml afterwards."
  (interactive "P")
  (let* ((par (twelf-current-decl))
	 (query-start (nth 0 par))
	 (query-end (nth 1 par)))
    (twelf-sml-set-mode 'TWELF)
    (twelf-sml-send-region query-start query-end and-go)))

(defun twelf-sml-send-newline (&optional and-go)
  "Send a newline to the inferior Twelf-SML process.
If a prefix argument is given, switches to Twelf-SML buffer afterwards."
  (interactive "P")
  (twelf-sml-send-string "\n")
  (if and-go (switch-to-twelf-sml t)
    (if twelf-sml-display-queries (display-twelf-sml-buffer))))

(defun twelf-sml-send-semicolon (&optional and-go)
  "Send a semi-colon to the inferior Twelf-SML process.
If a prefix argument is given, switched to Twelf-SML buffer afterwards."
  (interactive "P")
  (twelf-sml-send-string ";\n")
  (if and-go (switch-to-twelf-sml t)
    (if twelf-sml-display-queries (display-twelf-sml-buffer))))

(defun twelf-sml-status (&optional buffer)
  "Returns the status of the Twelf-SML process.
This employs a heuristic, looking at the contents of the Twelf-SML buffer.
Results:
 NONE --- no process
 ML   --- ML top level
 TWELF  --- Twelf top level
 MORE --- asking whether to find the next solution
 UNKNOWN --- process is running, but can't tell status."
  (let* ((twelf-sml-buffer (or buffer (twelf-sml-process-buffer)))
	 (twelf-sml-process (get-buffer-process twelf-sml-buffer)))
    (if (null twelf-sml-process)
	'NONE
      (save-excursion
	(set-buffer twelf-sml-buffer)
	(let ((buffer-end (buffer-substring (max (point-min) (- (point-max) 3))
					    (point-max))))
	  (cond ((string-match "\\?- " buffer-end) 'TWELF)
		((string-match "\n- " buffer-end) 'ML)
		((string-match "More\\? " buffer-end) 'MORE)
		(t 'UNKNOWN)))))))

(defvar twelf-sml-init "Twelf.Config.load (Twelf.Config.read \"sources.cfg\");\n"
  "Initial command sent to Twelf-SML process when started during twelf-sml-set-mode 'TWELF.")

(defun twelf-sml-set-mode (mode &optional buffer)
  "Attempts to read and if necessary correct the mode of the Twelf-SML buffer.
This does not check if the status has been achieved.  It returns NIL
if the status is unknown and T if it believes the status should have
been achieved.  This allows for asynchronous operation."
  (cond
    ((eq mode 'ML)
     (let ((status (twelf-sml-status)))
       (cond ((eq status 'NONE) (twelf-sml) 't)
	     ((eq status 'ML) 't)
	     ((eq status 'TWELF) (twelf-sml-send-string "") 't)
	     ((eq status 'MORE) (twelf-sml-send-string "q\n") 't)
	     ((eq status 'UNKNOWN) nil))))
    ((eq mode 'TWELF)
     (let ((status (twelf-sml-status)))
       (cond ((eq status 'NONE)
	      (twelf-sml)
	      (twelf-sml-send-string twelf-sml-init)
	      (twelf-sml-send-string "Twelf.top ();\n") 't)
	     ((eq status 'ML)
	      (twelf-sml-send-string "Twelf.top ();\n") 't)
	     ((eq status 'TWELF) 't)
	     ((eq status 'MORE) (twelf-sml-send-string "\n") 't)
	     ((eq status 'UNKNOWN) nil))))
    (t (error "twelf-sml-set-mode: illegal mode %s" mode))))

(defun twelf-sml-quit ()
  "Kill the Twelf-SML process."
  (interactive)
  (kill-process (twelf-sml-process)))

(defun twelf-sml-process-buffer ()
  "Returns the current Twelf-SML process buffer."
  (get-buffer "*twelf-sml*"))

(defun twelf-sml-process (&optional buffer)
  "Returns the current Twelf-SML process."
  (let ((proc (get-buffer-process (or buffer (twelf-sml-process-buffer)))))
    (or proc
	(error "No current process."))))

;;;----------------------------------------------------------------------
;;; 2Twelf-SML minor mode for Twelf
;;; Some keybindings now refer to Twelf-SML instead of the Twelf server.
;;; Toggle with twelf-to-twelf-sml-mode
;;;----------------------------------------------------------------------

(defvar twelf-to-twelf-sml-mode nil
  "Non-NIL means the minor mode is in effect.")

(defun install-twelf-to-twelf-sml-keybindings (map)
  ;; Process commands:
  (define-key map "\C-c\C-r" 'twelf-sml-send-region)
  (define-key map "\C-c\C-e" 'twelf-sml-send-query)
  (define-key map "\C-c\C-m" 'twelf-sml-send-newline)
  (define-key map "\C-c\n" 'twelf-sml-send-newline)
  (define-key map "\C-c;" 'twelf-sml-send-semicolon)
  (define-key map "\C-cd" 'twelf-sml-cd)
  )

(defvar twelf-to-twelf-sml-mode-map nil
  "Keymap for twelf-to-twelf-sml minor mode.")

(cond ((not twelf-to-twelf-sml-mode-map)
       (setq twelf-to-twelf-sml-mode-map (make-sparse-keymap))
       (install-basic-twelf-keybindings twelf-to-twelf-sml-mode-map)
       (install-twelf-keybindings twelf-to-twelf-sml-mode-map)
       ;; The next line shadows certain bindings to refer to
       ;; Twelf-SML instead of the Twelf server.
       (install-twelf-to-twelf-sml-keybindings twelf-to-twelf-sml-mode-map)))

(defun twelf-to-twelf-sml-mode (&optional prefix)
  "Toggles minor mode for sending queries to Twelf-SML instead of Twelf server.
Specifically:   \\<twelf-to-twelf-sml-mode-map>
 \\[twelf-sml-send-query] (for sending queries),
 \\[twelf-sml-send-newline] (for sending newlines) and
 \\[twelf-sml-send-semicolon] (for sending `;')
are rebound.

Mode map
========
\\{twelf-to-twelf-sml-mode-map}
"
  (interactive "P")
  (make-local-variable 'twelf-to-twelf-sml-mode)
  (cond ((not (assq 'twelf-to-twelf-sml-mode minor-mode-alist))
	 (setq minor-mode-alist
	       (cons '(twelf-to-twelf-sml-mode " 2Twelf-SML")
		     minor-mode-alist))))
  (cond ((or (not twelf-to-twelf-sml-mode) prefix)
	 (setq twelf-to-twelf-sml-mode t)
	 (use-local-map twelf-to-twelf-sml-mode-map)
	 (run-hooks 'twelf-to-twelf-sml-mode-hook))
	(t
	 (setq twelf-to-twelf-sml-mode nil)
	 (use-local-map twelf-mode-map))))

;;;----------------------------------------------------------------------
;;; Twelf mode menus
;;; requires auc-menu utilities
;;;----------------------------------------------------------------------

(cond
 ((string-match "XEmacs" emacs-version) ;; XEmacs nee Lucid Emacs
  (defun radio (label callback condition)
    (vector label callback ':style 'radio ':selected condition))
  (defun toggle (label callback condition)
    (vector label callback ':style 'toggle ':selected condition))
  (defun disable-form (label callback condition)
    (vector label callback condition))
  )
 (t ;; FSF Emacs 19
  (defun radio (label callback condition)
    (vector label callback t))
  (defun toggle (label callback condition)
    (vector label callback t))
  (defun disable-form (label callback condition)
    (cond ((symbolp condition) (vector label callback condition))
	  (t (vector label callback t))))
  ))

(defconst twelf-at-point-menu
  '("At Point"
    ["Constant" twelf-type-const t]
    ;["Type" twelf-type-at-point nil]	;disabled for Twelf 1.2
    ;["Expected Type" twelf-expected-type-at-point nil] ;disabled
    ;["List Completions" twelf-completions-at-point nil]	;disabled
    ;["Complete" twelf-complete nil] ;disabled
    )
  "Menu for commands applying at point.")

(defconst twelf-server-state-menu
  '("Server State"
    ["Configure" twelf-server-configure t]
    ["Interrupt" twelf-server-interrupt t]
    ["Reset" twelf-reset t]
    ["Start" twelf-server t]
    ["Restart" twelf-server-restart t]
    ["Quit" twelf-server-quit t])
  "Menu for commands affecting server state.")

(defconst twelf-error-menu
  '("Error Tracking"
    ["Next" twelf-next-error t]
    ["Goto" twelf-goto-error t])
  "Menu for error commands.")

(defconst twelf-tags-menu
  '("Tags"
    ["Find" find-tag t]
    ["Find Other Window" find-tag-other-window t]
    ["Query Replace" tags-query-replace t]
    ["Search" tags-search t]
    ["Continue" tags-loop-continue t]
    ["Create/Update" twelf-tag t])
  "Menu for tag commands.")

(defun twelf-toggle-server-display-commands ()
  (setq twelf-server-display-commands (not twelf-server-display-commands)))

(defconst twelf-options-menu
  `("Options"
    (, (toggle "Display Commands" '(twelf-toggle-server-display-commands)
	       'twelf-server-display-commands))
    ("chatter"
     (, (radio "0" '(twelf-set "chatter" 0) '(= twelf-chatter 0)))
     (, (radio "1" '(twelf-set "chatter" 1) '(= twelf-chatter 1)))
     (, (radio "2" '(twelf-set "chatter" 2) '(= twelf-chatter 2)))
     (, (radio "3*" '(twelf-set "chatter" 3) '(= twelf-chatter 3)))
     (, (radio "4" '(twelf-set "chatter" 4) '(= twelf-chatter 4)))
     (, (radio "5" '(twelf-set "chatter" 5) '(= twelf-chatter 5)))
     (, (radio "6" '(twelf-set "chatter" 6) '(= twelf-chatter 6))))
    (, (toggle "doubleCheck" '(twelf-toggle-double-check)
	       '(string-equal twelf-double-check "true")))
    ("Print."
     (, (toggle "implicit" '(twelf-toggle-print-implicit)
		'(string-equal twelf-print-implicit "true")))
     ["depth" (twelf-set-parm "Print.depth") t]
     ["length" (twelf-set-parm "Print.length") t]
     ["indent" (twelf-set-parm "Print.indent") t]
     ["width" (twelf-set-parm "Print.width") t])
    ("Prover."
     ["strategy" (twelf-set-parm "Prover.strategy") t]
     ["maxSplit" (twelf-set-parm "Prover.maxSplit") t]
     ["maxRecurse" (twelf-set-parm "Prover.maxRecurse") t])
    ;;["Trace" nil nil]
    ;; (, (radio "0" '(twelf-set "trace" 0) '(= twelf-trace 0)))
    ;; (, (radio "1" '(twelf-set "trace 1) '(= twelf-trace 1)))
    ;; (, (radio "2" '(twelf-set "trace" 2) '(= twelf-trace 2))))
    ;;["Untrace" nil nil]
    ;;(, (disable-form "Untrace" '(twelf-set "trace" 0)
    ;;	       '(not (= twelf-trace 0))))
    ["Reset Menubar" twelf-reset-menu t])
  "Menu to change options in Twelf mode.")

(defconst twelf-timers-menu
  '("Timing"
    ["Show and Reset" twelf-timers-show t]
    ["Check" twelf-timers-check t]
    ["Reset" twelf-timers-reset t]))

;(autoload 'toggle-twelf-font-immediate "twelf-font"
;  "Toggle experimental immediate highlighting in font-lock mode.")
(autoload 'twelf-font-fontify-decl "twelf-font"
  "Fontify current declaration using font-lock minor mode.")
(autoload 'twelf-font-fontify-buffer "twelf-font"
  "Fontify current buffer using font-lock minor mode.")

(defconst twelf-syntax-menu
  `("Syntax Highlighting"
    ["Highlight Declaration" twelf-font-fontify-decl t]
    ["Highlight Buffer" twelf-font-fontify-buffer t]
    ;;(, (toggle "Immediate Highlighting" 'toggle-twelf-font-immediate
    ;;'font-lock-mode))
    )
  "Menu for syntax highlighting in Twelf mode.")

(easy-menu-define twelf-menu (list twelf-mode-map)
  "Menu for Twelf mode.
This may be selected from the menubar.  In XEmacs, also bound to Button3."
  (list
   "Twelf"
   ["Display Server" twelf-server-display t]
   ["Check Configuration" twelf-save-check-config t]
   ["Check File" twelf-save-check-file t]
   ["Check Declaration" twelf-check-declaration t]
   twelf-at-point-menu
   twelf-error-menu
   twelf-options-menu
   twelf-syntax-menu
   twelf-tags-menu
   twelf-timers-menu
   twelf-server-state-menu
   ["Info" twelf-info t]))

(defun twelf-add-menu ()
  "Add Twelf menu to menubar."
  (easy-menu-add twelf-menu twelf-mode-map))

(defun twelf-remove-menu ()
  "Remove Twelf menu from menubar."
  (easy-menu-remove twelf-menu))

(defun twelf-reset-menu ()
  "Reset Twelf menu."
  (twelf-remove-menu)
  (twelf-add-menu))

;;;----------------------------------------------------------------------
;;; Twelf Server mode menu
;;;----------------------------------------------------------------------

(easy-menu-define twelf-server-menu (list twelf-server-mode-map)
  "Menu for Twelf Server mode.
This may be selected from the menubar.  In XEmacs, also bound to Button3."
  (list
   "Twelf-Server"
   ;; ["Display Server" twelf-server-display t]
   ["Check Configuration" twelf-save-check-config t]
   ;; ["Check File" twelf-save-check-file nil]
   ;; ["Check Declaration" twelf-check-declaration nil]
   ;; ["Check Query" twelf-check-query nil]
   ;; ["Solve Query" twelf-solve-query nil]
   ;; ["At Point" () nil]
   twelf-error-menu
   twelf-options-menu
   twelf-tags-menu
   twelf-server-state-menu
   ["Info" twelf-info t]))

(defun twelf-server-add-menu ()
  "Add Twelf menu to menubar."
  (easy-menu-add twelf-server-menu twelf-server-mode-map))

(defun twelf-server-remove-menu ()
  "Remove Twelf menu from menubar."
  (easy-menu-remove twelf-server-menu))

(defun twelf-server-reset-menu ()
  "Reset Twelf menu."
  (twelf-server-remove-menu)
  (twelf-server-add-menu))

(provide 'twelf-old)