tran@umn-cs.UUCP (Michael Tran) (10/05/87)
I wrote this small module this summer while exploring ways to get Emacs
to do remote editing on a Cray 2.
The main functions are find-remote-file (which I mapped to C-c C-f in my .emacs)
save-remote-file (C-c C-s)
write-remote-file (C-c C-w)
;; rcp.el
;; Module to do remote editing via rcp. Assume .rhosts files are
;; set up properly on both machines.
;; Modeled after ftp.el by MLY.PREP.AI.MIT.EDU
;;
;; Nick Tran
;; University of Minnesota
;; Summer 87
;;
(make-variable-buffer-local 'default-remote-directory)
(make-variable-buffer-local 'buffer-remote-file-name)
(setq-default default-remote-directory "sb:")
(defun find-remote-file ()
(interactive)
(let (proc temp s host file time default (olddir default-directory))
(setq s "")
(while (not (string-match "\\`[ \t]*\\([^ \t:]+\\)[ \t]*:\\(.+\\)\\'" s))
(setq s (read-string "Find remote file: " default-remote-directory)))
(setq host (substring s (match-beginning 1) (match-end 1)))
(setq file (substring s (match-beginning 2) (match-end 2)))
(if (string-match "[^\t /]+$" file)
(and (setq temp (substring file (match-beginning 0) nil))
(setq default (substring file 0 (match-beginning 0))))
(and (setq temp file) (setq default "")))
(setq temp (concat "/tmp/" temp))
(setq proc (start-process temp nil "/bin/rcp"
(concat host ":" file) temp))
(setq default-remote-directory (concat host ":" default))
(message "Finding %s:%s ..." host file)
(setq time 0)
(while (eq (process-status proc) 'run)
(setq time (1+ time))
(sleep-for 1)
)
(if (and (eq (process-status proc) 'exit)
(eq (process-exit-status proc) 0))
(progn
(find-file-read-only temp)
(message "%d bytes in %d seconds (~ %d Kb/s)"
(buffer-size) time (/ (buffer-size) (* time 1024)))
(delete-file temp)
(setq buffer-file-name "")
(setq buffer-remote-file-name (concat host ":" file))
(setq default-remote-directory (concat host ":" default))
(setq default-directory olddir)
)
(message "Find-remote-file failed (exit status %d)"
(process-exit-status proc)))
))
(defun save-remote-file()
(interactive)
(cond ((eq 0 (length buffer-remote-file-name)) (write-remote-file))
( t (do-write-remote-file buffer-remote-file-name))))
(defun write-remote-file ()
(interactive)
(let ((s ""))
(while (not (string-match "\\`[ \t]*\\([^ \t:]+\\)[ \t]*:\\(.+\\)\\'" s))
(or (not (and (string= s "")
(eq 0 (length (setq s buffer-remote-file-name)))))
(setq s default-remote-directory))
(setq s (read-string "Write remote file: " s)))
(do-write-remote-file s)))
(defun do-write-remote-file (s)
(if (buffer-modified-p)
(let (host file temp proc time (size (buffer-size))
(olddir default-directory))
(string-match "\\`[ \t]*\\([^ \t:]+\\)[ \t]*:\\(.+\\)\\'" s)
(setq host (substring s (match-beginning 1) (match-end 1)))
(setq file (substring s (match-beginning 2) (match-end 2)))
(setq temp (concat "/tmp/" (buffer-name)))
(if (string-match "[^\t /]+$" file)
(setq default-remote-directory
(concat host ":" (substring file 0 (match-beginning 0))))
(setq default (concat host ":")))
(setq buffer-remote-file-name (concat host ":" file))
(write-file temp)
(message "Writing %s:%s ..." host file)
(setq proc (start-process temp nil "/bin/rcp" temp (concat host ":" file)))
(setq time 0)
(while (eq (process-status proc) 'run)
(setq time (1+ time))
(sleep-for 1)
)
(if (and (eq (process-status proc) 'exit)
(eq (process-exit-status proc) 0))
(message "%d bytes in %d seconds (~ %d Kb/s)" size time (/ size (* time 1024)))
(and (set-buffer-modified-p t)
(message "Write-remote-file failed (exit status %d)"
(process-exit-status proc))))
(delete-file temp)
(set-visited-file-name "")
(setq default-directory olddir)
)
(message "(No changes need to be saved)")
))mayer@hplabsz.HPL.HP.COM (Niels Mayer) (10/08/87)
An intersting extension you might want to consider once you have remote editing up and running: When you want to do a 'make' after you've just edited a remote file, use a modified version of compile.el that looks at a buffer-local variable containing the remote host's name and run the compilation through rsh(1) on the remote host. Under HPUX+GNU, we can access remote files by opening a network connection via M-X netunam, and then access the file normally with ^X^F /net/host/path/file. I made a simple and crufty extension to compile.el that looks to see whether the buffer-file-name is remote and if so, I execute the compile command in a remsh (HPUX equivalent to rsh, renamed to prevent conflict with SYSV rsh which is a restricted sh).... Those of you using ftp.el or rcp.el to do remote editing may want to do something similar by storing the appropriate information in a buffer-local variable and munging compile.el appropriately. here's the relevant diffs between the 18.47 version of compile.el and my version: 82,91c82,119 < (setq compilation-process < (start-process "compilation" "*compilation*" < shell-file-name < "-c" (concat "exec " command))) < (with-output-to-temp-buffer "*compilation*" < (princ "cd ") < (princ default-directory) < (terpri) < (princ command) < (terpri)) --- > (cond > ((string-match "/net" default-directory) > (let (host > host-dir) > (setq host (substring default-directory > (+ 1 (match-end 0)) > (string-match "/" default-directory (+ 1 (match-end 0))))) > (setq host-dir (substring default-directory > (- (match-end 0) 1) > (length default-directory))) > (let ((default-directory (getenv "HOME"))) ;to prevent shell bug caused by pwd being a /net directory > (setq compilation-process > (start-process "compilation" "*compilation*" > "/usr/bin/remsh" host > "cd " host-dir ";" command))) > (with-output-to-temp-buffer "*compilation*" > (princ "remsh ") > (princ host) > (terpri) > (princ "cd ") > (princ host-dir) > (terpri) > (princ command) > (terpri)) > ) > ) > (t > (setq compilation-process > (start-process "compilation" "*compilation*" > shell-file-name > "-c" (concat "exec " command))) > (with-output-to-temp-buffer "*compilation*" > (princ "cd ") > (princ default-directory) > (terpri) > (princ command) > (terpri)) > ))