viper-util.el 53 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558
  1. ;;; viper-util.el --- Utilities used by viper.el
  2. ;; Copyright (C) 1994-1997, 1999-2012 Free Software Foundation, Inc.
  3. ;; Author: Michael Kifer <kifer@cs.stonybrook.edu>
  4. ;; Package: viper
  5. ;; This file is part of GNU Emacs.
  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 3 of the License, or
  9. ;; (at your option) any later version.
  10. ;; GNU Emacs is distributed in the hope that it will be useful,
  11. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ;; GNU General Public License for more details.
  14. ;; You should have received a copy of the GNU General Public License
  15. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
  16. ;;; Commentary:
  17. ;;; Code:
  18. (provide 'viper-util)
  19. ;; Compiler pacifier
  20. (defvar viper-overriding-map)
  21. (defvar pm-color-alist)
  22. (defvar viper-minibuffer-current-face)
  23. (defvar viper-minibuffer-insert-face)
  24. (defvar viper-minibuffer-vi-face)
  25. (defvar viper-minibuffer-emacs-face)
  26. (defvar viper-replace-overlay-face)
  27. (defvar viper-fast-keyseq-timeout)
  28. (defvar ex-unix-type-shell)
  29. (defvar ex-unix-type-shell-options)
  30. (defvar viper-ex-tmp-buf-name)
  31. (defvar viper-syntax-preference)
  32. (defvar viper-saved-mark)
  33. (require 'ring)
  34. (eval-and-compile
  35. (unless (fboundp 'declare-function) (defmacro declare-function (&rest r))))
  36. ;; end pacifier
  37. (require 'viper-init)
  38. (defalias 'viper-overlay-p
  39. (if (featurep 'xemacs) 'extentp 'overlayp))
  40. (defalias 'viper-make-overlay
  41. (if (featurep 'xemacs) 'make-extent 'make-overlay))
  42. (defalias 'viper-overlay-live-p
  43. (if (featurep 'xemacs) 'extent-live-p 'overlayp))
  44. (defalias 'viper-move-overlay
  45. (if (featurep 'xemacs) 'set-extent-endpoints 'move-overlay))
  46. (defalias 'viper-overlay-start
  47. (if (featurep 'xemacs) 'extent-start-position 'overlay-start))
  48. (defalias 'viper-overlay-end
  49. (if (featurep 'xemacs) 'extent-end-position 'overlay-end))
  50. (defalias 'viper-overlay-get
  51. (if (featurep 'xemacs) 'extent-property 'overlay-get))
  52. (defalias 'viper-overlay-put
  53. (if (featurep 'xemacs) 'set-extent-property 'overlay-put))
  54. (defalias 'viper-read-event
  55. (if (featurep 'xemacs) 'next-command-event 'read-event))
  56. (defalias 'viper-characterp
  57. (if (featurep 'xemacs) 'characterp 'integerp))
  58. (defalias 'viper-int-to-char
  59. (if (featurep 'xemacs) 'int-to-char 'identity))
  60. (defalias 'viper-get-face
  61. (if (featurep 'xemacs) 'get-face 'facep))
  62. (defalias 'viper-color-defined-p
  63. (if (featurep 'xemacs) 'valid-color-name-p 'x-color-defined-p))
  64. (defalias 'viper-iconify
  65. (if (featurep 'xemacs) 'iconify-frame 'iconify-or-deiconify-frame))
  66. ;; CHAR is supposed to be a char or an integer (positive or negative)
  67. ;; LIST is a list of chars, nil, and negative numbers
  68. ;; Check if CHAR is a member by trying to convert in characters, if necessary.
  69. ;; Introduced for compatibility with XEmacs, where integers are not the same as
  70. ;; chars.
  71. (defun viper-memq-char (char list)
  72. (cond ((and (integerp char) (>= char 0))
  73. (memq (viper-int-to-char char) list))
  74. ((memq char list))))
  75. ;; Check if char-or-int and char are the same as characters
  76. (defun viper-char-equal (char-or-int char)
  77. (cond ((and (integerp char-or-int) (>= char-or-int 0))
  78. (= (viper-int-to-char char-or-int) char))
  79. ((eq char-or-int char))))
  80. ;; Like =, but accommodates null and also is t for eq-objects
  81. (defun viper= (char char1)
  82. (cond ((eq char char1) t)
  83. ((and (viper-characterp char) (viper-characterp char1))
  84. (= char char1))
  85. (t nil)))
  86. (defsubst viper-color-display-p ()
  87. (if (featurep 'xemacs) (eq (device-class (selected-device)) 'color)
  88. (x-display-color-p)))
  89. (defun viper-get-cursor-color (&optional frame)
  90. (if (featurep 'xemacs)
  91. (color-instance-name
  92. (frame-property (or frame (selected-frame)) 'cursor-color))
  93. (cdr (assoc 'cursor-color (frame-parameters)))))
  94. (defmacro viper-frame-value (variable)
  95. "Return the value of VARIABLE local to the current frame, if there is one.
  96. Otherwise return the normal value."
  97. `(if (featurep 'xemacs)
  98. ,variable
  99. ;; Frame-local variables are obsolete from Emacs 22.2 onwards,
  100. ;; so we do it by hand instead.
  101. ;; Buffer-local values take precedence over frame-local ones.
  102. (if (local-variable-p ',variable)
  103. ,variable
  104. ;; Distinguish between no frame parameter and a frame parameter
  105. ;; with a value of nil.
  106. (let ((fp (assoc ',variable (frame-parameters))))
  107. (if fp (cdr fp)
  108. ,variable)))))
  109. ;; OS/2
  110. (cond ((eq (viper-device-type) 'pm)
  111. (fset 'viper-color-defined-p
  112. (lambda (color) (assoc color pm-color-alist)))))
  113. ;; cursor colors
  114. (defun viper-change-cursor-color (new-color &optional frame)
  115. (if (and (viper-window-display-p) (viper-color-display-p)
  116. (stringp new-color) (viper-color-defined-p new-color)
  117. (not (string= new-color (viper-get-cursor-color))))
  118. (if (featurep 'xemacs)
  119. (set-frame-property
  120. (or frame (selected-frame))
  121. 'cursor-color (make-color-instance new-color))
  122. (modify-frame-parameters
  123. (or frame (selected-frame))
  124. (list (cons 'cursor-color new-color))))))
  125. ;; Note that the colors this function uses might not be those
  126. ;; associated with FRAME, if there are frame-local values.
  127. ;; This was equally true before the advent of viper-frame-value.
  128. ;; Now it could be changed by passing frame to v-f-v.
  129. (defun viper-set-cursor-color-according-to-state (&optional frame)
  130. (cond ((eq viper-current-state 'replace-state)
  131. (viper-change-cursor-color
  132. (viper-frame-value viper-replace-overlay-cursor-color)
  133. frame))
  134. ((and (eq viper-current-state 'emacs-state)
  135. (viper-frame-value viper-emacs-state-cursor-color))
  136. (viper-change-cursor-color
  137. (viper-frame-value viper-emacs-state-cursor-color)
  138. frame))
  139. ((eq viper-current-state 'insert-state)
  140. (viper-change-cursor-color
  141. (viper-frame-value viper-insert-state-cursor-color)
  142. frame))
  143. (t
  144. (viper-change-cursor-color
  145. (viper-frame-value viper-vi-state-cursor-color)
  146. frame))))
  147. ;; By default, saves current frame cursor color before changing viper state
  148. (defun viper-save-cursor-color (before-which-mode)
  149. (if (and (viper-window-display-p) (viper-color-display-p))
  150. (let ((color (viper-get-cursor-color)))
  151. (if (and (stringp color) (viper-color-defined-p color)
  152. ;; there is something fishy in that the color is not saved if
  153. ;; it is the same as frames default cursor color. need to be
  154. ;; checked.
  155. (not (string= color
  156. (viper-frame-value
  157. viper-replace-overlay-cursor-color))))
  158. (modify-frame-parameters
  159. (selected-frame)
  160. (list
  161. (cons
  162. (cond ((eq before-which-mode 'before-replace-mode)
  163. 'viper-saved-cursor-color-in-replace-mode)
  164. ((eq before-which-mode 'before-emacs-mode)
  165. 'viper-saved-cursor-color-in-emacs-mode)
  166. (t
  167. 'viper-saved-cursor-color-in-insert-mode))
  168. color)))))))
  169. (defun viper-get-saved-cursor-color-in-replace-mode ()
  170. (or
  171. (funcall
  172. (if (featurep 'emacs) 'frame-parameter 'frame-property)
  173. (selected-frame)
  174. 'viper-saved-cursor-color-in-replace-mode)
  175. (or (and (eq viper-current-state 'emacs-mode)
  176. (viper-frame-value viper-emacs-state-cursor-color))
  177. (viper-frame-value viper-vi-state-cursor-color))))
  178. (defun viper-get-saved-cursor-color-in-insert-mode ()
  179. (or
  180. (funcall
  181. (if (featurep 'emacs) 'frame-parameter 'frame-property)
  182. (selected-frame)
  183. 'viper-saved-cursor-color-in-insert-mode)
  184. (or (and (eq viper-current-state 'emacs-mode)
  185. (viper-frame-value viper-emacs-state-cursor-color))
  186. (viper-frame-value viper-vi-state-cursor-color))))
  187. (defun viper-get-saved-cursor-color-in-emacs-mode ()
  188. (or
  189. (funcall
  190. (if (featurep 'emacs) 'frame-parameter 'frame-property)
  191. (selected-frame)
  192. 'viper-saved-cursor-color-in-emacs-mode)
  193. (viper-frame-value viper-vi-state-cursor-color)))
  194. ;; restore cursor color from replace overlay
  195. (defun viper-restore-cursor-color(after-which-mode)
  196. (if (viper-overlay-p viper-replace-overlay)
  197. (viper-change-cursor-color
  198. (cond ((eq after-which-mode 'after-replace-mode)
  199. (viper-get-saved-cursor-color-in-replace-mode))
  200. ((eq after-which-mode 'after-emacs-mode)
  201. (viper-get-saved-cursor-color-in-emacs-mode))
  202. (t (viper-get-saved-cursor-color-in-insert-mode)))
  203. )))
  204. ;; Check the current version against the major and minor version numbers
  205. ;; using op: cur-vers op major.minor If emacs-major-version or
  206. ;; emacs-minor-version are not defined, we assume that the current version
  207. ;; is hopelessly outdated. We assume that emacs-major-version and
  208. ;; emacs-minor-version are defined. Otherwise, for Emacs/XEmacs 19, if the
  209. ;; current minor version is < 10 (xemacs) or < 23 (emacs) the return value
  210. ;; will be nil (when op is =, >, or >=) and t (when op is <, <=), which may be
  211. ;; incorrect. However, this gives correct result in our cases, since we are
  212. ;; testing for sufficiently high Emacs versions.
  213. (defun viper-check-version (op major minor &optional type-of-emacs)
  214. (if (and (boundp 'emacs-major-version) (boundp 'emacs-minor-version))
  215. (and (cond ((eq type-of-emacs 'xemacs) (featurep 'xemacs))
  216. ((eq type-of-emacs 'emacs) (featurep 'emacs))
  217. (t t))
  218. (cond ((eq op '=) (and (= emacs-minor-version minor)
  219. (= emacs-major-version major)))
  220. ((memq op '(> >= < <=))
  221. (and (or (funcall op emacs-major-version major)
  222. (= emacs-major-version major))
  223. (if (= emacs-major-version major)
  224. (funcall op emacs-minor-version minor)
  225. t)))
  226. (t
  227. (error "%S: Invalid op in viper-check-version" op))))
  228. (cond ((memq op '(= > >=)) nil)
  229. ((memq op '(< <=)) t))))
  230. (defun viper-get-visible-buffer-window (wind)
  231. (if (featurep 'xemacs)
  232. (get-buffer-window wind t)
  233. (get-buffer-window wind 'visible)))
  234. ;; Return line position.
  235. ;; If pos is 'start then returns position of line start.
  236. ;; If pos is 'end, returns line end. If pos is 'mid, returns line center.
  237. ;; Pos = 'indent returns beginning of indentation.
  238. ;; Otherwise, returns point. Current point is not moved in any case."
  239. (defun viper-line-pos (pos)
  240. (let ((cur-pos (point))
  241. (result))
  242. (cond
  243. ((equal pos 'start)
  244. (beginning-of-line))
  245. ((equal pos 'end)
  246. (end-of-line))
  247. ((equal pos 'mid)
  248. (goto-char (+ (viper-line-pos 'start) (viper-line-pos 'end) 2)))
  249. ((equal pos 'indent)
  250. (back-to-indentation))
  251. (t nil))
  252. (setq result (point))
  253. (goto-char cur-pos)
  254. result))
  255. ;; Emacs used to count each multibyte character as several positions in the buffer,
  256. ;; so we had to use Emacs's chars-in-region to count characters. Since 20.3,
  257. ;; Emacs counts multibyte characters as 1 position. XEmacs has always been
  258. ;; counting each char as just one pos. So, now we can simply subtract beg from
  259. ;; end to determine the number of characters in a region.
  260. (defun viper-chars-in-region (beg end &optional preserve-sign)
  261. ;;(let ((count (abs (if (fboundp 'chars-in-region)
  262. ;; (chars-in-region beg end)
  263. ;; (- end beg)))))
  264. (let ((count (abs (- end beg))))
  265. (if (and (< end beg) preserve-sign)
  266. (- count)
  267. count)))
  268. ;; Test if POS is between BEG and END
  269. (defsubst viper-pos-within-region (pos beg end)
  270. (and (>= pos (min beg end)) (>= (max beg end) pos)))
  271. ;; Like move-marker but creates a virgin marker if arg isn't already a marker.
  272. ;; The first argument must eval to a variable name.
  273. ;; Arguments: (var-name position &optional buffer).
  274. ;;
  275. ;; This is useful for moving markers that are supposed to be local.
  276. ;; For this, VAR-NAME should be made buffer-local with nil as a default.
  277. ;; Then, each time this var is used in `viper-move-marker-locally' in a new
  278. ;; buffer, a new marker will be created.
  279. (defun viper-move-marker-locally (var pos &optional buffer)
  280. (if (markerp (eval var))
  281. ()
  282. (set var (make-marker)))
  283. (move-marker (eval var) pos buffer))
  284. ;; Print CONDITIONS as a message.
  285. (defun viper-message-conditions (conditions)
  286. (let ((case (car conditions)) (msg (cdr conditions)))
  287. (if (null msg)
  288. (message "%s" case)
  289. (message "%s: %s" case (mapconcat 'prin1-to-string msg " ")))
  290. (beep 1)))
  291. ;;; List/alist utilities
  292. ;; Convert LIST to an alist
  293. (defun viper-list-to-alist (lst)
  294. (let ((alist))
  295. (while lst
  296. (setq alist (cons (list (car lst)) alist))
  297. (setq lst (cdr lst)))
  298. alist))
  299. ;; Convert ALIST to a list.
  300. (defun viper-alist-to-list (alst)
  301. (let ((lst))
  302. (while alst
  303. (setq lst (cons (car (car alst)) lst))
  304. (setq alst (cdr alst)))
  305. lst))
  306. ;; Filter ALIST using REGEXP. Return alist whose elements match the regexp.
  307. (defun viper-filter-alist (regexp alst)
  308. (interactive "s x")
  309. (let ((outalst) (inalst alst))
  310. (while (car inalst)
  311. (if (string-match regexp (car (car inalst)))
  312. (setq outalst (cons (car inalst) outalst)))
  313. (setq inalst (cdr inalst)))
  314. outalst))
  315. ;; Filter LIST using REGEXP. Return list whose elements match the regexp.
  316. (defun viper-filter-list (regexp lst)
  317. (interactive "s x")
  318. (let ((outlst) (inlst lst))
  319. (while (car inlst)
  320. (if (string-match regexp (car inlst))
  321. (setq outlst (cons (car inlst) outlst)))
  322. (setq inlst (cdr inlst)))
  323. outlst))
  324. ;; Append LIS2 to LIS1, both alists, by side-effect and returns LIS1
  325. ;; LIS2 is modified by filtering it: deleting its members of the form
  326. ;; \(car elt\) such that (car elt') is in LIS1.
  327. (defun viper-append-filter-alist (lis1 lis2)
  328. (let ((temp lis1)
  329. elt)
  330. ;;filter-append the second list
  331. (while temp
  332. ;; delete all occurrences
  333. (while (setq elt (assoc (car (car temp)) lis2))
  334. (setq lis2 (delq elt lis2)))
  335. (setq temp (cdr temp)))
  336. (append lis1 lis2)))
  337. (declare-function viper-forward-Word "viper-cmd" (arg))
  338. ;;; Support for :e, :r, :w file globbing
  339. ;; Glob the file spec.
  340. ;; This function is designed to work under Unix.
  341. (defun viper-glob-unix-files (filespec)
  342. (let ((gshell
  343. (cond (ex-unix-type-shell shell-file-name)
  344. (t "sh"))) ; probably Unix anyway
  345. (gshell-options
  346. ;; using cond in anticipation of further additions
  347. (cond (ex-unix-type-shell-options)
  348. ))
  349. (command (cond (viper-ms-style-os-p (format "\"ls -1 -d %s\"" filespec))
  350. (t (format "ls -1 -d %s" filespec))))
  351. status)
  352. (with-current-buffer (get-buffer-create viper-ex-tmp-buf-name)
  353. (erase-buffer)
  354. (setq status
  355. (if gshell-options
  356. (call-process gshell nil t nil
  357. gshell-options
  358. "-c"
  359. command)
  360. (call-process gshell nil t nil
  361. "-c"
  362. command)))
  363. (goto-char (point-min))
  364. ;; Issue an error, if no match.
  365. (unless (eq 0 status)
  366. (save-excursion
  367. (skip-chars-forward " \t\n\j")
  368. (if (looking-at "ls:")
  369. (viper-forward-Word 1))
  370. (error "%s: %s"
  371. (if (stringp gshell)
  372. gshell
  373. "shell")
  374. (buffer-substring (point) (viper-line-pos 'end)))
  375. ))
  376. (goto-char (point-min))
  377. (viper-get-filenames-from-buffer 'one-per-line))
  378. ))
  379. ;; Interpret the stuff in the buffer as a list of file names
  380. ;; return a list of file names listed in the buffer beginning at point
  381. ;; If optional arg is supplied, assume each filename is listed on a separate
  382. ;; line
  383. (defun viper-get-filenames-from-buffer (&optional one-per-line)
  384. (let ((skip-chars (if one-per-line "\t\n" " \t\n"))
  385. result fname delim)
  386. (skip-chars-forward skip-chars)
  387. (while (not (eobp))
  388. (if (cond ((looking-at "\"")
  389. (setq delim ?\")
  390. (re-search-forward "[^\"]+" nil t)) ; noerror
  391. ((looking-at "'")
  392. (setq delim ?')
  393. (re-search-forward "[^']+" nil t)) ; noerror
  394. (t
  395. (re-search-forward
  396. (concat "[^" skip-chars "]+") nil t))) ;noerror
  397. (setq fname
  398. (buffer-substring (match-beginning 0) (match-end 0))))
  399. (if delim
  400. (forward-char 1))
  401. (skip-chars-forward " \t\n")
  402. (setq result (cons fname result)))
  403. result))
  404. ;; convert MS-DOS wildcards to regexp
  405. (defun viper-wildcard-to-regexp (wcard)
  406. (with-current-buffer (get-buffer-create viper-ex-tmp-buf-name)
  407. (erase-buffer)
  408. (insert wcard)
  409. (goto-char (point-min))
  410. (while (not (eobp))
  411. (skip-chars-forward "^*?.\\\\")
  412. (cond ((eq (char-after (point)) ?*) (insert ".")(forward-char 1))
  413. ((eq (char-after (point)) ?.) (insert "\\")(forward-char 1))
  414. ((eq (char-after (point)) ?\\) (insert "\\")(forward-char 1))
  415. ((eq (char-after (point)) ??) (delete-char 1)(insert ".")))
  416. )
  417. (buffer-string)
  418. ))
  419. ;; glob windows files
  420. ;; LIST is expected to be in reverse order
  421. (defun viper-glob-mswindows-files (filespec)
  422. (let ((case-fold-search t)
  423. tmp tmp2)
  424. (with-current-buffer (get-buffer-create viper-ex-tmp-buf-name)
  425. (erase-buffer)
  426. (insert filespec)
  427. (goto-char (point-min))
  428. (setq tmp (viper-get-filenames-from-buffer))
  429. (while tmp
  430. (setq tmp2 (cons (directory-files
  431. ;; the directory part
  432. (or (file-name-directory (car tmp))
  433. "")
  434. t ; return full names
  435. ;; the regexp part: globs the file names
  436. (concat "^"
  437. (viper-wildcard-to-regexp
  438. (file-name-nondirectory (car tmp)))
  439. "$"))
  440. tmp2))
  441. (setq tmp (cdr tmp)))
  442. (reverse (apply 'append tmp2)))))
  443. ;;; Insertion ring
  444. ;; Rotate RING's index. DIRection can be positive or negative.
  445. (defun viper-ring-rotate1 (ring dir)
  446. (if (and (ring-p ring) (> (ring-length ring) 0))
  447. (progn
  448. (setcar ring (cond ((> dir 0)
  449. (ring-plus1 (car ring) (ring-length ring)))
  450. ((< dir 0)
  451. (ring-minus1 (car ring) (ring-length ring)))
  452. ;; don't rotate if dir = 0
  453. (t (car ring))))
  454. (viper-current-ring-item ring)
  455. )))
  456. (defun viper-special-ring-rotate1 (ring dir)
  457. (if (memq viper-intermediate-command
  458. '(repeating-display-destructive-command
  459. repeating-insertion-from-ring))
  460. (viper-ring-rotate1 ring dir)
  461. ;; don't rotate otherwise
  462. (viper-ring-rotate1 ring 0)))
  463. ;; current ring item; if N is given, then so many items back from the
  464. ;; current
  465. (defun viper-current-ring-item (ring &optional n)
  466. (setq n (or n 0))
  467. (if (and (ring-p ring) (> (ring-length ring) 0))
  468. (aref (cdr (cdr ring)) (mod (- (car ring) 1 n) (ring-length ring)))))
  469. ;; Push item onto ring. The second argument is a ring-variable, not value.
  470. (defun viper-push-onto-ring (item ring-var)
  471. (or (ring-p (eval ring-var))
  472. (set ring-var (make-ring (eval (intern (format "%S-size" ring-var))))))
  473. (or (null item) ; don't push nil
  474. (and (stringp item) (string= item "")) ; or empty strings
  475. (equal item (viper-current-ring-item (eval ring-var))) ; or old stuff
  476. ;; Since viper-set-destructive-command checks if we are inside
  477. ;; viper-repeat, we don't check whether this-command-keys is a `.'. The
  478. ;; cmd viper-repeat makes a call to the current function only if `.' is
  479. ;; executing a command from the command history. It doesn't call the
  480. ;; push-onto-ring function if `.' is simply repeating the last
  481. ;; destructive command. We only check for ESC (which happens when we do
  482. ;; insert with a prefix argument, or if this-command-keys doesn't give
  483. ;; anything meaningful (in that case we don't know what to show to the
  484. ;; user).
  485. (and (eq ring-var 'viper-command-ring)
  486. (string-match "\\([0-9]*\e\\|^[ \t]*$\\|escape\\)"
  487. (viper-array-to-string (this-command-keys))))
  488. (viper-ring-insert (eval ring-var) item))
  489. )
  490. ;; removing elts from ring seems to break it
  491. (defun viper-cleanup-ring (ring)
  492. (or (< (ring-length ring) 2)
  493. (null (viper-current-ring-item ring))
  494. ;; last and previous equal
  495. (if (equal (viper-current-ring-item ring)
  496. (viper-current-ring-item ring 1))
  497. (viper-ring-pop ring))))
  498. ;; ring-remove seems to be buggy, so we concocted this for our purposes.
  499. (defun viper-ring-pop (ring)
  500. (let* ((ln (ring-length ring))
  501. (vec (cdr (cdr ring)))
  502. (veclen (length vec))
  503. (hd (car ring))
  504. (idx (max 0 (ring-minus1 hd ln)))
  505. (top-elt (aref vec idx)))
  506. ;; shift elements
  507. (while (< (1+ idx) veclen)
  508. (aset vec idx (aref vec (1+ idx)))
  509. (setq idx (1+ idx)))
  510. (aset vec idx nil)
  511. (setq hd (max 0 (ring-minus1 hd ln)))
  512. (if (= hd (1- ln)) (setq hd 0))
  513. (setcar ring hd) ; move head
  514. (setcar (cdr ring) (max 0 (1- ln))) ; adjust length
  515. top-elt
  516. ))
  517. (defun viper-ring-insert (ring item)
  518. (let* ((ln (ring-length ring))
  519. (vec (cdr (cdr ring)))
  520. (veclen (length vec))
  521. (hd (car ring))
  522. (vecpos-after-hd (if (= hd 0) ln hd))
  523. (idx ln))
  524. (if (= ln veclen)
  525. (progn
  526. (aset vec hd item) ; hd is always 1+ the actual head index in vec
  527. (setcar ring (ring-plus1 hd ln)))
  528. (setcar (cdr ring) (1+ ln))
  529. (setcar ring (ring-plus1 vecpos-after-hd (1+ ln)))
  530. (while (and (>= idx vecpos-after-hd) (> ln 0))
  531. (aset vec idx (aref vec (1- idx)))
  532. (setq idx (1- idx)))
  533. (aset vec vecpos-after-hd item))
  534. item))
  535. ;;; String utilities
  536. ;; If STRING is longer than MAX-LEN, truncate it and print ...... instead
  537. ;; PRE-STRING is a string to prepend to the abbrev string.
  538. ;; POST-STRING is a string to append to the abbrev string.
  539. ;; ABBREV_SIGN is a string to be inserted before POST-STRING
  540. ;; if the orig string was truncated.
  541. (defun viper-abbreviate-string (string max-len
  542. pre-string post-string abbrev-sign)
  543. (let (truncated-str)
  544. (setq truncated-str
  545. (if (stringp string)
  546. (substring string 0 (min max-len (length string)))))
  547. (cond ((null truncated-str) "")
  548. ((> (length string) max-len)
  549. (format "%s%s%s%s"
  550. pre-string truncated-str abbrev-sign post-string))
  551. (t (format "%s%s%s" pre-string truncated-str post-string)))))
  552. ;; tells if we are over a whitespace-only line
  553. (defsubst viper-over-whitespace-line ()
  554. (save-excursion
  555. (beginning-of-line)
  556. (looking-at "^[ \t]*$")))
  557. ;;; Saving settings in custom file
  558. ;; Save the current setting of VAR in CUSTOM-FILE.
  559. ;; If given, MESSAGE is a message to be displayed after that.
  560. ;; This message is erased after 2 secs, if erase-msg is non-nil.
  561. ;; Arguments: var message custom-file &optional erase-message
  562. (defun viper-save-setting (var message custom-file &optional erase-msg)
  563. (let* ((var-name (symbol-name var))
  564. (var-val (if (boundp var) (eval var)))
  565. (regexp (format "^[^;]*%s[ \t\n]*[a-zA-Z---_']*[ \t\n)]" var-name))
  566. (buf (find-file-noselect (substitute-in-file-name custom-file)))
  567. )
  568. (message "%s" (or message ""))
  569. (with-current-buffer buf
  570. (goto-char (point-min))
  571. (if (re-search-forward regexp nil t)
  572. (let ((reg-end (1- (match-end 0))))
  573. (search-backward var-name)
  574. (delete-region (match-beginning 0) reg-end)
  575. (goto-char (match-beginning 0))
  576. (insert (format "%s '%S" var-name var-val)))
  577. (goto-char (point-max))
  578. (if (not (bolp)) (insert "\n"))
  579. (insert (format "(setq %s '%S)\n" var-name var-val)))
  580. (save-buffer))
  581. (kill-buffer buf)
  582. (if erase-msg
  583. (progn
  584. (sit-for 2)
  585. (message "")))
  586. ))
  587. ;; Save STRING in CUSTOM-FILE. If PATTERN is non-nil, remove strings that
  588. ;; match this pattern.
  589. (defun viper-save-string-in-file (string custom-file &optional pattern)
  590. (let ((buf (find-file-noselect (substitute-in-file-name custom-file))))
  591. (with-current-buffer buf
  592. (let (buffer-read-only)
  593. (goto-char (point-min))
  594. (if pattern (delete-matching-lines pattern))
  595. (goto-char (point-max))
  596. (if string (insert string))
  597. (save-buffer)))
  598. (kill-buffer buf)
  599. ))
  600. ;; This is a simple-minded check for whether a file is under version control.
  601. ;; If file,v exists but file doesn't, this file is considered to be not checked
  602. ;; in and not checked out for the purpose of patching (since patch won't be
  603. ;; able to read such a file anyway).
  604. ;; FILE is a string representing file name
  605. ;;(defun viper-file-under-version-control (file)
  606. ;; (let* ((filedir (file-name-directory file))
  607. ;; (file-nondir (file-name-nondirectory file))
  608. ;; (trial (concat file-nondir ",v"))
  609. ;; (full-trial (concat filedir trial))
  610. ;; (full-rcs-trial (concat filedir "RCS/" trial)))
  611. ;; (and (stringp file)
  612. ;; (file-exists-p file)
  613. ;; (or
  614. ;; (and
  615. ;; (file-exists-p full-trial)
  616. ;; ;; in FAT FS, `file,v' and `file' may turn out to be the same!
  617. ;; ;; don't be fooled by this!
  618. ;; (not (equal (file-attributes file)
  619. ;; (file-attributes full-trial))))
  620. ;; ;; check if a version is in RCS/ directory
  621. ;; (file-exists-p full-rcs-trial)))
  622. ;; ))
  623. (defsubst viper-file-checked-in-p (file)
  624. (and (featurep 'vc-hooks)
  625. ;; CVS files are considered not checked in
  626. ;; FIXME: Should this deal with more than CVS?
  627. (not (memq (vc-backend file) '(nil CVS)))
  628. (if (fboundp 'vc-state)
  629. (and
  630. (not (memq (vc-state file) '(edited needs-merge)))
  631. (not (stringp (vc-state file))))
  632. ;; XEmacs has no vc-state
  633. (if (featurep 'xemacs) (not (vc-locking-user file))))))
  634. ;; checkout if visited file is checked in
  635. (defun viper-maybe-checkout (buf)
  636. (let ((file (expand-file-name (buffer-file-name buf)))
  637. (checkout-function (key-binding "\C-x\C-q")))
  638. (if (and (viper-file-checked-in-p file)
  639. (or (beep 1) t)
  640. (y-or-n-p
  641. (format
  642. "File %s is checked in. Check it out? "
  643. (viper-abbreviate-file-name file))))
  644. (with-current-buffer buf
  645. (command-execute checkout-function)))))
  646. ;;; Overlays
  647. (defun viper-put-on-search-overlay (beg end)
  648. (if (viper-overlay-p viper-search-overlay)
  649. (viper-move-overlay viper-search-overlay beg end)
  650. (setq viper-search-overlay (viper-make-overlay beg end (current-buffer)))
  651. (viper-overlay-put
  652. viper-search-overlay 'priority viper-search-overlay-priority))
  653. (viper-overlay-put viper-search-overlay 'face viper-search-face))
  654. ;; Search
  655. (defun viper-flash-search-pattern ()
  656. (if (not (viper-has-face-support-p))
  657. nil
  658. (viper-put-on-search-overlay (match-beginning 0) (match-end 0))
  659. (sit-for 2)
  660. (viper-overlay-put viper-search-overlay 'face nil)))
  661. (defun viper-hide-search-overlay ()
  662. (if (not (viper-overlay-p viper-search-overlay))
  663. (progn
  664. (setq viper-search-overlay
  665. (viper-make-overlay (point-min) (point-min) (current-buffer)))
  666. (viper-overlay-put
  667. viper-search-overlay 'priority viper-search-overlay-priority)))
  668. (viper-overlay-put viper-search-overlay 'face nil))
  669. ;; Replace state
  670. (defsubst viper-move-replace-overlay (beg end)
  671. (viper-move-overlay viper-replace-overlay beg end))
  672. (defun viper-set-replace-overlay (beg end)
  673. (if (viper-overlay-live-p viper-replace-overlay)
  674. (viper-move-replace-overlay beg end)
  675. (setq viper-replace-overlay (viper-make-overlay beg end (current-buffer)))
  676. ;; never detach
  677. (viper-overlay-put
  678. viper-replace-overlay (if (featurep 'emacs) 'evaporate 'detachable) nil)
  679. (viper-overlay-put
  680. viper-replace-overlay 'priority viper-replace-overlay-priority)
  681. ;; If Emacs will start supporting overlay maps, as it currently supports
  682. ;; text-property maps, we could do away with viper-replace-minor-mode and
  683. ;; just have keymap attached to replace overlay.
  684. ;;(viper-overlay-put
  685. ;; viper-replace-overlay
  686. ;; (if (featurep 'xemacs) 'keymap 'local-map)
  687. ;; viper-replace-map)
  688. )
  689. (if (viper-has-face-support-p)
  690. (viper-overlay-put
  691. viper-replace-overlay 'face viper-replace-overlay-face))
  692. (viper-save-cursor-color 'before-replace-mode)
  693. (viper-change-cursor-color
  694. (viper-frame-value viper-replace-overlay-cursor-color)))
  695. (defun viper-set-replace-overlay-glyphs (before-glyph after-glyph)
  696. (or (viper-overlay-live-p viper-replace-overlay)
  697. (viper-set-replace-overlay (point-min) (point-min)))
  698. (if (or (not (viper-has-face-support-p))
  699. viper-use-replace-region-delimiters)
  700. (let ((before-name (if (featurep 'xemacs) 'begin-glyph 'before-string))
  701. (after-name (if (featurep 'xemacs) 'end-glyph 'after-string)))
  702. (viper-overlay-put viper-replace-overlay before-name before-glyph)
  703. (viper-overlay-put viper-replace-overlay after-name after-glyph))))
  704. (defun viper-hide-replace-overlay ()
  705. (viper-set-replace-overlay-glyphs nil nil)
  706. (viper-restore-cursor-color 'after-replace-mode)
  707. (viper-restore-cursor-color 'after-insert-mode)
  708. (if (viper-has-face-support-p)
  709. (viper-overlay-put viper-replace-overlay 'face nil)))
  710. (defsubst viper-replace-start ()
  711. (viper-overlay-start viper-replace-overlay))
  712. (defsubst viper-replace-end ()
  713. (viper-overlay-end viper-replace-overlay))
  714. ;; Minibuffer
  715. (defun viper-set-minibuffer-overlay ()
  716. (viper-check-minibuffer-overlay)
  717. (when (viper-has-face-support-p)
  718. (viper-overlay-put
  719. viper-minibuffer-overlay 'face viper-minibuffer-current-face)
  720. (viper-overlay-put
  721. viper-minibuffer-overlay 'priority viper-minibuffer-overlay-priority)
  722. ;; never detach
  723. (viper-overlay-put
  724. viper-minibuffer-overlay
  725. (if (featurep 'emacs) 'evaporate 'detachable)
  726. nil)
  727. ;; make viper-minibuffer-overlay open-ended
  728. ;; In emacs, it is made open ended at creation time
  729. (when (featurep 'xemacs)
  730. (viper-overlay-put viper-minibuffer-overlay 'start-open nil)
  731. (viper-overlay-put viper-minibuffer-overlay 'end-open nil))))
  732. (defun viper-check-minibuffer-overlay ()
  733. (if (viper-overlay-live-p viper-minibuffer-overlay)
  734. (viper-move-overlay
  735. viper-minibuffer-overlay
  736. (if (fboundp 'minibuffer-prompt-end) (minibuffer-prompt-end) 1)
  737. (1+ (buffer-size)))
  738. (setq viper-minibuffer-overlay
  739. (if (featurep 'xemacs)
  740. (viper-make-overlay 1 (1+ (buffer-size)) (current-buffer))
  741. ;; make overlay open-ended
  742. (viper-make-overlay
  743. (if (fboundp 'minibuffer-prompt-end) (minibuffer-prompt-end) 1)
  744. (1+ (buffer-size))
  745. (current-buffer) nil 'rear-advance)))))
  746. (defsubst viper-is-in-minibuffer ()
  747. (save-match-data
  748. (string-match "\*Minibuf-" (buffer-name))))
  749. ;;; XEmacs compatibility
  750. (defun viper-abbreviate-file-name (file)
  751. (if (featurep 'xemacs)
  752. (abbreviate-file-name file t) ; XEmacs requires addl argument
  753. (abbreviate-file-name file)))
  754. ;; Sit for VAL milliseconds. XEmacs doesn't support the millisecond arg
  755. ;; in sit-for, so this function smooths out the differences.
  756. (defsubst viper-sit-for-short (val &optional nodisp)
  757. (sit-for (/ val 1000.0) nodisp))
  758. ;; EVENT may be a single event of a sequence of events
  759. (defsubst viper-ESC-event-p (event)
  760. (let ((ESC-keys '(?\e (control \[) escape))
  761. (key (viper-event-key event)))
  762. (member key ESC-keys)))
  763. ;; checks if object is a marker, has a buffer, and points to within that buffer
  764. (defun viper-valid-marker (marker)
  765. (if (and (markerp marker) (marker-buffer marker))
  766. (let ((buf (marker-buffer marker))
  767. (pos (marker-position marker)))
  768. (with-current-buffer buf
  769. (and (<= pos (point-max)) (<= (point-min) pos))))))
  770. (defsubst viper-mark-marker ()
  771. (if (featurep 'xemacs) (mark-marker t)
  772. (mark-marker)))
  773. ;; like (set-mark-command nil) but doesn't push twice, if (car mark-ring)
  774. ;; is the same as (mark t).
  775. (defsubst viper-set-mark-if-necessary ()
  776. (setq mark-ring (delete (viper-mark-marker) mark-ring))
  777. (set-mark-command nil)
  778. (setq viper-saved-mark (point)))
  779. ;; In transient mark mode (zmacs mode), it is annoying when regions become
  780. ;; highlighted due to Viper's pushing marks. So, we deactivate marks, unless
  781. ;; the user explicitly wants highlighting, e.g., by hitting '' or ``
  782. (defun viper-deactivate-mark ()
  783. (if (featurep 'xemacs)
  784. (zmacs-deactivate-region)
  785. (deactivate-mark)))
  786. (defsubst viper-leave-region-active ()
  787. (if (featurep 'xemacs) (setq zmacs-region-stays t)))
  788. ;; Check if arg is a valid character for register
  789. ;; TYPE is a list that can contain `letter', `Letter', and `digit'.
  790. ;; Letter means lowercase letters, Letter means uppercase letters, and
  791. ;; digit means digits from 1 to 9.
  792. ;; If TYPE is nil, then down/uppercase letters and digits are allowed.
  793. (defun viper-valid-register (reg &optional type)
  794. (or type (setq type '(letter Letter digit)))
  795. (or (if (memq 'letter type)
  796. (and (<= ?a reg) (<= reg ?z)))
  797. (if (memq 'digit type)
  798. (and (<= ?1 reg) (<= reg ?9)))
  799. (if (memq 'Letter type)
  800. (and (<= ?A reg) (<= reg ?Z)))
  801. ))
  802. ;; it is suggested that an event must be copied before it is assigned to
  803. ;; last-command-event in XEmacs
  804. (defun viper-copy-event (event)
  805. (if (featurep 'xemacs) (copy-event event)
  806. event))
  807. ;; Uses different timeouts for ESC-sequences and others
  808. (defun viper-fast-keysequence-p ()
  809. (not (viper-sit-for-short
  810. (if (viper-ESC-event-p last-input-event)
  811. (viper-ESC-keyseq-timeout)
  812. viper-fast-keyseq-timeout)
  813. t)))
  814. ;; like read-event, but in XEmacs also try to convert to char, if possible
  815. (defun viper-read-event-convert-to-char ()
  816. (let (event)
  817. (if (featurep 'xemacs)
  818. (progn
  819. (setq event (next-command-event))
  820. (or (event-to-character event)
  821. event))
  822. (read-event))))
  823. ;; Viperized read-key-sequence
  824. (defun viper-read-key-sequence (prompt &optional continue-echo)
  825. (let (inhibit-quit event keyseq)
  826. (setq keyseq (read-key-sequence prompt continue-echo))
  827. (setq event (if (featurep 'xemacs)
  828. (elt keyseq 0) ; XEmacs returns vector of events
  829. (elt (listify-key-sequence keyseq) 0)))
  830. (if (viper-ESC-event-p event)
  831. (let (unread-command-events)
  832. (if (viper-fast-keysequence-p)
  833. (let ((viper-vi-global-user-minor-mode nil)
  834. (viper-vi-local-user-minor-mode nil)
  835. (viper-vi-intercept-minor-mode nil)
  836. (viper-insert-intercept-minor-mode nil)
  837. (viper-replace-minor-mode nil) ; actually unnecessary
  838. (viper-insert-global-user-minor-mode nil)
  839. (viper-insert-local-user-minor-mode nil))
  840. ;; Note: set unread-command-events only after testing for fast
  841. ;; keysequence. Otherwise, viper-fast-keysequence-p will be
  842. ;; always t -- whether there is anything after ESC or not
  843. (viper-set-unread-command-events keyseq)
  844. (setq keyseq (read-key-sequence nil)))
  845. (viper-set-unread-command-events keyseq)
  846. (setq keyseq (read-key-sequence nil)))))
  847. keyseq))
  848. ;; This function lets function-key-map convert key sequences into logical
  849. ;; keys. This does a better job than viper-read-event when it comes to kbd
  850. ;; macros, since it enables certain macros to be shared between X and TTY modes
  851. ;; by correctly mapping key sequences for Left/Right/... (on an ascii
  852. ;; terminal) into logical keys left, right, etc.
  853. (defun viper-read-key ()
  854. (let ((overriding-local-map viper-overriding-map)
  855. (inhibit-quit t)
  856. help-char key)
  857. (use-global-map viper-overriding-map)
  858. (unwind-protect
  859. (setq key (elt (viper-read-key-sequence nil) 0))
  860. (use-global-map global-map))
  861. key))
  862. ;; Emacs has a bug in eventp, which causes (eventp nil) to return (nil)
  863. ;; instead of nil, if '(nil) was previously inadvertently assigned to
  864. ;; unread-command-events
  865. (defun viper-event-key (event)
  866. (or (and event (eventp event))
  867. (error "viper-event-key: Wrong type argument, eventp, %S" event))
  868. (when (if (featurep 'xemacs)
  869. (or (key-press-event-p event) (mouse-event-p event)) ; xemacs
  870. t ; emacs
  871. )
  872. (let ((mod (event-modifiers event))
  873. basis)
  874. (setq basis
  875. (if (featurep 'xemacs)
  876. ;; XEmacs
  877. (cond ((key-press-event-p event)
  878. (event-key event))
  879. ((button-event-p event)
  880. (concat "mouse-" (prin1-to-string (event-button event))))
  881. (t
  882. (error "viper-event-key: Unknown event, %S" event)))
  883. ;; Emacs doesn't handle capital letters correctly, since
  884. ;; \S-a isn't considered the same as A (it behaves as
  885. ;; plain `a' instead). So we take care of this here
  886. (cond ((and (viper-characterp event) (<= ?A event) (<= event ?Z))
  887. (setq mod nil
  888. event event))
  889. ;; Emacs has the oddity whereby characters 128+char
  890. ;; represent M-char *if* this appears inside a string.
  891. ;; So, we convert them manually to (meta char).
  892. ((and (viper-characterp event)
  893. (< ?\C-? event) (<= event 255))
  894. (setq mod '(meta)
  895. event (- event ?\C-? 1)))
  896. ((and (null mod) (eq event 'return))
  897. (setq event ?\C-m))
  898. ((and (null mod) (eq event 'space))
  899. (setq event ?\ ))
  900. ((and (null mod) (eq event 'delete))
  901. (setq event ?\C-?))
  902. ((and (null mod) (eq event 'backspace))
  903. (setq event ?\C-h))
  904. (t (event-basic-type event)))
  905. ) ; (featurep 'xemacs)
  906. )
  907. (if (viper-characterp basis)
  908. (setq basis
  909. (if (viper= basis ?\C-?)
  910. (list 'control '\?) ; taking care of an emacs bug
  911. (intern (char-to-string basis)))))
  912. (if mod
  913. (append mod (list basis))
  914. basis))))
  915. (defun viper-last-command-char ()
  916. (if (featurep 'xemacs)
  917. (event-to-character last-command-event)
  918. last-command-event))
  919. (defun viper-key-to-emacs-key (key)
  920. (let (key-name char-p modifiers mod-char-list base-key base-key-name)
  921. (cond ((featurep 'xemacs) key)
  922. ((symbolp key)
  923. (setq key-name (symbol-name key))
  924. (cond ((= (length key-name) 1) ; character event
  925. (string-to-char key-name))
  926. ;; Emacs doesn't recognize `return' and `escape' as events on
  927. ;; dumb terminals, so we translate them into characters
  928. ((and (featurep 'emacs) (not (viper-window-display-p))
  929. (string= key-name "return"))
  930. ?\C-m)
  931. ((and (featurep 'emacs) (not (viper-window-display-p))
  932. (string= key-name "escape"))
  933. ?\e)
  934. ;; pass symbol-event as is
  935. (t key)))
  936. ((listp key)
  937. (setq modifiers (viper-subseq key 0 (1- (length key)))
  938. base-key (viper-seq-last-elt key)
  939. base-key-name (symbol-name base-key)
  940. char-p (= (length base-key-name) 1))
  941. (setq mod-char-list
  942. (mapcar
  943. (lambda (elt) (upcase (substring (symbol-name elt) 0 1)))
  944. modifiers))
  945. (if char-p
  946. (setq key-name
  947. (car (read-from-string
  948. (concat
  949. "?\\"
  950. (mapconcat 'identity mod-char-list "-\\")
  951. "-"
  952. base-key-name))))
  953. (setq key-name
  954. (intern
  955. (concat
  956. (mapconcat 'identity mod-char-list "-")
  957. "-"
  958. base-key-name))))))
  959. ))
  960. ;; LIS is assumed to be a list of events of characters
  961. (defun viper-eventify-list-xemacs (lis)
  962. (if (featurep 'xemacs)
  963. (mapcar
  964. (lambda (elt)
  965. (cond ((viper-characterp elt) (character-to-event elt))
  966. ((eventp elt) elt)
  967. (t (error
  968. "viper-eventify-list-xemacs: can't convert to event, %S"
  969. elt))))
  970. lis)))
  971. ;; Smooths out the difference between Emacs's unread-command-events
  972. ;; and XEmacs unread-command-event. Arg is a character, an event, a list of
  973. ;; events or a sequence of keys.
  974. ;;
  975. ;; Due to the way unread-command-events in Emacs (not XEmacs), a non-event
  976. ;; symbol in unread-command-events list may cause Emacs to turn this symbol
  977. ;; into an event. Below, we delete nil from event lists, since nil is the most
  978. ;; common symbol that might appear in this wrong context.
  979. (defun viper-set-unread-command-events (arg)
  980. (if (featurep 'emacs)
  981. (setq
  982. unread-command-events
  983. (let ((new-events
  984. (cond ((eventp arg) (list arg))
  985. ((listp arg) arg)
  986. ((sequencep arg)
  987. (listify-key-sequence arg))
  988. (t (error
  989. "viper-set-unread-command-events: Invalid argument, %S"
  990. arg)))))
  991. (if (not (eventp nil))
  992. (setq new-events (delq nil new-events)))
  993. (append new-events unread-command-events)))
  994. ;; XEmacs
  995. (setq
  996. unread-command-events
  997. (append
  998. (cond ((viper-characterp arg) (list (character-to-event arg)))
  999. ((eventp arg) (list arg))
  1000. ((stringp arg) (mapcar 'character-to-event arg))
  1001. ((vectorp arg) (append arg nil)) ; turn into list
  1002. ((listp arg) (viper-eventify-list-xemacs arg))
  1003. (t (error
  1004. "viper-set-unread-command-events: Invalid argument, %S" arg)))
  1005. unread-command-events))))
  1006. ;; Check if vec is a vector of key-press events representing characters
  1007. ;; XEmacs only
  1008. (defun viper-event-vector-p (vec)
  1009. (and (vectorp vec)
  1010. (eval (cons 'and (mapcar (lambda (elt) (if (eventp elt) t)) vec)))))
  1011. ;; check if vec is a vector of character symbols
  1012. (defun viper-char-symbol-sequence-p (vec)
  1013. (and
  1014. (sequencep vec)
  1015. (eval
  1016. (cons 'and
  1017. (mapcar (lambda (elt)
  1018. (and (symbolp elt) (= (length (symbol-name elt)) 1)))
  1019. vec)))))
  1020. (defun viper-char-array-p (array)
  1021. (eval (cons 'and (mapcar 'viper-characterp array))))
  1022. ;; Args can be a sequence of events, a string, or a Viper macro. Will try to
  1023. ;; convert events to keys and, if all keys are regular printable
  1024. ;; characters, will return a string. Otherwise, will return a string
  1025. ;; representing a vector of converted events. If the input was a Viper macro,
  1026. ;; will return a string that represents this macro as a vector.
  1027. (defun viper-array-to-string (event-seq)
  1028. (let (temp temp2)
  1029. (cond ((stringp event-seq) event-seq)
  1030. ((viper-event-vector-p event-seq)
  1031. (setq temp (mapcar 'viper-event-key event-seq))
  1032. (cond ((viper-char-symbol-sequence-p temp)
  1033. (mapconcat 'symbol-name temp ""))
  1034. ((and (viper-char-array-p
  1035. (setq temp2 (mapcar 'viper-key-to-character temp))))
  1036. (mapconcat 'char-to-string temp2 ""))
  1037. (t (prin1-to-string (vconcat temp)))))
  1038. ((viper-char-symbol-sequence-p event-seq)
  1039. (mapconcat 'symbol-name event-seq ""))
  1040. ((and (vectorp event-seq)
  1041. (viper-char-array-p
  1042. (setq temp (mapcar 'viper-key-to-character event-seq))))
  1043. (mapconcat 'char-to-string temp ""))
  1044. (t (prin1-to-string event-seq)))))
  1045. (defun viper-key-press-events-to-chars (events)
  1046. (mapconcat (if (featurep 'xemacs)
  1047. (lambda (elt) (char-to-string (event-to-character elt))) ; xemacs
  1048. 'char-to-string ; emacs
  1049. )
  1050. events
  1051. ""))
  1052. (defun viper-read-char-exclusive ()
  1053. (let (char
  1054. (echo-keystrokes 1))
  1055. (while (null char)
  1056. (condition-case nil
  1057. (setq char (read-char))
  1058. (error
  1059. ;; skip event if not char
  1060. (viper-read-event))))
  1061. char))
  1062. ;; key is supposed to be in viper's representation, e.g., (control l), a
  1063. ;; character, etc.
  1064. (defun viper-key-to-character (key)
  1065. (cond ((eq key 'space) ?\ )
  1066. ((eq key 'delete) ?\C-?)
  1067. ((eq key 'return) ?\C-m)
  1068. ((eq key 'backspace) ?\C-h)
  1069. ((and (symbolp key)
  1070. (= 1 (length (symbol-name key))))
  1071. (string-to-char (symbol-name key)))
  1072. ((and (listp key)
  1073. (eq (car key) 'control)
  1074. (symbol-name (nth 1 key))
  1075. (= 1 (length (symbol-name (nth 1 key)))))
  1076. (read (format "?\\C-%s" (symbol-name (nth 1 key)))))
  1077. (t key)))
  1078. (defun viper-setup-master-buffer (&rest other-files-or-buffers)
  1079. "Set up the current buffer as a master buffer.
  1080. Arguments become related buffers. This function should normally be used in
  1081. the `Local variables' section of a file."
  1082. (setq viper-related-files-and-buffers-ring
  1083. (make-ring (1+ (length other-files-or-buffers))))
  1084. (mapc (lambda (elt)
  1085. (viper-ring-insert viper-related-files-and-buffers-ring elt))
  1086. other-files-or-buffers)
  1087. (viper-ring-insert viper-related-files-and-buffers-ring (buffer-name))
  1088. )
  1089. ;;; Movement utilities
  1090. ;; Characters that should not be considered as part of the word, in reformed-vi
  1091. ;; syntax mode.
  1092. ;; Note: \\ (quoted \) must appear before `-' because this string is listified
  1093. ;; into characters at some point and then put back to string. The result is
  1094. ;; used in skip-chars-forward, which treats - specially. Here we achieve the
  1095. ;; effect of quoting - and preventing it from being special.
  1096. (defconst viper-non-word-characters-reformed-vi
  1097. "!@#$%^&*()\\-+=|\\~`{}[];:'\",<.>/?")
  1098. ;; These are characters that are not to be considered as parts of a word in
  1099. ;; Viper.
  1100. ;; Set each time state changes and at loading time
  1101. (viper-deflocalvar viper-non-word-characters nil)
  1102. ;; must be buffer-local
  1103. (viper-deflocalvar viper-ALPHA-char-class "w"
  1104. "String of syntax classes characterizing Viper's alphanumeric symbols.
  1105. In addition, the symbol `_' may be considered alphanumeric if
  1106. `viper-syntax-preference' is `strict-vi' or `reformed-vi'.")
  1107. (defconst viper-strict-ALPHA-chars "a-zA-Z0-9_"
  1108. "Regexp matching the set of alphanumeric characters acceptable to strict
  1109. Vi.")
  1110. (defconst viper-strict-SEP-chars " \t\n"
  1111. "Regexp matching the set of alphanumeric characters acceptable to strict
  1112. Vi.")
  1113. (defconst viper-strict-SEP-chars-sans-newline " \t"
  1114. "Regexp matching the set of alphanumeric characters acceptable to strict
  1115. Vi.")
  1116. (defconst viper-SEP-char-class " -"
  1117. "String of syntax classes for Vi separators.
  1118. Usually contains ` ', linefeed, TAB or formfeed.")
  1119. ;; Set Viper syntax classes and related variables according to
  1120. ;; `viper-syntax-preference'.
  1121. (defun viper-update-syntax-classes (&optional set-default)
  1122. (let ((preference (cond ((eq viper-syntax-preference 'emacs)
  1123. "w") ; Viper words have only Emacs word chars
  1124. ((eq viper-syntax-preference 'extended)
  1125. "w_") ; Viper words have Emacs word & symbol chars
  1126. (t "w"))) ; Viper words are Emacs words plus `_'
  1127. (non-word-chars (cond ((eq viper-syntax-preference 'reformed-vi)
  1128. (viper-string-to-list
  1129. viper-non-word-characters-reformed-vi))
  1130. (t nil))))
  1131. (if set-default
  1132. (setq-default viper-ALPHA-char-class preference
  1133. viper-non-word-characters non-word-chars)
  1134. (setq viper-ALPHA-char-class preference
  1135. viper-non-word-characters non-word-chars))
  1136. ))
  1137. ;; SYMBOL is used because customize requires it, but it is ignored, unless it
  1138. ;; is `nil'. If nil, use setq.
  1139. (defun viper-set-syntax-preference (&optional symbol value)
  1140. "Set Viper syntax preference.
  1141. If called interactively or if SYMBOL is nil, sets syntax preference in current
  1142. buffer. If called non-interactively, preferably via the customization widget,
  1143. sets the default value."
  1144. (interactive)
  1145. (or value
  1146. (setq value
  1147. (completing-read
  1148. "Viper syntax preference: "
  1149. '(("strict-vi") ("reformed-vi") ("extended") ("emacs"))
  1150. nil 'require-match)))
  1151. (if (stringp value) (setq value (intern value)))
  1152. (or (memq value '(strict-vi reformed-vi extended emacs))
  1153. (error "Invalid Viper syntax preference, %S" value))
  1154. (if symbol
  1155. (setq-default viper-syntax-preference value)
  1156. (setq viper-syntax-preference value))
  1157. (viper-update-syntax-classes))
  1158. (defcustom viper-syntax-preference 'reformed-vi
  1159. "*Syntax type characterizing Viper's alphanumeric symbols.
  1160. Affects movement and change commands that deal with Vi-style words.
  1161. Works best when set in the hooks to various major modes.
  1162. `strict-vi' means Viper words are (hopefully) exactly as in Vi.
  1163. `reformed-vi' means Viper words are like Emacs words \(as determined using
  1164. Emacs syntax tables, which are different for different major modes\) with two
  1165. exceptions: the symbol `_' is always part of a word and typical Vi non-word
  1166. symbols, such as `,',:,\",),{, etc., are excluded.
  1167. This behaves very close to `strict-vi', but also works well with non-ASCII
  1168. characters from various alphabets.
  1169. `extended' means Viper word constituents are symbols that are marked as being
  1170. parts of words OR symbols in Emacs syntax tables.
  1171. This is most appropriate for major modes intended for editing programs.
  1172. `emacs' means Viper words are the same as Emacs words as specified by Emacs
  1173. syntax tables.
  1174. This option is appropriate if you like Emacs-style words."
  1175. :type '(radio (const strict-vi) (const reformed-vi)
  1176. (const extended) (const emacs))
  1177. :set 'viper-set-syntax-preference
  1178. :group 'viper)
  1179. (make-variable-buffer-local 'viper-syntax-preference)
  1180. ;; addl-chars are characters to be temporarily considered as alphanumerical
  1181. (defun viper-looking-at-alpha (&optional addl-chars)
  1182. (or (stringp addl-chars) (setq addl-chars ""))
  1183. (if (eq viper-syntax-preference 'reformed-vi)
  1184. (setq addl-chars (concat addl-chars "_")))
  1185. (let ((char (char-after (point))))
  1186. (if char
  1187. (if (eq viper-syntax-preference 'strict-vi)
  1188. (looking-at (concat "[" viper-strict-ALPHA-chars addl-chars "]"))
  1189. (or
  1190. ;; or one of the additional chars being asked to include
  1191. (viper-memq-char char (viper-string-to-list addl-chars))
  1192. (and
  1193. ;; not one of the excluded word chars (note:
  1194. ;; viper-non-word-characters is a list)
  1195. (not (viper-memq-char char viper-non-word-characters))
  1196. ;; char of the Viper-word syntax class
  1197. (viper-memq-char (char-syntax char)
  1198. (viper-string-to-list viper-ALPHA-char-class))))))
  1199. ))
  1200. (defun viper-looking-at-separator ()
  1201. (let ((char (char-after (point))))
  1202. (if char
  1203. (if (eq viper-syntax-preference 'strict-vi)
  1204. (viper-memq-char char (viper-string-to-list viper-strict-SEP-chars))
  1205. (or (eq char ?\n) ; RET is always a separator in Vi
  1206. (viper-memq-char (char-syntax char)
  1207. (viper-string-to-list viper-SEP-char-class)))))
  1208. ))
  1209. (defsubst viper-looking-at-alphasep (&optional addl-chars)
  1210. (or (viper-looking-at-separator) (viper-looking-at-alpha addl-chars)))
  1211. (defun viper-skip-alpha-forward (&optional addl-chars)
  1212. (or (stringp addl-chars) (setq addl-chars ""))
  1213. (viper-skip-syntax
  1214. 'forward
  1215. (cond ((eq viper-syntax-preference 'strict-vi)
  1216. "")
  1217. (t viper-ALPHA-char-class))
  1218. (cond ((eq viper-syntax-preference 'strict-vi)
  1219. (concat viper-strict-ALPHA-chars addl-chars))
  1220. (t addl-chars))))
  1221. (defun viper-skip-alpha-backward (&optional addl-chars)
  1222. (or (stringp addl-chars) (setq addl-chars ""))
  1223. (viper-skip-syntax
  1224. 'backward
  1225. (cond ((eq viper-syntax-preference 'strict-vi)
  1226. "")
  1227. (t viper-ALPHA-char-class))
  1228. (cond ((eq viper-syntax-preference 'strict-vi)
  1229. (concat viper-strict-ALPHA-chars addl-chars))
  1230. (t addl-chars))))
  1231. ;; weird syntax tables may confuse strict-vi style
  1232. (defsubst viper-skip-all-separators-forward (&optional within-line)
  1233. (if (eq viper-syntax-preference 'strict-vi)
  1234. (if within-line
  1235. (skip-chars-forward viper-strict-SEP-chars-sans-newline)
  1236. (skip-chars-forward viper-strict-SEP-chars))
  1237. (viper-skip-syntax 'forward
  1238. viper-SEP-char-class
  1239. (or within-line "\n")
  1240. (if within-line (viper-line-pos 'end)))))
  1241. (defsubst viper-skip-all-separators-backward (&optional within-line)
  1242. (if (eq viper-syntax-preference 'strict-vi)
  1243. (if within-line
  1244. (skip-chars-backward viper-strict-SEP-chars-sans-newline)
  1245. (skip-chars-backward viper-strict-SEP-chars))
  1246. (viper-skip-syntax 'backward
  1247. viper-SEP-char-class
  1248. (or within-line "\n")
  1249. (if within-line (viper-line-pos 'start)))))
  1250. (defun viper-skip-nonseparators (direction)
  1251. (viper-skip-syntax
  1252. direction
  1253. (concat "^" viper-SEP-char-class)
  1254. nil
  1255. (viper-line-pos (if (eq direction 'forward) 'end 'start))))
  1256. ;; skip over non-word constituents and non-separators
  1257. (defun viper-skip-nonalphasep-forward ()
  1258. (if (eq viper-syntax-preference 'strict-vi)
  1259. (skip-chars-forward
  1260. (concat "^" viper-strict-SEP-chars viper-strict-ALPHA-chars))
  1261. (viper-skip-syntax
  1262. 'forward
  1263. (concat "^" viper-ALPHA-char-class viper-SEP-char-class)
  1264. ;; Emacs may consider some of these as words, but we don't want them
  1265. viper-non-word-characters
  1266. (viper-line-pos 'end))))
  1267. (defun viper-skip-nonalphasep-backward ()
  1268. (if (eq viper-syntax-preference 'strict-vi)
  1269. (skip-chars-backward
  1270. (concat "^" viper-strict-SEP-chars viper-strict-ALPHA-chars))
  1271. (viper-skip-syntax
  1272. 'backward
  1273. (concat "^" viper-ALPHA-char-class viper-SEP-char-class)
  1274. ;; Emacs may consider some of these as words, but we don't want them
  1275. viper-non-word-characters
  1276. (viper-line-pos 'start))))
  1277. ;; Skip SYNTAX like skip-syntax-* and ADDL-CHARS like skip-chars-*
  1278. ;; Return the number of chars traveled.
  1279. ;; Both SYNTAX or ADDL-CHARS can be strings or lists of characters.
  1280. ;; When SYNTAX is "w", then viper-non-word-characters are not considered to be
  1281. ;; words, even if Emacs syntax table says they are.
  1282. (defun viper-skip-syntax (direction syntax addl-chars &optional limit)
  1283. (let ((total 0)
  1284. (local 1)
  1285. (skip-chars-func
  1286. (if (eq direction 'forward)
  1287. 'skip-chars-forward 'skip-chars-backward))
  1288. (skip-syntax-func
  1289. (if (eq direction 'forward)
  1290. 'viper-forward-char-carefully 'viper-backward-char-carefully))
  1291. char-looked-at syntax-of-char-looked-at negated-syntax)
  1292. (setq addl-chars
  1293. (cond ((listp addl-chars) (viper-charlist-to-string addl-chars))
  1294. ((stringp addl-chars) addl-chars)
  1295. (t "")))
  1296. (setq syntax
  1297. (cond ((listp syntax) syntax)
  1298. ((stringp syntax) (viper-string-to-list syntax))
  1299. (t nil)))
  1300. (if (memq ?^ syntax) (setq negated-syntax t))
  1301. (while (and (not (= local 0))
  1302. (cond ((eq direction 'forward)
  1303. (not (eobp)))
  1304. (t (not (bobp)))))
  1305. (setq char-looked-at (viper-char-at-pos direction)
  1306. ;; if outside the range, set to nil
  1307. syntax-of-char-looked-at (if char-looked-at
  1308. (char-syntax char-looked-at)))
  1309. (setq local
  1310. (+ (if (and
  1311. (cond ((and limit (eq direction 'forward))
  1312. (< (point) limit))
  1313. (limit ; backward & limit
  1314. (> (point) limit))
  1315. (t t)) ; no limit
  1316. ;; char under/before cursor has appropriate syntax
  1317. (if negated-syntax
  1318. (not (memq syntax-of-char-looked-at syntax))
  1319. (memq syntax-of-char-looked-at syntax))
  1320. ;; if char-syntax class is "word", make sure it is not one
  1321. ;; of the excluded characters
  1322. (if (and (eq syntax-of-char-looked-at ?w)
  1323. (not negated-syntax))
  1324. (not (viper-memq-char
  1325. char-looked-at viper-non-word-characters))
  1326. t))
  1327. (funcall skip-syntax-func 1)
  1328. 0)
  1329. (funcall skip-chars-func addl-chars limit)))
  1330. (setq total (+ total local)))
  1331. total
  1332. ))
  1333. ;; tells when point is at the beginning of field
  1334. (defun viper-beginning-of-field ()
  1335. (or (bobp)
  1336. (not (eq (get-char-property (point) 'field)
  1337. (get-char-property (1- (point)) 'field)))))
  1338. ;; this is copied from cl-extra.el
  1339. ;; Return the subsequence of SEQ from START to END.
  1340. ;; If END is omitted, it defaults to the length of the sequence.
  1341. ;; If START or END is negative, it counts from the end.
  1342. (defun viper-subseq (seq start &optional end)
  1343. (if (stringp seq) (substring seq start end)
  1344. (let (len)
  1345. (and end (< end 0) (setq end (+ end (setq len (length seq)))))
  1346. (if (< start 0) (setq start (+ start (or len (setq len (length seq))))))
  1347. (cond ((listp seq)
  1348. (if (> start 0) (setq seq (nthcdr start seq)))
  1349. (if end
  1350. (let ((res nil))
  1351. (while (>= (setq end (1- end)) start)
  1352. (push (pop seq) res))
  1353. (nreverse res))
  1354. (copy-sequence seq)))
  1355. (t
  1356. (or end (setq end (or len (length seq))))
  1357. (let ((res (make-vector (max (- end start) 0) nil))
  1358. (i 0))
  1359. (while (< start end)
  1360. (aset res i (aref seq start))
  1361. (setq i (1+ i) start (1+ start)))
  1362. res))))))
  1363. ;; Local Variables:
  1364. ;; eval: (put 'viper-deflocalvar 'lisp-indent-hook 'defun)
  1365. ;; End:
  1366. ;;; viper-util.el ends here