.emacs.d/sym-lock.el
author Adam Gomaa <adam@gomaa.us>
Sun Dec 18 13:13:02 2011 -0500
changeset 521 67f37d330ad0
permissions -rw-r--r--
Remove project & _list_projects, I don't use them anymore.
code@28
     1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
code@28
     2
;; sym-lock.el - Extension of Font-Lock mode for symbol fontification.
code@28
     3
code@28
     4
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
code@28
     5
;;        Copyright © 1997-2004 Albert Cohen, all rights reserved.
code@28
     6
;;         Copying is covered by the GNU General Public License.
code@28
     7
;;
code@28
     8
;;    This program is free software; you can redistribute it and/or modify
code@28
     9
;;    it under the terms of the GNU General Public License as published by
code@28
    10
;;    the Free Software Foundation; either version 2 of the License, or
code@28
    11
;;    (at your option) any later version.
code@28
    12
;;
code@28
    13
;;    This program is distributed in the hope that it will be useful,
code@28
    14
;;    but WITHOUT ANY WARRANTY; without even the implied warranty of
code@28
    15
;;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
code@28
    16
;;    GNU General Public License for more details.
code@28
    17
code@28
    18
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
code@28
    19
;;                                 History
code@28
    20
;; 
code@28
    21
;; first prototype by wg <wg@cs.tu-berlin.de> 5-96
code@28
    22
;; tweaked by Steve Dunham <dunham@gdl.msu.edu> 5-96
code@28
    23
;; rewritten and enhanced by Albert Cohen <Albert.Cohen@inria.fr> 3-97
code@28
    24
;;   new symbol-face format and ergonomy improvement 2-98
code@28
    25
;;   major step towards portability and customization 5-98
code@28
    26
;;   removed bug with multiple appends in hook by 3-99
code@28
    27
;;   removed use-fonts check (due to incomatibilities) 9-00
code@28
    28
;;   new after-change/pre-idle policy 6-01
code@28
    29
;;   disable M$ Windows (symbol font problem) and fixed movement bug
code@28
    30
;;     (incompatibile atomic-extents and paren) 8-01
code@28
    31
;;   check for the availability of a symbol font 1-02
code@28
    32
;;   patch size inference and use the upper bound (of <= sizes) 1-02
code@28
    33
;;   support for custom replacement faces (e.g., for the lambda symbol) 10-04
code@28
    34
code@28
    35
;; look at the symbol font? check out: xfd -fn '-adobe-symbol-*--14-*'
code@28
    36
code@28
    37
(require 'cl)
code@28
    38
(require 'font-lock)
code@28
    39
(require 'atomic-extents)
code@28
    40
code@28
    41
(defvar sym-lock-sym-count 0
code@28
    42
  "Counter for internal symbols.")
code@28
    43
code@28
    44
(defvar sym-lock-ext-start nil "Temporary for atomicization.")
code@28
    45
(make-variable-buffer-local 'sym-lock-ext-start)
code@28
    46
(defvar sym-lock-ext-end nil "Temporary for atomicization.")
code@28
    47
(make-variable-buffer-local 'sym-lock-ext-end)
code@28
    48
code@28
    49
(defvar sym-lock-font-size nil
code@28
    50
  "Default size for Sym-Lock symbol font.")
code@28
    51
(make-variable-buffer-local 'sym-lock-font-size)
code@28
    52
(put 'sym-lock-font-size 'permanent-local t)
code@28
    53
code@28
    54
(defvar sym-lock-keywords nil
code@28
    55
  "Similar to `font-lock-keywords'.")
code@28
    56
(make-variable-buffer-local 'sym-lock-keywords)
code@28
    57
(put 'sym-lock-keywords 'permanent-local t)
code@28
    58
code@28
    59
(defvar sym-lock-enabled nil
code@28
    60
  "Sym-Lock switch.")
code@28
    61
(make-variable-buffer-local 'sym-lock-enabled)
code@28
    62
(put 'sym-lock-enabled 'permanent-local t)
code@28
    63
code@28
    64
(defvar sym-lock-color (face-foreground 'default)
code@28
    65
  "*Sym-Lock default color in `font-lock-use-colors' mode.")
code@28
    66
(make-variable-buffer-local 'sym-lock-color)
code@28
    67
(put 'sym-lock-color 'permanent-local t)
code@28
    68
code@28
    69
(defvar sym-lock-mouse-face-enabled t
code@28
    70
  "Mouse face switch.")
code@28
    71
(make-variable-buffer-local 'sym-lock-mouse-face-enabled)
code@28
    72
(put 'sym-lock-mouse-face-enabled 'permanent-local t)
code@28
    73
code@28
    74
(defun sym-lock-gen-symbol (&optional prefix)
code@28
    75
  "Generate a new internal symbol."
code@28
    76
  ;; where is the standard function to do this ?
code@28
    77
  (setq sym-lock-sym-count (+ sym-lock-sym-count 1))
code@28
    78
  (intern (concat "sym-lock-gen-" (or prefix "") 
code@28
    79
		  (int-to-string sym-lock-sym-count))))
code@28
    80
code@28
    81
(defun sym-lock-make-symbols-atomic (&optional begin end)
code@28
    82
  "Function to make symbol faces atomic."
code@28
    83
  (if sym-lock-enabled
code@28
    84
      (map-extents
code@28
    85
       (lambda (extent maparg)
code@28
    86
	 (let ((face (extent-face extent)) (ext))
code@28
    87
	   (if (and face (setq ext (face-property face 'sym-lock-remap)))
code@28
    88
	       (progn
code@28
    89
		 (if (numberp ext)
code@28
    90
		     (set-extent-endpoints
code@28
    91
		      extent (- (extent-start-position extent) ext)
code@28
    92
		      (extent-end-position extent)))
code@28
    93
		 (if ext
code@28
    94
		     (progn
code@28
    95
		       (if sym-lock-mouse-face-enabled
code@28
    96
			   (set-extent-property extent 'mouse-face
code@28
    97
						'default))
code@28
    98
		       (set-extent-property extent 'atomic t)
code@28
    99
		       (set-extent-property extent 'start-open t))))))
code@28
   100
	 nil)
code@28
   101
       (current-buffer)
code@28
   102
       (if begin (save-excursion (goto-char begin) (beginning-of-line) (point))
code@28
   103
	 (point-min))
code@28
   104
       (if end (save-excursion (goto-char end) (end-of-line) (point))
code@28
   105
	 (point-max))
code@28
   106
       nil nil)))
code@28
   107
code@28
   108
(defun sym-lock-compute-font-size ()
code@28
   109
  "Computes the size of the \"better\" symbol font."
code@28
   110
  (let ((num (face-height 'default))
code@28
   111
	(size) (minsize)
code@28
   112
	(lf (list-fonts "-adobe-symbol-medium-r-normal--*")))
code@28
   113
    (setq minsize 8)
code@28
   114
    (while lf
code@28
   115
      (string-match "-[^-]*-[^-]*-[^-]*-[^-]*-[^-]*-[^-]*-\\([^-]*\\)-.*"
code@28
   116
		    (car lf))
code@28
   117
      (setq size (string-to-number (substring (car lf)
code@28
   118
					      (match-beginning 1)
code@28
   119
					      (match-end 1))))
code@28
   120
      (if (and (<= size num) (> size minsize))
code@28
   121
	  (setq minsize size))
code@28
   122
      (setq lf (cdr lf)))
code@28
   123
    minsize))
code@28
   124
code@28
   125
(defun sym-lock-enable ()
code@28
   126
  "Enable Sym-Lock on this buffer."
code@28
   127
  (interactive)
code@28
   128
  (if (not (and (fboundp 'console-type)
code@28
   129
		(or (eq (console-type) 'x)
code@28
   130
		    (eq (console-type) 'gtk))
code@28
   131
		(sym-lock-look-for-symbol-font)))
code@28
   132
      (setq sym-lock-enabled nil)
code@28
   133
    ;; X-Window with symbol font
code@28
   134
    (if (not sym-lock-keywords)
code@28
   135
	(error "No Sym-Lock keywords defined!")
code@28
   136
      (setq sym-lock-enabled t)
code@28
   137
      (if font-lock-mode
code@28
   138
	  (progn
code@28
   139
	    (setq font-lock-keywords nil) ; Font-Lock explicit-defaults bug!
code@28
   140
	    (font-lock-set-defaults t)
code@28
   141
	    (font-lock-fontify-buffer)))
code@28
   142
      (message "Sym-Lock enabled."))))
code@28
   143
code@28
   144
(defun sym-lock-disable ()
code@28
   145
  "Disable Sym-Lock on this buffer."
code@28
   146
  (interactive)
code@28
   147
  (if (not sym-lock-keywords)
code@28
   148
      (error "No Sym-Lock keywords defined!")
code@28
   149
    (setq sym-lock-enabled nil)
code@28
   150
    (if font-lock-mode
code@28
   151
	(progn
code@28
   152
	  (setq font-lock-keywords nil) ; Font-Lock explicit-defaults bug!
code@28
   153
	  (font-lock-set-defaults t)
code@28
   154
	  (font-lock-fontify-buffer)))
code@28
   155
    (message "Sym-Lock disabled.")))
code@28
   156
code@28
   157
(defvar sym-lock-font-name
code@28
   158
  (concat "-adobe-symbol-medium-r-normal--"
code@28
   159
	  (if sym-lock-font-size sym-lock-font-size
code@28
   160
	    (number-to-string (sym-lock-compute-font-size)))
code@28
   161
	  "-*-*-*-p-*-adobe-fontspecific")
code@28
   162
  "Name of the font used by Sym-Lock.")
code@28
   163
(make-variable-buffer-local 'sym-lock-font-name)
code@28
   164
(put 'sym-lock-font-name 'permanent-local t)
code@28
   165
code@28
   166
;;(make-face 'sym-lock-adobe-symbol-face "Face for Sym-Lock symbols")
code@28
   167
;;(set-face-property 'sym-lock-adobe-symbol-face 'font sym-lock-font-name)
code@28
   168
code@28
   169
(defun sym-lock-look-for-symbol-font ()
code@28
   170
  "Returns whether there is a symbol font registred in the font server,
code@28
   171
   and sets sym-lock-enabled to false if not."
code@28
   172
  (if (list-fonts sym-lock-font-name)
code@28
   173
      t
code@28
   174
    (setq sym-lock-enabled nil)
code@28
   175
    nil))
code@28
   176
code@28
   177
(defun sym-lock-set-foreground ()
code@28
   178
  "Set foreground color of Sym-Lock faces."
code@28
   179
  (if (and (boundp 'sym-lock-defaults) sym-lock-defaults)
code@28
   180
      (let ((l (car sym-lock-defaults))
code@28
   181
	    (color (face-foreground 'default) sym-lock-color))
code@28
   182
	(if (and (consp l) (eq (car l) 'quote)) (setq l (eval l)))
code@28
   183
	(if (symbolp l) (setq l (eval l)))
code@28
   184
	(dolist (c l)
code@28
   185
	  (setq c (nth 2 c))
code@28
   186
	  (if (consp c) (setq c (eval c)))
code@28
   187
	  (if (string-match "-adobe-symbol-medium-r-normal-"
code@28
   188
			    (font-name (face-font c)))
code@28
   189
	      (set-face-foreground c color))))))
code@28
   190
code@28
   191
(defun sym-lock-remap-face (pat pos obj atomic face)
code@28
   192
  "Make a temporary face which remaps the POS char of PAT to the
code@28
   193
given OBJ under the symbol face and all other characters to
code@28
   194
the empty string. OBJ may either be a string or a character."
code@28
   195
  (let* ((name (sym-lock-gen-symbol "face"))
code@28
   196
	 (table (make-display-table))
code@28
   197
	 (tface (make-face name "sym-lock-remap-face" t)))
code@28
   198
    (fillarray table "")
code@28
   199
    (aset table (string-to-char (substring pat (1- pos) pos))
code@28
   200
	  (if (stringp obj) obj (make-string 1 obj)))
code@28
   201
    (if face
code@28
   202
	(set-face-parent tface face)
code@28
   203
      (set-face-foreground tface sym-lock-color)
code@28
   204
      (set-face-property tface 'font sym-lock-font-name))
code@28
   205
    (set-face-property tface 'display-table table)
code@28
   206
    (set-face-property tface 'sym-lock-remap atomic) ; mark it
code@28
   207
    tface
code@28
   208
    ;; return face value and not face name
code@28
   209
    ;; the temporary face would be otherwise GCed
code@28
   210
    ))
code@28
   211
code@28
   212
(defvar sym-lock-clear-face
code@28
   213
  (let* ((name (sym-lock-gen-symbol "face"))
code@28
   214
	 (table (make-display-table))
code@28
   215
	 (tface (make-face name "sym-lock-remap-face" t)))
code@28
   216
    (fillarray table "")
code@28
   217
    (set-face-property tface 'display-table table)
code@28
   218
    (set-face-property tface 'sym-lock-remap 1) ; mark it
code@28
   219
    tface 
code@28
   220
    ;; return face value and not face name
code@28
   221
    ;; the temporary face would be otherwise GCed
code@28
   222
    ))
code@28
   223
code@28
   224
(defun sym-lock (fl)
code@28
   225
  "Create font-lock table entries from a list of (PAT NUM POS OBJ) where
code@28
   226
PAT (at NUM) is substituted by OBJ under the symbol face. The face's extent
code@28
   227
will become atomic."
code@28
   228
  (if (not (and (fboundp 'console-type)
code@28
   229
		(or (eq (console-type) 'x)
code@28
   230
		    (eq (console-type) 'gtk))))
code@28
   231
      (setq sym-lock-enabled nil)
code@28
   232
    ;; X-Window
code@28
   233
    (if (sym-lock-look-for-symbol-font)
code@28
   234
	(progn
code@28
   235
	  (message "Computing Sym-Lock faces...")
code@28
   236
	  (setq sym-lock-keywords (sym-lock-rec fl))
code@28
   237
	  (setq sym-lock-enabled t)
code@28
   238
	  (message "Computing Sym-Lock faces... done.")))
code@28
   239
    ;; ugly hack to make atomic keywords traversable when
code@28
   240
    ;; paren-highlighting is also using post-command-hook...
code@28
   241
    ;; it moves atomic-extents post-command-hook to the front
code@28
   242
    (remove-hook 'post-command-hook 'atomic-extent-post-hook)
code@28
   243
    (add-hook 'post-command-hook 'atomic-extent-post-hook)))
code@28
   244
code@28
   245
(defun sym-lock-rec (fl)
code@28
   246
  (let ((f (car fl)))
code@28
   247
    (if f (let* ((pat (car f))
code@28
   248
		 (pos (caddr f))
code@28
   249
		 (c (substring pat (1- pos) pos)))
code@28
   250
	    (if (or (string-match c (substring pat pos (length pat)))
code@28
   251
		    (string-match c (substring pat 0 (1- pos))))
code@28
   252
		(cons (apply 'sym-lock-atom f)
code@28
   253
		      (cons (apply 'sym-lock-face f)
code@28
   254
			    (sym-lock-rec (cdr fl))))
code@28
   255
	      (cons (apply 'sym-lock-atom-face f)
code@28
   256
		    (sym-lock-rec (cdr fl))))))))
code@28
   257
code@28
   258
(defun sym-lock-atom-face (pat num pos obj face &optional override)
code@28
   259
  "Define an entry for the font-lock table which substitutes PAT (at NUM) by
code@28
   260
OBJ under the symbol face. The face extent WILL become atomic."
code@28
   261
  (list pat num (sym-lock-remap-face pat pos obj t face) override))
code@28
   262
code@28
   263
(defun sym-lock-face (pat num pos obj face &optional override)
code@28
   264
  "Define an entry for the font-lock table which substitutes PAT (at NUM) by
code@28
   265
OBJ under symbol face. The face extent will NOT become
code@28
   266
atomic."
code@28
   267
  (list (concat "\\(" (substring pat 0 pos) "\\)"
code@28
   268
		(substring pat pos (length pat)))
code@28
   269
	(1+ num) (sym-lock-remap-face pat pos obj nil face) override))
code@28
   270
code@28
   271
(defun sym-lock-atom (pat num pos obj face &optional override)
code@28
   272
  "Define an entry for the font lock table which substitutes PAT (at NUM) by
code@28
   273
a void face. To build the atom, the face extent will be reshaped from
code@28
   274
\"begin_point\"-1 to \"end_point\"."
code@28
   275
  (list (concat (substring pat 0 pos) "\\("
code@28
   276
		(substring pat pos (length pat)) "\\)")
code@28
   277
	(1+ num) sym-lock-clear-face override))
code@28
   278
code@28
   279
(defun sym-lock-after-change-function (beg end old-len)
code@28
   280
  (when sym-lock-enabled
code@28
   281
    (setq sym-lock-ext-start (if sym-lock-ext-start
code@28
   282
				 (min beg sym-lock-ext-start) beg))
code@28
   283
    (setq sym-lock-ext-end (if sym-lock-ext-end
code@28
   284
			       (max end sym-lock-ext-end) end))))
code@28
   285
code@28
   286
(defun sym-lock-pre-idle-hook-last ()
code@28
   287
  (if sym-lock-enabled
code@28
   288
      (condition-case nil
code@28
   289
	  (when (and sym-lock-enabled sym-lock-ext-start)
code@28
   290
	    (sym-lock-make-symbols-atomic sym-lock-ext-start sym-lock-ext-end)
code@28
   291
	    (setq sym-lock-ext-start nil)
code@28
   292
	    (setq sym-lock-ext-end nil))
code@28
   293
	(error (warn "Error caught in `sym-lock-pre-idle-hook-last'")))))
code@28
   294
code@28
   295
(add-hook 'font-lock-after-fontify-buffer-hook
code@28
   296
	  'sym-lock-make-symbols-atomic)
code@28
   297
code@28
   298
(defun sym-lock-mouse-face-enable ()
code@28
   299
  "Enable special face for symbols under mouse."
code@28
   300
  (interactive)
code@28
   301
  (setq sym-lock-mouse-face-enabled t)
code@28
   302
  (if sym-lock-enabled
code@28
   303
      (font-lock-fontify-buffer)))
code@28
   304
code@28
   305
(defun sym-lock-mouse-face-disable ()
code@28
   306
  "Disable special face for symbols under mouse."
code@28
   307
  (interactive)
code@28
   308
  (setq sym-lock-mouse-face-enabled nil)
code@28
   309
  (if sym-lock-enabled
code@28
   310
      (font-lock-fontify-buffer)))
code@28
   311
code@28
   312
(defun sym-lock-font-lock-hook ()
code@28
   313
  "Function called by `font-lock-mode' for initialization purposes."
code@28
   314
  (add-hook 'after-change-functions 'sym-lock-after-change-function)
code@28
   315
  (add-hook 'pre-idle-hook 'sym-lock-pre-idle-hook-last t)
code@28
   316
  (if (and (featurep 'sym-lock) sym-lock-enabled
code@28
   317
	   font-lock-defaults (boundp 'sym-lock-keywords))
code@28
   318
      (progn
code@28
   319
	(sym-lock-patch-keywords)
code@28
   320
	(sym-lock-set-foreground))))
code@28
   321
code@28
   322
(defun font-lock-set-defaults (&optional explicit-defaults)
code@28
   323
  (when
code@28
   324
      (and
code@28
   325
       (featurep 'font-lock)
code@28
   326
       (if font-lock-auto-fontify
code@28
   327
           (not (memq major-mode font-lock-mode-disable-list))
code@28
   328
         (memq major-mode font-lock-mode-enable-list))
code@28
   329
       (font-lock-set-defaults-1 explicit-defaults)
code@28
   330
       (sym-lock-patch-keywords))
code@28
   331
    (turn-on-font-lock)))
code@28
   332
code@28
   333
(defun sym-lock-patch-keywords ()
code@28
   334
  (if (and font-lock-keywords sym-lock-enabled
code@28
   335
	   (boundp 'sym-lock-keywords)
code@28
   336
	   (listp (car font-lock-keywords))
code@28
   337
	   (listp (cdar font-lock-keywords))
code@28
   338
	   (listp (cddar font-lock-keywords))
code@28
   339
	   (or (listp (caddar font-lock-keywords))
code@28
   340
	       (not (string-match
code@28
   341
		     "sym-lock"
code@28
   342
		     (symbol-name
code@28
   343
		      (face-name (cadr (cdar font-lock-keywords))))))))
code@28
   344
      (setq font-lock-keywords (append sym-lock-keywords
code@28
   345
				       font-lock-keywords))) t)
code@28
   346
code@28
   347
(add-menu-button '("Options" "Syntax Highlighting")
code@28
   348
		 ["Sym-Lock"
code@28
   349
		  (if sym-lock-enabled (sym-lock-disable) (sym-lock-enable))
code@28
   350
		  :style toggle :selected sym-lock-enabled
code@28
   351
		  :active sym-lock-keywords] "Automatic")
code@28
   352
code@28
   353
(add-hook 'font-lock-mode-hook 'sym-lock-font-lock-hook)
code@28
   354
code@28
   355
(provide 'sym-lock)