p4.el v3.0

RajeshVrv at fore.com RajeshVrv at fore.com
Thu Jun 11 06:16:03 PDT 1998


This is a multi-part message in MIME format.
- --------------0F722EF1F016CE5D517F1BB7
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

The latest p4.el is significantly different in that all needs for an
emacsclient/gnuclient are eliminated and there is no need for a server
running within emacs anymore.

Since this major change occurred, I changed the major release number.

Here are the changes:

Release 3.0
	
1. Major release number change since a lot of code has been ripped out
and this fundamentally changes the way all external interaction is done.
The previous release techically didnot qualify for this	since p4-submit
still used the client server mechanism.
	
        a. All references to `server-start' and
           `gnuserv-start' removed.
        b. `p4-emacs-server-start' function removed.
        c. `p4-gnuclient' variable and `p4-set-gnu-client'
            function removed.
        d. `p4-async-commands' function removed.
	
2. `p4-async-process-command' modified to take optional parameter and
`p4-submit' also now works within that framework.


As usual, please send me your feedback.

Thank you.

rv
- --------------0F722EF1F016CE5D517F1BB7
Content-Type: text/plain; charset=us-ascii; name="p4.el"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="p4.el"

;;; p4.el --- Simple Perforce-Emacs Integration
;; Simple Emacs <-> Perforce Integration
;;
;; $Id: //depot/user/rv/lisp/20.2/lisp/fore/p4.el#18$

;;    Applied the GNU G.P.L. to this file - rv 3/27/1997

;;    Programs for  Emacs <-> Perforce Integration.
;;    Copyright (C) 1996, 1997  Eric Promislow 
;;    Copyright (C) 1997, 1998  Rajesh Vaidheeswarran
;;
;;    This program 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.
;;
;;    This program 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 this program; if not, write to the Free Software
;;    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
;;
;;    If you have any problems to report, or suggestions, please send them
;;    to rv at fore.com

;;
;; WARNING:
;; --------
;;
;;    % p4 edit foo.c
;;    ... make changes to foo.c in emacs
;;    % p4 submit
;;     ... keep the writable copy of foo.c in emacs.  Start making changes
;;     to it.  Discover that you can't save it.  If you do M-x:p4-edit,
;;     you'll lose your changes.  You need to do a 'p4 edit' at the
;;     command-line.
;; 

;; Original Functions:   (Contributed by Eric Promislow)
;; p4-exec-p4                (not exported)
;; p4-buffer-action          (not exported)
;; p4-edit 
;; p4-revert 
;; p4-diff 

;; Modified Original Functions
;; p4-buffer-action - modified to support optional args to be passed
;; p4-edit  - added help
;; p4-revert - added help
;; p4-diff  - added help

;; Added Functions:
;; p4-add
;; p4-delete
;; p4-diff2
;; p4-filelog
;; p4-files
;; p4-refresh
;; p4-noinput-exec-p4        (not exported)
;; p4-noinput-buffer-action  (not exported)
;; p4-get
;; p4-have
;; p4-help
;; p4-info
;; p4-integ
;; p4-opened 
;; p4-users
;; p4-where
;; p4-async-commands         (not exported) (deprecated)
;; p4-change 
;; p4-client 
;; p4-submit 
;; p4-user
;; p4-get-client-name 
;; p4-set-client-name 
;; p4-find-file-hook         (not exported)
;; p4-is-vc                  (not exported)
;; p4-check-mode             (not exported)
;; p4-menu-add

;; NOTES:
;; ------
;;
;; It is best if you take this file and byte compile it. To do that, you
;; need to do the following:
;;
;; % emacs -batch -f batch-byte-compile /full/path/to/file/p4.el
;; 
;; This creates a binary file p4.elc in the path. Add the path to your 
;; load-path variable in .emacs like this:
;;
;; (setq load-path (cons "/full/path/to/file" load-path))
;; 
;; Then add the library like this:
;;
;; (load-library "p4")
;;

;; NEW Additions in the 1.2 Release:
;;
;; Functions: 
;; -----------
;; p4-set-notify-list
;; p4-get-notify-list
;; p4-notify
;; p4-emacs-version
;;
;; Modifications:
;; --------------
;; The following functions now accept prefix argument (C-u) to specify
;; optional argument like -n or ..., etc.
;;
;; p4-files, p4-refresh, p4-get, p4-have, p4-integ, p4-opened, p4-users,
;; p4-where.
;; 
;; Now supports RCS/CVS type vc revision level display on mode line, and
;; menu bar support.

;; 
;; NEW Additions in the 1.3 Release:
;; ---------------------------------
;; 1. "/dev/null" replaced with grep-null-device for NT compatibility
;; 
;; 2. p4-is-vc now returns the version number if p4 owns the file
;; 
;; 3. added p4-ediff which uses ediff to allow more interactive diffing
;;
;; 4. removed p4-noinput-exec-p4 because it was the same as p4-exec-p4.
;;    p4-noinput-buffer-action and p4-buffer-action should probably be one
;;    routine but I left them alone for now.
;;
;; 5. changed kill-region to delete-region to avoid kill ring clutter
;;
;; 6. replaced 'nil with nil and 't with t
;; 
;; 7. removed unused p4-output-buffer
;;

;; New in 1.4 Release
;; ------------------
;; Split p4.el for Emacs and XEmacs
;; 

;; New in 1.5 Release
;; ------------------

;; 1. Make p4.el work with both Emacs and XEmacs.  The problem is that
;;    this might cause some compilation warnings since some functions are
;;    mutually exclusive and don't exist on both. But, testing has proved no
;;    conflicts or problems that arise due to this.
;;
;;    Functions added:
;;    ----------------
;;    p4-set-p4-executable   p4-set-gnu-client   p4-set-notifier
;;    p4-emacs-server-start  p4-mode-menu (For XEmacs)
;;
;; 2. Cleanup comments and a document some more functions.

;; New in 2.0 Release
;; ------------------

;; Technically, since 1.5 supports Emacs and XEmacs in the same
;; file, it should have been a major release, but all the cleanup
;; occurred only after I saw tested that thoroughly.. Hence, I'm calling
;; this 2.0

;; 1. Remove dependency on grep-null-device and use the system-type variable
;;    to check this instead.
;; 2. BUGFIX: Make sure to use p4-running-gnuemacs instead of
;;    running-gnuemacs and p4-running-xemacs instead of running-xemacs
;; 3. Added p4-force-mode-line-update to wrap the modeline updation
;;    for different flavors of Emacs.
;; 4. Quash all compiler warnings that are independant of Emacs flavor.
;;
;;    The only warnings that exist are:
;;    Emacs (20.2)
;;    ================
;;    While compiling p4-add:
;;      ** assignment to free variable p4-mode
;;    While compiling p4-emacs-server-start:
;;      ** reference to free variable server-process
;;    While compiling p4-check-mode:
;;      ** assignment to free variable p4-mode
;;    While compiling the end of the data:
;;      ** The following functions are not known to be defined:  gnuserv-start,
;;        gnuserv-running-p, p4-menu-add, redraw-modeline, easy-menu-add,
;;        p4-mode-menu
;;
;;    XEmacs (20.4)
;;    =============
;;   While compiling p4-emacs-server-start:
;;     ** reference to free variable server-process
;;   While compiling the end of the data:
;;     ** the function server-start is not known to be defined.

;; New in 2.1 Release
;; ------------------

;; 1. Added p4-toggle-vc-mode to administratively enable/disable the VC
;;    check (mainly for offline working, ro when a P4 server is
;;    unavailable).
;; 2. Emacs Menu works now.
;; 3. Standardized the Menus in XEmacs and Emacs.
;; 4. Add a lot of documentation to the variables, and cleanup indentation
;;    in function documentation.

;; New in 2.2 Release
;; ------------------

;; 1. p4-add now takes prefix argument to specify optional parameters.
;; 2. p4-check-mode modified to accept optional argument so that it can
;;    update menu of a buffer whose file has been added to p4.
;; 3. Add p4-get-client-name and p4-set-client-name to the menu.

;; New in 2.3 Release
;; ------------------

;; 1. Change all references to "GNU Emacs" and "XEmacs" to "Emacs" and
;;    "XEmacs" respectively, since the former may mistakenly portray XEmacs
;;    as a program that has nothing to do with GNU (It did originate from a
;;    GNU program), which is neither fair nor accurate. The only place where
;;    the explicit check is done for "GNU Emacs" is in the string-match.
;; 2. Rename p4-running-gnuemacs to p4-running-emacs per the above
;;    sentiment.
;; 3. Add p4-set-p4-port and p4-get-p4-port to set and get the current P4
;;    server/port that we are attached to.

;; New in 2.4 Release
;; ------------------

;; 1. Used `checkdoc' to correct all the documentation issues that it found.
;; 2. Start a server, only if one is not already in place.

;; New in 2.5 Release
;; ------------------

;; 1. Support C-x C-q to p4-edit/p4-revert a file under P4 VC. Revert to the
;;    normal behavior otherwise. This is done by `p4-toggle-read-only'.

;; New in 2.6 Release
;; ------------------

;; 1. Added globally settable variables `p4-my-clients' and
;;    `p4-strict-complete' to enable completion on p4 client names with
;;    `p4-set-client-name'.
;; 2. Added `p4-set-my-clients' to set `p4-my-clients' since it is a pain
;;    for users to set an alist.
;; 3. Bugfix in p4-menu-add for XEmacs to ensure that it didn't complain
;;    about p4-mode being void when called manually in non-p4 buffers.

;; New in 2.7 Release
;; ------------------

;; 1. p4-user, p4-change and p4-client now use the simpler and more elegant
;;    p4-async-process-command and p4-async-call-process pair to do their
;;    jobs. This leaves only p4-submit to be dealt with, after which the
;;    need for an external editor client (gnuclient/emacsclient) can be done
;;    away with. Thanks to Dima Barsky for the suggestion and sample code.

;; New in 3.0 Release
;; ------------------

;; 1. Major release number change since a lot of code has been ripped out
;;    and this fundamentally changes the way all external interaction is
;;    done. The previous release techically didnot qualify for this since 
;;    p4-submit still used the client server mechanism.
;;
;; a.  All references to `server-start' and `gnuserv-start'  removed. 
;; b. `p4-emacs-server-start' function removed.
;; c. `p4-gnuclient' variable and `p4-set-gnu-client' function removed.
;; d. `p4-async-commands' function removed.
;;
;; 2. `p4-async-process-command' modified to take optional parameter and
;;    `p4-submit' also now works within that framework.

;;; Commentary:
;; 

;;; Code:

;; We need to remap C-x C-q to p4-toggle-read-only, so, make sure that we
;; load vc first.. or else, when vc gets autoloaded, it will remap C-x C-q
;; to vc-toggle-read-only.
(require 'vc)

(defvar p4-emacs-version "3.0" "The Current P4-Emacs Integration Revision.")

;; Find out what type of emacs we are running in. We will be using this
;; quite a few times in this program.
(defvar p4-running-emacs 
  (string-match "GNU Emacs" (emacs-version))
  "If the current Emacs is not XEmacs, then, this is non-nil.")

(defvar p4-running-xemacs 
  (string-match "XEmacs\\|Lucid" (emacs-version))
  "If the current Emacs is XEmacs/Lucid, then, this is non-nil.")

;; This can be set to wherever 'p4' lies using p4-set-p4-executable
(defvar p4-executable 
  "/usr/swlocal/bin/p4"
  "This is the p4 executable.
To set this, use the function  `p4-set-p4-executable'")

;; Set the null device
(if (memq system-type '(ms-dos windows-nt))
    ;; Set the null device for Windows and DOS
    (defvar p4-null-device "NUL" "Null Device for MS-DOS/Windows")
  (defvar p4-null-device "/dev/null" "Null Device for UNIX"))

(defvar p4-output-buffer-name "*P4 Output*" "P4 Output Buffer.")
(defvar p4-oldclt (getenv "P4CLIENT") "The P4 Client in use.")

;; Set this variable in .emacs if you want p4-set-client-name to complete
;; your client name for you.
(defvar p4-my-clients nil
  "This variable holds the alist of p4 clients that the function
`p4-set-client-name' can complete on.

This is a alist, and should be set using the function
`p4-set-my-clients'. For example, in your .emacs:

\(load-library \"p4\"\)
\(p4-set-my-clients \'(client1 client2 client3)\)")

;; Set this variable in .emacs if you want to alter the completion
;; behavior of p4-set-client-name.

(defvar p4-strict-complete t 
  "Set this variable in .emacs if you want to alter the completion behavior
of `p4-set-client-name'. 

This is a boolean and should be set to either t or nil. (default is t).")

(defvar p4-old-p4-port (getenv "P4PORT") "The P4 Server/Port in use.")
(if (eq p4-old-p4-port nil)
    (progn
      (setq p4-old-p4-port "p4:1666") ;; Default P4 port.
      (setenv "P4PORT" p4-old-p4-port)))

(defvar p4-old-notify-list (getenv "P4NOTIFY") "The P4 Notify List.")
(defvar p4-notify-list (getenv "P4NOTIFY") "The P4 Notify List.")

;; This can be set with p4-set-notifier
(defvar p4-notifier "/usr/swlocal/bin/mailch" 
  "The P4 notification Program.  To set this use `p4-set-notifier'.")

(defvar p4-notify nil "To notify or not.")

;; This can be set with p4-toggle-vc-mode
(defvar p4-do-find-file t 
  "If non-nil, the `p4-find-file-hook' will run when opening files.")

;; Now add a hook to find-file-hooks
(add-hook 'find-file-hooks 'p4-find-file-hook)

;; Tell Emacs about this new kind of minor mode
(make-variable-buffer-local 'p4-mode)
(put 'p4-mode 'permanent-local t)

(if (not (assoc 'p4-mode minor-mode-alist))
    (setq minor-mode-alist (cons '(p4-mode p4-mode)
				 minor-mode-alist)))

;; A generic function that we use to execute p4 commands
(defun p4-exec-p4 (output-buffer
		   args
		   &optional clear-output-buffer)
  "Internal function called by various p4 commands."
  (if clear-output-buffer
      (progn
	(set-buffer output-buffer)
	(delete-region (point-min) (point-max))))
  (apply 'call-process 
	 (append 
	  (list p4-executable
		p4-null-device
		output-buffer
		nil)			; update display?
	  args)))

;; A generic function to take action of a buffer for interactive p4 commands
(defun p4-buffer-action (cmd do-revert 
			     show-output 
			     &optional argument
			     &optional argument1)
  "Internal function called by various p4 commands."
  (save-excursion
    (if (not (stringp cmd))
	(error "p4-buffer-action: Command not a string."))
    (save-excursion
      (if (and argument argument1)
	  (p4-exec-p4 (get-buffer-create p4-output-buffer-name)
		      (list cmd argument argument1) t)
	(p4-exec-p4 (get-buffer-create p4-output-buffer-name)
		    (list cmd (buffer-file-name)) t)))
    (if do-revert (revert-buffer t t))
    (if show-output
	(progn
	  (delete-other-windows)
	  (display-buffer p4-output-buffer-name t)))))

;; We use the noinput version for commands like p4 opened, p4 get etc.
;; which don't take any input file name.

(defun p4-noinput-buffer-action (cmd 
				 do-revert 
				 show-output
				 &optional argument)
  "Internal function called by various p4 commands."
  (save-excursion
    (if (not (stringp cmd))
	(error "p4-noinput-buffer-action: Command not a string."))
    (save-excursion
      (if argument
	  (p4-exec-p4 (get-buffer-create p4-output-buffer-name)
		      (append (list cmd) argument) t)
	(p4-exec-p4 (get-buffer-create p4-output-buffer-name)
		    (list cmd) t)))
    (if do-revert (revert-buffer t t))
    (if show-output
	(progn
	  (delete-other-windows)
	  (display-buffer p4-output-buffer-name t)))))

;; The p4 edit command
(defun p4-edit (show-output)
  "To open the current depot file for edit, type \\[p4-edit].

Open or re-open an existing file for edit.

If file is already open for edit or delete then it is reopened
for edit and moved into the specified change number (or 'default'
change if no change number is given.)

If -t type is given the file is explicitly opened as the specified
file type, which may be text, ltext, xtext, binary, xbinary, ktext
kxtext, symlink, or resource.  Not all types are supported on all
operating systems.  See the Users' Guide for a description of file
types.  If no type is specified, the type is determined automatically
by examination of the file's contents and execution permission bits.

Argument SHOW-OUTPUT  displays the *P4 Output* buffer on executing the
command if t."

  (interactive "P")
  (p4-buffer-action "edit" t show-output)
  (p4-check-mode))

;; The p4 revert command
(defun p4-revert (show-output)
  "Revert all change in the current file.

Argument SHOW-OUTPUT  displays the *P4 Output* buffer on executing the
command if t."
  (interactive "P")
  (if (yes-or-no-p "Really revert changes? ")
      (p4-buffer-action "revert" t show-output))
  (p4-check-mode))

;; The p4 diff command
(defun p4-diff ()
  "To diff the current file and topmost depot version, type \\[p4-diff].

Run diff (on the client) of a client file against the corresponding
revision in the depot.  The file is only compared if the file is
opened for edit or the revision provided with the file argument is
not the same as the revision had by the client.

If no file argument is given, diff all open files.
This can be used to view pending changes.

The -f flag forces a diff for every file, regardless of whether
they are opened or if the client has the named revision.
This can be used to verify the client contents.

The -s flag outputs reduces the output of diff to the names of files
satisfying the following criteria:

        -sa     Opened files that are different than the revision
                in the depot, or missing.

        -sd     Unopened files that are missing on the client.

        -se     Unopened files that are different than the revision
                in the depot.

        -sr     Opened files that are the same as the revision in the
                depot."

  (interactive)
  (p4-buffer-action "diff" nil t))

;; The p4 diff2 command
(defun p4-diff2 (version1 version2 )
  "Display diff of two depot files. 

When visiting a depot file, type \\[p4-diff2] and 
enter the versions.

Example:  (find-file \"/us/rv/tag/main/Construct\")
          \\[p4-diff2] <RET>
          First Version to diff: 113
          Second Version to diff: 100

          Will produce the diff between the two versions in the 
          output buffer *P4 Output*

Run diff (on the server) of two files in the depot.  Both files
may optionally include a revision specification; the default is
to compare the head revision.  Wildcards may be used, but they
must match between file1 and file2 and they must be escaped from
the user's shell by quoting or with backslashes (\).

The -d flag allows you to pass flags to the underlying diff
program.

- -dc passes the -c (context diff) flag. 

- -dn passes the the -n (rcs diff) flag.  

Other diff flags are not supported.

Argument VERSION1 First Version to use.
Argument VERSION2 Second Version to use."

  (interactive "sFirst Version to diff: \nsSecond Version to diff: ")
  (make-variable-buffer-local 'p4-diff-version1)
  (make-variable-buffer-local 'p4-diff-version2)
  (defvar p4-diff-version1 nil)
  (defvar p4-diff-version2 nil)
  (setq p4-diff-version1 (concat (buffer-file-name) "#" version1))
  (setq p4-diff-version2 (concat (buffer-file-name) "#" version2))
  (p4-buffer-action "diff2" nil t p4-diff-version1 p4-diff-version2))

;; p4-ediff for all those who diff using ediff

(defun p4-ediff ()
  "Use ediff to compare file with its original client version."
  (interactive)
  (require 'ediff)
  (p4-noinput-buffer-action "print" nil nil
			    (list "-q" 
				  (concat (buffer-file-name) "#have")))
  (let ((local (current-buffer))
	(depot (get-buffer-create p4-output-buffer-name)))
    (ediff-buffers local 
		   depot
		   `((lambda ()
		       (make-local-variable 'ediff-cleanup-hook)
		       (setq ediff-cleanup-hook
			     (cons (lambda ()
				     (kill-buffer ,depot))
				   ediff-cleanup-hook)))))))

;; The p4 add command
(defun p4-add ()   
  "To add the current file to the depot, type \\[p4-add].

Optional arguments like '-tktext' can be passed as prefix arguments.

Open a new file for adding to the depot.  If the file exists
on the client it is read to determine if it is text or binary.
If it does not exist it is assumed to be text.  The file must
either not exist in the depot, or it must be deleted at the
current head revision.  Files may be deleted and re-added arbitrarily.

If the -c flag is given the open files are associated with the
specified pending change number; otherwise the open files are
associated with the current 'default' change.

If file is already open it is moved into the specified pending
change.  It is not permissible to reopen a file for add unless
it was already open for add.

If -t type is given the file is explicitly opened as the specified
file type, which may be text, ltext, xtext, binary, xbinary, ktext
kxtext, symlink, or resource.  Not all types are supported on all
operating systems.  See the Users' Guide for a description of file
types.  If no type is specified, the type is determined automatically
by examination of the file's contents and execution permission bits."

  (interactive)
  (if (not (p4-is-vc))
      (progn
	(if current-prefix-arg
	    (let ((args ""))
	      (progn
		(setq args (read-string "Optional Args: "))
		(p4-buffer-action "add" nil t args buffer-file-name)))
	  (p4-buffer-action "add" nil t))
	(p4-check-mode "Add"))
    (message "%s already in depot client %s!" buffer-file-name 
	     (getenv "P4CLIENT"))))


;; The p4 delete command
(defun p4-delete ()
  "To delete the current file from the depot, type \\[p4-delete].

Opens a file that currently exists in the depot for deletion.
If the file is present on the client it is removed.  If a pending
change number is given with the -c flag the opened file is associated
with that change, otherwise it is associated with the 'default'
pending change.

If file is already open it is reopened for delete and moved into
the specified pending change (or 'default' change if no change
number is given.)

Files that are deleted generally do not appear on the have list."

  (interactive)
  (if (yes-or-no-p "Really delete from depot? ")
      (if (p4-is-vc)
	  (p4-buffer-action "delete" nil t))
    (p4-check-mode)))

;; The p4 filelog command
(defun p4-filelog ()

  "To view a history of the change made to the current file, type
\\[p4-filelog].

List the revision history of the files named, working backwards
from the latest revision to the most recent revision 'added'.
If file is given as a client file, the depot file last gotten is
listed.  The -l flag produces long output with the full text of the
change descriptions."

  (interactive)
  (p4-buffer-action "filelog" nil t))

;; The p4 files command
(defun p4-files ()
  "List files in the depot. Type, \\[p4-files].

Optional args [file ...] are passed as prefix arguments.

List files named or matching wild card specification.  Display shows depot
file name, revision, file type, change action and change number of the
current head revision.  If client file names are given as arguments the view
mapping is used to list the corresponding depot files."

  (interactive)
  (if current-prefix-arg
      (let ((args 'nil))
	(progn
	  (setq args (list (read-string "Optional Args: ")))
	  (p4-noinput-buffer-action "files" nil t args)))
    (p4-buffer-action "files" nil t)))

;; The p4 refresh command
(defun p4-refresh ()
  "Refresh the contents of an unopened file. \\[p4-refresh].

Optional args [file ...] are passed as prefix arguments.

Refresh replaces the files with their contents from the depot.  Refresh only
refreshes unopened files; opened files must be reverted.  This command
requires naming files explicitly."

  (interactive)
  (if current-prefix-arg
      (let ((args 'nil))
	(progn
	  (setq args (list (read-string "Optional Args: ")))
	  (p4-noinput-buffer-action "refresh" nil t args)))
    (p4-buffer-action "refresh" nil t)))

;; The p4 get/sync command 
(defun p4-get ()
  "To synchronise the local view with the depot, type \\[p4-get].

Optional args [-n] [file ...] can be passed as prefix arguments.

Synchronize a client with its view for the files named, or for the entire
client if no files named.  Get handles the case where files have been
updated in the depot and need to be brought up-to-date on the client as well
as the case when the view itself has changed.

Depot files in the clients view not currently gotten on the client will be
added.  Client files that were gotten from the depot but that are no longer
in the clients view (or have been deleted in the depot) will be deleted from
the client. Client files that are still in the client view but which have
been updated in the depot are replaced by the needed revision from the
depot.

If file gives a revision specifier, then retrieve the revision so indicated.

The client view is used to map client file names to depot file names and
vice versa.

If -n is given show what revisions would need to be gotten to synchronize
the client with the view, but do not actually get the files.  If no files
are named show the result for the entire client view."

  (interactive)
  (let ((args 'nil))
    (if current-prefix-arg
	(setq args (list (read-string "Optional Args: ")))
      (setq args (list "")))
    (p4-noinput-buffer-action "get" nil t args)))

;; The p4 have command
(defun p4-have ()
  "To list revisions last gotten, type \\[p4-have].

Optional args [file ...] are passed as prefix arguments.

List revisions of named files that were last gotten from the depot.  If no
file name is given list all files gotten on this client."

  (interactive)
  (let ((args 'nil))
    (if current-prefix-arg
	(setq args (list (read-string "Optional Args: ")))
      (setq args (list "")))
    (p4-noinput-buffer-action "have" nil t args)))

;; The p4 help command
(defun p4-help (arg)
  "To print help message , type \\[p4-help].

Print a help message about command.  If no command name is given print a
general help message about Perforce and give a list of available client
commands.

Argument ARG command for which help is needed."

  (interactive "sHelp on which command: ")
  (if (string< "" arg)
      (p4-noinput-buffer-action "help" nil t (list arg))
    (p4-noinput-buffer-action "help" nil t)))

;; The p4 info command
(defun p4-info ()
  "To print out client/server information, type \\[p4-info].

Info dumps out what the server knows about the client (the user
name, the client name, and the client directory) and some server
information (the server's address, version, and license data)."

  (interactive)
  (p4-noinput-buffer-action "info" nil t))

;; The p4 integrate command
(defun p4-integ (branch) 
  "To schedule integrations between branches, type \\[p4-integ].

Optional args [-n -r] [-c change#] [file ...] are passed as prefix
arguments.

Integ determines what integrations are necessary between related files,
according to the branch named and its view.  These integrations, represented
by a list of revisions of branch source files which need to be merged into
the related branch target file, are scheduled for later action.  The actual
merge and any necessary conflict resolution is performed using the resolve
command.  The -n flag displays what integrations would be necessary but does
not schedule them.  A branch name is required.

If the -r flag is present, the mappings in the branch view are reversed,
with the target files and source files exchanging place.

If no file names are given then the entire branch view is examined for
needed integrations.  Files that are not mapped in the client's view are
ignored.  Files scheduled for integration are opened for the appropriate
action in the default change.  If -c change# is given the files are opened
in the numbered pending change.

Argument BRANCH is the branch to integrate into."

  (interactive "sP4 Branch Name: ")
  (let ((args 'nil))
    (if current-prefix-arg
	(setq args (list "-b" branch (read-string "Optional Args: ")))
      (setq args (list "-b" branch)))
    (p4-noinput-buffer-action "integ" nil t args)))

;; The p4 opened command
(defun p4-opened ()
  "To display list of files opened for pending change, type \\[p4-opened].

Optional args [-a] [file ...] are passed as prefix arguments.

Shows files currently opened for pending changes or indicates for the
specified individual files whether they are currently opened.
If no file names are given, all files open on the current client
are listed.  The -a flag lists opened files in all clients."

  (interactive)
  (p4-noinput-buffer-action "opened" nil t))

;; The p4 users command
(defun p4-users ()
  "To display list of known users, type \\[p4-users].

Optional args [user ...] are passed as prefix arguments.

Reports the list of all users, or those users matching the argument,
currently known to the system.  The report includes the last time
each user accessed the system."

  (interactive)
  (let ((args 'nil))
    (if current-prefix-arg
	(setq args (list (read-string "Optional Args: ")))
      (setq args (list "")))
    (p4-noinput-buffer-action "users" nil t args)))

;; The p4 where command
(defun p4-where ()
  "To show how local file names map into depot names, type \\[p4-where].

Optional args [file ...] are passed as prefix arguments.

Where shows how the named files map through the client map
into the depot.  If no file is given, the mapping for '...'
\(all files in the current directory and below\) is shown."
  (interactive)
  (let ((args 'nil))
    (if current-prefix-arg
	(setq args (list (read-string "Optional Args: ")))
      (setq args (list "")))
    (p4-noinput-buffer-action "where" nil t args)))

;; The following two commands have replaced the deprecated `p4-async-commands'
;; and are much more elegant since they don't depend on external editor
;; clients.

(defvar p4-minor-mode nil
  "The minor mode for editing p4 asynchronous command buffers.")
(make-variable-buffer-local 'p4-minor-mode)
(setq p4-minor-map (make-keymap))
(fset 'p4-minor-map p4-minor-map)

(or (assoc 'p4-minor-mode minor-mode-alist)
    (setq minor-mode-alist
	  (cons '(p4-minor-mode " P4") minor-mode-alist)))

(or (assoc 'p4-minor-mode minor-mode-map-alist)
    (setq minor-mode-map-alist
	  (cons '(p4-minor-mode . p4-minor-map) minor-mode-map-alist)))

(put 'p4-current-command 'permanent-local t)

(defun p4-async-process-command (p4-this-command &optional 
						 p4-regexp
						 p4-this-buffer
						 p4-out-command)
  "Internal function to call an asynchronous process with a local buffer,
instead of calling an external client editor to run within emacs.

Arguments:
P4-THIS-COMMAND is the command that called this internal function.

P4-REGEXP is the optional regular expression to search for to set the cursor
on.

P4-THIS-BUFFER is the optional buffer to create. (Default is *P4 <command>*).

P4-OUT-COMMAND is the optional command that will be used as the command to
be called when `p4-async-call-process' is called."
  (if p4-this-buffer
      (set-buffer (get-buffer-create p4-this-buffer))
    (set-buffer (get-buffer-create (concat "*P4 " p4-this-command "*"))))
  (setq p4-current-command p4-this-command)
  (call-process-region (point-min) (point-max) p4-executable
		       t t nil p4-current-command "-o")
  (goto-char (point-min))
  (if p4-regexp (re-search-forward p4-regexp))
  (indented-text-mode)
  (setq p4-minor-mode t)
  (switch-to-buffer (current-buffer))
  (if p4-out-command
      (setq p4-current-command p4-out-command))
  (define-key p4-minor-map "\C-c\C-c" 'p4-async-call-process)
  (message "C-c C-c to finish editing and exit buffer."))

(defun p4-async-call-process ()
  "Internal function called by `p4-async-process-command' to process the
buffer after editing is done using the minor mode key mapped to `C-c C-c'."
  (interactive)
  (let ((max (point-max)) msg)
    (goto-char max)
    (call-process-region (point-min) max p4-executable 
			 nil '(t t) nil p4-current-command "-i")
    (goto-char max)
    (while (re-search-forward "\r\\\|\n" nil t)
      (replace-match " " nil t))
    (goto-char max)
    (setq msg (buffer-substring max (point-max)))
    (delete-region max (point-max))
    (message "%s" msg)
    (kill-buffer nil)))

;; The p4 change command
(defun p4-change ()
  "To edit the change specification, type \\[p4-change].
   
Optional args [-d | -o] [ change# ] passed as prefix arguments.

Creates a new change description with no argument or edit the
text description of an existing change if a change number is
given.  To associate or remove files from a pending change use
the open commands (edit, add, delete) or revert.

The -d flag discards a pending change, but only if it has no
opened files and no pending fixes associated with it.  Use 'opened -a'
to report on opened files and 'reopen' to move them to another
change.  Use 'fixes -c change#' to report on pending fixes and
'fix -d -c change# jobs...' to delete pending fixes.  The change
can only be deleted by the user and client who created it.

The -o flag causes the change specification to be written
to the standard output.  The user's editor is not invoked.

The -i flag causes a change specification to be read from the
standard input.  The user's editor is not invoked."

  (interactive)
  (p4-async-process-command "change" "Description:\n\t" "*P4 New Change*"))

;; The p4 client command
(defun p4-client ()
  "To edit a client specification , type \\[p4-client].
   
With no argument client creates a new client view specification or
edits an existing client specification. The client name is taken
from the environment variable $P4CLIENT if set, or else from
the current host name.  The specification form is put into a
temporary file and the editor (given by the environment variable
$EDITOR) is invoked.  If a name is given, the specification of
the named client is displayed read-only.

The specification form contains the following fields:

Client:      The client name (read only.)

Date:        The date specification was last modified (read only.)

Description: A short description of the client (optional).

Root:        The root directory of the client file workspace
             (given in local file system syntax), under which all
             client files will be placed.  If you change this, you
             must physically relocate any files as well.

View:        What files you want to see from the depot and how
             they map to locations on the client.  The left hand
             side specifies a depot path, which must begin with
             //depot/.  The right hand side gives the corresponding
             client path, given in canonical Perforce file syntax.
             On expansion to an actual local client file name the
             initial //client/ is replaced by the Root value, given
             above.  You may use wildcards:

                 ...            matches any characters including
                 *              matches any character except /
                 %1 to %9       like *, used to associate wild cards

             Wildcarding must be congruent in both the client and
             depot paths.  You may have any number of view entries.
             A new view takes effect on the next 'get'.

Normally, new clients are created with a default view that maps
all depot files onto the client.  The -t flag uses the view from
the named template client as a default instead.

The -d flag causes the named client to be deleted.

The -o flag causes the named client specification to be written
to the standard output.  The user's editor is not invoked.

The -i flag causes a client specification to be read from the
standard input.  The user's editor is not invoked."

  (interactive)
  (p4-async-process-command "client"))

;; The p4 submit command
(defun p4-submit ()
  "To submit a pending change to the depot, type \\[p4-submit].
   
Submit commits a pending change with its associated files to the depot.
With no argument submit sends the 'default' change.  With the -c flag
the designated pending change is sent.  Before committing the change
submit locks all associated files not already locked.  If any file
cannot be locked the change is aborted.  If submit is sending the
default change it first provides the user with a dialog similar to
'p4 change' so the user can compose a change description.  In this
dialog the user is presented with the list of open files in change
'default'.  Files may be deleted from this list but they cannot be
added.  (Use an open command (open, edit, add, delete) to add
additional files to a change or to move files between changes.)

If the submit fails for any reason the files are left open in
a newly created pending change.

Submit is guaranteed to be atomic.  Either all files will be
updated in the depot as a unit or none will be.

The -i flag causes a change specification to be read from the
standard input.  The user's editor is not invoked."

  (interactive)
  (p4-async-process-command "change" "Description:\n\t" 
			    "*P4 Submit*" "submit"))

;; The p4 user command
(defun p4-user ()
  "To create or edit a user specification, type \\[p4-user].
   
Create a new user specification or edit an existing user
specification. The specification form is put into a temporary
file and the editor (given by the environment variable $EDITOR)
is invoked.

Normally, a user specification is created automatically the
first time the user invokes any client command that can update
the depot.  The 'user' command is generally used to edit the
user's reviewing subscription list for change review.

The user specification form contains the following fields:

User:        The user name (read only).

Email:       The user's email address (user at client default).

Update:      The date the specification was last modified (read only).

Access:      The date the user last issued a client command.

FullName:    The user's real name.

Reviews:     The subscription list for change review.  You may
             use wildcards:
                 ...            matches any characters including

                 *              matches any character except /
             There may be any number of review lines.

The -d flag deletes the named user, but only if the user is not
the owner of any branches, clients, jobs, labels, or opened files.

The -o flag causes the named user specification to be written
to the standard output.  The user's editor is not invoked.

The -i flag causes a user specification to be read from the
standard input.  The user's editor is not invoked."

  (interactive)
  (p4-async-process-command "user"))
  
;; A function to get the current P4 client name
(defun p4-get-client-name ()
  "To get the current value of the environment variable P4CLIENT, 
type \\[p4-get-client-name].

   This will be  the current client that is in use for access through 
   Emacs P4."

  (interactive)
  (message "P4CLIENT is %s" (getenv "P4CLIENT")))

;; A function to set the current P4 client name
(defun p4-set-client-name (p4-new-client-name)
  "To set the current value of P4CLIENT, type \\[p4-set-client-name].

This will change the current client from the previous client to the new 
given value.

Setting this value to nil would disable P4 Version Checking.

`p4-set-client-name' will complete any client names set using the function
`p4-set-my-clients'. The strictness of completion will depend on the
variable `p4-strict-complete' (default is t).

Argument P4-NEW-CLIENT-NAME The new client to set to. The default value is
the current client."
  (interactive (list 
		(if (not (eq p4-my-clients nil))
		    (completing-read "Change Client to: " p4-my-clients
				     nil p4-strict-complete p4-oldclt)
		  (let ((symbol (read-string "Change Client to: "
					     p4-oldclt)))
		    (if (equal symbol "")
			p4-oldclt
		      symbol))
		  )))
  (if (equal p4-new-client-name "nil")
      (progn
	(setenv "P4CLIENT"  nil)
	(message 
	 "P4 Version check disabled. Set a valid client name to enable."))
    (progn
      (setenv "P4CLIENT"  p4-new-client-name)
      (setq p4-oldclt p4-new-client-name)
      (message  "P4CLIENT changed to %s" p4-new-client-name))))

(defun p4-set-my-clients (client-list)
  "To set the client completion list used by `p4-set-client-name', use
this function in your .emacs (or any lisp interaction buffer).

This will change the current client list from the previous list to the new
given value.

Setting this value to nil would disable client completion by
`p4-set-client-name'.

The strictness of completion will depend on the variable
`p4-strict-complete' (default is t).

Argument CLIENT-LIST is the 'list' of clients.

To set your clients using your .emacs, use the following:

\(load-library \"p4\"\)
\(p4-set-my-clients \'(client1 client2 client3)\)"
  (setq p4-my-clients nil)
  (let ((p4-tmp-client-var nil))
    (while client-list
      (setq p4-tmp-client-var (format "%s" (car client-list)))
      (setq client-list (cdr client-list))
      (setq p4-my-clients (append p4-my-clients
				  (list (list p4-tmp-client-var)))))))

;; A function to get the current P4PORT
(defun p4-get-p4-port ()
  "To get the current value of the environment variable P4PORT, type \\[p4-get-p4-port].

   This will be  the current server/port that is in use for access through 
   Emacs P4."

  (interactive)
  (message "P4PORT is %s" (getenv "P4PORT")))

;; A function to set the current P4PORT
(defun p4-set-p4-port (p4-new-p4-port)
  "To set the current value of P4PORT, type \\[p4-set-p4-port].

This will change the current server from the previous server to the new
given value.

Argument P4-NEW-P4-PORT The new server:port to set to. The default value is
the current value of P4PORT."
  (interactive (list (let 
			 ((symbol (read-string "Change server:port to: "
					       p4-old-p4-port)))
		       (if (equal symbol "")
			   p4-old-p4-port
			 symbol))))
  (if (equal p4-new-p4-port "nil")
      (progn
	(setenv "P4PORT"  nil)
	(message 
	 "P4 Version check disabled. Set a valid client name to enable."))
    (progn
      (setenv "P4PORT"  p4-new-p4-port)
      (setq p4-old-p4-port p4-new-p4-port)
      (message  "P4PORT changed to %s" p4-new-p4-port))))

;; The find-file hook for p4.
(defun p4-find-file-hook ()
  "To check while loading the file, if it is a P4 version controlled file."
  (if (getenv "P4CLIENT")
      (p4-check-mode)))

;; A function to check if the file being opened is version controlled by p4.
(defun p4-is-vc ()
  "If a file is controlled by P4 then return version else return nil."
  (save-excursion
    (get-buffer-create p4-output-buffer-name)
    (set-buffer p4-output-buffer-name)
    (delete-region (point-min) (point-max)))
  (if (zerop (call-process
	      p4-executable
	      nil
	      p4-output-buffer-name
	      nil
	      "files" buffer-file-name))
      (progn
	(save-excursion
	  (set-buffer p4-output-buffer-name)
	  (goto-char (point-min))
	  (if (re-search-forward  "#[0-9]+" (point-max)  t)
	      (substring (match-string 0) 1)
	    nil)))
    nil))

;; set keymap. We use the C-x P Keymap for all perforce commands

(defvar p4-prefix-map (lookup-key global-map "\C-xP") 
  "The Prefix for P4 Library Commands.")
(if (not (keymapp p4-prefix-map))
    (progn
      (setq p4-prefix-map (make-sparse-keymap))
      (define-key global-map "\C-xP" p4-prefix-map)
      (define-key p4-prefix-map "a" 'p4-add)
      (define-key p4-prefix-map "c" 'p4-client)
      (define-key p4-prefix-map "d" 'p4-diff2)
      (define-key p4-prefix-map "e" 'p4-edit)
      (define-key p4-prefix-map "f" 'p4-filelog)
      (define-key p4-prefix-map "g" 'p4-get-client-name)
      (define-key p4-prefix-map "G" 'p4-get)
      (define-key p4-prefix-map "h" 'p4-help)
      (define-key p4-prefix-map "i" 'p4-info)
      (define-key p4-prefix-map "n" 'p4-notify)
      (define-key p4-prefix-map "o" 'p4-opened)
      (define-key p4-prefix-map "P" 'p4-set-p4-port)
      (define-key p4-prefix-map "r" 'p4-revert)
      (define-key p4-prefix-map "R" 'p4-refresh)
      (define-key p4-prefix-map "s" 'p4-set-client-name)
      (define-key p4-prefix-map "S" 'p4-submit)
      (define-key p4-prefix-map "t" 'p4-toggle-vc-mode)
      (define-key p4-prefix-map "u" 'p4-user)
      (define-key p4-prefix-map "v" 'p4-emacs-version)
      (define-key p4-prefix-map "x" 'p4-delete)
      (define-key p4-prefix-map "=" 'p4-diff)
      (define-key p4-prefix-map "-" 'p4-ediff)))

;; For users interested in notifying a change, a notification list can be
;; set up using this function. 
(defun p4-set-notify-list (p4-new-notify-list)
  "To set the current value of P4NOTIFY, type \\[p4-set-notify-list].

This will change the current notify list from the existing list to the new
given value.

Enter nil to disable notification.

Argument P4-NEW-NOTIFY-LIST The new value of the notification list."
  (interactive (list (let 
			 ((symbol (read-string 
				   "Change Notification List to: "
				   p4-notify-list)))
		       (if (equal symbol "")
			   p4-notify-list
			 symbol))))      
  (setq p4-old-notify-list p4-notify-list)
  (if (equal p4-new-notify-list "nil")
      (progn
	(setenv "P4NOTIFY"  nil)
	(setq p4-notify-list nil)
	(setq p4-notify nil))
    (progn
      (setenv "P4NOTIFY"  p4-new-notify-list)
      (setq p4-notify-list p4-new-notify-list)
      (setq p4-notify t)))
  (message  "Notification list changed from '%s' to '%s'" 
	    p4-old-notify-list p4-notify-list))

;; To get the current notification list.
(defun p4-get-notify-list ()
  "To get the current value of the environment variable P4NOTIFY, type \\[p4-get-notify-list].

   This will be the current notification list that is in use for mailing
   change notifications through Emacs P4."

  (interactive)
  (message "P4NOTIFY is %s" p4-notify-list))

;; Function to actually notify the users. Unfortunately, there are
;; limitations to this. It uses an external program to make the
;; notification, and since Emacs is not threaded, we can't really do
;; autonotification without going through pains, since p4-submit calls an
;; async process. The closest thing would be a diligent user who notifies
;; voluntarily after submitting a change.
(defun p4-notify (users)
  "To notify a list of users of a change submission.

Since Emacs is not threaded, there is no good way to make this happen
intelligently. So, function `p4-notify' is supposed to be used only after
you submit `p4-submit' or `C-x P S' a change _from_ Emacs using the Emacs-P4
Interface. function `p4-notify' will look for a submitted change returned
from the submit command. Any external program can be used to actually mail
the change description, and the default is a perl-based program `mailch' -
mail change description.

Argument USERS The users to notify to. The default value is the notification
list."

  (interactive (list (let
			 ((symbol (read-string "Notify whom? "
					       p4-notify-list)))
		       (if (equal symbol "")
			   p4-notify-list
			 symbol))))
  
  (set-buffer (get-buffer-create p4-output-buffer-name))
  (goto-char (point-min))
  (if (re-search-forward  "[0-9]+.*submitted" (point-max)  t)
      (progn
	(p4-set-notify-list users)
	(let ((p4-matched-change 'nil))
	  (setq p4-matched-change (substring (match-string 0) 0 -9))
	  (start-process p4-matched-change 
			 nil
			 p4-notifier (concat p4-matched-change " "
					     users))))
    (message "No Changes Submitted." users)))

;; Function to return the current version.
(defun p4-emacs-version ()
  "Return the current Emacs-P4 Integration version."
  (interactive)
  (cond (p4-running-xemacs
	 (message "XEmacs-P4 Integration v%s" p4-emacs-version))
	(p4-running-emacs
	 (message "Emacs-P4 Integration v%s" p4-emacs-version))))

;; To set the path to the p4 executable
(defun p4-set-p4-executable (p4-exe-name)
  "Set the path to the correct P4 Executable.

To set this as a part of the .emacs, add the following to your .emacs:

(load-library \"p4\")
(p4-set-p4-executable \"/my/path/to/p4\")

Argument P4-EXE-NAME The new value of the p4 executable, with full path."
  (interactive "fFull path to your P4 executable: " )
  (setq p4-executable p4-exe-name))

;; To set the path to the mailch notification program (if it exists).
(defun p4-set-notifier (p4-notify-name)
  "Set the path to the correct mailch.

To set this as a part of the .emacs, add the following to your .emacs:

\(load-library \"p4\"\)
\(p4-set-notifier \"/my/path/to/mailch\"\)

Argument P4-NOTIFY-NAME The full path to mailch."
  (interactive "fFull path to your P4 Notifier (mailch): " )
  (setq p4-notifier p4-notify-name))

;; To check if the current buffer's modeline and menu need to be altered
(defun p4-check-mode (&optional args)
  "Check to see whether we should export the menu map to this buffer.

Optional argument ARGS Used only by `p4-add', the `p4-mode' variable is set
to this instead of the value returned from `p4-is-vc'."
  (if p4-do-find-file
      (progn
	(let ((p4-vc-check 'nil))
	  (if args
	      (setq p4-vc-check args)
	    (setq p4-vc-check (p4-is-vc)))
	  (if p4-vc-check
	      (progn
		(cond (p4-running-xemacs
		       (p4-menu-add)))
		(setq p4-mode (concat " P4:" p4-vc-check)))
	    (setq p4-mode nil)))
	(if p4-mode
	    (define-key global-map "\C-x\C-q" 'p4-toggle-read-only))
	(p4-force-mode-line-update))))

;; Force mode line updation for different Emacs versions
(defun p4-force-mode-line-update ()
  "To Force the mode line update for different flavors of Emacs."
  (cond (p4-running-xemacs
	 (redraw-modeline))
	(p4-running-emacs
	 (force-mode-line-update))))

;; In case, the P4 server is not available, or when operating off-line, the
;; p4-find-file-hook becomes a pain... this functions toggles the use of the
;; hook when opening files.

(defun p4-toggle-vc-mode ()
  "In case, the P4 server is not available, or when working off-line, toggle
the VC check on/off when opening files."
  (interactive)
  (setq p4-do-find-file (not p4-do-find-file))
  (if p4-do-find-file
      (message "P4 mode check enabled.")
    (message "P4 mode check disabled.")))

;; Wrap C-x C-q to allow p4-edit/revert and also to ensure that
;; we don't stomp on vc-toggle-read-only.

(defun p4-toggle-read-only (&optional verbose)
  "If p4-mode is non-nil, \\[p4-toggle-read-only] toggles between `p4-edit'
and `p4-revert'. 

If the current buffer's file is not under p4, then this function passes on
all the parameters to `vc-toggle-read-only'."
  (interactive "P")
  (if (and (boundp 'p4-mode) (not (eq p4-mode nil)))
      (if buffer-read-only
	  (p4-edit verbose)
	(p4-revert verbose))
    (vc-toggle-read-only verbose)))

;; I separated the menu support for Emacs and XEmacs since they seemed
;; to differ considerably.

(cond (p4-running-xemacs  
       ;; Menu Support for XEmacs
       (require 'easymenu)
       (defun p4-mode-menu (modestr)
	 (let ((m
		'(["Add Current to P4" p4-add  
		   (and buffer-file-name (not p4-mode))]
		  ["Check out/Edit"    p4-edit (and buffer-file-name 
					  (and buffer-read-only p4-mode))]
		  ["------------------" nil nil]
		  ["Revert File"  p4-revert (and buffer-file-name 
						 (and (not buffer-read-only)
						      p4-mode))]
		  ["Filelog" p4-filelog (and buffer-file-name p4-mode)]
		  ["------------------" nil nil]
		  ["Diff 2 Versions" p4-diff2 (and buffer-file-name 
						   p4-mode)]
		  ["Diff Current" p4-diff (and buffer-file-name 
					       (and (not buffer-read-only)
						    p4-mode))]
		  ["Diff Current with Ediff"   p4-ediff 
		   (and buffer-file-name (and (not buffer-read-only)
					      p4-mode))]
		  ["------------------" nil nil]
		  ["Delete File from Depot"  p4-delete 
		   (and buffer-file-name 
			(and buffer-read-only p4-mode))]
		  ["------------------" nil nil]
		  ["Submit Changes"  p4-submit (and 
						buffer-file-name 
						p4-mode)]
		  ["------------------" nil nil]
		  ["Show Version" p4-emacs-version (and 
						    buffer-file-name 
						    p4-mode)]
		  ["Disable P4 VC Check"  p4-toggle-vc-mode 
		   p4-do-find-file]
		  ["Enable P4 VC Check"  p4-toggle-vc-mode 
		   (not p4-do-find-file)]
		  ["------------------" nil nil]
		  ["Set P4 Client"  p4-set-client-name p4-do-find-file]
		  ["Get Current P4 Client"  p4-get-client-name 
		   p4-do-find-file]
		  ["------------------" nil nil]
		  ["Set P4 Server/Port"  p4-set-p4-port p4-do-find-file]
		  ["Get Current P4 Server/Port"  p4-get-p4-port 
		   p4-do-find-file]
		  )))
	   (cons modestr m)))

       (defun p4-menu-add ()
	 "To add the P4 menu bar button for files that are already not in
          the P4 depot or in the current client view.." 
	 (interactive)
	 (if (not (boundp 'p4-mode))
	     (setq p4-mode nil))
	 (easy-menu-add (p4-mode-menu "P4"))))
      
      (p4-running-emacs
       ;; Menu support for Emacs
       (or (lookup-key global-map [menu-bar])
	   (define-key global-map [menu-bar] (make-sparse-keymap "menu-bar")))
       (defvar menu-bar-p4-menu (make-sparse-keymap "P4"))
       (setq menu-bar-final-items (cons 'p4-menu menu-bar-final-items))
       (define-key global-map [menu-bar p4-menu] 
	 (cons "P4" menu-bar-p4-menu))
       (define-key menu-bar-p4-menu [p4-get-p4-port]
	 '("Get Current P4 Server/Port" . p4-get-p4-port))
       (define-key menu-bar-p4-menu [p4-set-p4-port]
	 '("Set P4 Server/Port" . p4-set-p4-port))
       (define-key menu-bar-p4-menu [separator-server-name]
	 '("--"))
       (define-key menu-bar-p4-menu [p4-get-client-name]
	 '("Get Current P4 Client" . p4-get-client-name))
       (define-key menu-bar-p4-menu [p4-set-client-name]
	 '("Set P4 Client" . p4-set-client-name))
       (define-key menu-bar-p4-menu [separator-client-name]
	 '("--"))
       (define-key menu-bar-p4-menu [p4-toggle-vc-mode]
	 '("Toggle P4 VC Check" . p4-toggle-vc-mode))
       (define-key menu-bar-p4-menu [p4-emacs-version]
	 '("Show Version" . p4-emacs-version))
       (define-key menu-bar-p4-menu [separator-vc-check]
	 '("--"))
       (define-key menu-bar-p4-menu [p4-submit]
	 '("Submit Changes" . p4-submit))
       (define-key menu-bar-p4-menu [separator-submit]
	 '("--"))
       (define-key menu-bar-p4-menu [p4-delete]
	 '("Delete File from Depot" . p4-delete))
       (define-key menu-bar-p4-menu [separator-delete]
	 '("--"))
       (define-key menu-bar-p4-menu [p4-ediff]
	 '("Diff Current with Ediff" . p4-ediff))
       (define-key menu-bar-p4-menu [p4-diff]
	 '("Diff Current" . p4-diff))
       (define-key menu-bar-p4-menu [p4-diff2]
	 '("Diff 2 Versions" . p4-diff2))
       (define-key menu-bar-p4-menu [separator-diff]
	 '("--"))
       (define-key menu-bar-p4-menu [p4-filelog]
	 '("Filelog" . p4-filelog))
       (define-key menu-bar-p4-menu [p4-revert]
	 '("Revert File" . p4-revert))
       (define-key menu-bar-p4-menu [separator-revert]
	 '("--"))
       (define-key menu-bar-p4-menu [p4-edit]
	 '("Checkout/Edit" . p4-edit))
       (define-key menu-bar-p4-menu [p4-add]
	 '("Add Current to P4" . p4-add))
       (put 'p4-add 'menu-enable '(and buffer-file-name (not p4-mode)))
       (put 'p4-edit 'menu-enable '(and buffer-file-name 
					(and p4-mode buffer-read-only)))
       (put 'p4-delete 'menu-enable '(and buffer-file-name 
					  (and p4-mode buffer-read-only)))
       (put 'p4-revert 'menu-enable '(and buffer-file-name 
					  (and p4-mode 
					       (not buffer-read-only))))
       
       (put 'p4-ediff 'menu-enable '(and buffer-file-name 
					 (and p4-mode 
					      (not buffer-read-only))))
       
       (put 'p4-diff 'menu-enable '(and buffer-file-name 
					(and p4-mode 
					     (not buffer-read-only))))
       
       (put 'p4-diff2 'menu-enable '(and buffer-file-name p4-mode))
       (put 'p4-filelog 'menu-enable '(and buffer-file-name p4-mode))
       (put 'p4-get-client-name 'menu-enable '(and t p4-do-find-file))
       (put 'p4-set-client-name 'menu-enable '(and t p4-do-find-file))
       (put 'p4-get-p4-port 'menu-enable '(and t p4-do-find-file))
       (put 'p4-set-p4-port 'menu-enable '(and t p4-do-find-file))
       ))

;;;###autoload
(define-key global-map "\C-x\C-q" 'p4-toggle-read-only)
(provide 'p4)

;;; p4.el ends here


- --------------0F722EF1F016CE5D517F1BB7--






More information about the perforce-user mailing list