;; and a venomous VI PERil.
;; Viper Is also a Package for Emacs Rebels.
-;; Copyright (C) 1994-2013 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.
;; ----------------
;; 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
(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)
dired-mode
efs-mode
tar-mode
+ egg-status-buffer-mode
browse-kill-ring-mode
recentf-mode
(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
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
(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.
(require 'viper)
in your init 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."))
+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)