]> code.delx.au - gnu-emacs/blobdiff - lisp/emulation/viper-util.el
(vietnamese-viscii): Fix the value of
[gnu-emacs] / lisp / emulation / viper-util.el
index 28584aa3971dec15d205fc6fd9c6bd86ddcbcfe3..111edd10b6ab8b5ab3931f92a80f07280127ddc4 100644 (file)
@@ -35,6 +35,7 @@
 (defvar ex-unix-type-shell)
 (defvar ex-unix-type-shell-options)
 (defvar viper-ex-tmp-buf-name)
+(defvar viper-syntax-preference)
 
 (require 'cl)
 (require 'ring)
 (require 'viper-init)
 
 
+;; A fix for NeXT Step
+;; Should go away, when NS people fix the design flaw, which leaves the
+;; two x-* functions undefined.
+(if (and (not (fboundp 'x-display-color-p)) (fboundp 'ns-display-color-p))
+    (fset 'x-display-color-p (symbol-function 'ns-display-color-p)))
+(if (and (not (fboundp 'x-color-defined-p)) (fboundp 'ns-color-defined-p))
+      (fset 'x-color-defined-p (symbol-function 'ns-color-defined-p)))
+
 \f
 ;;; XEmacs support
 
-;; A fix for NeXT Step
-;; Should probably be eliminated in later versions.
-(if (and (viper-window-display-p) (eq (viper-device-type) 'ns))
-    (progn
-      (fset 'x-display-color-p (symbol-function 'ns-display-color-p))
-      (fset 'x-color-defined-p (symbol-function 'ns-color-defined-p))
-      ))
 
 (if viper-xemacs-p
     (progn
       (cdr (assoc 'cursor-color (frame-parameters)))
     (color-instance-name (frame-property (selected-frame) 'cursor-color))))
   
-(defun viper-set-face-pixmap (face pixmap)
-  "Set face pixmap on a monochrome display."
-  (if (and (viper-window-display-p) (not (viper-color-display-p)))
-      (condition-case nil
-         (set-face-background-pixmap face pixmap)
-       (error
-        (message "Pixmap not found for %S: %s" (face-name face) pixmap)
-        (sit-for 1)))))
 
-  
 ;; OS/2
 (cond ((eq (viper-device-type) 'pm)
        (fset 'viper-color-defined-p
             (function (lambda (color) (assoc color pm-color-alist))))))
     
-;; needed to smooth out the difference between Emacs and XEmacs
-(defsubst viper-italicize-face (face)
-  (if viper-xemacs-p
-      (make-face-italic face)
-    (make-face-italic face nil 'noerror)))
-    
-;; test if display is color and the colors are defined
-(defsubst viper-can-use-colors (&rest colors)
-  (if (viper-color-display-p)
-      (not (memq nil (mapcar 'viper-color-defined-p colors)))
-    ))
-
-(defun viper-hide-face (face)
-  (if (and (viper-has-face-support-p) viper-emacs-p)
-      (add-to-list 'facemenu-unlisted-faces face)))
 
 ;; cursor colors
 (defun viper-change-cursor-color (new-color)
 (defsubst viper-restore-cursor-color-after-insert ()
   (viper-change-cursor-color viper-saved-cursor-color))
         
-\f
-;; Face-saving tricks
-
-(defvar viper-search-face
-  (if (viper-has-face-support-p)
-      (progn
-       (make-face 'viper-search-face)
-       (viper-hide-face 'viper-search-face)
-       (or (face-differs-from-default-p 'viper-search-face)
-           ;; face wasn't set in .viper or .Xdefaults
-           (if (viper-can-use-colors "Black" "khaki")
-               (progn
-                 (set-face-background 'viper-search-face "khaki")
-                 (set-face-foreground 'viper-search-face "Black"))
-             (set-face-underline-p 'viper-search-face t)
-             (viper-set-face-pixmap 'viper-search-face viper-search-face-pixmap)))
-       'viper-search-face))
-  "*Face used to flash out the search pattern.")
-  
-(defvar viper-replace-overlay-face
-  (if (viper-has-face-support-p)
-      (progn
-       (make-face 'viper-replace-overlay-face)
-       (viper-hide-face 'viper-replace-overlay-face)
-       (or (face-differs-from-default-p 'viper-replace-overlay-face)
-           (progn
-             (if (viper-can-use-colors "darkseagreen2" "Black")
-                 (progn
-                   (set-face-background
-                    'viper-replace-overlay-face "darkseagreen2")
-                   (set-face-foreground 'viper-replace-overlay-face "Black")))
-             (set-face-underline-p 'viper-replace-overlay-face t)
-             (viper-set-face-pixmap
-              'viper-replace-overlay-face viper-replace-overlay-pixmap)))
-       'viper-replace-overlay-face))
-  "*Face for highlighting replace regions on a window display.")
-
-(defvar viper-minibuffer-emacs-face
-  (if (viper-has-face-support-p)
-      (progn
-       (make-face 'viper-minibuffer-emacs-face)
-       (viper-hide-face 'viper-minibuffer-emacs-face)
-       (or (face-differs-from-default-p 'viper-minibuffer-emacs-face)
-           ;; face wasn't set in .viper or .Xdefaults
-           (if viper-vi-style-in-minibuffer
-               ;; emacs state is an exception in the minibuffer
-               (if (viper-can-use-colors "darkseagreen2" "Black")
-                   (progn
-                     (set-face-background
-                      'viper-minibuffer-emacs-face "darkseagreen2")
-                     (set-face-foreground
-                      'viper-minibuffer-emacs-face "Black"))
-                 (copy-face 'modeline 'viper-minibuffer-emacs-face))
-             ;; emacs state is the main state in the minibuffer
-             (if (viper-can-use-colors "Black" "pink")
-                 (progn
-                   (set-face-background 'viper-minibuffer-emacs-face "pink") 
-                   (set-face-foreground
-                    'viper-minibuffer-emacs-face "Black"))
-               (copy-face 'italic 'viper-minibuffer-emacs-face))
-             ))
-       'viper-minibuffer-emacs-face))
-  "Face used in the Minibuffer when it is in Emacs state.")
-    
-(defvar viper-minibuffer-insert-face
-  (if (viper-has-face-support-p)
-      (progn
-       (make-face 'viper-minibuffer-insert-face)
-       (viper-hide-face 'viper-minibuffer-insert-face)
-       (or (face-differs-from-default-p 'viper-minibuffer-insert-face)
-           (if viper-vi-style-in-minibuffer
-               (if (viper-can-use-colors "Black" "pink")
-                   (progn
-                     (set-face-background 'viper-minibuffer-insert-face "pink") 
-                     (set-face-foreground
-                      'viper-minibuffer-insert-face "Black"))
-                 (copy-face 'italic 'viper-minibuffer-insert-face))
-             ;; If Insert state is an exception
-             (if (viper-can-use-colors "darkseagreen2" "Black")
-                 (progn
-                   (set-face-background
-                    'viper-minibuffer-insert-face "darkseagreen2")
-                   (set-face-foreground
-                    'viper-minibuffer-insert-face "Black"))
-               (copy-face 'modeline 'viper-minibuffer-insert-face))
-             (viper-italicize-face 'viper-minibuffer-insert-face)))
-       'viper-minibuffer-insert-face))
-  "Face used in the Minibuffer when it is in Insert state.")
-    
-(defvar viper-minibuffer-vi-face
-  (if (viper-has-face-support-p)
-      (progn
-       (make-face 'viper-minibuffer-vi-face)
-       (viper-hide-face 'viper-minibuffer-vi-face)
-       (or (face-differs-from-default-p 'viper-minibuffer-vi-face)
-           (if viper-vi-style-in-minibuffer
-               (if (viper-can-use-colors "Black" "grey")
-                   (progn
-                     (set-face-background 'viper-minibuffer-vi-face "grey")
-                     (set-face-foreground 'viper-minibuffer-vi-face "Black"))
-                 (copy-face 'bold 'viper-minibuffer-vi-face))
-             (copy-face 'bold 'viper-minibuffer-vi-face)
-             (invert-face 'viper-minibuffer-vi-face)))
-       'viper-minibuffer-vi-face))
-  "Face used in the Minibuffer when it is in Vi state.")
-    
-;; the current face to be used in the minibuffer
-(viper-deflocalvar viper-minibuffer-current-face viper-minibuffer-emacs-face "")
    
 \f
 ;; Check the current version against the major and minor version numbers
     (goto-char cur-pos)
     result))
 
+;; Emacs counts each multibyte character as several positions in the buffer, so
+;; we use Emacs' chars-in-region. XEmacs is counting each char as just one pos,
+;; so we can simply subtract. 
+(defun viper-chars-in-region (beg end &optional preserve-sign)
+  (let ((count (abs (if (fboundp 'chars-in-region)
+                       (chars-in-region beg end)
+                     (- end beg)))))
+    (if (and (< end beg) preserve-sign)
+       (- count)
+      count)))
+
+;; Test if POS is between BEG and END
+(defsubst viper-pos-within-region (pos beg end)
+  (and (>= pos (min beg end)) (>= (max beg end) pos)))
+
 
 ;; Like move-marker but creates a virgin marker if arg isn't already a marker.
 ;; The first argument must eval to a variable name.
@@ -715,13 +600,69 @@ to write a custom function, similar to `viper-ex-nontrivial-find-file-unix'."
   (let ((buf (find-file-noselect (substitute-in-file-name custom-file))))
     (save-excursion
       (set-buffer buf)
-      (goto-char (point-min))
-      (if pattern (delete-matching-lines pattern))
-      (goto-char (point-max))
-      (if string (insert string))
-      (save-buffer))
+      (let (buffer-read-only)
+       (goto-char (point-min))
+       (if pattern (delete-matching-lines pattern))
+       (goto-char (point-max))
+       (if string (insert string))
+       (save-buffer)))
     (kill-buffer buf)
     ))
+
+
+;; define remote file test
+(or (fboundp 'viper-file-remote-p) ; user supplied his own function: use it
+    (defun viper-file-remote-p (file-name)
+      (car (cond ((featurep 'efs-auto) (efs-ftp-path file-name))
+                ((fboundp 'file-remote-p) (file-remote-p file-name))
+                (t (require 'ange-ftp)
+                   ;; Can happen only in Emacs, since XEmacs has file-remote-p
+                   (ange-ftp-ftp-name file-name))))))
+
+    
+
+;; This is a simple-minded check for whether a file is under version control.
+;; If file,v exists but file doesn't, this file is considered to be not checked
+;; in and not checked out for the purpose of patching (since patch won't be
+;; able to read such a file anyway).
+;; FILE is a string representing file name
+;;(defun viper-file-under-version-control (file)
+;;  (let* ((filedir (file-name-directory file))
+;;      (file-nondir (file-name-nondirectory file))
+;;      (trial (concat file-nondir ",v"))
+;;      (full-trial (concat filedir trial))
+;;      (full-rcs-trial (concat filedir "RCS/" trial)))
+;;    (and (stringp file)
+;;      (file-exists-p file)
+;;      (or
+;;       (and
+;;        (file-exists-p full-trial)
+;;        ;; in FAT FS, `file,v' and `file' may turn out to be the same!
+;;        ;; don't be fooled by this!
+;;        (not (equal (file-attributes file)
+;;                    (file-attributes full-trial))))
+;;       ;; check if a version is in RCS/ directory
+;;       (file-exists-p full-rcs-trial)))
+;;       ))
+
+
+(defsubst viper-file-checked-in-p (file)
+  (and (vc-backend file)
+       (not (vc-locking-user file))))
+;; checkout if visited file is checked in
+(defun viper-maybe-checkout (buf)
+  (let ((file (expand-file-name (buffer-file-name buf)))
+       (checkout-function (key-binding "\C-x\C-q")))
+    (if (and (viper-file-checked-in-p file)
+            (or (beep 1) t)
+            (y-or-n-p
+             (format
+              "File %s is checked in. Check it out? "
+              (viper-abbreviate-file-name file))))
+       (with-current-buffer buf
+         (command-execute checkout-function)))))
+        
+
     
 \f
 ;;; Overlays
@@ -832,7 +773,8 @@ to write a custom function, similar to `viper-ex-nontrivial-find-file-unix'."
 
 
 (defsubst viper-is-in-minibuffer ()
-  (string-match "\*Minibuf-" (buffer-name)))
+  (save-match-data
+    (string-match "\*Minibuf-" (buffer-name))))
   
 
 \f
@@ -909,50 +851,6 @@ to write a custom function, similar to `viper-ex-nontrivial-find-file-unix'."
   (cond (viper-xemacs-p (events-to-keys events))
        (t events)))
                  
-       
-;; This is here because Emacs changed the way local hooks work.
-;;
-;;Add to the value of HOOK the function FUNCTION.
-;;FUNCTION is not added if already present.
-;;FUNCTION is added (if necessary) at the beginning of the hook list
-;;unless the optional argument APPEND is non-nil, in which case
-;;FUNCTION is added at the end.
-;;
-;;HOOK should be a symbol, and FUNCTION may be any valid function.  If
-;;HOOK is void, it is first set to nil.  If HOOK's value is a single
-;;function, it is changed to a list of functions."
-(defun viper-add-hook (hook function &optional append)
-  (if (not (boundp hook)) (set hook nil))
-  ;; If the hook value is a single function, turn it into a list.
-  (let ((old (symbol-value hook)))
-    (if (or (not (listp old)) (eq (car old) 'lambda))
-       (setq old (list old)))
-    (if (member function old)
-       nil
-      (set hook (if append
-                   (append old (list function)) ; don't nconc
-                 (cons function old))))))
-
-;; This is here because of Emacs's changes in the semantics of add/remove-hooks
-;; and due to the bugs they introduced.
-;;
-;; Remove from the value of HOOK the function FUNCTION.
-;; HOOK should be a symbol, and FUNCTION may be any valid function.  If
-;; FUNCTION isn't the value of HOOK, or, if FUNCTION doesn't appear in the
-;; list of hooks to run in HOOK, then nothing is done.  See `viper-add-hook'."
-(defun viper-remove-hook (hook function)
-  (if (or (not (boundp hook))          ;unbound symbol, or
-         (null (symbol-value hook))    ;value is nil, or
-         (null function))              ;function is nil, then
-      nil                              ;Do nothing.
-    (let ((hook-value (symbol-value hook)))
-      (if (consp hook-value)
-         ;; don't side-effect the list
-         (setq hook-value (delete function (copy-sequence hook-value)))
-       (if (equal hook-value function)
-           (setq hook-value nil)))
-      (set hook hook-value))))
-
     
 ;; it is suggested that an event must be copied before it is assigned to
 ;; last-command-event in XEmacs
@@ -979,10 +877,11 @@ to write a custom function, similar to `viper-ex-nontrivial-find-file-unix'."
 (defun viper-read-key () 
   (let ((overriding-local-map viper-overriding-map) 
        (inhibit-quit t)
-        key) 
+       help-char key) 
     (use-global-map viper-overriding-map) 
-    (setq key (elt (read-key-sequence nil) 0)) 
-    (use-global-map global-map) 
+    (unwind-protect
+       (setq key (elt (read-key-sequence nil) 0)) 
+      (use-global-map global-map))
     key))
 
 
@@ -1168,45 +1067,104 @@ the `Local variables' section of a file."
 
 ;;; Movement utilities
 
-(defcustom viper-syntax-preference 'strict-vi
-  "*Syntax type characterizing Viper's alphanumeric symbols.
-`emacs' means only word constituents are considered to be alphanumeric.
-Word constituents are symbols specified as word constituents by the current
-syntax table.
-`extended' means word and symbol constituents.
-`reformed-vi' means Vi-ish behavior: word constituents and the symbol `_'.
-However, word constituents are determined according to Emacs syntax tables,
-which may be different from Vi in some major modes.
-`strict-vi' means Viper words are exactly as in Vi."
-  :type '(radio (const strict-vi) (const reformed-vi) 
-                (const extended) (const emacs))
-  :group 'viper)
+;; Characters that should not be considered as part of the word, in reformed-vi
+;; syntax mode.
+(defconst viper-non-word-characters-reformed-vi
+  "!@#$%^&*()-+=|\\~`{}[];:'\",<.>/?")
+;; These are characters that are not to be considered as parts of a word in
+;; Viper.
+;; Set each time state changes and at loading time
+(viper-deflocalvar viper-non-word-characters  nil)
 
+;; must be buffer-local
 (viper-deflocalvar viper-ALPHA-char-class "w"
   "String of syntax classes characterizing Viper's alphanumeric symbols.
 In addition, the symbol `_' may be considered alphanumeric if
-`viper-syntax-preference'is `reformed-vi'.")
+`viper-syntax-preference' is `strict-vi' or `reformed-vi'.")
 
-(viper-deflocalvar viper-strict-ALPHA-chars "a-zA-Z0-9_"
+(defconst viper-strict-ALPHA-chars "a-zA-Z0-9_"
   "Regexp matching the set of alphanumeric characters acceptable to strict
 Vi.")
-(viper-deflocalvar viper-strict-SEP-chars " \t\n"
+(defconst viper-strict-SEP-chars " \t\n"
+  "Regexp matching the set of alphanumeric characters acceptable to strict
+Vi.")
+(defconst viper-strict-SEP-chars-sans-newline " \t"
   "Regexp matching the set of alphanumeric characters acceptable to strict
 Vi.")
 
-(viper-deflocalvar viper-SEP-char-class " -"
+(defconst viper-SEP-char-class " -"
   "String of syntax classes for Vi separators.
 Usually contains ` ', linefeed, TAB or formfeed.")
 
-(defun viper-update-alphanumeric-class ()
-  "Set the syntax class of Viper alphanumerals according to `viper-syntax-preference'.
-Must be called in order for changes to `viper-syntax-preference' to take effect."
+
+;; Set Viper syntax classes and related variables according to
+;; `viper-syntax-preference'.  
+(defun viper-update-syntax-classes (&optional set-default)
+  (let ((preference (cond ((eq viper-syntax-preference 'emacs)
+                          "w")   ; Viper words have only Emacs word chars
+                         ((eq viper-syntax-preference 'extended)
+                          "w_")  ; Viper words have Emacs word & symbol chars
+                         (t "w"))) ; Viper words are Emacs words plus `_'
+       (non-word-chars (cond ((eq viper-syntax-preference 'reformed-vi)
+                              (viper-string-to-list
+                               viper-non-word-characters-reformed-vi))
+                             (t nil))))
+    (if set-default
+       (setq-default viper-ALPHA-char-class preference
+                     viper-non-word-characters non-word-chars)
+      (setq viper-ALPHA-char-class preference
+           viper-non-word-characters non-word-chars))
+    ))
+
+;; SYMBOL is used because customize requires it, but it is ignored, unless it
+;; is `nil'. If nil, use setq.
+(defun viper-set-syntax-preference (&optional symbol value)
+  "Set Viper syntax preference.
+If called interactively or if SYMBOL is nil, sets syntax preference in current
+buffer. If called non-interactively, preferably via the customization widget,
+sets the default value."
   (interactive)
-  (setq-default
-   viper-ALPHA-char-class
-   (cond ((eq viper-syntax-preference 'emacs) "w")     ; only word constituents
-        ((eq viper-syntax-preference 'extended) "w_") ; word & symbol chars
-        (t "w"))))     ; vi syntax: word constituents and the symbol `_'
+  (or value
+      (setq value
+           (completing-read
+            "Viper syntax preference: "
+            '(("strict-vi") ("reformed-vi") ("extended") ("emacs"))
+            nil 'require-match)))
+  (if (stringp value) (setq value (intern value)))
+  (or (memq value '(strict-vi reformed-vi extended emacs))
+      (error "Invalid Viper syntax preference, %S" value))
+  (if symbol
+      (setq-default viper-syntax-preference value)
+    (setq viper-syntax-preference value))
+  (viper-update-syntax-classes))
+
+(defcustom viper-syntax-preference 'reformed-vi
+  "*Syntax type characterizing Viper's alphanumeric symbols.
+Affects movement and change commands that deal with Vi-style words.
+Works best when set in the hooks to various major modes.
+
+`strict-vi' means Viper words are (hopefully) exactly as in Vi.
+
+`reformed-vi' means Viper words are like Emacs words \(as determined using
+Emacs syntax tables, which are different for different major modes\) with two
+exceptions: the symbol `_' is always part of a word and typical Vi non-word
+symbols, such as `,',:,\",),{, etc., are excluded.
+This behaves very close to `strict-vi', but also works well with non-ASCII
+characters from various alphabets.
+
+`extended' means Viper word constituents are symbols that are marked as being
+parts of words OR symbols in Emacs syntax tables.
+This is most appropriate for major modes intended for editing programs.
+
+`emacs' means Viper words are the same as Emacs words as specified by Emacs
+syntax tables.
+This option is appropriate if you like Emacs-style words."
+  :type '(radio (const strict-vi) (const reformed-vi) 
+                (const extended) (const emacs))
+  :set 'viper-set-syntax-preference
+  :group 'viper)
+(make-variable-buffer-local 'viper-syntax-preference)
+
 
 ;; addl-chars are characters to be temporarily considered as alphanumerical
 (defun viper-looking-at-alpha (&optional addl-chars)
@@ -1217,19 +1175,26 @@ Must be called in order for changes to `viper-syntax-preference' to take effect.
     (if char
        (if (eq viper-syntax-preference 'strict-vi)
            (looking-at (concat "[" viper-strict-ALPHA-chars addl-chars "]"))
-         (or (memq char
-                   ;; convert string to list
-                   (append (vconcat addl-chars) nil))
-             (memq (char-syntax char)
-                   (append (vconcat viper-ALPHA-char-class) nil)))))
+         (or
+          ;; or one of the additional chars being asked to include
+          (memq char (viper-string-to-list addl-chars))
+          (and
+           ;; not one of the excluded word chars
+           (not (memq char viper-non-word-characters))
+           ;; char of the Viper-word syntax class
+           (memq (char-syntax char)
+                 (viper-string-to-list viper-ALPHA-char-class))))))
     ))
 
 (defun viper-looking-at-separator ()
   (let ((char (char-after (point))))
     (if char
-       (or (eq char ?\n) ; RET is always a separator in Vi
-           (memq (char-syntax char)
-                 (append (vconcat viper-SEP-char-class) nil))))))
+       (if (eq viper-syntax-preference 'strict-vi)
+           (memq char (viper-string-to-list viper-strict-SEP-chars))
+         (or (eq char ?\n) ; RET is always a separator in Vi
+             (memq (char-syntax char)
+                   (viper-string-to-list viper-SEP-char-class)))))
+    ))
 
 (defsubst viper-looking-at-alphasep (&optional addl-chars)
   (or (viper-looking-at-separator) (viper-looking-at-alpha addl-chars)))
@@ -1240,7 +1205,7 @@ Must be called in order for changes to `viper-syntax-preference' to take effect.
    'forward 
    (cond ((eq viper-syntax-preference 'strict-vi)
          "")
-        (t viper-ALPHA-char-class ))
+        (t viper-ALPHA-char-class))
    (cond ((eq viper-syntax-preference 'strict-vi)
          (concat viper-strict-ALPHA-chars addl-chars))
         (t addl-chars))))
@@ -1251,58 +1216,112 @@ Must be called in order for changes to `viper-syntax-preference' to take effect.
    'backward 
    (cond ((eq viper-syntax-preference 'strict-vi)
          "")
-        (t viper-ALPHA-char-class ))
+        (t viper-ALPHA-char-class))
    (cond ((eq viper-syntax-preference 'strict-vi)
          (concat viper-strict-ALPHA-chars addl-chars))
         (t addl-chars))))
 
 ;; weird syntax tables may confuse strict-vi style
 (defsubst viper-skip-all-separators-forward (&optional within-line)
-  (viper-skip-syntax 'forward
-                    viper-SEP-char-class
-                    (or within-line "\n")
-                    (if within-line (viper-line-pos 'end))))
+  (if (eq viper-syntax-preference 'strict-vi)
+      (if within-line 
+         (skip-chars-forward viper-strict-SEP-chars-sans-newline)
+       (skip-chars-forward viper-strict-SEP-chars))
+    (viper-skip-syntax 'forward
+                      viper-SEP-char-class
+                      (or within-line "\n")
+                      (if within-line (viper-line-pos 'end)))))
 (defsubst viper-skip-all-separators-backward (&optional within-line)
-  (viper-skip-syntax 'backward
-                    viper-SEP-char-class
-                    (or within-line "\n")
-                    (if within-line (viper-line-pos 'start))))
+  (if (eq viper-syntax-preference 'strict-vi)
+      (if within-line 
+         (skip-chars-backward viper-strict-SEP-chars-sans-newline)
+       (skip-chars-backward viper-strict-SEP-chars))
+    (viper-skip-syntax 'backward
+                      viper-SEP-char-class
+                      (or within-line "\n")
+                      (if within-line (viper-line-pos 'start)))))
 (defun viper-skip-nonseparators (direction)
-  (let ((func (intern (format "skip-syntax-%S" direction))))
-    (funcall func (concat "^" viper-SEP-char-class)
-            (viper-line-pos (if (eq direction 'forward) 'end 'start)))))
+  (viper-skip-syntax
+   direction
+   (concat "^" viper-SEP-char-class)
+   nil
+   (viper-line-pos (if (eq direction 'forward) 'end 'start))))
+
 
+;; skip over non-word constituents and non-separators
 (defun viper-skip-nonalphasep-forward ()
   (if (eq viper-syntax-preference 'strict-vi)
       (skip-chars-forward
        (concat "^" viper-strict-SEP-chars viper-strict-ALPHA-chars))
-    (skip-syntax-forward
-     (concat
-      "^" viper-ALPHA-char-class viper-SEP-char-class) (viper-line-pos 'end))))
+    (viper-skip-syntax
+     'forward
+     (concat "^" viper-ALPHA-char-class viper-SEP-char-class)
+     ;; Emacs may consider some of these as words, but we don't want them
+     viper-non-word-characters 
+     (viper-line-pos 'end))))
 (defun viper-skip-nonalphasep-backward ()
   (if (eq viper-syntax-preference 'strict-vi)
       (skip-chars-backward
        (concat "^" viper-strict-SEP-chars viper-strict-ALPHA-chars))
-    (skip-syntax-backward
-     (concat
-      "^"
-      viper-ALPHA-char-class viper-SEP-char-class)
+    (viper-skip-syntax
+     'backward
+     (concat "^" viper-ALPHA-char-class viper-SEP-char-class)
+     ;; Emacs may consider some of these as words, but we don't want them
+     viper-non-word-characters
      (viper-line-pos 'start))))
 
 ;; Skip SYNTAX like skip-syntax-* and ADDL-CHARS like skip-chars-*
 ;; Return the number of chars traveled.
-;; Either SYNTAX or ADDL-CHARS can be nil, in which case they are interpreted
-;; as an empty string.
+;; Both SYNTAX or ADDL-CHARS can be strings or lists of characters.
+;; When SYNTAX is "w", then viper-non-word-characters are not considered to be
+;; words, even if Emacs syntax table says they are.
 (defun viper-skip-syntax (direction syntax addl-chars &optional limit)
   (let ((total 0)
        (local 1)
-       (skip-chars-func (intern (format "skip-chars-%S" direction)))
-       (skip-syntax-func (intern (format "skip-syntax-%S" direction))))
-    (or (stringp addl-chars) (setq addl-chars ""))
-    (or (stringp syntax) (setq syntax ""))
-    (while (and (not (= local 0)) (not (eobp)))
+       (skip-chars-func
+        (if (eq direction 'forward)
+            'skip-chars-forward 'skip-chars-backward))
+       (skip-syntax-func
+        (if (eq direction 'forward)
+            'viper-forward-char-carefully 'viper-backward-char-carefully))
+       char-looked-at syntax-of-char-looked-at negated-syntax)
+    (setq addl-chars
+         (cond ((listp addl-chars) (viper-charlist-to-string addl-chars))
+               ((stringp addl-chars) addl-chars)
+               (t "")))
+    (setq syntax
+         (cond ((listp syntax) syntax)
+               ((stringp syntax) (viper-string-to-list syntax))
+               (t nil)))
+    (if (memq ?^ syntax) (setq negated-syntax t))
+
+    (while (and (not (= local 0)) 
+               (cond ((eq direction 'forward) 
+                      (not (eobp)))
+                     (t (not (bobp)))))
+      (setq char-looked-at (viper-char-at-pos direction)
+           ;; if outside the range, set to nil
+           syntax-of-char-looked-at (if char-looked-at
+                                        (char-syntax char-looked-at)))
       (setq local
-           (+ (funcall skip-syntax-func syntax limit)
+           (+ (if (and
+                   (cond ((and limit (eq direction 'forward))
+                          (< (point) limit))
+                         (limit ; backward & limit
+                          (> (point) limit))
+                         (t t)) ; no limit
+                   ;; char under/before cursor has appropriate syntax
+                   (if negated-syntax
+                       (not (memq syntax-of-char-looked-at syntax))
+                     (memq syntax-of-char-looked-at syntax))
+                   ;; if char-syntax class is "word", make sure it is not one
+                   ;; of the excluded characters
+                   (if (and (eq syntax-of-char-looked-at ?w)
+                            (not negated-syntax))
+                       (not (memq char-looked-at viper-non-word-characters))
+                     t))
+                  (funcall skip-syntax-func 1)
+                0)
               (funcall skip-chars-func addl-chars limit)))
       (setq total (+ total local)))
     total