This commit was manufactured by cvs2svn to create branch 'chise-r21-4-18'.
[chise/xemacs-chise.git-] / lisp / view-less.el
diff --git a/lisp/view-less.el b/lisp/view-less.el
new file mode 100644 (file)
index 0000000..7dd3e30
--- /dev/null
@@ -0,0 +1,406 @@
+;;; view-less.el --- Minor mode for browsing files with keybindings like `less'
+
+;; Copyright (C) 1994, 1995 Tinker Systems and INS Engineering Corp.
+
+;; Author: Jonathan Stigelman <stig@hackvan.com>
+;; Maintainer: XEmacs Development Team
+;; Keywords: wp, unix
+
+;; This file is part of XEmacs.
+;;
+;; XEmacs is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2 of the License, or
+;; (at your option) any later version.
+;;
+;; XEmacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with XEmacs; if not, write to the Free Software
+;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+;;; Synched up with: Not in FSF.
+
+;;; Commentary:
+
+;; This mode is for browsing files without changing them.  Keybindings
+;; similar to those used by the less(1) program are used.
+;;
+;; Originally written for v18 by David Gudeman (gudeman@arizona.edu)
+;; Mods by Bengt Martensson, to closely resemble less (July 1987)
+;;
+;; If you would like all write-protected files to be visited in view-mode,
+;; then add the following to your .emacs file:
+;;
+;;      (add-hook 'find-file-hooks 'auto-view-mode)
+
+;;; Code:
+
+(defvar view-search-string ""
+  "Last string searched for with view-search functions.")
+
+(defvar view-search-arg 1
+  "Argument to last view search.")
+
+(defvar view-default-lines 10
+  "Default value for the \"d\" and \"u\" commands in view-mode")
+
+(defvar view-minor-mode nil
+  "Non-nil when view-mode is active.  Call `view-mode' to toggle.")
+(make-variable-buffer-local 'view-minor-mode)
+
+;;;###autoload
+(defvar view-minor-mode-map
+  (let ((map (make-keymap)))
+    (set-keymap-name map 'view-minor-mode-map)
+    (suppress-keymap map)
+    (define-key map "-" 'negative-argument)
+    (define-key map " " 'scroll-up)
+    (define-key map "f" 'scroll-up)
+    (define-key map "b" 'scroll-down)
+    (define-key map 'backspace 'scroll-down)
+    (define-key map 'delete 'scroll-down)
+    (define-key map "\r" 'view-scroll-lines-up)
+    (define-key map "\n" 'view-scroll-lines-up)
+    (define-key map "e" 'view-scroll-lines-up)
+    (define-key map "j" 'view-scroll-lines-up)
+    (define-key map "y" 'view-scroll-lines-down)
+    (define-key map "k" 'view-scroll-lines-down)
+    (define-key map "d" 'view-scroll-some-lines-up)
+    (define-key map "u" 'view-scroll-some-lines-down)
+    (define-key map "r" 'recenter)
+    (define-key map "t" 'toggle-truncate-lines)
+    (define-key map "N" 'view-buffer)
+    (define-key map "E" 'view-file)
+    (define-key map "P" 'view-buffer)
+    (define-key map "!" 'shell-command)
+    (define-key map "|" 'shell-command-on-region)
+    (define-key map "=" 'what-line)
+    (define-key map "?" 'view-search-backward)
+    (define-key map "h" 'view-mode-describe)
+    (define-key map "s" 'view-repeat-search)
+    (define-key map "n" 'view-repeat-search)
+    (define-key map "/" 'view-search-forward)
+    (define-key map "\\" 'view-search-backward)
+    (define-key map "g" 'view-goto-line)
+    (define-key map "G" 'view-last-windowful)
+    (define-key map "%" 'view-goto-percent)
+    (define-key map "p" 'view-goto-percent)
+    (define-key map "m" 'point-to-register)
+    (define-key map "'" 'register-to-point)
+    (define-key map "C" 'view-cleanup-backspaces)
+    (define-key map "\C-c\C-c" 'view-quit)
+    ;; #### - should this use substitute-command-keys?
+    (define-key map "\C-x\C-q" 'view-quit-toggle-ro)
+    (define-key map "q" 'view-quit)
+    map
+    ))
+
+(add-minor-mode 'view-minor-mode " View" view-minor-mode-map)
+
+;;;###autoload
+(defvar view-mode-map
+  (let ((map (copy-keymap view-minor-mode-map)))
+    (set-keymap-name map 'view-mode-map)
+    map))
+
+;;;###autoload
+(defun view-file (filename &optional other-window-p)
+  "Find FILENAME, enter view mode.  With prefix arg OTHER-WINDOW-P, use other window."
+  (interactive "fView File: \nP")
+  (let ((old-p (get-file-buffer filename))
+       (obuf (current-buffer)))
+    (if other-window-p
+       (find-file-other-window filename)
+      (find-file filename))
+    (view-mode (if other-window-p nil obuf)
+              (if old-p nil 'kill-buffer))
+    nil))
+
+;;;###autoload
+(defun view-buffer (buffer &optional other-window-p)
+  "Switch to BUFFER, enter view mode.  With prefix arg use other window."
+  (interactive "bView Buffer: \nP")
+  (let ((obuf (current-buffer)))
+    (if other-window-p
+       (switch-to-buffer-other-window buffer)
+      (switch-to-buffer buffer))
+    (view-mode (if other-window-p nil obuf)
+              (if other-window-p nil 'bury-buffer))))
+
+;;;###autoload
+(defun view-file-other-window (filename)
+  "Find FILENAME in other window, and enter view mode."
+  (interactive "fView File: ")
+  (view-file filename t))
+
+;;;###autoload
+(defun view-buffer-other-window (buffer)
+  "Switch to BUFFER in another window, and enter view mode."
+  (interactive "bView Buffer: ")
+  (view-buffer buffer t))
+
+(defun view-brief-help ()
+  (message
+   (substitute-command-keys
+    "\\<view-minor-mode-map>\\[scroll-up] = page forward; \\[scroll-down] = page back; \
+\\[view-mode-describe] = help; \\[view-quit] = quit.")))
+
+(defvar view-major-mode)
+(defvar view-exit-position)
+(defvar view-prev-buffer)
+(defvar view-exit-action)
+(defvar view-old-buffer-read-only)
+
+;;;###autoload
+(defun view-minor-mode (&optional prev-buffer exit-action)
+  "Minor mode for viewing text, with bindings like `less'.
+Commands are:
+\\<view-minor-mode-map>
+0..9   prefix args
+-      prefix minus
+\\[scroll-up]  page forward
+\\[scroll-down]        page back
+\\[view-scroll-lines-up]       scroll prefix-arg lines forward, default 1.
+\\[view-scroll-lines-down]     scroll prefix-arg lines backward, default 1.
+\\[view-scroll-some-lines-down]        scroll prefix-arg lines backward, default 10.
+\\[view-scroll-some-lines-up]  scroll prefix-arg lines forward, default 10.
+\\[what-line]  print line number
+\\[view-mode-describe] print this help message
+\\[view-search-forward]        regexp search, uses previous string if you just hit RET
+\\[view-search-backward]       as above but searches backward
+\\[view-repeat-search] repeat last search
+\\[view-goto-line]     goto line prefix-arg, default 1
+\\[view-last-windowful]        goto line prefix-arg, default last line
+\\[view-goto-percent]  goto a position by percentage
+\\[toggle-truncate-lines]      toggle truncate-lines
+\\[view-file]  view another file
+\\[view-buffer]        view another buffer
+\\[view-cleanup-backspaces]    cleanup backspace constructions
+\\[shell-command]      execute a shell command
+\\[shell-command-on-region]\
+       execute a shell command with the region as input
+\\[view-quit]  exit view-mode, and bury the current buffer.
+
+If invoked with the optional (prefix) arg non-nil, view-mode cleans up
+backspace constructions.
+
+More precisely:
+\\{view-minor-mode-map}"
+  (interactive)
+
+  (make-local-variable 'view-default-lines)
+  (set (make-local-variable 'view-exit-position)      (point))
+  (set (make-local-variable 'view-prev-buffer)   prev-buffer)
+  (set (make-local-variable 'view-exit-action)   exit-action)
+  (set (make-local-variable 'view-old-buffer-read-only)     buffer-read-only)
+  (add-hook (make-local-variable 'change-major-mode-hook)
+           'view-fixup-read-only)
+  (setq view-minor-mode  t
+       buffer-read-only t)
+  (view-brief-help))
+
+;;;###autoload
+(defun view-mode (&optional prev-buffer exit-action clean-bs)
+  "View the current buffer using view-minor-mode.  This exists to be 99.9%
+compatible with the implementations of `view-mode' in view.el and older
+versions of view-less.el."
+  (interactive (list nil 'bury-buffer current-prefix-arg))
+  ;; #### - The first two arguments provide compatibility with view.el (and
+  ;; thus FSFmacs), while the third argument as a prefix argument maintains
+  ;; interactive compatibility with older versions of view-less.  --Stig
+  (if clean-bs (cleanup-backspaces))
+  (view-minor-mode prev-buffer exit-action))
+
+;;;###autoload
+(defun view-major-mode (&optional prev-buffer exit-action clean-bs)
+  "View the current buffer using view-mode, as a major mode.
+This function has a nonstandard name because `view-mode' is wrongly
+named but is like this for compatibility reasons."
+  ;; #### - The first two arguments provide compatibility with view.el (and
+  ;; thus FSFmacs), while the third argument as a prefix argument maintains
+  ;; interactive compatibility with older versions of view-less.  --Stig
+  (interactive (list nil 'bury-buffer current-prefix-arg))
+  (kill-all-local-variables)
+  (use-local-map view-mode-map)
+  (setq major-mode 'view-mode)
+  (set (make-local-variable 'view-exit-position)      (point))
+  (set (make-local-variable 'view-prev-buffer)   prev-buffer)
+  (set (make-local-variable 'view-exit-action)   exit-action)
+  (set (make-local-variable 'view-old-buffer-read-only)     buffer-read-only)
+  (set (make-local-variable 'view-major-mode) t)
+  (setq buffer-read-only t)
+  (if clean-bs (cleanup-backspaces))
+  (run-hooks 'view-mode-hook))
+
+;;;###autoload
+(defun auto-view-mode ()
+  "If the file of the current buffer is not writable, call view-mode.
+This is meant to be added to `find-file-hooks'."
+  (or (file-writable-p buffer-file-name)
+      (view-minor-mode)))
+
+(defun view-fixup-read-only ()
+  ;; doing M-x normal mode should NOT leave the buffer read-only
+  (and (boundp 'view-old-buffer-read-only)
+       (progn (setq buffer-read-only view-old-buffer-read-only)
+             (kill-local-variable 'view-old-buffer-read-only))))
+
+(defun view-quit-toggle-ro ()
+  "Exit view mode and execute the global binding of the key that invoked this
+command.  Normally, this will toggle the state of `buffer-read-only', perhaps
+invoking some version-control mechanism."
+  (interactive)
+  (setq view-exit-position nil)
+  ;; Kludge so this works as advertised.  Stig, why can't you write
+  ;; bug-free code???
+  (let ((buffer-read-only buffer-read-only))
+    (view-quit t))
+  ;; no longer in view-minor-mode, so the keymap has changed...
+  (call-interactively (key-binding (this-command-keys))))
+
+(defun view-quit (&optional no-exit-action)
+  "Exit view mode.  With prefix argument, keep the current buffer selected."
+  (interactive "P")
+  (view-fixup-read-only)
+  (setq view-minor-mode nil)
+  (if view-exit-position (goto-char view-exit-position))
+  (if (and (boundp 'view-major-mode) view-major-mode)
+      (fundamental-mode)
+    (let ((pbuf view-prev-buffer)
+         (exitact view-exit-action))
+      (if no-exit-action
+         nil
+       (if exitact (funcall exitact (current-buffer)))
+       (if pbuf (switch-to-buffer pbuf))))))
+
+;; #### - similar to what's in man.el and this ought to be written in C anyway...  --Stig
+(defun cleanup-backspaces ()
+  "Cleanup backspace constructions.
+_^H and ^H_ sequences are deleted.  x^Hx sequences are turned into x for all
+characters x.  ^^H| and |^H^ sequences are turned into ^.  +^Ho and o^H+ are
+turned into (+)."
+  (interactive)
+  (save-excursion
+    (goto-char (point-min))
+    (while (= (following-char) ?\C-h)
+      (delete-char 1))
+    (while (search-forward "\C-h" nil t)
+      (backward-char 2)
+      (cond ((looking-at "_\C-h\\|\\(.\\)\C-h\\1\\||\C-h\\^")
+            (delete-char 2))
+           ((looking-at ".\C-h_\\|\\^\C-h|")
+            (forward-char 1)
+            (delete-char 2))
+           ((looking-at "+\C-ho\\|o\C-h+")
+            (delete-char 3)
+            (insert "(+)"))
+           ((looking-at "|\C-h-")
+            (delete-char 3)
+            (insert "*"))
+           (t (forward-char 2))))))
+
+(defun view-cleanup-backspaces ()
+  "Cleanup backspaces and if buffer is currently unmodified, don't flag it
+as a modified buffer.  This works even if the buffer is read-only."
+  (interactive)
+  (let ((buffer-read-only)
+       (buf-mod (buffer-modified-p)))
+    (cleanup-backspaces)
+    ;; #### - THIS IS PROBABLY A REALLY DANGEROUS THING TO DO IN A MINOR MODE!!
+    (set-buffer-modified-p buf-mod)))
+
+;;;###autoload
+(defun toggle-truncate-lines (&optional p)
+  "Toggles the values of truncate-lines.
+Positive prefix arg sets, negative disables."
+  (interactive "P")
+  (setq truncate-lines (if p
+                          (> (prefix-numeric-value p) 0)
+                        (not truncate-lines)))
+  (recenter))
+
+(defun view-scroll-lines-up (p)
+  "Scroll up prefix-arg lines, default 1."
+  (interactive "p")
+  (scroll-up p))
+
+(defun view-scroll-lines-down (p)
+  "Scroll down prefix-arg lines, default 1."
+  (interactive "p")
+  (scroll-up (- p)))
+
+(defun view-scroll-some-lines-down (&optional n)
+  "Scroll down prefix-arg lines, default 10, or last argument."
+  (interactive "p")
+  (if (> n 1) (setq view-default-lines n))
+  (scroll-down view-default-lines))
+
+(defun view-scroll-some-lines-up (&optional n)
+  "Scroll up prefix-arg lines, default 10, or last argument."
+  (interactive "p")
+  (if (> n 1) (setq view-default-lines n))
+  (scroll-up view-default-lines))
+
+(defun view-goto-line (&optional n)
+  "Goto prefix arg line N.  N = 1 by default.."
+  (interactive "p")
+  (goto-line n))
+
+(defun view-last-windowful (&optional n)
+  "Goto prefix arg line N or the first line of the last windowful in buffer."
+  (interactive "p")
+  (if current-prefix-arg
+      (goto-line n)
+    (end-of-buffer)
+    (recenter -1)
+    (move-to-window-line 0)))
+
+(defun view-goto-percent (&optional percent)
+  "Set mark and go to a position PERCENT way into the current buffer."
+  (interactive "p")
+  (set-mark-command nil)
+  (goto-char (+ (point-min) (/ (* percent (- (point-max) (point-min))) 100)))
+  (beginning-of-line))
+
+(defun view-mode-describe ()
+  (interactive)
+  (let ((mode-name "View")
+       (major-mode 'view-mode))
+    (describe-mode)))
+
+(defun view-search-forward (s p)
+  "Search forward for REGEXP.  If regexp is empty, use last search string.
+With prefix ARG, search forward that many occurrences."
+  (interactive "sView search: \np")
+  (unwind-protect
+      (re-search-forward
+       (if (string-equal "" s) view-search-string s) nil nil p)
+    (setq view-search-arg p)
+    (or (string-equal "" s)
+       (setq view-search-string s))))
+
+(defun view-search-backward (s p)
+  "Search backward for REGEXP.  If regexp is empty, use last search string.
+With prefix ARG, search forward that many occurrences."
+  (interactive "sView search backward: \np")
+  (view-search-forward s (- p)))
+
+(defun view-repeat-search (p)
+  "Repeat last view search command.  If a prefix arg is given, use that
+instead of the previous arg, if the prefix is just a -, then take the
+negative of the last prefix arg."
+  (interactive "P")
+  (view-search-forward
+   view-search-string
+   (cond ((null p) view-search-arg)
+        ((eq p '-) (- view-search-arg))
+        (t (prefix-numeric-value p)))))
+
+(provide 'view)
+(provide 'view-less)
+
+;;; view-less.el ends here