]> code.delx.au - gnu-emacs/blobdiff - lisp/emulation/viper-ex.el
new version
[gnu-emacs] / lisp / emulation / viper-ex.el
index 4720fcf2494652b6f55ed163f350b507c5ab10b6..4b29dc1465e70476d576dfcef64a6f88d6186096 100644 (file)
@@ -1,6 +1,6 @@
 ;;; viper-ex.el --- functions implementing the Ex commands for Viper
 
-;; Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
+;; Copyright (C) 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
 
 ;; This file is part of GNU Emacs.
 
 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 ;; Boston, MA 02111-1307, USA.
 
-
 ;; Code
 
-(require 'viper-util)
+(provide 'viper-ex)
 
 ;; Compiler pacifier
 (defvar read-file-name-map)
-;; end compiler pacifier
+(defvar vip-use-register)
+(defvar vip-s-string)
+(defvar vip-shift-width)
+(defvar vip-ex-history)
+(defvar vip-related-files-and-buffers-ring)
+(defvar vip-local-search-start-marker)
+(defvar viper-expert-level)
+(defvar vip-custom-file-name)
+(defvar vip-case-fold-search)
+(defvar explicit-shell-file-name)
+
+;; loading happens only in non-interactive compilation
+;; in order to spare non-viperized emacs from being viperized
+(if noninteractive
+    (eval-when-compile
+      (let ((load-path (cons (expand-file-name ".") load-path)))
+       (or (featurep 'viper-util)
+           (load "viper-util.el" nil nil 'nosuffix))
+       (or (featurep 'viper-keym)
+           (load "viper-keym.el" nil nil 'nosuffix))
+       (or (featurep 'viper-cmd)
+           (load "viper-cmd.el" nil nil 'nosuffix))
+       )))
+;; end pacifier
+
+(require 'viper-util)
+
+(defgroup viper-ex nil
+  "Viper support for Ex commands"
+  :prefix "ex-"
+  :group 'viper)
+
+
 
 ;;; Variables
 
 ;; A-list of Ex variables that can be set using the :set command.
 (defconst ex-variable-alist 
   '(("wrapscan") ("ws") ("wrapmargin") ("wm")
-    ("global-tabstop") ("gts") ("tabstop") ("ts")
+    ("tabstop-global") ("ts-g") ("tabstop") ("ts")
     ("showmatch") ("sm") ("shiftwidth") ("sw") ("shell") ("sh")
     ("readonly") ("ro") 
     ("nowrapscan") ("nows") ("noshowmatch") ("nosm")
     ("noreadonly") ("noro") ("nomagic") ("noma")
     ("noignorecase") ("noic")
-    ("global-noautoindent") ("gnoai") ("noautoindent") ("noai")
+    ("noautoindent-global") ("noai-g") ("noautoindent") ("noai")
     ("magic") ("ma") ("ignorecase") ("ic")
-    ("global-autoindent") ("gai") ("autoindent") ("ai")
+    ("autoindent-global") ("ai-g") ("autoindent") ("ai") 
+    ("all") 
     ))
 
   
 ;; Value of ex count.
 (defvar ex-count nil)
 
-;; Flag for global command.
+;; Flag indicating that :global Ex command is being executed.
 (defvar ex-g-flag nil)
-
-;; If t, global command is executed on lines not matching ex-g-pat.
+;; Flag indicating that :vglobal Ex command is being executed.
 (defvar ex-g-variant nil)
 
 ;; Save reg-exp used in substitute.
 ;; Pattern for global command.
 (defvar ex-g-pat nil)
 
-;; `sh' doesn't seem to expand wildcards, like `*'
-(defconst ex-find-file-shell "csh"
-  "Shell in which to interpret wildcards. Must be csh, tcsh, or similar.
-Bourne shell doesn't seem to work here.")
-(defvar ex-find-file-shell-options "-f"
-  "*Options to pass to `ex-find-file-shell'.")
+(defcustom ex-unix-type-shell
+  (let ((case-fold-search t))
+    (and (stringp shell-file-name)
+        (string-match
+         (concat
+          "\\("
+          "csh$\\|csh.exe$"
+          "\\|"
+          "ksh$\\|ksh.exe$"
+          "\\|"
+          "^sh$\\|sh.exe$"
+          "\\|"
+          "[^a-z]sh$\\|[^a-z]sh.exe$"
+          "\\|"
+          "bash$\\|bash.exe$"
+          "\\)")
+         shell-file-name)))
+  "Is the user using a unix-type shell under a non-OS?"
+  :type 'string
+  :group 'viper-ex)
+
+(defcustom ex-unix-type-shell-options
+  (let ((case-fold-search t))
+    (if ex-unix-type-shell
+       (cond ((string-match "\\(csh$\\|csh.exe$\\)" shell-file-name)
+              "-f") ; csh: do it fast
+             ((string-match "\\(bash$\\|bash.exe$\\)" shell-file-name)
+              "-noprofile") ; bash: ignore .profile
+             )))
+  "Options to pass to the Unix-style shell. 
+Don't put `-c' here, as it is added automatically."
+  :type 'string
+  :group 'viper-ex)
+
+(defvar ex-nontrivial-find-file-function
+  (cond (ex-unix-type-shell 'vip-ex-nontrivial-find-file-unix)
+       ((eq system-type 'emx) 'vip-ex-nontrivial-find-file-ms) ; OS/2
+       (vip-ms-style-os-p 'vip-ex-nontrivial-find-file-ms) ; a Microsoft OS
+       (vip-vms-os-p 'vip-ex-nontrivial-find-file-unix) ; VMS
+       (t  'vip-ex-nontrivial-find-file-unix) ; presumably UNIX
+       ))
 
 ;; Remembers the previous Ex tag.
 (defvar ex-tag nil)
@@ -132,13 +198,17 @@ Bourne shell doesn't seem to work here.")
 ;; multiple file names. Used for :edit and :next
 (defvar vip-keep-reading-filename nil)
 
-(defconst ex-cycle-other-window t
+(defcustom ex-cycle-other-window t
   "*If t, :n and :b cycles through files and buffers in other window.
 Then :N and :B cycles in the current window. If nil, this behavior is
-reversed.")
+reversed."
+  :type 'boolean
+  :group 'viper-ex)
 
-(defconst ex-cycle-through-non-files nil
-  "*Cycle through *scratch* and other buffers that don't visit any file.")
+(defcustom ex-cycle-through-non-files nil
+  "*Cycle through *scratch* and other buffers that don't visit any file."
+  :type 'boolean
+  :group 'viper-ex)
 
 ;; Last shell command executed with :! command.
 (defvar vip-ex-last-shell-com nil)
@@ -253,6 +323,7 @@ reversed.")
 ;; A token has a type, \(command, address, end-mark\), and a value
 (defun vip-get-ex-token ()
   (save-window-excursion
+    (setq vip-ex-work-buf (get-buffer-create vip-ex-work-buf-name)) 
     (set-buffer vip-ex-work-buf)
     (skip-chars-forward " \t|")
     (cond ((looking-at "#")
@@ -368,7 +439,7 @@ reversed.")
                      "*[ \t]*$"))
        (stay-regex (concat
                     "\\(" "^[ \t]*$"
-                    "\\|" "[?/].*[?/].*"
+                    "\\|" "[?/].*"
                     "\\|" "[ktgjmsz][ \t]*$"
                     "\\|" "^[ \t]*ab.*"
                     "\\|" "tr[ansfer \t]*"
@@ -388,6 +459,7 @@ reversed.")
                     "!*")))
        
     (save-window-excursion ;; put cursor at the end of the Ex working buffer
+      (setq vip-ex-work-buf (get-buffer-create vip-ex-work-buf-name)) 
       (set-buffer vip-ex-work-buf)
       (goto-char (point-max)))
     (cond ((vip-looking-back quit-regex1) (exit-minibuffer))
@@ -443,7 +515,6 @@ reversed.")
     
 
 ;; Read Ex commands 
-;; Ex commands themselves are implemented in viper-ex.el
 (defun vip-ex (&optional string)
   (interactive)
   (or string
@@ -465,8 +536,7 @@ reversed.")
                              map)))
     (save-window-excursion
       ;; just a precaution
-      (or (vip-buffer-live-p vip-ex-work-buf)
-         (setq vip-ex-work-buf (get-buffer-create vip-ex-work-buf-name)))
+      (setq vip-ex-work-buf (get-buffer-create vip-ex-work-buf-name)) 
       (set-buffer vip-ex-work-buf)
       (delete-region (point-min) (point-max))
       (insert com-str "\n")
@@ -486,6 +556,8 @@ reversed.")
                   (t
                    (vip-execute-ex-command)
                    (save-window-excursion
+                     (setq vip-ex-work-buf
+                           (get-buffer-create vip-ex-work-buf-name))
                      (set-buffer vip-ex-work-buf)
                      (skip-chars-forward " \t")
                      (cond ((looking-at "|")
@@ -522,6 +594,7 @@ reversed.")
 ;; Get a regular expression and set `ex-variant', if found
 (defun vip-get-ex-pat ()
   (save-window-excursion
+    (setq vip-ex-work-buf (get-buffer-create vip-ex-work-buf-name))
     (set-buffer vip-ex-work-buf)
     (skip-chars-forward " \t")
     (if (looking-at "!")
@@ -551,13 +624,22 @@ reversed.")
            (setq ex-token
                  (if (= (mark t) (point)) ""
                    (buffer-substring (1- (point)) (mark t))))
-           (backward-char 1))
+           (backward-char 1)
+           ;; if the user doesn't specify the final pattern delimiter, we're
+           ;; at newline now. In this case, insert the initial delimiter
+           ;; specified in variable c
+           (if (looking-at "\n")
+               (progn
+                   (insert c)
+                     (backward-char 1)))
+           )
        (setq ex-token nil))
       c)))
 
 ;; get an ex command
 (defun vip-get-ex-command ()
   (save-window-excursion
+    (setq vip-ex-work-buf (get-buffer-create vip-ex-work-buf-name)) 
     (set-buffer vip-ex-work-buf)
     (if (looking-at "/") (forward-char 1))
     (skip-chars-forward " \t")
@@ -573,6 +655,7 @@ reversed.")
 ;; Get an Ex option g or c
 (defun vip-get-ex-opt-gc (c)
   (save-window-excursion
+    (setq vip-ex-work-buf (get-buffer-create vip-ex-work-buf-name)) 
     (set-buffer vip-ex-work-buf)
     (if (looking-at (format "%c" c)) (forward-char 1))
     (skip-chars-forward " \t")
@@ -599,7 +682,8 @@ reversed.")
 
 ;; Get an ex-address as a marker and set ex-flag if a flag is found
 (defun vip-get-ex-address ()
-  (let ((address (point-marker)) (cont t))
+  (let ((address (point-marker))
+       (cont t))
     (setq ex-token "")
     (setq ex-flag nil)
     (while cont
@@ -684,6 +768,7 @@ reversed.")
   (setq ex-count nil)
   (setq ex-flag nil)
   (save-window-excursion
+    (setq vip-ex-work-buf (get-buffer-create vip-ex-work-buf-name)) 
     (set-buffer vip-ex-work-buf)
     (skip-chars-forward " \t")
     (if (looking-at "[a-zA-Z]")
@@ -709,6 +794,7 @@ reversed.")
        ex-count nil
        ex-flag nil)
   (save-window-excursion
+    (setq vip-ex-work-buf (get-buffer-create vip-ex-work-buf-name)) 
     (set-buffer vip-ex-work-buf)
     (skip-chars-forward " \t")
     (if (looking-at "!")
@@ -770,6 +856,7 @@ reversed.")
          ex-cmdfile nil)
     (save-excursion
       (save-window-excursion
+       (setq vip-ex-work-buf (get-buffer-create vip-ex-work-buf-name)) 
        (set-buffer vip-ex-work-buf)
        (skip-chars-forward " \t")
        (if (looking-at "!")
@@ -882,8 +969,10 @@ reversed.")
     (setq cont (setq vip-keep-reading-filename t))
     (while cont
       (setq vip-keep-reading-filename nil
-           val (read-file-name (concat prompt str) nil default-directory)
-           str  (concat str (if (equal val "") "" " ")
+           val (read-file-name (concat prompt str) nil default-directory))
+      (if (string-match " " val)
+         (setq val (concat "\\\"" val "\\\"")))
+      (setq str  (concat str (if (equal val "") "" " ")
                         val (if (equal val "") "" " ")))
                         
       ;; Only edit, next, and Next commands accept multiple files.
@@ -1133,12 +1222,14 @@ reversed.")
   (if (null (setq file (get-file-buffer ex-file)))
       (progn 
        (ex-find-file ex-file)
-       (vip-change-state-to-vi)
+       (or (eq major-mode 'dired-mode)
+           (vip-change-state-to-vi))
        (goto-char (point-min)))
     (switch-to-buffer file))
   (if ex-offset
       (progn
        (save-window-excursion
+         (setq vip-ex-work-buf (get-buffer-create vip-ex-work-buf-name)) 
          (set-buffer vip-ex-work-buf)
          (delete-region (point-min) (point-max))
          (insert ex-offset "\n")
@@ -1147,44 +1238,28 @@ reversed.")
        (beginning-of-line)))
   (ex-fixup-history vip-last-ex-prompt ex-file))
 
-;; splits the string FILESPEC into substrings separated by newlines `\012'
-;; each line assumed to be a file name. find-file's each file thus obtained.
+;; Find-file FILESPEC if it appears to specify a single file.
+;; Otherwise, assume that FILES{EC is a wildcard.
+;; In this case, split it into substrings separated by newlines.
+;; Each line is assumed to be a file name. find-file's each file thus obtained.
 (defun ex-find-file (filespec)
-  (let (f filebuf tmp-buf status)
-    (if (string-match "[^a-zA-Z0-9_.-/]" filespec)
-       (progn
-         (save-excursion 
-           (set-buffer (setq tmp-buf (get-buffer-create vip-ex-tmp-buf-name)))
-           (erase-buffer)
-           (setq status
-                 (call-process ex-find-file-shell nil t nil
-                               ex-find-file-shell-options 
-                               "-c"
-                               (format "echo %s | tr ' ' '\\012'" filespec)))
-           (goto-char (point-min))
-           ;; Issue an error, if no match.
-           (if (> status 0)
-               (save-excursion
-                 (skip-chars-forward " \t\n\j")
-                 (if (looking-at "echo:")
-                     (vip-forward-word 1))
-                 (error "%S%s"
-                        filespec
-                        (buffer-substring (point) (vip-line-pos 'end)))
-                 ))
-           (reverse-region (point-min) (point-max))
-           (goto-char (point-min))
-           (while (not (eobp))
-             (setq f (buffer-substring (point) (vip-line-pos 'end)))
-             (setq filebuf (find-file f))
-             (set-buffer tmp-buf) ; otherwise it'll be in f.
-             (forward-to-indentation 1))
-           ))
-      (setq filebuf (find-file-noselect (setq f filespec))))
-    (switch-to-buffer filebuf)
+  (let ((nonstandard-filename-chars "[^-a-zA-Z0-9_./,~$\\]"))
+    (cond ((file-exists-p filespec) (find-file filespec))
+         ((string-match nonstandard-filename-chars  filespec)
+          (funcall ex-nontrivial-find-file-function filespec))
+         (t (find-file filespec)))
     ))
 
+
 ;; Ex global command
+;; This is executed in response to:
+;;             :global "pattern" ex-command
+;;             :vglobal "pattern" ex-command
+;; :global executes ex-command on all lines matching <pattern>
+;; :vglobal executes ex-command on all lines that don't match <pattern>
+;;
+;; With VARIANT nil, this functions executes :global
+;; With VARIANT t, executes :vglobal
 (defun ex-global (variant)
   (let ((gcommand ex-token))
     (if (or ex-g-flag ex-g-variant)
@@ -1207,8 +1282,11 @@ reversed.")
   (if (null ex-addresses)
       (setq ex-addresses (list (point-max) (point-min)))
     (vip-default-ex-addresses))
-  (let ((marks nil) (mark-count 0)
-       com-str (end (car ex-addresses)) (beg (car (cdr ex-addresses))))
+  (let ((marks nil)
+       (mark-count 0)
+       (end (car ex-addresses))
+       (beg (car (cdr ex-addresses)))
+       com-str)
     (if (> beg end) (error vip-FirstAddrExceedsSecond))
     (save-excursion
       (vip-enlarge-region beg end)
@@ -1234,6 +1312,7 @@ reversed.")
            (forward-line -1)
            (end-of-line)))))
     (save-window-excursion
+      (setq vip-ex-work-buf (get-buffer-create vip-ex-work-buf-name)) 
       (set-buffer vip-ex-work-buf)
       (setq com-str (buffer-substring (1+ (point)) (1- (point-max)))))
     (while marks
@@ -1305,6 +1384,7 @@ reversed.")
        (setq ex-addresses
              (cons (point) nil)))
     (save-window-excursion
+      (setq vip-ex-work-buf (get-buffer-create vip-ex-work-buf-name)) 
       (set-buffer vip-ex-work-buf)
       (skip-chars-forward " \t")
       (if (looking-at "[a-z]")
@@ -1439,9 +1519,10 @@ reversed.")
 (defun ex-quit ()
   ;; skip "!", if it is q!. In Viper q!, w!, etc., behave as q, w, etc.
   (save-excursion
+    (setq vip-ex-work-buf (get-buffer-create vip-ex-work-buf-name)) 
     (set-buffer vip-ex-work-buf)
     (if (looking-at "!") (forward-char 1)))
-  (if (< vip-expert-level 3)
+  (if (< viper-expert-level 3)
       (save-buffers-kill-emacs)
     (kill-buffer (current-buffer))))
 
@@ -1515,7 +1596,7 @@ reversed.")
     (while (string-match "^[ \\t\\n]*$"
                         (setq str
                               (completing-read ":set " ex-variable-alist)))
-      (message ":set <Variable> ")
+      (message ":set <Variable> [= <Value>]")
       ;; if there are unread events, don't wait
       (or (vip-set-unread-command-events "") (sit-for 2))
       ) ; while
@@ -1533,12 +1614,15 @@ reversed.")
        actual-lisp-cmd lisp-cmd-del-pattern
        val2 orig-var)
     (setq orig-var var)
-    (cond ((member var '("ai" "autoindent"))
+    (cond ((string= var "all")
+          (setq ask-if-save nil
+                set-cmd nil))
+         ((member var '("ai" "autoindent"))
           (setq var "vip-auto-indent"
                 set-cmd "setq"
                 ask-if-save nil
                 val "t"))
-         ((member var '("gai" "global-autoindent"))
+         ((member var '("ai-g" "autoindent-global"))
           (kill-local-variable 'vip-auto-indent)
           (setq var "vip-auto-indent"
                 set-cmd "setq-default"
@@ -1547,7 +1631,7 @@ reversed.")
           (setq var "vip-auto-indent"
                 ask-if-save nil
                 val "nil"))
-         ((member var '("gnoai" "global-noautoindent"))
+         ((member var '("noai-g" "noautoindent-global"))
           (kill-local-variable 'vip-auto-indent)
           (setq var "vip-auto-indent"
                 set-cmd "setq-default"
@@ -1561,7 +1645,7 @@ reversed.")
          ((member var '("ma" "magic"))
           (setq var "vip-re-search"
                 val "t"))
-         ((member var '("noma" "nomagic"))
+         ((member var '("noma" "nomagic"))
           (setq var "vip-re-search"
                 val "nil"))
          ((member var '("ro" "readonly"))
@@ -1582,7 +1666,7 @@ reversed.")
          ((member var '("nows" "nowrapscan"))
           (setq var "vip-search-wrap-around-t"
                 val "nil")))
-    (if (eq val 0) ; value must be set by the user
+    (if (and set-cmd (eq val 0)) ; value must be set by the user
        (let ((cursor-in-echo-area t))
          (message ":set %s = <Value>" var)
          ;; if there are unread events, don't wait
@@ -1594,7 +1678,7 @@ reversed.")
          (if (member var
                      '("sw" "shiftwidth"
                        "ts" "tabstop"
-                       "gts" "global-tabstop"
+                       "ts-g" "tabstop-global"
                        "wm" "wrapmargin")) 
              (condition-case nil
                  (or (numberp (setq val2 (car (read-from-string val))))
@@ -1610,7 +1694,7 @@ reversed.")
            (setq var "tab-width"
                  set-cmd "setq"
                  ask-if-save nil))
-          ((member var '("gts" "global-tabstop"))
+          ((member var '("ts-g" "tabstop-global"))
            (kill-local-variable 'tab-width)
            (setq var "tab-width"
                  set-cmd "setq-default"))
@@ -1625,11 +1709,12 @@ reversed.")
                  val (format "\"%s\"" val)))))
       (ex-fixup-history "set" orig-var))
     
-    (setq actual-lisp-cmd (format "\n(%s %s %s) %s"
-                                 set-cmd var val auto-cmd-label))
-    (setq lisp-cmd-del-pattern
-         (format "^\n?[ \t]*([ \t]*%s[ \t]+%s[ \t].*)[ \t]*%s"
-                 set-cmd var auto-cmd-label))
+    (if set-cmd
+       (setq actual-lisp-cmd
+             (format "\n(%s %s %s) %s" set-cmd var val auto-cmd-label)
+             lisp-cmd-del-pattern
+             (format "^\n?[ \t]*([ \t]*%s[ \t]+%s[ \t].*)[ \t]*%s"
+                     set-cmd var auto-cmd-label)))
     
     (if (and ask-if-save
             (y-or-n-p (format "Do you want to save this setting in %s "
@@ -1656,15 +1741,19 @@ reversed.")
                ))
          ))
     
-    (message "%s %s %s" set-cmd var (if (string-match "^[ \t]*$" val)
-                                       (format "%S" val)
-                                     val))
-    (eval (car (read-from-string actual-lisp-cmd)))
-       (if (string= var "fill-column")
-               (if (> val2 0)
-                       (auto-fill-mode 1)
-                 (auto-fill-mode -1)))
-               
+    (if set-cmd
+       (message "%s %s %s"
+                set-cmd var
+                (if (string-match "^[ \t]*$" val)
+                    (format "%S" val)
+                  val)))
+    (if actual-lisp-cmd
+       (eval (car (read-from-string actual-lisp-cmd))))
+    (if (string= var "fill-column")
+       (if (> val2 0)
+           (auto-fill-mode 1)
+         (auto-fill-mode -1)))
+    (if (string= var "all") (ex-show-vars))
     ))
 
 ;; In inline args, skip regex-forw and (optionally) chars-back.
@@ -1672,6 +1761,7 @@ reversed.")
 ;; special meaning
 (defun ex-get-inline-cmd-args (regex-forw &optional chars-back replace-str)
   (save-excursion
+    (setq vip-ex-work-buf (get-buffer-create vip-ex-work-buf-name)) 
     (set-buffer vip-ex-work-buf)
     (goto-char (point-min))
     (re-search-forward regex-forw nil t)
@@ -1805,6 +1895,7 @@ Please contact your system administrator. "
 (defun ex-tag ()
   (let (tag)
     (save-window-excursion
+      (setq vip-ex-work-buf (get-buffer-create vip-ex-work-buf-name)) 
       (set-buffer vip-ex-work-buf)
       (skip-chars-forward " \t")
       (set-mark (point))
@@ -1826,7 +1917,12 @@ Please contact your system administrator. "
 (defun ex-write (q-flag)
   (vip-default-ex-addresses t)
   (vip-get-ex-file)
-  (let ((end (car ex-addresses)) (beg (car (cdr ex-addresses))) 
+  (let ((end (car ex-addresses))
+       (beg (car (cdr ex-addresses))) 
+       (orig-buf (current-buffer))
+       (orig-buf-file-name (buffer-file-name))
+       (orig-buf-name (buffer-name))
+       (buff-changed-p (buffer-modified-p))
        temp-buf writing-same-file region
        file-exists writing-whole-file)
     (if (> beg end) (error vip-FirstAddrExceedsSecond))
@@ -1849,8 +1945,9 @@ Please contact your system administrator. "
               buffer-file-name
               (not (file-directory-p buffer-file-name)))
          (setq ex-file
-               (concat ex-file (file-name-nondirectory buffer-file-name))))
-
+               (concat (file-name-as-directory ex-file)
+                       (file-name-nondirectory buffer-file-name))))
+      
       (setq file-exists (file-exists-p ex-file)
            writing-same-file (string= ex-file (buffer-file-name)))
 
@@ -1858,35 +1955,58 @@ Please contact your system administrator. "
          (if (not (buffer-modified-p))
              (message "(No changes need to be saved)")
            (save-buffer)
-           (ex-write-info file-exists ex-file beg end))
-       ;; writing some other file or portion of the currents
-       ;; file---create temp buffer for it
-       ;; disable undo in that buffer, for efficiency
-       (buffer-disable-undo (setq temp-buf (create-file-buffer ex-file)))
-       (unwind-protect 
-           (save-excursion
-             (if (and file-exists
-                      (not writing-same-file)
-                      (not (yes-or-no-p
-                            (format "File %s exists. Overwrite? " ex-file))))
-                 (error "Quit")
-               (vip-enlarge-region beg end)
-               (setq region (buffer-substring (point) (mark t)))
-               (set-buffer temp-buf)
-               (set-visited-file-name ex-file)
-               (erase-buffer)
-               (if (and file-exists ex-append)
-                   (insert-file-contents ex-file))
-               (goto-char (point-max))
-               (insert region)
-               (save-buffer)
-               (ex-write-info file-exists ex-file (point-min) (point-max))
-               )
-             (set-buffer temp-buf)
-             (set-buffer-modified-p nil)
-             (kill-buffer temp-buf)
+           (save-restriction
+                (widen)
+                (ex-write-info file-exists ex-file (point-min) (point-max))
+                ))
+       ;; writing some other file or portion of the current file
+       (cond ((and file-exists
+                   (not writing-same-file)
+                   (not (yes-or-no-p
+                         (format "File %s exists. Overwrite? " ex-file))))
+              (error "Quit"))
+             ((and writing-whole-file (not ex-append))
+              (unwind-protect
+                  (progn
+                    (set-visited-file-name ex-file)
+                    (set-buffer-modified-p t)
+                    (save-buffer))
+                ;; restore the buffer file name
+                (set-visited-file-name orig-buf-file-name)
+                (set-buffer-modified-p buff-changed-p)
+                ;; If the buffer wasn't visiting a file, restore buffer name.
+                ;; Name could've been changed by packages such as uniquify.
+                (or orig-buf-file-name
+                    (progn
+                      (unlock-buffer)
+                      (rename-buffer orig-buf-name))))
+              (save-restriction
+                (widen)
+                (ex-write-info
+                 file-exists ex-file (point-min) (point-max))))
+             (t ; writing a region
+              (unwind-protect 
+                  (save-excursion
+                    (vip-enlarge-region beg end)
+                    (setq region (buffer-substring (point) (mark t)))
+                    ;; create temp buffer for the region
+                    (setq temp-buf (get-buffer-create " *ex-write*"))
+                    (set-buffer temp-buf)
+                    (set-visited-file-name ex-file 'noquerry)
+                    (erase-buffer)
+                    (if (and file-exists ex-append)
+                        (insert-file-contents ex-file))
+                    (goto-char (point-max))
+                    (insert region)
+                    (save-buffer)
+                    (ex-write-info
+                     file-exists ex-file (point-min) (point-max))
+                    ))
+              (set-buffer temp-buf)
+              (set-buffer-modified-p nil)
+              (kill-buffer temp-buf))
              ))
-       )
+      (set-buffer orig-buf)
       ;; this prevents the loss of data if writing part of the buffer
       (if (and (buffer-file-name) writing-same-file)
          (set-visited-file-modtime))
@@ -1894,7 +2014,7 @@ Please contact your system administrator. "
          (not writing-same-file)
          (set-buffer-modified-p t))
       (if q-flag
-         (if (< vip-expert-level 2)
+         (if (< viper-expert-level 2)
              (save-buffers-kill-emacs)
            (kill-buffer (current-buffer))))
       )))
@@ -1938,6 +2058,7 @@ Please contact your system administrator. "
 (defun ex-command ()
   (let (command)
     (save-window-excursion
+      (setq vip-ex-work-buf (get-buffer-create vip-ex-work-buf-name)) 
       (set-buffer vip-ex-work-buf)
       (skip-chars-forward " \t")
       (setq command (buffer-substring (point) (point-max)))
@@ -1996,7 +2117,32 @@ Please contact your system administrator. "
        (kill-buffer " *vip-info*")))
     ))
 
+;; display all variables set through :set
+(defun ex-show-vars ()
+  (with-output-to-temp-buffer " *vip-info*"
+    (princ (if vip-auto-indent
+              "autoindent (local)\n" "noautoindent (local)\n"))
+    (princ (if (default-value 'vip-auto-indent) 
+              "autoindent (global) \n" "noautoindent (global) \n"))
+    (princ (if vip-case-fold-search "ignorecase\n" "noignorecase\n"))
+    (princ (if vip-re-search "magic\n" "nomagic\n"))
+    (princ (if buffer-read-only "readonly\n" "noreadonly\n"))
+    (princ (if blink-matching-paren "showmatch\n" "noshowmatch\n"))
+    (princ (if vip-search-wrap-around-t "wrapscan\n" "nowrapscan\n"))
+    (princ (format "shiftwidth \t\t= %S\n" vip-shift-width))
+    (princ (format "tabstop (local) \t= %S\n" tab-width))
+    (princ (format "tabstop (global) \t= %S\n" (default-value 'tab-width)))
+    (princ (format "wrapmargin (local) \t= %S\n"
+                  (- (window-width) fill-column)))
+    (princ (format "wrapmargin (global) \t= %S\n"
+                  (- (window-width) (default-value 'fill-column))))
+    (princ (format "shell \t\t\t= %S\n" (if (boundp 'explicit-shell-file-name)
+                                           explicit-shell-file-name
+                                         'none)))
+    ))
+
+
+
 
-(provide 'viper-ex)
 
 ;;;  viper-ex.el ends here