]> code.delx.au - gnu-emacs/blobdiff - lisp/emulation/viper.el
Update copyright year to 2015
[gnu-emacs] / lisp / emulation / viper.el
index 9cf6c91265e45f59cbb9be263765bc934e35dcb2..0933c949df0a789900195285e3ba91f6de2c9300 100644 (file)
@@ -3,7 +3,7 @@
 ;;              and a venomous VI PERil.
 ;;              Viper Is also a Package for Emacs Rebels.
 
-;; Copyright (C) 1994-2012 Free Software Foundation, Inc.
+;; Copyright (C) 1994-2015 Free Software Foundation, Inc.
 
 ;; Author: Michael Kifer <kifer@cs.stonybrook.edu>
 ;; Keywords: emulations
@@ -14,7 +14,7 @@
 ;; filed in the Emacs bug reporting system against this file, a copy
 ;; of the bug report be sent to the maintainer's email address.
 
-(defconst viper-version "3.14.1 of August 15, 2009"
+(defconst viper-version "3.14.2 of July 4, 2013"
   "The current version of Viper")
 
 ;; This file is part of GNU Emacs.
 ;;  (require 'viper)
 ;;
 
-;;; Acknowledgements:
-;;  -----------------
+;;; Acknowledgments:
+;;  ----------------
 ;;  Bug reports and ideas contributed by many users have helped
 ;;  improve Viper and the various versions of VIP.
-;;  See the on-line manual for a complete list of contributors.
+;;  See the manual for a complete list of contributors.
 ;;
 ;;
 ;;; Notes:
 ;;
 ;;  The last viper-vi-basic-minor-mode contains most of the usual Vi bindings
 ;;  in its edit mode.  This mode provides access to all Emacs facilities.
-;;  Novice users, however, may want to set their viper-expert-level to 1
-;;  in their .viper file.  This will enable viper-vi-diehard-minor-mode.  This
-;;  minor mode's bindings make Viper simulate the usual Vi very closely.
+;;  Novice users, however, may want to set their viper-expert-level to 1 in
+;;  their viper-custom-file-name.  This will enable viper-vi-diehard-minor-mode.
+;;  This minor mode's bindings make Viper simulate the usual Vi very closely.
 ;;  For instance,  C-c will not have its standard Emacs binding
 ;;  and so many of the goodies of Emacs are not available.
 ;;
 ;;
 ;;  Viper gurus should have at least
 ;;      (setq viper-expert-level 4)
-;;  in their ~/.viper files.  This will unsuppress all Emacs keys that are not
-;;  essential for VI-style editing.
+;;  in their viper-custom-file-name.  This will unsuppress all Emacs keys
+;;  that are not essential for VI-style editing.
 ;;  Pick-and-choose users may want to put
 ;;      (setq viper-expert-level 5)
-;;  in ~/.viper.  Viper will then leave it up to the user to set the variables
-;;  viper-want-*  See viper-set-expert-level for details.
+;;  in viper-custom-file-name.  Viper will then leave it up to the user to
+;;  set the variables viper-want-*  See viper-set-expert-level for details.
 ;;
 ;;  The very first minor mode, viper-vi-intercept-minor-mode, is of no
 ;;  concern for the user.  It is needed to bind Viper's vital keys, such as
 (require 'viper-keym)
 
 ;; better be defined before Viper custom group.
-(defvar viper-custom-file-name (convert-standard-filename "~/.viper")
+(defvar viper-custom-file-name (locate-user-emacs-file "viper" ".viper")
   "Viper customization file.
 If set by the user, this must be done _before_ Viper is loaded in `~/.emacs'.")
 
 (defgroup viper nil
   "Vi emulation within Emacs.
-NOTE: Viper customization should be saved in `viper-custom-file-name', which
-defaults to `~/.viper'."
+NOTE: Viper customization should be saved in `viper-custom-file-name'."
   :prefix "viper-"
   :group 'emulations)
 
@@ -351,7 +350,7 @@ user decide when to invoke Viper in a major mode."
 If t, viperize Emacs.  If nil -- don't.  If `ask', ask the user.
 This variable is used primarily when Viper is being loaded.
 
-Must be set in `~/.emacs' before Viper is loaded.
+Must be set in your init file before Viper is loaded.
 DO NOT set this variable interactively, unless you are using the customization
 widget."
   :type '(choice (const nil) (const t) (const ask))
@@ -411,6 +410,7 @@ widget."
     dired-mode
     efs-mode
     tar-mode
+    egg-status-buffer-mode
 
     browse-kill-ring-mode
     recentf-mode
@@ -531,6 +531,7 @@ If Viper is enabled, turn it off.  Otherwise, turn it on."
        (if viper-mode
            ()
          (setq viper-mode t)
+          ;; FIXME: Don't reload!
          (load-library "viper"))
 
        (if viper-first-time ; Important check.  Prevents mix-up of startup
@@ -660,7 +661,7 @@ user customization, unrelated to Viper.  For instance, if the user advised
 undone.
 It also can't undo some Viper settings."
   (interactive)
-
+  (viper-setup-ESC-to-escape nil)
   ;; restore non-viper vars
   (setq-default
    next-line-add-newlines
@@ -825,6 +826,58 @@ It also can't undo some Viper settings."
   (add-hook 'viper-post-command-hooks 'set-viper-state-in-major-mode t))
 
 
+;;; Handling of tty's ESC event
+
+;; On a tty, an ESC event can either be the user hitting the escape key, or
+;; some element of a byte sequence used to encode for example cursor keys.
+;; So we try to recognize those events that correspond to the escape key and
+;; turn them into `escape' events (same as used under GUIs).  The heuristic we
+;; use to distinguish the two cases is based, as usual, on a timeout, and on
+;; the fact that the special ESC=>escape mapping only takes place if the whole
+;; last key-sequence so far is just [?\e], i.e. either we're still in
+;; read-key-sequence, or the last read-key-sequence only read [?\e], which
+;; should ideally never happen because it should have been mapped to [escape].
+
+(defun viper--tty-ESC-filter (map)
+  (if (and (equal (this-single-command-keys) [?\e])
+           (sit-for (/ viper-fast-keyseq-timeout 1000)))
+      [escape] map))
+
+(defun viper--lookup-key (map key)
+  "Kind of like `lookup-key'.
+Two differences:
+- KEY is a single key, not a sequence.
+- the result is the \"raw\" binding, so it can be a `menu-item', rather than the
+  binding contained in that menu item."
+  (catch 'found
+    (map-keymap (lambda (k b) (if (equal key k) (throw 'found b))) map)))
+
+(defun viper-catch-tty-ESC ()
+  "Setup key mappings of current terminal to turn a tty's ESC into `escape'."
+  (when (memq (terminal-live-p (frame-terminal)) '(t pc))
+    (let ((esc-binding (viper-uncatch-tty-ESC)))
+      (define-key input-decode-map
+        [?\e] `(menu-item "" ,esc-binding :filter viper--tty-ESC-filter)))))
+
+(defun viper-uncatch-tty-ESC ()
+  "Don't hack ESC into `escape' any more."
+  (let ((b (viper--lookup-key input-decode-map ?\e)))
+    (and (eq 'menu-item (car-safe b))
+         (eq 'viper--tty-ESC-filter (nth 4 b))
+         (define-key input-decode-map [?\e] (setq b (nth 2 b))))
+    b))
+
+(defun viper-setup-ESC-to-escape (enable)
+  (if enable
+      (add-hook 'tty-setup-hook 'viper-catch-tty-ESC)
+    (remove-hook 'tty-setup-hook 'viper-catch-tty-ESC))
+  (let ((seen ()))
+    (dolist (frame (frame-list))
+      (let ((terminal (frame-terminal frame)))
+        (unless (memq terminal seen)
+          (push terminal seen)
+          (with-selected-frame frame
+            (if enable (viper-catch-tty-ESC) (viper-uncatch-tty-ESC))))))))
 
 ;; This sets major mode hooks to make them come up in vi-state.
 (defun viper-set-hooks ()
@@ -835,8 +888,11 @@ It also can't undo some Viper settings."
   ;; When viper-mode is executed in such a case, it will set the major mode
   ;; back to fundamental-mode.
   (if (eq (default-value 'major-mode) 'fundamental-mode)
+      ;; FIXME: We should use after-change-major-mode-hook instead!
       (setq-default major-mode 'viper-mode))
 
+  (viper-setup-ESC-to-escape t)
+
   (add-hook 'change-major-mode-hook 'viper-major-mode-change-sentinel)
   (add-hook 'find-file-hooks 'set-viper-state-in-major-mode)
 
@@ -847,13 +903,6 @@ It also can't undo some Viper settings."
   (defvar emerge-startup-hook)
   (add-hook 'emerge-startup-hook 'viper-change-state-to-emacs)
 
-  ;; Zap bad bindings in flyspell-mouse-map, which prevent ESC from working
-  ;; over misspelled words (due to the overlay keymaps)
-  (defvar flyspell-mode-hook)
-  (defvar flyspell-mouse-map)
-  (add-hook 'flyspell-mode-hook
-           (lambda ()
-              (define-key flyspell-mouse-map viper-ESC-key nil)))
   ;; if viper is started from .emacs, it might be impossible to get certain
   ;; info about the display and windows until emacs initialization is complete
   ;; So do it via the window-setup-hook
@@ -889,6 +938,7 @@ It also can't undo some Viper settings."
 
   (defadvice self-insert-command (around viper-self-insert-ad activate)
     "Ignore all self-inserting keys in the vi-state."
+    ;; FIXME: Use remapping?
     (if (and (eq viper-current-state 'vi-state)
             ;; Do not use called-interactively-p here. XEmacs does not have it
             ;; and interactive-p is just fine.
@@ -971,9 +1021,9 @@ It also can't undo some Viper settings."
   (if (featurep 'emacs)
       (eval-after-load "mule-cmds"
        '(progn
-          (defadvice inactivate-input-method (after viper-mule-advice activate)
+          (defadvice deactivate-input-method (after viper-mule-advice activate)
             "Set viper-special-input-method to disable intl. input methods."
-            (viper-inactivate-input-method-action))
+            (viper-deactivate-input-method-action))
           (defadvice activate-input-method (after viper-mule-advice activate)
             "Set viper-special-input-method to enable intl. input methods."
             (viper-activate-input-method-action))
@@ -985,14 +1035,14 @@ It also can't undo some Viper settings."
       '(progn
         (add-hook 'input-method-activate-hook
                   'viper-activate-input-method-action t)
-        (add-hook 'input-method-inactivate-hook
-                  'viper-inactivate-input-method-action t)))
+        (add-hook 'input-method-deactivate-hook
+                  'viper-deactivate-input-method-action t)))
     )
   (eval-after-load "mule-cmds"
     '(defadvice toggle-input-method (around viper-mule-advice activate)
        "Adjust input-method toggling in vi-state."
        (if (and viper-special-input-method (eq viper-current-state 'vi-state))
-          (viper-inactivate-input-method)
+          (viper-deactivate-input-method)
         ad-do-it)))
 
   ) ; viper-set-hooks
@@ -1173,12 +1223,8 @@ If you wish to Viperize AND make this your way of life, please put
        (setq viper-mode t)
        (require 'viper)
 
-in your .emacs file (preferably, close to the top).
-These two lines must come in the order given.
-
-** Viper users:
-       **** The startup file name has been changed from .vip to .viper
-       **** All vip-* style names have been converted to viper-* style."))
+in your init file (preferably, close to the top).
+These two lines must come in the order given."))
         (if (y-or-n-p "Viperize? ")
             (setq viper-mode t)
           (setq viper-mode nil))
@@ -1220,8 +1266,8 @@ These two lines must come in the order given.
 
 
 ;; Set some useful macros, advices
-;; These must be BEFORE ~/.viper is loaded,
-;; so the user can unrecord them in ~/.viper.
+;; These must be BEFORE viper-custom-file-name is loaded,
+;; so the user can unrecord them in viper-custom-file-name.
 (if viper-mode
     (progn
       ;; set advices and some variables that give emacs Vi look.
@@ -1241,7 +1287,7 @@ These two lines must come in the order given.
       ;; Make %%% toggle parsing comments for matching parentheses
       (viper-set-parsing-style-toggling-macro nil)
 
-      ;; ~/.viper is loaded if exists
+      ;; viper-custom-file-name is loaded if exists
       (viper-load-custom-file)
 
       ;; should be after loading custom file to avoid the pesky msg that
@@ -1252,7 +1298,7 @@ These two lines must come in the order given.
 
 
 \f
-;; Applying Viper customization -- runs after (load .viper)
+;; Applying Viper customization -- runs after (load viper-custom-file-name)
 
 ;; Save user settings or Viper defaults for vars controlled by
 ;; viper-expert-level
@@ -1302,7 +1348,7 @@ These two lines must come in the order given.
 
 
 ;; Intercept maps could go in viper-keym.el
-;; We keep them here in case someone redefines them in ~/.viper
+;; We keep them here in case someone redefines them in viper-custom-file-name
 
 (define-key viper-vi-intercept-map viper-ESC-key 'viper-intercept-ESC-key)
 (define-key viper-insert-intercept-map viper-ESC-key 'viper-intercept-ESC-key)