;; and a venomous VI PERil.
;; Viper Is also a Package for Emacs Rebels.
-;; Copyright (C) 1994-2011 Free Software Foundation, Inc.
+;; Copyright (C) 1994-2015 Free Software Foundation, Inc.
;; Author: Michael Kifer <kifer@cs.stonybrook.edu>
;; Keywords: emulations
;; 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.
;; facility in the original Vi.
;; First, one can execute any Emacs command while defining a
;; macro, not just the Vi commands. Second, macros are defined in a
-;; WYSYWYG mode, using an interface to Emacs' WYSIWYG style of defining
+;; WYSYWYG mode, using an interface to Emacs's WYSIWYG style of defining
;; macros. Third, in Viper, one can define macros that are specific to
;; a given buffer, a given major mode, or macros defined for all buffers.
;; The same macro name can have several different definitions:
;; (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)
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))
dired-mode
efs-mode
tar-mode
+ egg-status-buffer-mode
browse-kill-ring-mode
recentf-mode
view-mode
vm-mode
vm-summary-mode)
- "*A list of major modes that should come up in Emacs state.
+ "A list of major modes that should come up in Emacs state.
Normally, Viper would bring buffers up in Emacs state, unless the corresponding
major mode has been placed on `viper-vi-state-mode-list' or
`viper-insert-state-mode-list'. So, don't place a new mode on this list,
erc-mode
eshell-mode
shell-mode)
- "*A list of major modes that should come up in Vi Insert state."
+ "A list of major modes that should come up in Vi Insert state."
:type '(repeat symbol)
:group 'viper-misc)
)
"List specifying how to modify the various major modes to enable some Viperisms.
The list has the structure: ((mode viper-state keymap) (mode viper-state
-keymap) ...). If `mode' is on the list, the `kemap' will be made active (on
+keymap) ...). If `mode' is on the list, the `keymap' will be made active (on
the minor-mode-map-alist) in the specified viper state.
If you change this list, have to restart Emacs for the change to take effect.
However, if you did the change through the customization widget, then Emacs
(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
use Emacs productively, you are advised to reach user level 3 or higher.
At user level 2 or higher, ^X and ^C have Emacs, not Vi, bindings;
- ^Z toggles Vi/Emacs states; ^G is Emacs' keyboard-quit (like ^C in Vi).
+ ^Z toggles Vi/Emacs states; ^G is Emacs's keyboard-quit (like ^C in Vi).
2. Vi exit functions (e.g., :wq, ZZ) work on INDIVIDUAL files -- they
do not cause Emacs to quit, except at user level 1 (for a novice).
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
(viper-unbind-mouse-search-key)
(viper-unbind-mouse-insert-key)
;; In emacs, we have to advice handle-switch-frame
- ;; This advice is undone earlier, when all advices matchine "viper-" are
+ ;; This advice is undone earlier, when all advices matching "viper-" are
;; deactivated.
(if (featurep 'xemacs)
(remove-hook 'mouse-leave-frame-hook 'viper-remember-current-frame))
(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 ()
;; 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)
(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
(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.
(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))
'(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
(memq 'down (event-modifiers (aref key 1)))))
(read-event))))))
) ; (if (featurep 'xemacs)
-
+
(if (featurep 'xemacs)
;; XEmacs
(defadvice describe-key-briefly
(prefix-numeric-value current-prefix-arg))
1))))
) ; (if (featurep 'xemacs)
-
+
(defadvice find-file (before viper-add-suffix-advice activate)
"Use `read-file-name' for reading arguments."
(interactive (cons (read-file-name "Find file: " nil default-directory)
(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))
;; 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.
;; 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
\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
;; 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)