Source

edit-utils / lazy-lock.el

Full commit
   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
;;; lazy-lock.el --- Lazy demand-driven fontification for fast Font Lock mode.

;; Copyright (C) 1994, 1995 Free Software Foundation, Inc.

;; Author: Simon Marshall <simon@gnu.ai.mit.edu>
;; X-Modified-By: Ben Wing <ben@xemacs.org>
;; Maintainer: XEmacs Development Team
;; Keywords: faces files
;; Version: 1.14

;; LCD Archive Entry:
;; lazy-lock|Simon Marshall|simon@gnu.ai.mit.edu|
;; Lazy Font Lock mode (with fast demand-driven fontification).|
;; 13-Oct-95|1.14|~/modes/lazy-lock.el.Z|

;; The archive is archive.cis.ohio-state.edu in /pub/gnu/emacs/elisp-archive.

;;; This file is part of GNU Emacs.

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

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

;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING.  If not, write to the
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.

;;; Synched up with: Divergent from Official Version.

;;; Commentary:

;; This version of Lazy Lock has special modifications for XEmacs by Ben Wing
;; that have never been merged into the official version.

;; Purpose:
;;
;; To make visiting buffers in `font-lock-mode' faster by making fontification
;; be demand-driven and stealthy.
;; Fontification only occurs when, and where, necessary.
;;
;; See caveats and feedback below.  See also the defer-lock and fast-lock
;; packages.  (But don't use lazy-lock.el and fast-lock.el at the same time!)

;; Installation:
;; 
;; Put this file somewhere where Emacs can find it (i.e., in one of the paths
;; in your `load-path'), `byte-compile-file' it, and put in your ~/.emacs:
;;
;; (autoload 'turn-on-lazy-lock "lazy-lock"
;;   "Unconditionally turn on Lazy Lock mode.")
;;
;; (add-hook 'font-lock-mode-hook 'turn-on-lazy-lock)
;;
;; Start up a new Emacs and use font-lock as usual (except that you can use the
;; so-called "gaudier" fontification regexps on big files without frustration).
;;
;; In a buffer (which has `font-lock-mode' enabled) which is at least
;; `lazy-lock-minimum-size' characters long, only the visible portion of the
;; buffer will be fontified.  Motion around the buffer will fontify those
;; visible portions that were not previous fontified.  If the variable
;; `lazy-lock-hide-invisible' is non-nil, redisplay will be delayed until after
;; fontification.  Otherwise, text that has not yet been fontified is displayed
;; in `lazy-lock-invisible-foreground'.
;;
;; If stealth fontification is enabled, fontification will occur in invisible
;; parts of the buffer after `lazy-lock-stealth-time' seconds of idle time.

;; Advanced Use:
;;
;; You can also do fancy things with `advice'.  For example, to fontify when
;; dragging the scroll-bar in Emacs, you could put in your ~/.emacs:
;;
;; (autoload 'lazy-lock-post-command-fontify-windows "lazy-lock")
;;
;; (defadvice scroll-bar-drag-1 (after fontify-window activate compile)
;;   (let ((lazy-lock-walk-windows nil) (lazy-lock-hide-invisible nil))
;;     (lazy-lock-post-command-fontify-windows)))
;;
;; Or to fontify when the Debugger pops up a source code window:
;;
;; (autoload 'lazy-lock-fontify-walk-windows "lazy-lock")
;;
;; (defadvice gud-display-line (after fontify-window activate compile)
;;   (let ((lazy-lock-walk-windows t) (lazy-lock-hide-invisible t))
;;     (lazy-lock-fontify-walk-windows)))
;;
;; Scott Byer <byer@mv.us.adobe.com> suggested this to fontify the visible part
;; of an insertion only:
;;
;; (defvar lazy-lock-insert-commands
;;   '(yank yank-pop clipboard-yank hilit-yank hilit-yank-pop 
;;     mail-yank-original mouse-yank-at-click mouse-yank-secondary
;;     yank-rectangle)
;;   "A list of insertion commands.")
;;
;; (defadvice font-lock-after-change-function (around fontify-insertion
;;                                             activate compile)
;;   (if (or (not (memq this-command lazy-lock-insert-commands))
;; 	  (and (pos-visible-in-window-p beg) (pos-visible-in-window-p end)))
;;       ad-do-it
;;     (let ((this-command 'ignore))
;;       (put-text-property beg end 'fontified nil)
;;       (lazy-lock-fontify-window))))
;;
;; Let me know if you use any other `advice' and I'll put it here.  Thanks.
;;
;; These kinds of things with `advice' aren't done automatically because they
;; cause large packages (advice.el plus bytecomp.el and friends) to be loaded.

;; Caveats:
;;
;; Lazy Lock mode does not work efficiently with Outline mode.  This is because
;; when in Outline mode, although text may be hidden (not visible in the
;; window), the text is visible to Emacs Lisp code (not surprisingly) and Lazy
;; Lock fontifies it mercilessly.  Hopefully this will be fixed one day.
;;
;; Lazy Lock mode does not fontify windows as they appear:
;;
;; 1.  With `query-replace' or `ispell-*', as Lazy Lock only knows about point
;; motion after the command exits.
;;
;; 2.  When displayed by gud.el (the Grand Unified Debugger), as they are
;; displayed via a process sentinel.  See `Advanced Use' above.
;;
;; 3.  In XEmacs 19.12, when the last command was invoked via a mouse event,
;; because of a bug/feature in/of `sit-for'.
;;
;; 4.  In other random situations that I don't know about (yet).
;;
;; If you have `lazy-lock-hide-invisible' you may notice that redisplay occurs
;; before fontification regardlessly.  This is due to other packages sitting on
;; `post-command-hook' and provoking redisplay.  If you use these packages, you
;; can't use `lazy-lock-hide-invisible'.
;;
;; If you have `lazy-lock-hide-invisible' and use scrollbar scrolling using
;; Emacs 19, hidden text will not be fontified as it becomes visible.  It is
;; expected that Emacs 19 will provide the necessary hooks in future, to solve
;; this problem and the problem above.
;;
;; Unless otherwise stated, "Emacs 19.X" means versions up to and including X.
;;
;; In Emacs 19.25, one `window-start'/`window-end' bug means that if you open a
;; file in another frame (such as via `find-tag-other-frame'), the whole buffer
;; is fontified regardless.  Upgrade!
;;
;; In Emacs 19.25, fontification by stealth is turned off because of a fatal
;; bug in `previous-single-property-change'.  Upgrade!
;;
;; In Emacs 19.28, if you see a message in the minibuffer of the form
;;  "Fontifying window... done.  (Restarted in foo.c)"
;; it means the Garbage Collector has marked some (subsequently used) text
;; properties.  Lazy Lock attempts to recover the situation by restarting in
;; that buffer.  Unfortunately, that buffer will be left in a writable and
;; modified state.  Also, other windows may not be fontified when this happens.
;; To reduce the frequency of this bug occuring, increase in your ~/.emacs the
;; value of `gc-cons-threshold' to, say, 1Meg, e.g.:
;;
;; (setq gc-cons-threshold (* 1024 1024))
;;
;; The solution is to upgrade!  (With thanks to Kevin Broadey for help here.)
;;
;; For XEmacs 19.11 and Lucid Emacs 19.10 users, lazy-lock sort-of works.
;; There are bugs in text property and point/window primatives.  Upgrade!

;; Feedback:
;;
;; Feedback is welcome.
;; To submit a bug report (or make comments) please use the mechanism provided:
;;
;; M-x lazy-lock-submit-bug-report RET

;; History:
;;
;; 0.01--1.00:
;; - Changed name from fore-lock to lazy-lock.  Shame though.
;; - Dropped `advice'-wrapping completely.  Ask me if you're interested in it.
;; - Made `lazy-lock-mode' ignore `post-command-hook' and `buffer-file-name'.
;; - Made `lazy-lock-fontify-window' check `lazy-lock-mode' and `this-command'.
;; - Made `lazy-lock-fontify-window' redisplay via `sit-for'.
;; - Added `lazy-lock-minimum-size' to control `lazy-lock-mode'.
;; 1.00--1.01:
;; - Added `lazy-lock-fontify-buffer'.
;; - Made `lazy-lock-fontify-window' ignore `lazy-lock-mode'.
;; - Made `lazy-lock-fontify-window' suspicious of `window-' favourites again.
;; - Added `lazy-lock-delay-commands' (idea from William G. Dubuque).
;; - Added `lazy-lock-ignore-commands' for completeness.
;; - Added `lazy-lock-continuity-time' for normal input delay.
;; 1.01--1.02:
;; - Made `lazy-lock-fontify-window' cope with multiple unfontified regions.
;; - Made `lazy-lock-mode' remove `fontified' properties if turned off.
;; - Made `lazy-lock-fontify-window' fontify by lines.
;; - Added `lazy-lock-cache-position' buffer local to detect visibility change.
;; - Added `lazy-lock-post-command-hook' to do the waiting.
;; - Made `lazy-lock-fontify-window' just do the fontification.
;; - Made `lazy-lock-mode' append `lazy-lock-post-command-hook'.
;; - Added `lazy-lock-walk-windows' to hack multi-window motion.
;; - Made `lazy-lock-post-command-hook' `walk-windows' if variable is non-nil.
;; - Removed `lazy-lock-ignore-commands' since insertion may change window.
;; - Added `lazy-lock-fontify-stealthily' and `lazy-lock-stealth-time'.
;; - Made `lazy-lock-post-command-hook' use them.
;; 1.02--1.03:
;; - Made `lazy-lock-fontify-stealthily' do `forward-line' not `previous-line'.
;; - Made `lazy-lock-fontify-stealthily' `move-to-window-line' first.
;; - Made `lazy-lock-fontify-stealthily' use `text-property-any' for region.
;; - Made `lazy-lock-post-command-hook' loop on `lazy-lock-fontify-stealthily'.
;; 1.03--1.04:
;; - Made `lazy-lock-mode' reset `lazy-lock-cache-position'.
;; - Made `lazy-lock-post-command-hook' `widen' for `if' `text-property-any'.
;; - Made `lazy-lock-fontify-stealthily' return `text-property-any'.
;; - Added `lazy-lock-percent-fontified' for a/be-musement.
;; - Made `lazy-lock-post-command-hook' use it.
;; - Made `lazy-lock-mode' use `make-local-hook' etc. if available.
;; - Made `lazy-lock-mode' use `before-revert-hook' and `after-revert-hook'.
;; - Made `lazy-lock-post-command-hook' protect `deactivate-mark'.
;; - Adds `lazy-lock-post-command-hook' globally to `post-command-hook'.
;; 1.04--1.05:
;; - Made `lazy-lock-mode' test `make-local-hook' not `emacs-minor-version'.
;; 1.05--1.06:
;; - Added `lazy-lock-ignore-commands' for commands that leave no event but do.
;; - Made `lazy-lock-post-command-hook' check `lazy-lock-ignore-commands'.
;; 1.06--1.07:
;; - Removed `before-revert-hook' and `after-revert-hook' use.
;; 1.07--1.08:
;; - Added `lazy-lock-submit-bug-report'.
;; - Made `lazy-lock-post-command-hook' check `executing-macro'.
;; - Made it sort-of/almost work for XEmacs (help from Jonas Jarnestrom).
;; - XEmacs: Fix `text-property-not-all' (fix based on fast-lock.el 3.05 fix).
;; - XEmacs: Set `font-lock-no-comments' and alias `frame-parameters'.
;; - Made `byte-compile-warnings' omit `unresolved' on compilation.
;; - Made `lazy-lock-post-command-hook' protect `buffer-undo-list'.
;; - Moved `deactivate-mark' and `buffer-undo-list' protection to functions.
;; - Added `lazy-lock-invisible-foreground' (idea from Boris Goldowsky).
;; - XEmacs: Fix to use `text-property-not-all' t, not `text-property-any' nil.
;; - Made `lazy-lock-percent-fontified' return `round' to an integer.
;; - XEmacs: Fix `text-property-any' (fix and work around for a bug elsewhere).
;; - XEmacs: Fix `lazy-lock-submit-bug-report' for reporter.el & vm-window.el.
;; - XEmacs: Made `lazy-lock-fontify-window' loop `while' `<' not `/='.
;; - Use `font-lock-after-change-function' to do the fontification.
;; 1.08--1.09:
;; - Made `lazy-lock-post-command-hook' protect with `condition-case'.
;; - Made `lazy-lock-cache-start' to cache `window-start'.
;; - Made `lazy-lock-fontify-window' check and cache `lazy-lock-cache-start'.
;; - Renamed `lazy-lock-cache-position' to `lazy-lock-cache-end'.
;; - XEmacs: Fix for `font-lock-after-change-function'.
;; - Adds `lazy-lock-post-command-hook' globally to `window-setup-hook'.
;; 1.09--1.10:
;; - Made `buffer-file-name' be `let' to prevent supersession (Kevin Broadey).
;; - Made `lazy-lock-submit-bug-report' `require' reporter (Ilya Zakharevich).
;; - Made `lazy-lock-mode' and `turn-on-lazy-lock' succeed `autoload' cookies.
;; - Added `lazy-lock-fontify-walk-windows' for walking window fontification.
;; - Added `lazy-lock-fontify-walk-stealthily' for walking stealth.
;; - Removed `move-to-window-line' from `lazy-lock-fontify-stealthily'.
;; - Made `lazy-lock-percent-fontified' use `truncate' rather than `round'.
;; - Added other `*-argument' to `lazy-lock-ignore-commands' (Kevin Broadey).
;; - Made `lazy-lock-fontify-stealthily' not assume buffer is part `fontified'.
;; - Emacs: Fix for `font-lock-fontify-region'.
;; - Made `lazy-lock-post-command-hook' check for minibuffer (Kevin Broadey).
;; - Added `lazy-lock-stealth-nice' for niceness during stealth fontification.
;; - Added `lazy-lock-stealth-lines' for chunks of stealth fontification.
;; 1.10--1.11: incorporated hack by Ben Wing from William Dubuque's fontifly.el
;; - Made `lazy-lock-fontify-stealthily' see a non `fontified' preceding line.
;; - XEmacs: Fix `text-property-any' and `text-property-not-all' (Ben Wing).
;; - XEmacs: Fix `lazy-lock-continuity-time' (Ben Wing).
;; - Added awful `lazy-lock-running-xemacs-p' (Ben Wing).
;; - Made loading set `emacs-minor-version' if it's not bound.
;; - Added `lazy-lock-hide-invisible' to control redisplay.
;; - Made `lazy-lock-post-command-hook' use it in `sit-for' (Ben Wing).
;; - Made `lazy-lock-fontify-window' move relative to `end-of-line' if non-nil.
;; - Added `lazy-lock-fontify-region' so packages can ensure fontification.
;; - Made `lazy-lock-fontify-walk-stealthily' do stealth widening.
;; - Made `lazy-lock-fontify-stealthily' always do adjacent preceding regions.
;; - Added `lazy-lock-after-fontify-buffer'.
;; - XEmacs: Removed `font-lock-no-comments' incompatibility code.
;; - Removed `lazy-lock-delay-time' and `lazy-lock-delay-commands'.
;; - Removed `lazy-lock-post-command' and split the functionality.
;; - Adds `lazy-lock-post-command-fontify-windows' on first.
;; - Adds `lazy-lock-post-command-fontify-stealthily' on last.
;; - Made `lazy-lock-mode' ensure both first and last on `post-command-hook'.
;; - Made `lazy-lock-mode' ensure `font-lock-mode' is on.
;; - Wrap `lazy-lock-post-command-fontify-stealthily' for errors (David Karr).
;; - Added `calcDigit-key' to `lazy-lock-ignore-commands' (Bob Glickstein).
;; - Wrap `lazy-lock-running-xemacs-p' with `eval-and-compile' (Erik Naggum).
;; - XEmacs: Fix use of `previous-single-property-change' (Jim Thompson).
;; - XEmacs: Fix `next-single-property-change' fix for 19.11 (Jim Thompson).
;; - Added `lazy-lock-post-resize-fontify-windows' to fontify on resizing.
;; - Adds globally to `window-size-change-functions'.
;; - Added `lazy-lock-post-setup-fontify-windows' to fontify after start up.
;; - Adds globally to `window-setup-hook'.
;; - Made `lazy-lock-post-command-fontify-windows' check for `input-pending-p'.
;; - Made `save-selected-window' to restore the `selected-window'.
;; - Use `save-selected-window' rather than `save-window-excursion'.
;; 1.11--1.12:
;; - Made `lazy-lock-post-command-fontify-windows' do `set-buffer' first.
;; - Made `lazy-lock-fontify-stealthily' respect narrowing before point.
;; - Added `lazy-lock-post-setup-ediff-control-frame' for Ediff control frame.
;; - Adds globally to `ediff-after-setup-control-frame-hooks'.
;; - Wrap `save-selected-window' with `save-excursion' for `current-buffer'.
;; 1.12--1.13:
;; - XEmacs: Add `lazy-lock-after-fontify-buffer' to the Font Lock hook.
;; - Made `buffer-file-truename' also wrapped for supersession (Rick Sladkey).
;; - Made `font-lock-beginning-of-syntax-function' wrapped for fontification.
;; - Added `lazy-lock-stealth-verbose' (after harassment from Ben Wing).
;; - XEmacs: Made `font-lock-verbose' wrapped for stealth fontification.
;; 1.13--1.14:
;; - Wrap `lazy-lock-colour-invisible' for `set-face-foreground' (Jari Aalto).

(require 'font-lock)

(eval-when-compile
  ;; Only `require' so `ediff-multiframe-setup-p' is expanded at compile time.
  (condition-case nil (require 'ediff) (file-error))
  ;; Well, shouldn't Lazy Lock be as lazy as possible?
  ;(setq byte-compile-dynamic t byte-compile-dynamic-docstrings t)
  ;; Shut Emacs' byte-compiler up (cf. stop me getting mail from users).
  (setq byte-compile-warnings '(free-vars callargs redefine)))

(defun lazy-lock-submit-bug-report ()
  "Submit via mail a bug report on lazy-lock.el."
  (interactive)
  (require 'reporter)
  (let ((reporter-prompt-for-summary-p t))
    (reporter-submit-bug-report "simon@gnu.ai.mit.edu" "lazy-lock 1.14"
     '(lazy-lock-walk-windows lazy-lock-continuity-time
       lazy-lock-stealth-time lazy-lock-stealth-nice
       lazy-lock-stealth-lines lazy-lock-stealth-verbose
       lazy-lock-hide-invisible lazy-lock-invisible-foreground
       lazy-lock-minimum-size lazy-lock-ignore-commands)
     nil nil
     (concat "Hi Si.,

I want to report a bug.  I've read the `Bugs' section of `Info' on Emacs, so I
know how to make a clear and unambiguous report.  To reproduce the bug:

Start a fresh Emacs via `" invocation-name " -no-init-file -no-site-file'.
In the `*scratch*' buffer, evaluate:"))))

;; Let's define `emacs-major-version', `emacs-minor-version', and
;; `emacs-version>=' if no-one else has.

(if (not (boundp 'emacs-major-version))
    (eval-and-compile
      (defconst emacs-major-version
	(progn (or (string-match "^[0-9]+" emacs-version)
		   (error "emacs-version unparsable"))
	       (string-to-int (match-string 0 emacs-version)))
	"Major version number of this version of Emacs, as an integer.
Warning, this variable did not exist in Emacs versions earlier than:
  FSF Emacs:   19.23
  XEmacs:      19.10")))

(if (not (boundp 'emacs-minor-version))
    (eval-and-compile
      (defconst emacs-minor-version
	(progn (or (string-match "^[0-9]+\\.\\([0-9]+\\)" emacs-version)
		   (error "emacs-version unparsable"))
	       (string-to-int (match-string 1 emacs-version)))
	"Minor version number of this version of Emacs, as an integer.
Warning, this variable did not exist in Emacs versions earlier than:
  FSF Emacs:   19.23
  XEmacs:      19.10")))

(if (not (fboundp 'emacs-version>=))
    (eval-and-compile
      (defun emacs-version>= (major &optional minor)
	"Return true if the Emacs version is >= to the given MAJOR and MINOR numbers.

The MAJOR version number argument is required, but the MINOR version number
argument is optional.  If the minor version number is not specified (or is the
symbol `nil') then only the major version numbers are considered in the test."
	(if (null minor)
	    (>= emacs-major-version major)
	  (or (> emacs-major-version major)
	      (and (=  emacs-major-version major)
		   (>= emacs-minor-version minor))
	      )
	  ))))

;; Yuck, but we make so much use of this variable it's probably worth it.
(eval-and-compile
  (defconst lazy-lock-running-xemacs-p
    (not (null (save-match-data (string-match "XEmacs\\|Lucid" emacs-version))))))

(defvar lazy-lock-cache-start nil)	; for window fontifiction
(defvar lazy-lock-cache-end nil)	; for window fontifiction
(defvar lazy-lock-cache-continue nil)	; for stealth fontifiction

;;;###autoload
(defvar lazy-lock-mode nil)		; for modeline

;; User Variables:

(defvar lazy-lock-minimum-size (* 25 1024)
  "*If non-nil, the minimum size for buffers.
Only buffers more than this can have demand-driven fontification.
If nil, means size is irrelevant.")

(defvar lazy-lock-walk-windows t
  "*If non-nil, fontify windows other than the selected window.
If `all-frames', fontify windows even on other frames.
A non-nil value slows down redisplay.")

;; XEmacs 19.11 and below exercise a bug in the Xt event loop.
(defvar lazy-lock-continuity-time
  (if (or (not lazy-lock-running-xemacs-p) (emacs-version>= 19 12))
      0
    (if (featurep 'lisp-float-type) 0.001 1))
  "*Time in seconds to delay before normal window fontification.
Window fontification occurs if there is no input within this time.")

;; `previous-single-property-change' at `point-min' up to Emacs 19.25 is fatal.
;; `text-property-any', `text-property-not-all' and
;; `next-single-property-change' up to XEmacs 19.11 are too broke.
(defvar lazy-lock-stealth-time
  (if (emacs-version>= 19 (if lazy-lock-running-xemacs-p 12 26)) 30)
  "*Time in seconds to delay before beginning stealth fontification.
Stealth fontification occurs if there is no input within this time.
If nil, means no fontification by stealth.")

(defvar lazy-lock-stealth-lines
  (cond ((boundp 'font-lock-maximum-decoration)
	 (if font-lock-maximum-decoration 75 150))
	((boundp 'font-lock-use-maximal-decoration)
	 (if font-lock-use-maximal-decoration 50 100))
	(t
	 50))
  "*If non-nil, the maximum size of a chunk of stealth fontification.
Each iteration of stealth fontification can fontify this number of lines.
To speed up input response during stealth fontification, at the cost of stealth
taking longer to fontify, you could reduce the value of this variable.
If nil, means use `window-height' for the maximum chunk size.")

(defvar lazy-lock-stealth-nice (if (featurep 'lisp-float-type) 0.125 1)
  "*Time in seconds to pause during chunks of stealth fontification.
To reduce machine load during stealth fontification, at the cost of stealth
taking longer to fontify, you could increase the value of this variable.")

(defvar lazy-lock-stealth-verbose font-lock-verbose
  "*If non-nil, means stealth fontification should show status messages.")

(defvar lazy-lock-ignore-commands
  (append
   ;; Standard commands...
   '(universal-argument digit-argument negative-argument
     isearch-other-control-char isearch-other-meta-char)
   ;; And some resulting from non-standard packages...
   (if (fboundp 'calc) '(calcDigit-key)))
  "A list of commands after which fontification should not occur.
To speed up typing response, at the cost of Lazy Lock not fontifying when
insertion causes scrolling, you could add `self-insert-command' to this list.")

(defvar lazy-lock-hide-invisible lazy-lock-running-xemacs-p
  "*If non-nil, hide invisible text while it is fontified.
If non-nil, redisplay is delayed until after fontification occurs.  If nil,
text is shown (in `lazy-lock-invisible-foreground') while it is fontified.
A non-nil value slows down redisplay and can slow down cursor motion.")

(defvar lazy-lock-invisible-foreground "gray50" 
  "The foreground colour to use to display invisible text.
If nil, the default foreground is used.  If t, the default background is used.
If a string, it should be a colour to use (either its name or its RGB value).
Invisible text is momentarily seen (if `lazy-lock-hide-invisible' is nil) when
scrolling into unfontified regions.")

;; User Functions:

;;;###autoload
(defun lazy-lock-mode (&optional arg)
  "Toggle Lazy Lock mode.
With arg, turn Lazy Lock mode on if and only if arg is positive and the buffer
is at least `lazy-lock-minimum-size' characters long.

When Lazy Lock mode is enabled, fontification is demand-driven and stealthy:

 - Fontification occurs in visible parts of buffers when necessary.
   Occurs if there is no input after pausing for `lazy-lock-continuity-time'.

 - Fontification occurs in invisible parts when Emacs has been idle.
   Occurs if there is no input after pausing for `lazy-lock-stealth-time'.

If `lazy-lock-hide-invisible' is non-nil, text is not displayed until it is
fontified, otherwise it is displayed in `lazy-lock-invisible-foreground'.

See also variables `lazy-lock-walk-windows' and `lazy-lock-ignore-commands' for
window (scroll) fontification, and `lazy-lock-stealth-lines',
`lazy-lock-stealth-nice' and `lazy-lock-stealth-verbose' for stealth
fontification.

Use \\[lazy-lock-submit-bug-report] to send bug reports or feedback."
  (interactive "P")
  (set (make-local-variable 'lazy-lock-mode)
       (and (<= (or lazy-lock-minimum-size 0) (buffer-size))
	    (if arg (> (prefix-numeric-value arg) 0) (not lazy-lock-mode))))
  (if (and lazy-lock-mode (not font-lock-mode))
      ;; Turned on `lazy-lock-mode' rather than using `font-lock-mode-hook'.
      (progn
	(add-hook 'font-lock-mode-hook 'turn-on-lazy-lock)
	(font-lock-mode 1))
    (lazy-lock-fixup-hooks)
    ;; Let's get down to business.
    (if (not lazy-lock-mode)
	(let ((modified (buffer-modified-p)) (inhibit-read-only t)
	      (buffer-undo-list t)
	      deactivate-mark buffer-file-name buffer-file-truename)
	  (remove-text-properties (point-min) (point-max) '(fontified nil))
	  (or modified (set-buffer-modified-p nil)))
      (if (and (not lazy-lock-hide-invisible) lazy-lock-invisible-foreground)
	  (lazy-lock-colour-invisible))
      (set (make-local-variable 'lazy-lock-cache-start) 0)
      (set (make-local-variable 'lazy-lock-cache-end) 0)
      (set (make-local-variable 'font-lock-fontified) t))))

;;;###autoload
(defun turn-on-lazy-lock ()
  "Unconditionally turn on Lazy Lock mode."
  (lazy-lock-mode 1))

(if (not (emacs-version>= 19 (if lazy-lock-running-xemacs-p 12 29)))
    ;; We don't need this in Emacs 19.29 or XEmacs 19.12.
    (defun lazy-lock-fontify-buffer ()
      "Fontify the current buffer where necessary."
      (interactive)
      (lazy-lock-fontify-region (point-min) (point-max))))

;; API Functions:

(defun lazy-lock-fixup-hooks ()
  ;; Make sure our hooks are correct.
  (remove-hook 'pre-idle-hook 'lazy-lock-pre-idle-fontify-windows)
  (remove-hook 'post-command-hook 'lazy-lock-post-command-fontify-stealthily)
  ;; Make sure our hooks are at the end.  Font-lock in XEmacs installs
  ;; its own pre-idle-hook to implement deferral (#### something that
  ;; should really be merged with this file; or more likely, lazy-lock
  ;; in its entirety should be merged into font-lock).
  (add-hook 'pre-idle-hook 'lazy-lock-pre-idle-fontify-windows t)
  (add-hook 'post-command-hook 'lazy-lock-post-command-fontify-stealthily t)
  ;; Fascistically remove font-lock's after-change-function and install
  ;; our own.  We know better than font-lock what to do.  Otherwise,
  ;; revert-buffer, insert-file, etc. cause full refontification of the
  ;; entire changed area.
  (if lazy-lock-mode
      (progn
	(remove-hook 'after-change-functions 'font-lock-after-change-function
		     t)
	(make-local-hook 'after-change-functions)
	(add-hook 'after-change-functions 'lazy-lock-after-change-function
		  nil t))
    (remove-hook 'after-change-functions 'lazy-lock-after-change-function t)
    (if font-lock-mode
	(add-hook 'after-change-functions 'font-lock-after-change-function
		  nil t)))
)

;; use put-nonduplicable-text-property to avoid unfriendly behavior
;; when doing undo, etc.  We really don't want syntax-highlighting text
;; properties copied into strings or tracked by undo.
;;
;; #### If start-open and end-open really behaved like they are supposed to,
;; we wouldn't really need this.  I kind of fixed them up, but there's still
;; a bug -- inserting text into the middle of a region of
;; (start-open t end-open t) text should cause it not to inherit, but it
;; does.

(if lazy-lock-running-xemacs-p
    (defalias 'lazy-lock-put-text-property 'put-nonduplicable-text-property)
  (defalias 'lazy-lock-put-text-property 'put-text-property))

(defun lazy-lock-fontify-region (start end &optional buffer)
  "Fontify between START and END in BUFFER where necessary."
  (save-excursion
    (and buffer (set-buffer buffer))
    (save-restriction
      (narrow-to-region start end)
      (let ((lazy-lock-stealth-lines (count-lines start end)))
	(while (text-property-not-all start end 'fontified t)
	  (lazy-lock-fontify-stealthily))))))

(defun lazy-lock-after-fontify-buffer ()
  ;; Mark the buffer as `fontified'.
  (let ((modified (buffer-modified-p)) (inhibit-read-only t)
	(buffer-undo-list t)
	deactivate-mark buffer-file-name buffer-file-truename)
    (lazy-lock-put-text-property (point-min) (point-max) 'fontified t)
    (or modified (set-buffer-modified-p nil))))

;; Just a cleaner-looking way of coping with Emacs' and XEmacs' `sit-for'.
(defmacro lazy-lock-sit-for (seconds &optional nodisp)
  (if lazy-lock-running-xemacs-p
      (` (sit-for (, seconds) (, nodisp)))
    (` (sit-for (, seconds) 0 (, nodisp)))))

;; Using `save-window-excursion' provokes `window-size-change-functions'.
;; I prefer `save-walking-excursion', of course, because I have a warped mind.
(if (fboundp 'save-selected-window)
    nil
  (eval-and-compile
    (defmacro save-selected-window (&rest body)
      "Execute the BODY forms, restoring the selected window.
Does not restore the value of point in the selected window, or anything else."
      (` (let ((original-window (selected-window)))
	   (unwind-protect
	       (progn (,@ body))
	     (select-window original-window))))))
  (put 'save-selected-window 'lisp-indent-function 0))

;; Functions for hooks:

;; lazy-lock optimization:
;;
;; pre-idle-hook is called an awful lot -- pretty much every time the
;; mouse moves or a timeout expires, for example.  On Linux (sometimes),
;; IRIX 5.x, and Solaris 2.something, it happens every 1/4 of a second
;; due to the 1/4-second timers installed to compensate for various
;; operating system deficiencies in the handling of SIGIO and SIGCHLD.
;; (Those timers cause a cycle of the event loop.  They don't necessarily
;; have to, but rewriting to avoid this is fairly tricky and requires
;; having significant amounts of code called from signal handlers, which
;; (despite that fact that FSF Emacs reads its X input during a signal
;; handler ?!), is almost always a bad idea -- it's extremely easy to
;; introduce race conditions, which are very hard to track down.
;;
;; So to improve things, I added `frame-modified-tick'.  This is an
;; internal counter that gets ticked any time that any internal
;; redisplay variable gets ticked.  If `frame-modified-tick' is
;; the same as the last time we checked, it means that redisplay will
;; do absolutely nothing when encountering this frame, and thus we
;; can skip out immediately.  This happens when the 1/4-second timer
;; fires while we're idle, or if we just move the mouse. (Moving
;; around in a buffer changes `frame-modified-tick' because the
;; internal redisplay variable "point_changed" gets ticked.  We could
;; easily improve things further by adding more tick counters, mirroring
;; more closely the internal redisplay counters -- e.g. if we had
;; another counter that didn't get ticked when point moved, we could
;; tell if anything was going to happen by seeing if point is within
;; window-start and window-end, since we know that redisplay will
;; only do a window-scroll if it's not. (If window-start or window-end
;; or window-buffer or anything else changed, windows_changed or
;; some other variable will get ticked.))
;;
;; Also, it's wise to try and avoid things that cons.  Avoiding
;; `save-window-excursion', as we do, is definitely a major win
;; because that's a heavy-duty function as regards consing and such.

(defvar lazy-lock-pre-idle-frame-modified-tick nil)
(defvar lazy-lock-pre-idle-selected-frame nil)

(defun lazy-lock-pre-idle-fontify-windows ()
  ;; Do groovy things always unless we're in one of the ignored commands.
  ;; The old version did the following five checks:
  ;;
  ;; (a) not in a macro,
  ;; (b) no input pending,
  ;; (c) got a real command (i.e. not an ignored command)
  ;; (d) not in the minibuffer
  ;; (e) no input after waiting for `lazy-lock-continuity-time'.
  ;;
  ;; (a), (b), and (e) are automatically taken care of by `pre-idle-hook'.
  ;;
  ;; Also, we do not have to `set-buffer' and in fact it would be
  ;; incorrect to do so, since we may be being called from
  ;; `accept-process-output' or whatever.
  ;;
  (if (or (memq this-command lazy-lock-ignore-commands)
	  (window-minibuffer-p (selected-window)))
      (setq lazy-lock-cache-continue nil)
    (setq lazy-lock-cache-continue t)
    ;; #### we don't yet handle frame-modified-tick on multiple frames.
    ;; handling this shouldn't be hard but I just haven't done it yet.
    (if (or (eq 'all-frames lazy-lock-walk-windows)
	    (not (eq lazy-lock-pre-idle-selected-frame (selected-frame)))
	    (not (eq lazy-lock-pre-idle-frame-modified-tick
		     (frame-modified-tick (selected-frame)))))
	(progn
	  ;; Do the visible parts of the buffer(s), i.e., the window(s).
	  (if (or (not lazy-lock-walk-windows)
		  (and (eq lazy-lock-walk-windows t) (one-window-p t)))
	      (if lazy-lock-mode (condition-case nil
				     (lazy-lock-fontify-window)))
	    (lazy-lock-fontify-walk-windows))
	  (setq lazy-lock-pre-idle-selected-frame (selected-frame))
	  (setq lazy-lock-pre-idle-frame-modified-tick
		(frame-modified-tick (selected-frame)))))))

(defun lazy-lock-after-change-function (beg end old-len)
  (and lazy-lock-mode
       (if (= beg end)
	   (font-lock-after-change-function beg end old-len)
	 (lazy-lock-put-text-property beg end 'fontified nil))))

;; DO NOT put this as a pre-idle hook!  The sit-for messes up
;; mouse dragging.
(defun lazy-lock-post-command-fontify-stealthily ()
  ;; Do groovy things if (a-d) above, (e) not moving the mouse, and (f) no
  ;; input after after waiting for `lazy-lock-stealth-time'.
  (if (and lazy-lock-cache-continue lazy-lock-stealth-time)
      (condition-case data
	  (if (lazy-lock-sit-for lazy-lock-stealth-time)
	      ;; Do the invisible parts of buffers.
	      (lazy-lock-fontify-walk-stealthily)) 
	(error (message "Fontifying stealthily... %s" data)))))

;; In XEmacs 19.14 with pre-idle-hook we do not have to call this.
(defun lazy-lock-post-resize-fontify-windows (frame)
  ;; Fontify all windows in FRAME.
  (let ((lazy-lock-walk-windows t) executing-kbd-macro this-command)
    (save-excursion
      (save-selected-window
	(select-frame frame)
	(lazy-lock-pre-idle-fontify-windows)))))

(defun lazy-lock-post-setup-emacs-fontify-windows ()
  ;; Fontify all windows in all frames.
  (let ((lazy-lock-walk-windows 'all-frames) executing-kbd-macro this-command)
    (lazy-lock-pre-idle-fontify-windows)))

(defun lazy-lock-post-setup-ediff-control-frame ()
  ;; Fontify all windows in all frames when using the Ediff control frame.
  (make-local-variable 'lazy-lock-walk-windows)
  (setq lazy-lock-walk-windows (if (ediff-multiframe-setup-p) 'all-frames t))
  (lazy-lock-fixup-hooks))

;; Functions for fontification:

(defun lazy-lock-fontify-window ()
  ;; Fontify the visible part of the buffer where necessary.
  (let ((ws (if lazy-lock-hide-invisible
		(save-excursion
		  (end-of-line) (forward-line (- (window-height))) (point))
	      (min (max (window-start) (point-min)) (point-max))))
	(we (if lazy-lock-hide-invisible
		(save-excursion
		  (end-of-line) (forward-line (window-height)) (point))
	      (min (max (1- (window-end nil t)) (point-min)) (point-max)))))
    (if (or (/= ws lazy-lock-cache-start) (/= we lazy-lock-cache-end))
	;; Find where we haven't `fontified' before.
	(let* ((start (or (text-property-not-all ws we 'fontified t) ws))
	       (end (or (text-property-any start we 'fontified t) we))
	       (modified (buffer-modified-p)) (inhibit-read-only t)
	       ;; We do the following to prevent: undo list addition; region
	       ;; highlight disappearance; supersession/locking checks.
	       (buffer-undo-list t)
	       deactivate-mark buffer-file-name buffer-file-truename
	       ;; Ensure Emacs 19.30 syntactic fontification is always correct.
	       font-lock-beginning-of-syntax-function
	       ;; Prevent XEmacs 19.13 during fontification from messages.
	       font-lock-verbose)
	  (while (< start end)
	    ;; Fontify and flag the region as `fontified'.
	    ;; XEmacs: need to bind `font-lock-always-fontify-immediately'
	    ;; or we'll mess up in the presence of deferred font-locking.
	    (let ((font-lock-always-fontify-immediately t))
	      (font-lock-after-change-function start end 0))
	    (lazy-lock-put-text-property start end 'fontified t)
	    ;; Find the next region.
	    (setq start (or (text-property-not-all ws we 'fontified t) ws)
		  end (or (text-property-any start we 'fontified t) we)))
	  (setq lazy-lock-cache-start ws lazy-lock-cache-end we)
	  (or modified (set-buffer-modified-p nil))))))

(defun lazy-lock-fontify-walk-windows ()
  ;; Fontify windows in all required by walking through them.
  (save-excursion
    (save-selected-window
      (condition-case nil
	  (walk-windows
	   (function (lambda (window)
		       (select-window window)
		       (if lazy-lock-mode (lazy-lock-fontify-window))))
	   'no-minibuf (eq lazy-lock-walk-windows 'all-frames))
	(wrong-type-argument
	 ;; Looks like the Emacs 19.28 Garbage Collection bug has hit town.
	 ;; Completely remove all text properties and restart.
	 (set-text-properties (point-min) (point-max) nil)
	 (turn-on-lazy-lock)
	 (lazy-lock-fontify-window)
	 (message "Fontifying window... done.  (Restarted in %s)"
		  (buffer-name)))))))

(defun lazy-lock-fontify-stealthily ()
  ;; Fontify an invisible part of the buffer where necessary.
  (save-excursion
    ;; Move to the end in case the character to the left is not `fontified'.
    (end-of-line)
    ;; Find where the next and previous regions not `fontified' begin and end.
    (let ((next (text-property-not-all (point) (point-max) 'fontified t))
	  (prev (let ((p (previous-single-property-change (point) 'fontified)))
		  (and p (> p (point-min)) p)))
	  (modified (buffer-modified-p)) (inhibit-read-only t) start end
	  ;; We do the following to prevent: undo list addition; region
	  ;; highlight disappearance; supersession/locking checks.
	  (buffer-undo-list t)
	  deactivate-mark buffer-file-name buffer-file-truename
	  ;; Ensure Emacs 19.30 syntactic fontification is always correct.
	  font-lock-beginning-of-syntax-function
	  ;; Prevent XEmacs 19.13 during fontification from spewing messages.
	  font-lock-verbose)
      (cond ((and (null next) (null prev))
	     ;; Nothing has been `fontified' yet.
	     (beginning-of-line 1) (setq start (point))
	     (forward-line (or lazy-lock-stealth-lines (window-height)))
	     (setq end (point)))
	    ((or (null prev)
		 (and next (> (- (point) prev) (- next (point)))))
	     ;; The next region is the nearest not `fontified'.
	     (goto-char next) (beginning-of-line 1) (setq start (point))
	     (forward-line (or lazy-lock-stealth-lines (window-height)))
	     ;; Maybe the region is already partially `fontified'.
	     (setq end (or (text-property-any next (point) 'fontified t)
			   (point))))
	    (t
	     ;; The previous region is the nearest not `fontified'.
	     (goto-char prev) (forward-line 1) (setq end (point))
	     (forward-line (- (or lazy-lock-stealth-lines (window-height))))
	     ;; Maybe the region is already partially `fontified'.
	     (setq start
	      (or (previous-single-property-change prev 'fontified nil (point))
		  (point)))))
      ;; Fontify and flag the region as `fontified'.
      ;; XEmacs: need to bind `font-lock-always-fontify-immediately'
      ;; or we'll mess up in the presence of deferred font-locking.
      (let ((font-lock-always-fontify-immediately t))
	(font-lock-after-change-function start end 0))
      (lazy-lock-put-text-property start end 'fontified t)
      (or modified (set-buffer-modified-p nil)))))

(defun lazy-lock-fontify-walk-stealthily ()
  ;; Fontify regions in all required buffers while there is no input.
  (let ((buffers (buffer-list)) (continue t) fontified message-log-max)
    (save-excursion
      (while (and buffers continue)
	(set-buffer (car buffers))
	(if (and lazy-lock-mode (lazy-lock-unfontified-p))
	    ;; Fontify regions in this buffer while there is no input.
	    (let ((bufname (buffer-name)))
	      (if (and lazy-lock-stealth-verbose (not fontified))
		  (message "Fontifying stealthily..."))
	      ;; We `save-restriction' and `widen' around everything as
	      ;; `lazy-lock-fontify-stealthily' doesn't and we `sit-for'.
	      (save-restriction (widen) (lazy-lock-fontify-stealthily))
	      (while (and (lazy-lock-unfontified-p)
			  (setq continue (lazy-lock-sit-for
					  lazy-lock-stealth-nice)))
		(if lazy-lock-stealth-verbose
		    (message "Fontifying stealthily... %2d%% of %s"
			     (lazy-lock-percent-fontified) bufname))
		(save-restriction (widen) (lazy-lock-fontify-stealthily)))
	      ;; Note that fontification occurred.
	      (setq fontified t)))
	(setq buffers (cdr buffers))))
    (if (and lazy-lock-stealth-verbose fontified)
	(message "Fontifying stealthily... %s." (if continue "done" "quit")))))

(defun lazy-lock-unfontified-p ()
  ;; Return non-nil if there is anywhere still to be `fontified'.
  (save-restriction
    (widen)
    (text-property-not-all (point-min) (point-max) 'fontified t)))

(defun lazy-lock-percent-fontified ()
  ;; Return the percentage (of characters) of the buffer that are `fontified'.
  (save-restriction
    (widen)
    (let ((size 0) (start (point-min)) (max (point-max)) end)
      (while (setq start (text-property-any start max 'fontified t))
	(setq end (or (text-property-not-all start max 'fontified t) max)
	      size (+ size (- end start))
	      start end))
      ;; Saying "99% done" is probably better than "100% done" when it isn't.
      (truncate (/ (* size 100.0) (buffer-size))))))

(defun lazy-lock-colour-invisible ()
  ;; Fontify the current buffer in `lazy-lock-invisible-face'.
  (save-restriction
    (widen)
    (let ((face 'lazy-lock-invisible-face)
	  (fore (if (stringp lazy-lock-invisible-foreground)
		    lazy-lock-invisible-foreground
		  (cdr (assq 'background-color (frame-parameters)))))
	  (modified (buffer-modified-p)) (inhibit-read-only t)
	  (buffer-undo-list t)
	  deactivate-mark buffer-file-name buffer-file-truename)
      (make-face face)
      (if (not (equal (face-foreground face) fore))
	  (condition-case nil
	      (set-face-foreground face fore)
	    (error (message "Unable to use foreground \"%s\"" fore))))
      (lazy-lock-put-text-property (point-min) (point-max) 'face face)
      (lazy-lock-put-text-property (point-min) (point-max) 'fontified nil)
      (or modified (set-buffer-modified-p nil)))))

;; Functions for Emacs:

;; This fix is for a number of bugs in the function in Emacs 19.28.
(if (and (not lazy-lock-running-xemacs-p)
	 (not (emacs-version>= 19 29)))			       
    (defun font-lock-fontify-region (start end &optional loudly)
      "Put proper face on each string and comment between START and END."
      (save-excursion
	(save-restriction
	  (widen)
	  (goto-char start)
	  (beginning-of-line)
	  (if loudly (message "Fontifying %s... (syntactically...)" (buffer-name)))
	  (let ((inhibit-read-only t) (buffer-undo-list t)
		buffer-file-name buffer-file-truename
		(modified (buffer-modified-p))
		(old-syntax (syntax-table))
		(synstart (if comment-start-skip
			      (concat "\\s\"\\|" comment-start-skip)
			    "\\s\""))
		(comstart (if comment-start-skip
			      (concat "\\s<\\|" comment-start-skip)
			    "\\s<"))
		(startline (point))
		state prev prevstate)
	    (unwind-protect
		(progn
		  (if font-lock-syntax-table
		      (set-syntax-table font-lock-syntax-table))
		  ;; Find the state at the line-beginning before START.
		  (if (eq startline font-lock-cache-position)
		      (setq state font-lock-cache-state)
		    ;; Find outermost containing sexp.
		    (beginning-of-defun)
		    ;; Find the state at STARTLINE.
		    (while (< (point) startline)
		      (setq state (parse-partial-sexp (point) startline 0)))
		    (setq font-lock-cache-state state
			  font-lock-cache-position (point)))
		  ;; Now find the state precisely at START.
		  (setq state (parse-partial-sexp (point) start nil nil state))
		  ;; If the region starts inside a string, show the extent of it.
		  (if (nth 3 state)
		      (let ((beg (point)))
			(while (and (re-search-forward "\\s\"" end 'move)
				    (nth 3 (parse-partial-sexp beg (point) nil nil
							       state))))
			(lazy-lock-put-text-property
			 beg (point) 'face font-lock-string-face)
			(setq state (parse-partial-sexp beg (point)
							nil nil state))))
		  ;; Likewise for a comment.
		  (if (or (nth 4 state) (nth 7 state))
		      (let ((beg (point)))
			(save-restriction
			  (narrow-to-region (point-min) end)
			  (condition-case nil
			      (progn
				(re-search-backward comstart (point-min) 'move)
				(forward-comment 1)
				;; forward-comment skips all whitespace,
				;; so go back to the real end of the comment.
				(skip-chars-backward " \t"))
			    (error (goto-char end))))
			(lazy-lock-put-text-property beg (point) 'face
						     font-lock-comment-face)
			(setq state (parse-partial-sexp beg (point)
							nil nil state))))
		  ;; Find each interesting place between here and END.
		  (while (and (< (point) end)
			      (setq prev (point) prevstate state)
			      (re-search-forward synstart end t)
			      (progn
				;; Clear out the fonts of what we skip over.
				(remove-text-properties prev (point) '(face nil))
				;; Verify the state at that place
				;; so we don't get fooled by \" or \;.
				(setq state (parse-partial-sexp prev (point)
								nil nil state))))
		    (let ((here (point)))
		      (if (or (nth 4 state) (nth 7 state))
			  ;; We found a real comment start.
			  (let ((beg (match-beginning 0)))
			    (goto-char beg)
			    (save-restriction
			      (narrow-to-region (point-min) end)
			      (condition-case nil
				  (progn
				    (forward-comment 1)
				    ;; forward-comment skips all whitespace,
				    ;; so go back to the real end of the comment.
				    (skip-chars-backward " \t"))
				(error (goto-char end))))
			    (lazy-lock-put-text-property
			     beg (point) 'face font-lock-comment-face)
			    (setq state (parse-partial-sexp here (point)
							    nil nil state)))
			(if (nth 3 state)
			    (let ((beg (match-beginning 0)))
			      (while (and (re-search-forward "\\s\"" end 'move)
					  (nth 3 (parse-partial-sexp
						  here (point) nil nil state))))
			      (lazy-lock-put-text-property
			       beg (point) 'face font-lock-string-face)
			      (setq state (parse-partial-sexp here (point)
							      nil nil state))))))
		    ;; Make sure PREV is non-nil after the loop
		    ;; only if it was set on the very last iteration.
		    (setq prev nil)))
	      (set-syntax-table old-syntax)
	      (and prev
		   (remove-text-properties prev end '(face nil)))
	      (and (buffer-modified-p)
		   (not modified)
		   (set-buffer-modified-p nil))))))))

;; Functions for XEmacs:

;; These fix bugs in `text-property-any' and `text-property-not-all'.  They may
;; not work perfectly in 19.11 and below because `next-single-property-change'
;; is also broke and not easily fixable in Lisp.
(if (and lazy-lock-running-xemacs-p
	 (not (emacs-version>= 19 12)))
    (progn
      ;; Loop through property changes until found.  This fix includes a work
      ;; around which prevents a bug in `window-start' causing a barf here.
      (defun text-property-any (start end prop value &optional buffer)
	"Check text from START to END to see if PROP is ever `eq' to VALUE.
If so, return the position of the first character whose PROP is `eq'
to VALUE.  Otherwise return nil."
	(let ((start (min start end)) (end (max start end)))
	  (while (and start (not (eq (get-text-property start prop buffer) value)))
	    (setq start (next-single-property-change start prop buffer end)))
	  start))
      ;; No need to loop here; if it's not at START it's at the next change.
      ;; However, `next-single-property-change' sometimes returns LIMIT, or
      ;; `point-max', if no change is found and sometimes returns nil.
      (defun text-property-not-all (start end prop value &optional buffer)
	"Check text from START to END to see if PROP is ever not `eq' to VALUE.
If so, return the position of the first character whose PROP is not
`eq' to VALUE.  Otherwise, return nil."
	(if (not (eq value (get-text-property start prop buffer)))
	    start
	  (let ((next (next-single-property-change start prop buffer end))
		(end (or end (save-excursion (and buffer (set-buffer buffer))
					     (point-max)))))
	    (and next (< next end) next))))))

;; XEmacs 19.11 function `font-lock-any-extents-p' looks for `text-prop' rather
;; than `face'.  Since `font-lock-unfontify-region' only removes `face', and we
;; have non-font-lock properties hanging about, `text-prop' never gets removed.
;; Unfortunately `font-lock-any-extents-p' is inlined so we can't redefine it.
(if (and lazy-lock-running-xemacs-p
	 (not (emacs-version>= 19 12)))
    (add-hook 'font-lock-mode-hook
     (function (lambda ()
	(remove-hook 'after-change-functions 'font-lock-after-change-function)
	(add-hook 'after-change-functions
	 (function (lambda (beg end old-len)
	    (let ((a-c-beg beg) (a-c-end end))
	      (save-excursion
		;; First set `text-prop' to nil for `font-lock-any-extents-p'.
		(goto-char end) (forward-line 1) (setq end (point))
		(goto-char beg) (beginning-of-line) (setq beg (point))
		(lazy-lock-put-text-property beg end 'text-prop nil)
		;; Then do the real `font-lock-after-change-function'.
		(font-lock-after-change-function a-c-beg a-c-end old-len)
		;; Now set `fontified' to t to stop `lazy-lock-fontify-window'.
		(lazy-lock-put-text-property beg end 'fontified t))))))))))

(if (and lazy-lock-running-xemacs-p (emacs-version>= 19 12))
    ;; XEmacs 19.12 font-lock.el's `font-lock-fontify-buffer' runs a hook.
    (add-hook 'font-lock-after-fontify-buffer-hook
	      'lazy-lock-after-fontify-buffer))

;; Cope with the differences between Emacs and [LX]Emacs.
(or (fboundp 'frame-parameters)
    (defalias 'frame-parameters 'screen-parameters))

;; Install ourselves:

;; We don't install ourselves on `font-lock-mode-hook' as other packages can be
;; used with font-lock.el, and lazy-lock.el should be dumpable without forcing
;; people to get lazy or making it difficult for people to use alternatives.
;; make sure we add after font-lock's own pre-idle-hook.
(add-hook 'window-setup-hook 'lazy-lock-post-setup-emacs-fontify-windows)
;Not needed in XEmacs 19.14:
;(add-hook 'window-size-change-functions 'lazy-lock-post-resize-fontify-windows)

;; Package-specific.
(add-hook 'ediff-after-setup-control-frame-hooks
	  'lazy-lock-post-setup-ediff-control-frame)

;; Might as well uninstall too.  Package-local symbols would be nice...
(and (fboundp 'unintern) (unintern 'lazy-lock-running-xemacs-p))
(and (fboundp 'unintern) (unintern 'lazy-lock-sit-for))

;; Maybe save on the modeline?
;;(setcdr (assq 'font-lock-mode minor-mode-alist) '(" Lazy"))

;(or (assq 'lazy-lock-mode minor-mode-alist)
;    (setq minor-mode-alist (cons '(lazy-lock-mode " Lazy") minor-mode-alist)))

;; XEmacs change: do it the right way.  This works with modeline mousing.
;;;###autoload
(add-minor-mode 'lazy-lock-mode " Lazy")

;; Provide ourselves:

(provide 'lazy-lock)

;;; lazy-lock.el ends here