Warning: this is an htmlized version!
The original is here, and the conversion rules are here. |
;;; eev-channels.el -- control external processes using signals, -*- lexical-binding: nil; -*- ;;; temporary files, and Expect scripts. ;; Copyright (C) 2012-2019 Free Software Foundation, Inc. ;; ;; This file is part of GNU eev. ;; ;; GNU eev 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 3 of the License, or ;; (at your option) any later version. ;; ;; GNU eev 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 GNU Emacs. If not, see <http://www.gnu.org/licenses/>. ;; ;; Author: Eduardo Ochs <eduardoochs@gmail.com> ;; Maintainer: Eduardo Ochs <eduardoochs@gmail.com> ;; Version: 20240307 ;; Keywords: e-scripts ;; ;; Latest version: <http://angg.twu.net/eev-current/eev-channels.el> ;; htmlized: <http://angg.twu.net/eev-current/eev-channels.el.html> ;; See also: <http://angg.twu.net/eev-current/eev-beginner.el.html> ;; <http://angg.twu.net/eev-intros/find-eev-intro.html> ;; (find-eev-intro) ;;; Commentary: ;; `eechannel' is very difficult to set up and has been mostly ;; superseded by `eepitch'. There is some documentation here - ;; including e-scripts for tests - but it is incomplete and some parts ;; need to be rewritten: ;; ;; (find-channels-intro) ;; (find-channels-intro "2. Low-level tests") ;; ;; TODO: import code from: ;; (find-eevgrep "grep -nH -e channel *.el") ;; (find-eev "anim/channels.anim") ;; (find-eev "eechannel.el") ;; «.eechannel» (to "eechannel") ;; «.eechannel-assert» (to "eechannel-assert") ;; «.eexterm» (to "eexterm") (require 'eev-prepared) ; (find-eev "eev-prepared.el") (defun ee-read-file (fname) (with-temp-buffer (insert-file-contents fname) (buffer-string))) ;;; _ _ ;;; ___ ___ ___| |__ __ _ _ __ _ __ ___| | ;;; / _ \/ _ \/ __| '_ \ / _` | '_ \| '_ \ / _ \ | ;;; | __/ __/ (__| | | | (_| | | | | | | | __/ | ;;; \___|\___|\___|_| |_|\__,_|_| |_|_| |_|\___|_| ;;; ;; (find-man "xterm" "-T string") ;; (find-man "xterm" "-e program [ arguments ... ]") ;; (find-eev "eegchannel") ;; (find-eev "eegchannel" "pidfile") ;; (find-eev "eegchannel" "strfile") ;; ;; There is a big diagram explaining how this works at: ;; ;; (find-eev "anim/channels.anim") ;; ;; Note that this is a "communication diagram" - it shows which ;; programs start which other programs, and how they communicate. ;; Here is a call diagram for the lisp functions (and some ;; variables): ;; ;; <F9> ---> eechannel-this-line ;; | \ (on "*" lines) ;; (on non-"*" | v ;; lines) | ee-eval-string ;; v ;; eechannel-send ;; | | | ;; | | v (sets) ;; | v eechannel-default <------ eechannel ;; v eechannel-strfile ;; /---> eechannel-pid ----------> eechannel-pidfile ;; | ;; eechannel-kill ;; ;; «eechannel» (to ".eechannel") (defvar eechannel-default nil) ;; Test: (eechannel-strfile "A") (defun eechannel-strfile (channel) (ee-expand (format "$EEVTMPDIR/eeg.%s.str" channel))) ;; Test: (eechannel-pidfile "A") (defun eechannel-pidfile (channel) (ee-expand (format "$EEVTMPDIR/eeg.%s.pid" channel))) (defun eechannel-pid (channel) "Return the pid stored in the eeg.CHANNEL.pid file, as a string (or nil on error)." (let ((pidfile (eechannel-pidfile channel))) (if (file-exists-p pidfile) (ee-no-trailing-nl (ee-read-file pidfile))))) (defun eechannel-kill (channel sig) "Send the signal SIG to the process listening on the channel CHANNEL." ;; We call "kill" to send the signal. (find-callprocess0 (format "kill %s %s" sig (eechannel-pid channel)))) (defun eechannel-send (channel str) "Send STR through channel CHANNEL (or through channel `eechannel-default')." (setq channel (or channel eechannel-default)) (write-region str nil (eechannel-strfile channel)) (find-callprocess0 (format "kill -USR1 %s" (eechannel-pid channel)))) (defun eechannel-this-line () (interactive) "Send the current line through the channel `eechannel-default', and go down. If the line starts with a `*' then evaluate it as lisp instead of sending it." (let ((line (buffer-substring (ee-bol) (ee-eol)))) ; contents of this line (if (string-match "^*\\(.*\\)" line) ; lines with a red star (ee-eval-string (match-string 1 line)) ; are eval'ed (eechannel-send nil (concat line "\n"))) ; other lines are sent (ee-next-line 1))) ; go down (defun eechannel (channel) "Set the default channel to CHANNEL." (interactive "sDefault channel: ") (setq eechannel-default channel)) ;;; _ _ ;;; ___ ___ ___| |__ __ _ ___ ___ ___ _ __| |_ ;;; / _ \/ _ \/ __| '_ \ _____ / _` / __/ __|/ _ \ '__| __| ;;; | __/ __/ (__| | | |_____| (_| \__ \__ \ __/ | | |_ ;;; \___|\___|\___|_| |_| \__,_|___/___/\___|_| \__| ;;; ;; «eechannel-assert» (to ".eechannel-assert") (defun eechannel-pid-running-p (pid) "Return t if a process with pid PID is running. This is linux-specific." ;; I've heard the on BSDs "/proc" is optional and often disabled... ;; Calling "ps" every time sounds expensive, what should I do? (file-exists-p (format "/proc/%s" pid))) ;; The six functions below are for when we want to use eegchannel ;; directly, without calling it from an xterm (as in eexterm)... (defun eechannel-args-ne (channel prog-and-args) `(,(ee-expand "$EEVDIR/eegchannel") ,channel ,@(ee-split prog-and-args))) (defun eechannel-create-ne (channel prog-and-args) (find-bgprocess-ne (eechannel-args-ne channel prog-and-args))) (defun eechannel-assert-ne (channel prog-and-args) (let ((pid (eechannel-pid channel))) (if (eechannel-pid-running-p (eechannel-pid channel)) (message "Channel %s (pid %s) looks alive, reusing" channel pid) (eechannel-create-ne channel prog-and-args)))) (defun eechannel-args (channel prog-and-args) (eechannel-args-ne channel (ee-split-and-expand prog-and-args))) (defun eechannel-create (channel prog-and-args) (eechannel-create-ne channel (ee-split-and-expand prog-and-args))) (defun eechannel-assert (channel prog-and-args) (eechannel-assert-ne channel (ee-split-and-expand prog-and-args))) ;;; _ ;;; ___ _____ _| |_ ___ _ __ _ __ ___ ;;; / _ \/ _ \ \/ / __/ _ \ '__| '_ ` _ \ ;;; | __/ __/> <| || __/ | | | | | | | ;;; \___|\___/_/\_\\__\___|_| |_| |_| |_| ;;; ;; A call diagram: ;; ;; eexterm ---------> eexterm-ne ;; | | ;; | v ;; | eechannel-pid-running-p ;; v ;; eexterm-create --> eexterm-create-ne ;; | ;; v ;; eexterm-args ----> eexterm-args-ne ;; ;; eexterm-kill -----> eechannel-kill ;; ;; «eexterm» (to ".eexterm") ;; Tests: ;; (eexterm-args-ne "A") ;; (eexterm-args-ne "A" '("ssh" "foo@bar") "-geometry 80x20") ;; (eexterm-create-ne "A") ;; (eexterm-create "A") ;; (eexterm-create "A") ;; (eexterm "A") ;; (eechannel-send "A" "echo hello") ;; (eechannel-send "A" "echo hello\n") ;; (eexterm-kill "A") ;; (defun eexterm-args-ne (channel &optional prog-and-args xterm-args) "Return a list of arguments for running a xterm listening on CHANNEL. Try these examples: (eexterm-args-ne \"A\" nil nil) (eexterm-args-ne \"A\" '(\"ssh\" \"foo@bar\") \"-geometry 80x20\")" `("xterm" "-T" ,(format "channel %s" channel) ,@(ee-split xterm-args) "-e" ,(ee-expand "$EEVDIR/eegchannel") ,channel ,@(ee-split (or prog-and-args (ee-expand "$SHELL"))))) (defun eexterm-create-ne (channel &optional prog-and-args xterm-args) "Start a xterm listening on CHANNEL. See `eexterm-args-ne'." (find-bgprocess-ne (eexterm-args-ne channel prog-and-args xterm-args))) (defun eexterm-ne (channel &optional prog-and-args xterm-args) "Set the default channel to CHANNEL; create an xterm listening on CHANNEL if needed." (interactive "sDefault channel: ") (setq eechannel-default channel) (if (eechannel-pid-running-p (eechannel-pid channel)) (message "Reusing xterm at channel %s" channel) (eexterm-create-ne channel prog-and-args xterm-args))) (defun eexterm-args (channel &optional prog-and-args xterm-args) (eexterm-args-ne channel (ee-split-and-expand prog-and-args) xterm-args)) (defun eexterm-create (channel &optional prog-and-args xterm-args) "Create an xterm listening on CHANNEL." (eexterm-create-ne channel (ee-split-and-expand prog-and-args) xterm-args)) (defun eexterm (channel &optional prog-and-args xterm-args) "Set the default channel to CHANNEL; create an xterm listening on CHANNEL if needed." (interactive "sDefault channel: ") (eexterm-ne channel (ee-split-and-expand prog-and-args) xterm-args)) (defalias 'eechannel-xterm 'eexterm) (defun eexterm-kill (&optional channel sig) (interactive) (eechannel-kill (or channel eechannel-default) (or sig ""))) (provide 'eev-channels) ;; Local Variables: ;; coding: utf-8-unix ;; no-byte-compile: t ;; End: