1 ;;; tinylibo.el --- Library for handling (o)verlays
3 ;; This file is not part of Emacs
7 ;; Copyright (C) 1995-2007 Jari Aalto
8 ;; Keywords: extensions
10 ;; Maintainer: Jari Aalto
12 ;; To get information on this program, call M-x tinylibo-version.
13 ;; Look at the code with folding.el
17 ;; This program is free software; you can redistribute it and/or modify it
18 ;; under the terms of the GNU General Public License as published by the Free
19 ;; Software Foundation; either version 2 of the License, or (at your option)
22 ;; This program is distributed in the hope that it will be useful, but
23 ;; WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
24 ;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
27 ;; You should have received a copy of the GNU General Public License
28 ;; along with program; see the file COPYING. If not, write to the
29 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
30 ;; Boston, MA 02110-1301, USA.
32 ;; Visit <http://www.gnu.org/copyleft/gpl.html> for more information
39 ;; ........................................................ &t-install ...
40 ;; Put this file on your Emacs-Lisp load path, add following into your
41 ;; ~/.emacs startup file. Yes, you require 'm' lib which publishes
42 ;; this modules interface.
44 ;; (require 'tinylibm)
49 ;; ..................................................... &t-commentary ...
55 ;; The functions were developed to ease the highlighting,
56 ;; at the time when these function were new in Emacs. The overlays
57 ;; really seemed like "inside" stuff when tried for the first time
58 ;; to make text colored.
60 ;; o This is LIBRARY module, it does nothing on its own.
61 ;; o Offers functions for overlay handling
69 ;;{{{ setup: -- require
71 ;;; ......................................................... &require ...
75 (ti::package-use-dynamic-compilation)
78 (ti::overlay-require-macro
80 tinylibo: ** XEmacs needs overlay.el package; emulation may not work.")
82 ;; Idea in setnu.el, note that XEmacs 19.15+ includes an overlay.el
84 (unless (fboundp 'overlayp)
85 (defalias 'overlayp 'extent-live-p))
87 (unless (fboundp 'make-overlay)
88 (defalias 'make-overlay 'make-extent))
90 (unless (fboundp 'delete-overlay)
91 (defalias 'delete-overlay 'delete-extent))
93 (unless (fboundp 'overlay-get)
94 (defalias 'overlay-get 'extent-property))
96 (unless (fboundp 'overlay-put)
97 (defalias 'overlay-put 'set-extent-property))
99 (unless (fboundp 'move-overlay)
100 (defalias 'move-overlay 'set-extent-endpoints))
102 (unless (fboundp 'overlay-end)
103 (defalias 'overlay-end 'extent-end-position))
105 (unless (fboundp 'overlay-start)
106 (defalias 'overlay-start 'extent-start-position))
108 (unless (fboundp 'overlay-buffer)
109 (defalias 'overlay-buffer 'extent-start-position))
111 (unless (fboundp 'overlay-buffer)
112 (defalias 'overlay-buffer 'extent-start-position))
114 (unless (fboundp 'next-overlay-change)
115 (defalias 'next-overlay-change 'next-extent-change))
117 (unless (fboundp 'overlay-properties)
118 (defalias 'overlay-properties 'extent-properties))
120 (unless (fboundp 'overlay-length)
121 (defalias 'overlay-length 'extent-length))
123 (unless (fboundp 'overlays-at)
124 (defun overlays-at (point)
125 "tinylibo.el -- return overlay at POINT."
126 (ti::funcall 'extent-list (current-buffer) point)))))
131 ;;; ....................................................... &v-version ...
133 (defconst tinylibo-version
134 (substring "$Revision: 2.39 $" 11 15)
135 "Latest version number.")
137 (defconst tinylibo-version-id
138 "$Id: tinylibo.el,v 2.39 2007/05/01 17:20:45 jaalto Exp $"
139 "Latest modification time and version number.")
141 ;;; ----------------------------------------------------------------------
143 (defun tinylibo-version (&optional arg)
144 "Show version information. ARG will instruct to print message to echo area."
146 (ti::package-version-info "tinylibo.el" arg))
148 ;;; ----------------------------------------------------------------------
150 (defun tinylibo-feedback ()
151 "Submit suggestions, error corrections, impressions, anything..."
153 (ti::package-submit-feedback "tinylibo.el"))
157 ;;; ########################################################### &funcs ###
161 ;;; .......................................................... ¯os ...
163 ;;; ----------------------------------------------------------------------
165 (defsubst ti::overlay-make (level)
166 "Make overlay according to match in buffer at LEVEL.
167 The match is NOT checked. Returns new overlay."
169 (match-beginning level)
172 ;;; ----------------------------------------------------------------------
174 (defsubst ti::overlay-makec (level)
175 "Make overlay according to match in buffer at LEVEL.
176 The match is checked. Returns new overlay or nil."
177 (if (match-end level)
179 (match-beginning level)
185 ;;; ----------------------------------------------------------------------
187 (defun ti::overlay-make-match (level plist)
188 "Make overlay over the matched text portion. The match level is checked.
192 PLIST property list '(PRO-NAME PROP-VAL)
196 (let* ((ov (ti::overlay-makec level))
201 (setq prop (nth 0 plist) propv (nth 1 plist))
202 (setq plist (cdr (cdr plist))) ;go 2 fwd
203 (overlay-put ov prop propv)))
206 ;;; ----------------------------------------------------------------------
208 (defsubst ti::overlay-buffer-substring (ov &optional no-properties)
209 "Read `buffer-substring' underneath overlay OV.
213 OV overlay, can also be nil.
214 NO-PROPERTIES flag, if non-nil remove all properties
222 (buffer-substring-no-properties (overlay-start ov) (overlay-end ov))
223 (buffer-substring (overlay-start ov) (overlay-end ov)))))
225 ;;; ----------------------------------------------------------------------
227 (defun ti::overlay-mouse-on-p (ov)
228 "Check if overlay OV has `mouse-face' on.
229 If `mouse-face' contains 'default, it's treated to mean same as nil.
232 nil or property value of `mouse-face'"
236 (setq propl (overlay-properties ov)
237 prop (when (memq 'mouse-face propl)
238 (overlay-get ov 'mouse-face)))
239 (unless (or (null prop)
241 ;; it had some property
244 ;;; ----------------------------------------------------------------------
246 (defun ti::overlay-get-mouse ()
247 "Check if the point has 'mouse-face overlay.
251 nil no overlay at the point found
254 (let* (ovl ;overlay list
256 (when (setq ovl (overlays-at (point)))
257 (setq ov (ti::overlay-get-prop ovl (list 'mouse-face)))
259 (setq ov t))) ;no mouse
262 ;; ----------------------------------------------------------------------
263 ;; 'prop' means parameter form
264 ;; - There should only one unique...
266 (defun ti::overlay-get-prop (ovl prop-list)
267 "Read OVL and return first overlay where is property list PROP-LIST.
272 PROP-LIST list of properties (PROP PROP ..)"
273 (let ((len (length prop-list))
278 (unless (and ovl prop-list)
279 (error "Invalid parameters"))
281 (while (and ovl ;until list end
282 (null ov)) ;until found
284 propl (overlay-properties ovx)
287 (dolist (elt prop-list) ;check all properties
288 (when (memq elt propl)
289 (incf i))) ;hit counter
292 (setq ov ovx)) ;found all matches
293 (setq ovl (cdr ovl)))
296 ;; ----------------------------------------------------------------------
297 ;; 'prop-val' means parameter form
298 ;; - This is more heavier function
300 (defun ti::overlay-get-prop-val (ovl prop-list)
301 "Read OVL and find overlay(s) which contain PROP-LIST '(PROP VAL PROP VAL..)
306 PROP-LIST list of properties (PROP VAL PROP VAL ..)"
315 (setq len (length prop-list))
317 (if (or (not (and ovl prop-list))
318 (not (= 0 (% len 2)))) ;must go paired
319 (error "Invalid parameters" ovl prop-list)
321 (setq len (/ (length prop-list) 2))
323 ;; ..................................................... check ...
325 (while (and (setq ovx (pop ovl)) ;until list end
326 (null ov)) ;until found
329 propl (overlay-properties ovx))
332 (setq prop (car ptr) ptr (cdr ptr)
333 propv (car ptr) ptr (cdr ptr))
335 ;;; (ti::d!! '!! prop propv
336 ;;; 'memq (memq prop propl)
337 ;;; 'get (overlay-get ovx prop) propv propl "\n")
339 (if (and (memq prop propl)
340 (equal (overlay-get ovx prop) propv))
343 (setq ovl (cdr ovl)))) ;; while-if
345 ;;; (ti::d!! "~out" (prin1-to-string ov))
348 ;;; ----------------------------------------------------------------------
350 (defun ti::overlay-re-search
351 (re level list &optional max back reuse reuse-t no-prop-l)
352 "Search for RE at LEVEL by creating overlay and its property LIST.
353 Assigning LIST (PROP PROP_VAL) to the overlay. The search is repeated
354 until no more hits or up till MAX point is reached.
359 LEVEL subexpression level in regexp
360 LIST list of (PROP PROP_VAL)
361 MAX if non-nil, searches up till MAX point.
363 REUSE (PROP PROP PROP ..) or (PROP_SYM PROP_VAL ..)
365 When re match is found it looks overlays underneath the
366 point, and the first overlay that satisfies list, will
367 be reused, instead of creating new one. Note that _first_
368 overlay matched is used, if none is found, new is created
372 Specifies the list _type_ that was given in REUSE.
373 nil = first type , non-nil = second type.
377 Ig given, then possible overlay starting at the same point must
378 not have properties PROP-L (PROL VAL PROP VAL ..). If there is
379 susch matching overlay, then do not create overlay.
383 nil nothing created or used.
384 '(used-list created-list) two lists, list of used and created overlays."
385 (let* ((func (if back 're-search-backward 're-search-forward))
402 (zerop (% (length list ) 2)))
403 (error "Parameter LIST invalid" re level list))
406 (while (funcall func re max t)
407 (setq mb (match-beginning level))
409 ;;; (ti::d! level (match-string level) mb)
411 (when mb ;match on this level found
413 ;; ....................................... find or create ov ...
415 (setq ovl (overlays-at mb)) ;try finding all overlays
419 (ti::overlay-get-prop-val ovl no-prop-l))
420 ;; Do nothing, overlap happened
425 (setq ov (ti::overlay-make level))
426 (push ov ret-created ))
429 ;;; (ti::d! "r" reuse ovl) (setq OVL ovl RE reuse)
430 (if reuse-t ;what type the list is ?
432 (setq ov (car-safe (ti::overlay-get-prop-val ovl reuse))))
434 (setq ov (ti::overlay-get-prop ovl reuse))))
436 ;;; (ti::d! "after" ov)
440 (setq ov (ti::overlay-make level)) ;none satisfies us
441 (push ov ret-created)))) ;; cond
443 ;; .................................... add properties to ov ...
444 ;; Now we should have overlay in a way or other
450 (setq prop (nth 0 ptr) propv (nth 1 ptr))
451 (setq ptr (cdr (cdr ptr))) ;go 2 fwd
452 ;;; (ti::d! "put" prop propv ov)
453 (overlay-put ov prop propv))))))
455 (when (or ret-reused ret-created)
456 (list ret-reused ret-created))))
458 ;;; ----------------------------------------------------------------------
459 ;;; Try following example:
461 ;;; (setq OV (make-overlay (point) (point)))
462 ;;; (overlay-put OV 'face 'highlight)
463 ;;; (ti::overlay-re-search-move OV "ti::o")
466 (defun ti::overlay-re-search-move (ov re &optional level back max)
467 "Maove OV to Search forward for match RE at LEVEL.
468 Default level is 0, full match. if BACK is given, search is done
469 backward. MAX is last position to search.
471 If overlay OV is currently in some other buffer, it will be transferred
472 to the current buffer.
478 LEVEL subexpression level in regexp
479 BACK flag, is non-nil, go backward
480 MAX max point of search
485 nbr overlay end position [matched portion end]"
487 (if back (point-min) (point-max))))
488 (level (or level 0))) ;default is full string
490 (error "invalid overlay, nil"))
493 (re-search-backward re max t)
494 (re-search-forward re max t))
497 (match-beginning level)
502 ;;; ----------------------------------------------------------------------
504 (defun ti::overlay-get-within-area (propl &optional propl-t beg end)
505 "Return all overlays which match property list PROPL.
506 If PROPL is t then returns all overlays. Default is to search from
507 current point forward.
510 PROPL property list, see next
511 PROPL-T if nil the propl is of type (PROP PROP .. )
512 if non-nil (PROP VAL PROP VAL ..)
515 (let* ((p (or beg (point)))
516 (max (or end (point-max)))
524 (setq ovl (overlays-at p))
527 (setq list (append ovl list))
529 (setq ovx (car-safe (ti::overlay-get-prop-val ovl propl)))
530 (setq ovx (ti::overlay-get-prop ovl propl)))
533 (setq p (next-overlay-change p))))
536 ;;; ----------------------------------------------------------------------
537 ;;; If you're in trouble, call this function interactively
538 ;;; and it wipes out all overlays.
540 (defun ti::overlay-remove-region (&optional beg end propl propl-t)
541 "Remove all matched overlays within area.
542 Default is from point forward. Ignores buffer read-only status.
548 PROPL (PROP PROP ..) or
549 (PROP VAL PROP VAL ..)
550 If this value is t, removes all overlays
552 PROPL-T Specifies the list type given. nil = first list type."
554 (let* (buffer-read-only
556 (max (or end (point-max)))
559 t)) ;set to t is not given
560 (ovl (ti::overlay-get-within-area propl propl-t p max))
562 (dolist (overlay ovl)
563 (delete-overlay overlay))))
569 ;;; tinylibo.el ends here