Removed auto-mode-alist hacking for html-mode to files.el.
[bpt/emacs.git] / lisp / emulation / viper-util.el
CommitLineData
6c2e12f4 1;;; viper-util.el --- Utilities used by viper.el
75551c46 2;; Copyright (C) 1994, 1995 Free Software Foundation, Inc.
d6fd318f 3
6c2e12f4
KH
4;; This file is part of GNU Emacs.
5
6;; GNU Emacs is free software; you can redistribute it and/or modify
7;; it under the terms of the GNU General Public License as published by
8;; the Free Software Foundation; either version 2, or (at your option)
9;; any later version.
10
11;; GNU Emacs is distributed in the hope that it will be useful,
12;; but WITHOUT ANY WARRANTY; without even the implied warranty of
13;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14;; GNU General Public License for more details.
15
16;; You should have received a copy of the GNU General Public License
17;; along with GNU Emacs; see the file COPYING. If not, write to
18;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19
20(require 'ring)
21
75551c46 22;; Whether it is XEmacs or not
c8085774 23(defconst vip-xemacs-p (string-match "\\(Lucid\\|XEmacs\\)" emacs-version))
75551c46
KH
24;; Whether it is Emacs or not
25(defconst vip-emacs-p (not vip-xemacs-p))
26;; Tell whether we are running as a window application or on a TTY
27(defsubst vip-device-type ()
28 (if vip-emacs-p
29 window-system
30 (device-type (selected-device))))
31;; in XEmacs: device-type is tty on tty and stream in batch.
32(defsubst vip-window-display-p ()
33 (and (vip-device-type) (not (memq (vip-device-type) '(tty stream)))))
6c2e12f4
KH
34
35\f
36;;; Macros
37
38(defmacro vip-deflocalvar (var default-value &optional documentation)
39 (` (progn
40 (defvar (, var) (, default-value)
41 (, (format "%s\n\(buffer local\)" documentation)))
42 (make-variable-buffer-local '(, var))
43 )))
44
45(defmacro vip-loop (count body)
46 "(vip-loop COUNT BODY) Execute BODY COUNT times."
47 (list 'let (list (list 'count count))
48 (list 'while '(> count 0)
49 body
50 '(setq count (1- count))
51 )))
52
53(defmacro vip-buffer-live-p (buf)
54 (` (and (, buf) (get-buffer (, buf)) (buffer-name (get-buffer (, buf))))))
55
56;; return buffer-specific macro definition, given a full macro definition
57(defmacro vip-kbd-buf-alist (macro-elt)
58 (` (nth 1 (, macro-elt))))
59;; get a pair: (curr-buffer . macro-definition)
60(defmacro vip-kbd-buf-pair (macro-elt)
61 (` (assoc (buffer-name) (vip-kbd-buf-alist (, macro-elt)))))
62;; get macro definition for current buffer
63(defmacro vip-kbd-buf-definition (macro-elt)
64 (` (cdr (vip-kbd-buf-pair (, macro-elt)))))
65
66;; return mode-specific macro definitions, given a full macro definition
67(defmacro vip-kbd-mode-alist (macro-elt)
68 (` (nth 2 (, macro-elt))))
69;; get a pair: (major-mode . macro-definition)
70(defmacro vip-kbd-mode-pair (macro-elt)
71 (` (assoc major-mode (vip-kbd-mode-alist (, macro-elt)))))
72;; get macro definition for the current major mode
73(defmacro vip-kbd-mode-definition (macro-elt)
74 (` (cdr (vip-kbd-mode-pair (, macro-elt)))))
75
76;; return global macro definition, given a full macro definition
77(defmacro vip-kbd-global-pair (macro-elt)
78 (` (nth 3 (, macro-elt))))
79;; get global macro definition from an elt of macro-alist
80(defmacro vip-kbd-global-definition (macro-elt)
81 (` (cdr (vip-kbd-global-pair (, macro-elt)))))
82
83;; last elt of a sequence
84(defsubst vip-seq-last-elt (seq)
85 (elt seq (1- (length seq))))
86
87;; Check if arg is a valid character for register
88;; TYPE is a list that can contain `letter', `Letter', and `digit'.
89;; Letter means lowercase letters, Letter means uppercase letters, and
90;; digit means digits from 1 to 9.
91;; If TYPE is nil, then down/uppercase letters and digits are allowed.
92(defun vip-valid-register (reg &optional type)
93 (or type (setq type '(letter Letter digit)))
94 (or (if (memq 'letter type)
95 (and (<= ?a reg) (<= reg ?z)))
96 (if (memq 'digit type)
97 (and (<= ?1 reg) (<= reg ?9)))
98 (if (memq 'Letter type)
99 (and (<= ?A reg) (<= reg ?Z)))
100 ))
101
75551c46 102;; checks if object is a marker, has a buffer, and points to within that buffer
6c2e12f4 103(defun vip-valid-marker (marker)
75551c46 104 (if (and (markerp marker) (marker-buffer marker))
6c2e12f4
KH
105 (let ((buf (marker-buffer marker))
106 (pos (marker-position marker)))
107 (save-excursion
108 (set-buffer buf)
109 (and (<= pos (point-max)) (<= (point-min) pos))))))
110
111\f
112(defvar vip-minibuffer-overlay-priority 300)
113(defvar vip-replace-overlay-priority 400)
114(defvar vip-search-overlay-priority 500)
115
116\f
117;;; XEmacs support
118
119(if vip-xemacs-p
120 (progn
121 (fset 'vip-read-event (symbol-function 'next-command-event))
122 (fset 'vip-make-overlay (symbol-function 'make-extent))
123 (fset 'vip-overlay-start (symbol-function 'extent-start-position))
124 (fset 'vip-overlay-end (symbol-function 'extent-end-position))
125 (fset 'vip-overlay-put (symbol-function 'set-extent-property))
126 (fset 'vip-overlay-p (symbol-function 'extentp))
127 (fset 'vip-overlay-get (symbol-function 'extent-property))
128 (fset 'vip-move-overlay (symbol-function 'set-extent-endpoints))
75551c46
KH
129 (if (vip-window-display-p)
130 (fset 'vip-iconify (symbol-function 'iconify-frame)))
131 (cond ((vip-window-display-p)
6c2e12f4
KH
132 (fset 'vip-get-face (symbol-function 'get-face))
133 (fset 'vip-color-defined-p
75551c46
KH
134 (symbol-function 'valid-color-name-p))
135 )))
6c2e12f4
KH
136 (fset 'vip-read-event (symbol-function 'read-event))
137 (fset 'vip-make-overlay (symbol-function 'make-overlay))
138 (fset 'vip-overlay-start (symbol-function 'overlay-start))
139 (fset 'vip-overlay-end (symbol-function 'overlay-end))
140 (fset 'vip-overlay-put (symbol-function 'overlay-put))
141 (fset 'vip-overlay-p (symbol-function 'overlayp))
142 (fset 'vip-overlay-get (symbol-function 'overlay-get))
143 (fset 'vip-move-overlay (symbol-function 'move-overlay))
75551c46 144 (if (vip-window-display-p)
6c2e12f4 145 (fset 'vip-iconify (symbol-function 'iconify-or-deiconify-frame)))
75551c46 146 (cond ((vip-window-display-p)
6c2e12f4
KH
147 (fset 'vip-get-face (symbol-function 'internal-get-face))
148 (fset 'vip-color-defined-p (symbol-function 'x-color-defined-p))
75551c46
KH
149 )))
150
151(defsubst vip-color-display-p ()
152 (if vip-emacs-p
153 (x-display-color-p)
154 (eq (device-class (selected-device)) 'color)))
6c2e12f4
KH
155
156;; OS/2
75551c46 157(cond ((eq (vip-device-type) 'pm)
6c2e12f4
KH
158 (fset 'vip-color-defined-p
159 (function (lambda (color) (assoc color pm-color-alist))))))
160
161;; needed to smooth out the difference between Emacs and XEmacs
162(defsubst vip-italicize-face (face)
163 (if vip-xemacs-p
164 (make-face-italic face)
165 (make-face-italic face nil 'noerror)))
166
167;; test if display is color and the colors are defined
168(defsubst vip-can-use-colors (&rest colors)
75551c46 169 (if (vip-color-display-p)
6c2e12f4
KH
170 (not (memq nil (mapcar 'vip-color-defined-p colors)))
171 ))
172
173;; currently doesn't work for XEmacs
174(defun vip-change-cursor-color (new-color)
75551c46
KH
175 (if (and (vip-window-display-p) (vip-color-display-p)
176 (stringp new-color) (vip-color-defined-p new-color)
177 (not (string= new-color (vip-get-cursor-color))))
178 (modify-frame-parameters
179 (selected-frame) (list (cons 'cursor-color new-color)))))
6c2e12f4
KH
180
181(defsubst vip-save-cursor-color ()
75551c46
KH
182 (if (and (vip-window-display-p) (vip-color-display-p))
183 (let ((color (vip-get-cursor-color)))
6c2e12f4
KH
184 (if (and (stringp color) (vip-color-defined-p color)
185 (not (string= color vip-replace-overlay-cursor-color)))
186 (vip-overlay-put vip-replace-overlay 'vip-cursor-color color)))))
187
188(defsubst vip-restore-cursor-color ()
189 (vip-change-cursor-color
190 (vip-overlay-get vip-replace-overlay 'vip-cursor-color)))
75551c46
KH
191
192(defsubst vip-get-cursor-color ()
193 (cdr (assoc 'cursor-color (frame-parameters))))
6c2e12f4
KH
194
195\f
196;; Check the current version against the major and minor version numbers
197;; using op: cur-vers op major.minor If emacs-major-version or
198;; emacs-minor-version are not defined, we assume that the current version
199;; is hopelessly outdated. We assume that emacs-major-version and
200;; emacs-minor-version are defined. Otherwise, for Emacs/XEmacs 19, if the
201;; current minor version is < 10 (xemacs) or < 23 (emacs) the return value
202;; will be nil (when op is =, >, or >=) and t (when op is <, <=), which may be
203;; incorrect. However, this gives correct result in our cases, since we are
204;; testing for sufficiently high Emacs versions.
205(defun vip-check-version (op major minor &optional type-of-emacs)
206 (if (and (boundp 'emacs-major-version) (boundp 'emacs-minor-version))
207 (and (cond ((eq type-of-emacs 'xemacs) vip-xemacs-p)
208 ((eq type-of-emacs 'emacs) vip-emacs-p)
209 (t t))
210 (cond ((eq op '=) (and (= emacs-minor-version minor)
211 (= emacs-major-version major)))
212 ((memq op '(> >= < <=))
213 (and (or (funcall op emacs-major-version major)
214 (= emacs-major-version major))
215 (if (= emacs-major-version major)
216 (funcall op emacs-minor-version minor)
217 t)))
218 (t
219 (error "%S: Invalid op in vip-check-version" op))))
220 (cond ((memq op '(= > >=)) nil)
221 ((memq op '(< <=)) t))))
4702a420
MK
222
223;;;; warn if it is a wrong version of emacs
224;;(if (or (vip-check-version '< 19 29 'emacs)
225;; (vip-check-version '< 19 12 'xemacs))
226;; (progn
227;; (with-output-to-temp-buffer " *vip-info*"
228;; (switch-to-buffer " *vip-info*")
229;; (insert
230;; (format "
231;;
232;;This version of Viper requires
233;;
234;;\t Emacs 19.29 and higher
235;;\t OR
236;;\t XEmacs 19.12 and higher
237;;
238;;It is unlikely to work under Emacs version %s
239;;that you are using... " emacs-version))
240;;
241;; (if noninteractive
242;; ()
243;; (beep 1)
244;; (beep 1)
245;; (insert "\n\nType any key to continue... ")
246;; (vip-read-event)))
247;; (kill-buffer " *vip-info*")))
75551c46 248
6c2e12f4
KH
249
250(defun vip-get-visible-buffer-window (wind)
251 (if vip-xemacs-p
252 (get-buffer-window wind t)
253 (get-buffer-window wind 'visible)))
254
255
75551c46
KH
256;; Return line position.
257;; If pos is 'start then returns position of line start.
258;; If pos is 'end, returns line end. If pos is 'mid, returns line center.
259;; Pos = 'indent returns beginning of indentation.
260;; Otherwise, returns point. Current point is not moved in any case."
6c2e12f4 261(defun vip-line-pos (pos)
6c2e12f4
KH
262 (let ((cur-pos (point))
263 (result))
264 (cond
265 ((equal pos 'start)
266 (beginning-of-line))
267 ((equal pos 'end)
268 (end-of-line))
269 ((equal pos 'mid)
270 (goto-char (+ (vip-line-pos 'start) (vip-line-pos 'end) 2)))
271 ((equal pos 'indent)
272 (back-to-indentation))
273 (t nil))
274 (setq result (point))
275 (goto-char cur-pos)
276 result))
277
278
75551c46
KH
279;; Like move-marker but creates a virgin marker if arg isn't already a marker.
280;; The first argument must eval to a variable name.
281;; Arguments: (var-name position &optional buffer).
282;;
283;; This is useful for moving markers that are supposed to be local.
284;; For this, VAR-NAME should be made buffer-local with nil as a default.
285;; Then, each time this var is used in `vip-move-marker-locally' in a new
286;; buffer, a new marker will be created.
6c2e12f4 287(defun vip-move-marker-locally (var pos &optional buffer)
6c2e12f4
KH
288 (if (markerp (eval var))
289 ()
290 (set var (make-marker)))
291 (move-marker (eval var) pos buffer))
292
293
75551c46 294;; Print CONDITIONS as a message.
6c2e12f4 295(defun vip-message-conditions (conditions)
6c2e12f4
KH
296 (let ((case (car conditions)) (msg (cdr conditions)))
297 (if (null msg)
298 (message "%s" case)
299 (message "%s: %s" case (mapconcat 'prin1-to-string msg " ")))
300 (beep 1)))
301
75551c46 302
6c2e12f4
KH
303\f
304;;; List/alist utilities
305
75551c46 306;; Convert LIST to an alist
6c2e12f4 307(defun vip-list-to-alist (lst)
6c2e12f4
KH
308 (let ((alist))
309 (while lst
310 (setq alist (cons (list (car lst)) alist))
311 (setq lst (cdr lst)))
312 alist))
313
75551c46 314;; Convert ALIST to a list.
6c2e12f4 315(defun vip-alist-to-list (alst)
6c2e12f4
KH
316 (let ((lst))
317 (while alst
318 (setq lst (cons (car (car alst)) lst))
319 (setq alst (cdr alst)))
320 lst))
321
75551c46 322;; Filter ALIST using REGEXP. Return alist whose elements match the regexp.
6c2e12f4 323(defun vip-filter-alist (regexp alst)
6c2e12f4
KH
324 (interactive "s x")
325 (let ((outalst) (inalst alst))
326 (while (car inalst)
327 (if (string-match regexp (car (car inalst)))
328 (setq outalst (cons (car inalst) outalst)))
329 (setq inalst (cdr inalst)))
330 outalst))
331
75551c46 332;; Filter LIST using REGEXP. Return list whose elements match the regexp.
6c2e12f4 333(defun vip-filter-list (regexp lst)
6c2e12f4
KH
334 (interactive "s x")
335 (let ((outlst) (inlst lst))
336 (while (car inlst)
337 (if (string-match regexp (car inlst))
338 (setq outlst (cons (car inlst) outlst)))
339 (setq inlst (cdr inlst)))
340 outlst))
341
342
343;; Append LIS2 to LIS1, both alists, by side-effect and returns LIS1
344;; LIS2 is modified by filtering it: deleting its members of the form
345;; \(car elt\) such that (car elt') is in LIS1.
346(defun vip-append-filter-alist (lis1 lis2)
347 (let ((temp lis1)
348 elt)
349
350 ;;filter-append the second list
351 (while temp
352 ;; delete all occurrences
353 (while (setq elt (assoc (car (car temp)) lis2))
354 (setq lis2 (delq elt lis2)))
355 (setq temp (cdr temp)))
356
357 (nconc lis1 lis2)))
358
359
360
361\f
362;;; Insertion ring
363
364;; Rotate RING's index. DIRection can be positive or negative.
365(defun vip-ring-rotate1 (ring dir)
366 (if (and (ring-p ring) (> (ring-length ring) 0))
367 (progn
368 (setcar ring (cond ((> dir 0)
369 (ring-plus1 (car ring) (ring-length ring)))
370 ((< dir 0)
371 (ring-minus1 (car ring) (ring-length ring)))
372 ;; don't rotate if dir = 0
373 (t (car ring))))
374 (vip-current-ring-item ring)
375 )))
376
377(defun vip-special-ring-rotate1 (ring dir)
378 (if (memq vip-intermediate-command
379 '(repeating-display-destructive-command
380 repeating-insertion-from-ring))
381 (vip-ring-rotate1 ring dir)
382 ;; don't rotate otherwise
383 (vip-ring-rotate1 ring 0)))
384
385;; current ring item; if N is given, then so many items back from the
386;; current
387(defun vip-current-ring-item (ring &optional n)
388 (setq n (or n 0))
389 (if (and (ring-p ring) (> (ring-length ring) 0))
390 (aref (cdr (cdr ring)) (mod (- (car ring) 1 n) (ring-length ring)))))
391
392;; push item onto ring. the second argument is a ring-variable, not value.
393(defun vip-push-onto-ring (item ring-var)
394 (or (ring-p (eval ring-var))
395 (set ring-var (make-ring (eval (intern (format "%S-size" ring-var))))))
396 (or (null item) ; don't push nil
397 (and (stringp item) (string= item "")) ; or empty strings
398 (equal item (vip-current-ring-item (eval ring-var))) ; or old stuff
399 ;; Since vip-set-destructive-command checks if we are inside vip-repeat,
400 ;; we don't check whether this-command-keys is a `.'.
401 ;; The cmd vip-repeat makes a call to the current function only if
402 ;; `.' is executing a command from the command history. It doesn't
403 ;; call the push-onto-ring function if `.' is simply repeating the
404 ;; last destructive command.
405 ;; We only check for ESC (which happens when we do insert with a
406 ;; prefix argument, or if this-command-keys doesn't give anything
407 ;; meaningful (in that case we don't know what to show to the user).
408 (and (eq ring-var 'vip-command-ring)
409 (string-match "\\([0-9]*\e\\|^[ \t]*$\\|escape\\)"
410 (vip-array-to-string (this-command-keys))))
411 (vip-ring-insert (eval ring-var) item))
412 )
413
414
415;; removing elts from ring seems to break it
416(defun vip-cleanup-ring (ring)
417 (or (< (ring-length ring) 2)
418 (null (vip-current-ring-item ring))
419 ;; last and previous equal
420 (if (equal (vip-current-ring-item ring) (vip-current-ring-item ring 1))
421 (vip-ring-pop ring))))
422
423;; ring-remove seems to be buggy, so we concocted this for our purposes.
424(defun vip-ring-pop (ring)
425 (let* ((ln (ring-length ring))
426 (vec (cdr (cdr ring)))
427 (veclen (length vec))
428 (hd (car ring))
429 (idx (max 0 (ring-minus1 hd ln)))
430 (top-elt (aref vec idx)))
431
432 ;; shift elements
433 (while (< (1+ idx) veclen)
434 (aset vec idx (aref vec (1+ idx)))
435 (setq idx (1+ idx)))
436 (aset vec idx nil)
437
438 (setq hd (max 0 (ring-minus1 hd ln)))
439 (if (= hd (1- ln)) (setq hd 0))
440 (setcar ring hd) ; move head
441 (setcar (cdr ring) (max 0 (1- ln))) ; adjust length
442 top-elt
443 ))
444
445(defun vip-ring-insert (ring item)
446 (let* ((ln (ring-length ring))
447 (vec (cdr (cdr ring)))
448 (veclen (length vec))
449 (hd (car ring))
450 (vecpos-after-hd (if (= hd 0) ln hd))
451 (idx ln))
452
453 (if (= ln veclen)
454 (progn
455 (aset vec hd item) ; hd is always 1+ the actual head index in vec
456 (setcar ring (ring-plus1 hd ln)))
457 (setcar (cdr ring) (1+ ln))
458 (setcar ring (ring-plus1 vecpos-after-hd (1+ ln)))
459 (while (and (>= idx vecpos-after-hd) (> ln 0))
460 (aset vec idx (aref vec (1- idx)))
461 (setq idx (1- idx)))
462 (aset vec vecpos-after-hd item))
463 item))
464
465\f
466;;; String utilities
467
468;; If STRING is longer than MAX-LEN, truncate it and print ...... instead
469;; PRE-STRING is a string to prepend to the abbrev string.
470;; POST-STRING is a string to append to the abbrev string.
471;; ABBREV_SIGN is a string to be inserted before POST-STRING
472;; if the orig string was truncated.
473(defun vip-abbreviate-string (string max-len
474 pre-string post-string abbrev-sign)
475 (let (truncated-str)
476 (setq truncated-str
477 (if (stringp string)
478 (substring string 0 (min max-len (length string)))))
479 (cond ((null truncated-str) "")
480 ((> (length string) max-len)
481 (format "%s%s%s%s"
482 pre-string truncated-str abbrev-sign post-string))
483 (t (format "%s%s%s" pre-string truncated-str post-string)))))
c8085774
KH
484
485;; tells if we are over a whitespace-only line
486(defsubst vip-over-whitespace-line ()
487 (save-excursion
488 (beginning-of-line)
489 (looking-at "^[ \t]*$")))
6c2e12f4
KH
490
491\f
492;;; Saving settings in custom file
493
75551c46
KH
494;; Save the current setting of VAR in CUSTOM-FILE.
495;; If given, MESSAGE is a message to be displayed after that.
496;; This message is erased after 2 secs, if erase-msg is non-nil.
497;; Arguments: var message custom-file &optional erase-message
6c2e12f4 498(defun vip-save-setting (var message custom-file &optional erase-msg)
6c2e12f4
KH
499 (let* ((var-name (symbol-name var))
500 (var-val (if (boundp var) (eval var)))
501 (regexp (format "^[^;]*%s[ \t\n]*[a-zA-Z---_']*[ \t\n)]" var-name))
502 (buf (find-file-noselect (substitute-in-file-name custom-file)))
503 )
504 (message message)
505 (save-excursion
506 (set-buffer buf)
507 (goto-char (point-min))
508 (if (re-search-forward regexp nil t)
509 (let ((reg-end (1- (match-end 0))))
510 (search-backward var-name)
511 (delete-region (match-beginning 0) reg-end)
512 (goto-char (match-beginning 0))
513 (insert (format "%s '%S" var-name var-val)))
514 (goto-char (point-max))
515 (if (not (bolp)) (insert "\n"))
516 (insert (format "(setq %s '%S)\n" var-name var-val)))
517 (save-buffer))
518 (kill-buffer buf)
519 (if erase-msg
520 (progn
521 (sit-for 2)
522 (message "")))
523 ))
524
525;; Save STRING in CUSTOM-FILE. If PATTERN is non-nil, remove strings that
526;; match this pattern.
527(defun vip-save-string-in-file (string custom-file &optional pattern)
528 (let ((buf (find-file-noselect (substitute-in-file-name custom-file))))
529 (save-excursion
530 (set-buffer buf)
531 (goto-char (point-min))
532 (if pattern (delete-matching-lines pattern))
533 (goto-char (point-max))
534 (if string (insert string))
535 (save-buffer))
536 (kill-buffer buf)
537 ))
538
539\f
540;;; Overlays
541
542;; Search
543
544(defun vip-flash-search-pattern ()
545 (if (vip-overlay-p vip-search-overlay)
546 (vip-move-overlay vip-search-overlay (match-beginning 0) (match-end 0))
547 (setq vip-search-overlay
548 (vip-make-overlay
549 (match-beginning 0) (match-end 0) (current-buffer))))
550
551 (vip-overlay-put vip-search-overlay 'priority vip-search-overlay-priority)
75551c46 552 (if (vip-window-display-p)
6c2e12f4
KH
553 (progn
554 (vip-overlay-put vip-search-overlay 'face vip-search-face)
555 (sit-for 2)
556 (vip-overlay-put vip-search-overlay 'face nil))))
557
558;; Replace state
559
560(defun vip-set-replace-overlay (beg end)
561 (if (vip-overlay-p vip-replace-overlay)
562 (vip-move-replace-overlay beg end)
563 (setq vip-replace-overlay (vip-make-overlay beg end (current-buffer)))
564 (vip-overlay-put vip-replace-overlay
565 'vip-start
566 (move-marker (make-marker)
567 (vip-overlay-start vip-replace-overlay)))
568 (vip-overlay-put vip-replace-overlay
569 'vip-end
570 (move-marker (make-marker)
571 (vip-overlay-end vip-replace-overlay)))
572 (vip-overlay-put
573 vip-replace-overlay 'priority vip-replace-overlay-priority))
75551c46 574 (if (vip-window-display-p)
6c2e12f4
KH
575 (vip-overlay-put vip-replace-overlay 'face vip-replace-overlay-face))
576 (vip-save-cursor-color)
577 (vip-change-cursor-color vip-replace-overlay-cursor-color)
578 )
579
dd7c19d4 580
6c2e12f4
KH
581
582(defsubst vip-hide-replace-overlay ()
75551c46 583 (vip-set-replace-overlay-glyphs nil nil)
6c2e12f4 584 (vip-restore-cursor-color)
75551c46 585 (if (vip-window-display-p)
6c2e12f4 586 (vip-overlay-put vip-replace-overlay 'face nil)))
75551c46
KH
587
588(defsubst vip-set-replace-overlay-glyphs (before-glyph after-glyph)
589 (if (or (not (vip-window-display-p))
590 vip-use-replace-region-delimiters)
591 (let ((before-name (if vip-xemacs-p 'begin-glyph 'before-string))
592 (after-name (if vip-xemacs-p 'end-glyph 'after-string)))
593 (vip-overlay-put vip-replace-overlay before-name before-glyph)
594 (vip-overlay-put vip-replace-overlay after-name after-glyph))))
6c2e12f4
KH
595
596
597(defsubst vip-replace-start ()
598 (vip-overlay-get vip-replace-overlay 'vip-start))
599(defsubst vip-replace-end ()
600 (vip-overlay-get vip-replace-overlay 'vip-end))
601
602(defsubst vip-move-replace-overlay (beg end)
603 (vip-move-overlay vip-replace-overlay beg end)
604 (move-marker (vip-replace-start) (vip-overlay-start vip-replace-overlay))
605 (move-marker (vip-replace-end) (vip-overlay-end vip-replace-overlay)))
606
607
608;; Minibuffer
609
610(defun vip-set-minibuffer-overlay ()
611 (vip-check-minibuffer-overlay)
612 ;; We always move the minibuffer overlay, since in XEmacs
613 ;; this overlay may get detached. Moving will reattach it.
75551c46
KH
614 ;; This overlay is also moved via the vip-post-command-hook,
615 ;; to insure that it covers the whole minibuffer.
6c2e12f4 616 (vip-move-minibuffer-overlay)
75551c46 617 (if (vip-window-display-p)
6c2e12f4
KH
618 (progn
619 (vip-overlay-put
620 vip-minibuffer-overlay 'face vip-minibuffer-current-face)
621 (vip-overlay-put
622 vip-minibuffer-overlay 'priority vip-minibuffer-overlay-priority))
623 ))
624
625(defun vip-check-minibuffer-overlay ()
626 (if (vip-overlay-p vip-minibuffer-overlay)
627 ()
628 (setq vip-minibuffer-overlay
629 (vip-make-overlay 1 (1+ (buffer-size)) (current-buffer)))))
630
631;; arguments to this function are dummies. they are needed just because
632;; it is used as a insert-in-front-hook to vip-minibuffer-overlay, and such
633;; hooks require 3 arguments.
634(defun vip-move-minibuffer-overlay (&optional overl beg end)
635 (if (vip-is-in-minibuffer)
636 (progn
637 (vip-check-minibuffer-overlay)
638 (vip-move-overlay vip-minibuffer-overlay 1 (1+ (buffer-size))))))
639
640(defsubst vip-is-in-minibuffer ()
641 (string-match "\*Minibuf-" (buffer-name)))
642
643
644\f
645;;; XEmacs compatibility
646
dd7c19d4 647;; Sit for VAL milliseconds. XEmacs doesn't support the millisecond arg
75551c46 648;; in sit-for, so this function smoothes out the differences.
6c2e12f4
KH
649(defsubst vip-sit-for-short (val &optional nodisp)
650 (if vip-xemacs-p
651 (sit-for (/ val 1000.0) nodisp)
652 (sit-for 0 val nodisp)))
653
654;; EVENT may be a single event of a sequence of events
655(defsubst vip-ESC-event-p (event)
656 (let ((ESC-keys '(?\e (control \[) escape))
657 (key (vip-event-key event)))
658 (member key ESC-keys)))
659
660;; like (set-mark-command nil) but doesn't push twice, if (car mark-ring)
661;; is the same as (mark t).
662(defsubst vip-set-mark-if-necessary ()
663 (setq mark-ring (delete (vip-mark-marker) mark-ring))
664 (set-mark-command nil))
665
666(defsubst vip-mark-marker ()
667 (if vip-xemacs-p
668 (mark-marker t)
669 (mark-marker)))
670
671;; In transient mark mode (zmacs mode), it is annoying when regions become
672;; highlighted due to Viper's pushing marks. So, we deactivate marks, unless
673;; the user explicitly wants highlighting, e.g., by hitting '' or ``
674(defun vip-deactivate-mark ()
675 (if vip-xemacs-p
676 (zmacs-deactivate-region)
677 (deactivate-mark)))
678
dd7c19d4
MK
679(defsubst vip-leave-region-active ()
680 (if vip-xemacs-p
681 (setq zmacs-region-stays t)))
682
6c2e12f4
KH
683
684(defsubst vip-events-to-keys (events)
685 (cond (vip-xemacs-p (events-to-keys events))
686 (t events)))
687
688
689(defun vip-eval-after-load (file form)
690 (if vip-emacs-p
691 (eval-after-load file form)
692 (or (assoc file after-load-alist)
693 (setq after-load-alist (cons (list file) after-load-alist)))
694 (let ((elt (assoc file after-load-alist)))
695 (or (member form (cdr elt))
696 (setq elt (nconc elt (list form)))))
697 form
698 ))
4702a420
MK
699
700;; This is here because Emacs changed the way local hooks work.
701;;
702;;Add to the value of HOOK the function FUNCTION.
703;;FUNCTION is not added if already present.
704;;FUNCTION is added (if necessary) at the beginning of the hook list
705;;unless the optional argument APPEND is non-nil, in which case
706;;FUNCTION is added at the end.
707;;
708;;HOOK should be a symbol, and FUNCTION may be any valid function. If
709;;HOOK is void, it is first set to nil. If HOOK's value is a single
710;;function, it is changed to a list of functions."
711(defun vip-add-hook (hook function &optional append)
712 (if (not (boundp hook)) (set hook nil))
713 ;; If the hook value is a single function, turn it into a list.
714 (let ((old (symbol-value hook)))
715 (if (or (not (listp old)) (eq (car old) 'lambda))
716 (setq old (list old)))
717 (if (member function old)
718 nil
719 (set hook (if append
720 (append old (list function)) ; don't nconc
721 (cons function old))))))
722
723;; This is here because of Emacs's changes in the semantics of add/remove-hooks
724;; and due to the bugs they introduced.
725;;
726;; Remove from the value of HOOK the function FUNCTION.
727;; HOOK should be a symbol, and FUNCTION may be any valid function. If
728;; FUNCTION isn't the value of HOOK, or, if FUNCTION doesn't appear in the
729;; list of hooks to run in HOOK, then nothing is done. See `vip-add-hook'."
730(defun vip-remove-hook (hook function)
731 (if (or (not (boundp hook)) ;unbound symbol, or
732 (null (symbol-value hook)) ;value is nil, or
733 (null function)) ;function is nil, then
734 nil ;Do nothing.
735 (let ((hook-value (symbol-value hook)))
736 (if (consp hook-value)
737 ;; don't side-effect the list
738 (setq hook-value (delete function (copy-sequence hook-value)))
739 (if (equal hook-value function)
740 (setq hook-value nil)))
741 (set hook hook-value))))
742
6c2e12f4
KH
743
744
745;; like read-event, but in XEmacs also try to convert to char, if possible
746(defun vip-read-event-convert-to-char ()
747 (let (event)
748 (if vip-emacs-p
749 (read-event)
750 (setq event (next-command-event))
751 (or (event-to-character event)
752 event))
753 ))
754
4702a420
MK
755;; This function lets function-key-map convert key sequences into logical
756;; keys. This does a better job than vip-read-event when it comes to kbd
757;; macros, since it enables certain macros to be shared between X and TTY
758;; modes.
759(defun vip-read-key ()
760 (let ((overriding-local-map vip-overriding-map)
761 key)
762 (use-global-map vip-overriding-map)
763 (setq key (elt (read-key-sequence nil) 0))
764 (use-global-map global-map)
765 key))
766
6c2e12f4 767
75551c46 768;; Emacs has a bug in eventp, which causes (eventp nil) to return (nil)
a7acbbe4 769;; instead of nil, if '(nil) was previously inadvertently assigned to
6c2e12f4
KH
770;; unread-command-events
771(defun vip-event-key (event)
772 (or (and event (eventp event))
773 (error "vip-event-key: Wrong type argument, eventp, %S" event))
774 (let ((mod (event-modifiers event))
775 basis)
776 (setq basis
777 (cond
778 (vip-xemacs-p
779 (cond ((key-press-event-p event)
780 (event-key event))
781 ((button-event-p event)
75551c46 782 (concat "mouse-" (prin1-to-string (event-button event))))
6c2e12f4
KH
783 (t
784 (error "vip-event-key: Unknown event, %S" event))))
785 (t
786 ;; Emacs doesn't handle capital letters correctly, since
787 ;; \S-a isn't considered the same as A (it behaves as
788 ;; plain `a' instead). So we take care of this here
75551c46
KH
789 (cond ((and (numberp event) (<= ?A event) (<= event ?Z))
790 (setq mod nil
791 event event))
792 ;; Emacs has the oddity whereby characters 128+char
793 ;; represent M-char *if* this appears inside a string.
794 ;; So, we convert them manually into (mata char).
795 ((and (numberp event) (< ?\C-? event) (<= event 255))
796 (setq mod '(meta)
797 event (- event ?\C-? 1)))
798 (t (event-basic-type event)))
799 )))
6c2e12f4
KH
800
801 (if (numberp basis)
802 (setq basis
803 (if (= basis ?\C-?)
804 (list 'control '\?) ; taking care of an emacs bug
805 (intern (char-to-string basis)))))
806
807 (if mod
808 (append mod (list basis))
809 basis)
810 ))
811
812(defun vip-key-to-emacs-key (key)
813 (let (key-name char-p modifiers mod-char-list base-key base-key-name)
814 (cond (vip-xemacs-p key)
815 ((symbolp key)
816 (setq key-name (symbol-name key))
817 (if (= (length key-name) 1) ; character event
818 (string-to-char key-name)
819 key))
820 ((listp key)
821 (setq modifiers (subseq key 0 (1- (length key)))
822 base-key (vip-seq-last-elt key)
823 base-key-name (symbol-name base-key)
824 char-p (= (length base-key-name) 1))
825 (setq mod-char-list
826 (mapcar
827 '(lambda (elt) (upcase (substring (symbol-name elt) 0 1)))
828 modifiers))
829 (if char-p
830 (setq key-name
831 (car (read-from-string
832 (concat
833 "?\\"
834 (mapconcat 'identity mod-char-list "-\\")
835 "-"
836 base-key-name))))
837 (setq key-name
838 (intern
839 (concat
840 (mapconcat 'identity mod-char-list "-")
841 "-"
842 base-key-name))))))
843 ))
844
845
846;; Args can be a sequence of events, a string, or a Viper macro. Will try to
847;; convert events to keys and, if all keys are regular printable
848;; characters, will return a string. Otherwise, will return a string
849;; representing a vector of converted events. If the input was a Viper macro,
850;; will return a string that represents this macro as a vector.
851(defun vip-array-to-string (event-seq &optional representation)
852 (let (temp)
853 (cond ((stringp event-seq) event-seq)
854 ((vip-event-vector-p event-seq)
855 (setq temp (mapcar 'vip-event-key event-seq))
856 (if (vip-char-symbol-sequence-p temp)
857 (mapconcat 'symbol-name temp "")
858 (prin1-to-string (vconcat temp))))
859 ((vip-char-symbol-sequence-p event-seq)
860 (mapconcat 'symbol-name event-seq ""))
861 (t (prin1-to-string event-seq)))))
e0c82342
MK
862
863(defun vip-key-press-events-to-chars (events)
864 (mapconcat (if vip-emacs-p
865 'char-to-string
866 (function
867 (lambda (elt) (char-to-string (event-to-character elt)))))
868 events
869 ""))
6c2e12f4
KH
870
871
872(defsubst vip-fast-keysequence-p ()
873 (not (vip-sit-for-short vip-fast-keyseq-timeout t)))
874
875(defun vip-read-char-exclusive ()
876 (let (char
877 (echo-keystrokes 1))
878 (while (null char)
879 (condition-case nil
880 (setq char (read-char))
881 (error
882 ;; skip event if not char
883 (vip-read-event))))
884 char))
885
886
887
888(defun vip-setup-master-buffer (&rest other-files-or-buffers)
889 "Set up the current buffer as a master buffer.
890Arguments become related buffers. This function should normally be used in
891the `Local variables' section of a file."
892 (setq vip-related-files-and-buffers-ring
893 (make-ring (1+ (length other-files-or-buffers))))
894 (mapcar '(lambda (elt)
895 (vip-ring-insert vip-related-files-and-buffers-ring elt))
896 other-files-or-buffers)
897 (vip-ring-insert vip-related-files-and-buffers-ring (buffer-name))
898 )
e0c82342
MK
899
900;;; Movement utilities
901
902(defvar vip-syntax-preference 'strict-vi
903 "*Syntax type characterizing Viper's alphanumeric symbols.
904`emacs' means only word constituents are considered to be alphanumeric.
905Word constituents are symbols specified as word constituents by the current
906syntax table.
907`extended' means word and symbol constituents.
908`reformed-vi' means Vi-ish behavior: word constituents and the symbol `_'.
909However, word constituents are determined according to Emacs syntax tables,
910which may be different from Vi in some major modes.
911`strict-vi' means Viper words are exactly as in Vi.")
912
913(vip-deflocalvar vip-ALPHA-char-class "w"
914 "String of syntax classes characterizing Viper's alphanumeric symbols.
915In addition, the symbol `_' may be considered alphanumeric if
916`vip-syntax-preference'is `reformed-vi'.")
917
918(vip-deflocalvar vip-strict-ALPHA-chars "a-zA-Z0-9_"
919 "Regexp matching the set of alphanumeric characters acceptable to strict
920Vi.")
921(vip-deflocalvar vip-strict-SEP-chars " \t\n"
922 "Regexp matching the set of alphanumeric characters acceptable to strict
923Vi.")
924
925(vip-deflocalvar vip-SEP-char-class " -"
926 "String of syntax classes for Vi separators.
927Usually contains ` ', linefeed, TAB or formfeed.")
928
929(defun vip-update-alphanumeric-class ()
930 "Set the syntactic class of Viper alphanumeric symbols according to
931the variable `vip-ALPHA-char-class'. Should be called in order for changes to
932`vip-ALPHA-char-class' to take effect."
933 (interactive)
934 (setq-default
935 vip-ALPHA-char-class
936 (cond ((eq vip-syntax-preference 'emacs) "w") ; only word constituents
937 ((eq vip-syntax-preference 'extended) "w_") ; word & symbol chars
938 (t "w")))) ; vi syntax: word constituents and the symbol `_'
939
940;; addl-chars are characters to be temporarily considered as alphanumerical
941(defun vip-looking-at-alpha (&optional addl-chars)
942 (or (stringp addl-chars) (setq addl-chars ""))
943 (if (eq vip-syntax-preference 'reformed-vi)
944 (setq addl-chars (concat addl-chars "_")))
945 (let ((char (char-after (point))))
946 (if char
947 (if (eq vip-syntax-preference 'strict-vi)
948 (looking-at (concat "[" vip-strict-ALPHA-chars addl-chars "]"))
949 (or (memq char
950 ;; convert string to list
951 (append (vconcat addl-chars) nil))
952 (memq (char-syntax char)
953 (append (vconcat vip-ALPHA-char-class) nil)))))
954 ))
955
956(defsubst vip-looking-at-separator ()
957 (let ((char (char-after (point))))
958 (if char
959 (or (eq char ?\n) ; RET is always a separator in Vi
960 (memq (char-syntax char)
961 (append (vconcat vip-SEP-char-class) nil))))))
962
963(defsubst vip-looking-at-alphasep (&optional addl-chars)
964 (or (vip-looking-at-separator) (vip-looking-at-alpha addl-chars)))
965
966(defsubst vip-skip-alpha-forward (&optional addl-chars)
967 (or (stringp addl-chars) (setq addl-chars ""))
968 (vip-skip-syntax
969 'forward
970 (cond ((eq vip-syntax-preference 'strict-vi)
971 "")
972 (t vip-ALPHA-char-class ))
973 (cond ((eq vip-syntax-preference 'strict-vi)
974 (concat vip-strict-ALPHA-chars addl-chars))
975 (t addl-chars))))
976
977(defsubst vip-skip-alpha-backward (&optional addl-chars)
978 (or (stringp addl-chars) (setq addl-chars ""))
979 (vip-skip-syntax
980 'backward
981 (cond ((eq vip-syntax-preference 'strict-vi)
982 "")
983 (t vip-ALPHA-char-class ))
984 (cond ((eq vip-syntax-preference 'strict-vi)
985 (concat vip-strict-ALPHA-chars addl-chars))
986 (t addl-chars))))
987
988;; weird syntax tables may confuse strict-vi style
989(defsubst vip-skip-all-separators-forward (&optional within-line)
990 (vip-skip-syntax 'forward
991 vip-SEP-char-class
992 (or within-line "\n")
993 (if within-line (vip-line-pos 'end))))
994(defsubst vip-skip-all-separators-backward (&optional within-line)
995 (vip-skip-syntax 'backward
996 vip-SEP-char-class
997 (or within-line "\n")
998 (if within-line (vip-line-pos 'start))))
999(defun vip-skip-nonseparators (direction)
1000 (let ((func (intern (format "skip-syntax-%S" direction))))
1001 (funcall func (concat "^" vip-SEP-char-class)
1002 (vip-line-pos (if (eq direction 'forward) 'end 'start)))))
1003
1004(defsubst vip-skip-nonalphasep-forward ()
1005 (if (eq vip-syntax-preference 'strict-vi)
1006 (skip-chars-forward
1007 (concat "^" vip-strict-SEP-chars vip-strict-ALPHA-chars))
1008 (skip-syntax-forward
1009 (concat
1010 "^" vip-ALPHA-char-class vip-SEP-char-class) (vip-line-pos 'end))))
1011(defsubst vip-skip-nonalphasep-backward ()
1012 (if (eq vip-syntax-preference 'strict-vi)
1013 (skip-chars-backward
1014 (concat "^" vip-strict-SEP-chars vip-strict-ALPHA-chars))
1015 (skip-syntax-backward
1016 (concat
1017 "^" vip-ALPHA-char-class vip-SEP-char-class) (vip-line-pos 'start))))
1018
1019;; Skip SYNTAX like skip-syntax-* and ADDL-CHARS like skip-chars-*
1020;; Return the number of chars traveled.
1021;; Either SYNTAX or ADDL-CHARS can be nil, in which case they are interpreted
1022;; as an empty string.
1023(defun vip-skip-syntax (direction syntax addl-chars &optional limit)
1024 (let ((total 0)
1025 (local 1)
1026 (skip-chars-func (intern (format "skip-chars-%S" direction)))
1027 (skip-syntax-func (intern (format "skip-syntax-%S" direction))))
1028 (or (stringp addl-chars) (setq addl-chars ""))
1029 (or (stringp syntax) (setq syntax ""))
1030 (while (and (not (= local 0)) (not (eobp)))
1031 (setq local
1032 (+ (funcall skip-syntax-func syntax limit)
1033 (funcall skip-chars-func addl-chars limit)))
1034 (setq total (+ total local)))
1035 total
1036 ))
1037
1038
6c2e12f4
KH
1039
1040
1041(provide 'viper-util)
1042
1043;;; viper-util.el ends here