;;; eev-plinks.el -- elisp hyperlinks to invoke external processes. ;; 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 . ;; ;; Author: Eduardo Ochs ;; Maintainer: Eduardo Ochs ;; Version: 20190624 ;; Keywords: e-scripts ;; ;; Latest version: ;; htmlized: ;; See also: ;; ;; ;; (find-eev-intro) ;; (find-links-intro) ;;; Commentary: ;; Emacs can invoke external processes "synchronously", ;; "asynchronously", and as "command interpreters", as described here: ;; ;; (find-elnode "Synchronous Processes" "waits for the process to" "terminate") ;; (find-elnode "Asynchronous Processes" "runs in parallel") ;; (find-enode "Interactive Shell" "M-x shell") ;; (find-efile "comint.el" "shell-in-a-buffer") ;; ;; The most basic examples of each type in eev are: ;; ;; synchronous: `find-sh0', `find-sh' ;; asynchronous: `find-pdf-page', `find-firefox' ;; comint: `eepitch-shell' ;; ;; The low-level functions to create such processes are very different ;; in each of the three cases - and this file defines functions that ;; let us treat the three cases somewhat similarly. The main idea is ;; that the functions ;; ;; `find-bgprocess-ne' ;; `find-bgprocess' ;; `find-callprocess00-ne' ;; `find-callprocess0-ne' ;; `find-callprocess-ne' ;; `find-callprocess00' ;; `find-callprocess0' ;; `find-callprocess' ;; `find-comintprocess-ne' ;; `find-comintprocess' ;; ;; all receive an argument `program-and-args' that is either a string ;; or list of strings, and the functions `ee-split' and ;; `ee-split-and-expand' convert a `program-and-args' into a list of ;; strings. For example: ;; ;; (ee-split "xpdf ~/LATEX/foo.pdf") ;; (ee-split '("xpdf" "~/LATEX/foo.pdf")) ;; ;; both return the list ("xpdf" "~/LATEX/foo.pdf"), and ;; ;; (ee-split-and-expand "xpdf ~/LATEX/foo.pdf") ;; (ee-split-and-expand '("xpdf" "~/LATEX/foo.pdf")) ;; ;; both return the list ("xpdf" "/home/edrx/LATEX/foo.pdf"). ;; ;; The suffix `-ne' in the `find-xxx-ne' functions means "do not ;; expand", i.e., do not run `ee-expand' on each member of the list, ;; i.e., run `ee-split' instead of `ee-split-and-expand' on ;; `program-and-args'; and the suffixes `00' and `0' to the ;; `find-callprocess' functions work similarly to the suffixes `00' ;; and `0' in `find-sh'. Compare: ;; ;; (find-sh00 "seq 9 12") ;; (find-sh0 "seq 9 12") ;; (find-sh "seq 9 12") ;; ;; The `find-sh00' shows a newline-terminated string in the each area; ;; the `find-sh0' shows that string with the newline deleted; and the ;; `find-sh' shows it in a temporary buffer instead of in the acho ;; area. ;; «.find-bgprocess» (to "find-bgprocess") ;; «.find-callprocess» (to "find-callprocess") ;; «.find-callprocessregion» (to "find-callprocessregion") ;; «.find-comintprocess» (to "find-comintprocess") ;; See: ;; (find-eev "eepitch.el" "find-comintprocess-ne") ;; (find-eev "eev-blinks.el" "find-sh") ;; (find-node "(libc)Executing a File" "execv") ;; Obvious applications: ;; (find-eev "eev-pdflike.el") ;; (find-eev "eev-audiovideo.el") ;; (find-eev "eev-brxxx.el") ;; «.find-urlretrieve» (to "find-urlretrieve") ;; «.find-wget» (to "find-wget") ;; «.find-gitk» (to "find-gitk") ;; «.find-tkdiff» (to "find-tkdiff") ;;; ;;; _ __ _ __ ___ ___ ___ ___ ___ ___ ___ ;;; | '_ \| '__/ _ \ / __/ _ \/ __/ __|/ _ \/ __| ;;; | |_) | | | (_) | (_| __/\__ \__ \ __/\__ \ ;;; | .__/|_| \___/ \___\___||___/___/\___||___/ ;;; |_| ;; ;; 2007sep29: Copied these functions from eev-mini.el to here... ;; In a near future all calls to external processes in eev will happen ;; through these functions... mainly because (1) they accept their ;; "program-and-args" argument as either a string (to be split at ;; whitespace) or as a list of strings, (2) they can either expand ;; each "word" or "program-and-args" with ee-expand or keep all words ;; unchanged, (3) they're short and clean. ;; Note that the functions `ee-split' and `ee-split-and-expand' are ;; defined in eepitch.el, because we want that library to be as ;; self-contained as possible; `find-comintprocess-ne' and ;; `find-comintprocess' are also defined there. See: ;; ;; (find-eevfile "eepitch.el" "defun ee-split") ;; (find-eevfile "eepitch.el" "defun find-comintprocess-ne") (defun ee-unsplit (list) (if (listp list) (mapconcat 'identity list " ") list)) (defun ee-no-trailing-nl (str) (replace-regexp-in-string "\n$" "" str)) ;;; _ ;;; | |__ __ _ _ __ _ __ ___ ___ ___ ___ ___ ;;; | '_ \ / _` | '_ \| '__/ _ \ / __/ _ \/ __/ __| ;;; | |_) | (_| | |_) | | | (_) | (_| __/\__ \__ \ ;;; |_.__/ \__, | .__/|_| \___/ \___\___||___/___/ ;;; |___/|_| ;; ;; «find-bgprocess» (to ".find-bgprocess") ;; (defun find-bgprocess-ne (program-and-args) (let ((argv (ee-split program-and-args))) (apply 'start-process (car argv) "*Messages*" argv))) (defun find-bgprocess (program-and-args) (find-bgprocess-ne (ee-split-and-expand program-and-args))) ;;; _ _ ;;; ___ __ _| | |_ __ _ __ ___ ___ ___ ___ ___ ;;; / __/ _` | | | '_ \| '__/ _ \ / __/ _ \/ __/ __| ;;; | (_| (_| | | | |_) | | | (_) | (_| __/\__ \__ \ ;;; \___\__,_|_|_| .__/|_| \___/ \___\___||___/___/ ;;; |_| ;; ;; «find-callprocess» (to ".find-callprocess") ;; (defun find-callprocess00-ne (program-and-args) (let ((argv (ee-split program-and-args))) (with-output-to-string (with-current-buffer standard-output (apply 'call-process (car argv) nil t nil (cdr argv)))))) (defun find-callprocess00 (program-and-args) (find-callprocess00-ne (ee-split-and-expand program-and-args))) (defun find-callprocess0-ne (program-and-args) (ee-no-trailing-nl (find-callprocess00 program-and-args))) (defun find-callprocess0 (program-and-args) (find-callprocess0-ne (ee-split-and-expand program-and-args))) ;; Like `find-sh', but more low-level. ;; See: (find-eev "eev-blinks.el" "find-eoutput") ;; (find-eev "eev-blinks.el" "find-sh") ;; (defun find-callprocess-ne (program-and-args &rest pos-spec-list) (apply 'find-eoutput-reuse (ee-unsplit program-and-args) `(insert (find-callprocess00-ne ',program-and-args)) pos-spec-list)) (defun find-callprocess (program-and-args &rest pos-spec-list) (apply 'find-eoutput-reuse (ee-unsplit program-and-args) `(insert (find-callprocess00 ',program-and-args)) pos-spec-list)) ;;; _ ;;; _ __ _ __ ___ ___ ___ ___ ___ _ __ ___ __ _(_) ___ _ __ ;;; | '_ \| '__/ _ \ / __/ _ \/ __/ __| '__/ _ \/ _` | |/ _ \| '_ \ ;;; | |_) | | | (_) | (_| __/\__ \__ \ | | __/ (_| | | (_) | | | | ;;; | .__/|_| \___/ \___\___||___/___/_| \___|\__, |_|\___/|_| |_| ;;; |_| |___/ ;; ;; «find-callprocessregion» (to ".find-callprocessregion") ;; Use this when program-and-args expects input from stdin. ;; Note: Code salvaged from a very old version of eev. ;; To do: write examples and test cases for this. ;; See: (find-efunctiondescr 'call-process-region) ;; (find-elnode "Synchronous Processes" "Function: call-process-region") ;; (defun find-callprocessregion-ne (program-and-args input) (let ((argv (ee-split program-and-args))) (with-temp-buffer (insert input) (apply 'call-process-region (point-min) (point-max) (car argv) 'delete t nil (cdr argv)) (buffer-substring (point-min) (point-max))))) (defun find-callprocessregion (program-and-args input) (find-callprocessregion-ne (ee-split-and-expand program-and-args))) ;;; _ _ ;;; ___ ___ _ __ ___ (_)_ __ | |_ ;;; / __/ _ \| '_ ` _ \| | '_ \| __| ;;; | (_| (_) | | | | | | | | | | |_ ;;; \___\___/|_| |_| |_|_|_| |_|\__| ;;; ;; «find-comintprocess» (to ".find-comintprocess") ;; `find-comintprocess-ne' and `find-comintprocess' are defined in ;; eepitch.el. See: ;; (find-eev "eepitch.el" "find-comintprocess") ;;; _ _ _ ;;; _ _ _ __| | _ __ ___| |_ _ __(_) _____ _____ ;;; | | | | '__| |_____| '__/ _ \ __| '__| |/ _ \ \ / / _ \ ;;; | |_| | | | |_____| | | __/ |_| | | | __/\ V / __/ ;;; \__,_|_| |_| |_| \___|\__|_| |_|\___| \_/ \___| ;;; ;; «find-urlretrieve» (to ".find-urlretrieve") ;; See: (find-node "(url)Retrieving URLs" "url-retrieve-synchronously") ;; Tests: http://angg.twu.net/e/emacs.e.html#find-urlretrieve ;; (find-es "emacs" "find-urlretrieve") ;; (defun find-urlretrieve00 (url &rest pos-spec-list) "Download URL with `url-retrieve-synchronously'. Show the full response." (apply 'find-ebuffer (url-retrieve-synchronously url) pos-spec-list)) (defun ee-urlretrieve-3 (url) "Download URL with `url-retrieve-synchronously'. Return status, headers, body." (find-urlretrieve00 url 1 "\n\n") (let* ((header (buffer-substring 1 (- (point) 1))) (body (buffer-substring (point) (point-max))) (status (replace-regexp-in-string "\n.*" "" header))) (ee-kill-this-buffer) (list status header body))) (defun find-urlretrieve0 (url) "Download URL with `url-retrieve-synchronously'. Return body as a raw string." (let* ((shb (ee-urlretrieve-3 url)) (status (nth 0 shb)) (body (nth 2 shb))) (if (equal status "HTTP/1.1 200 OK") body (error "%s -> %s" url status)))) (defun find-urlretrieve (url &rest pos-spec-list) "Download URL with `url-retrieve-synchronously'. TODO: detect the encoding!!!" (let ((ee-buffer-name url)) (apply 'find-estring (find-urlretrieve0 url) pos-spec-list))) ;; «find-wget» (to ".find-wget") ;; (defun find-wget00 (url) (find-callprocess00 `("wget" "-q" "-O" "-" ,url))) (defun find-wget (url &rest rest) "Download URL with \"wget -q -O - URL\" and display the output." (setq url (ee-expand url)) (apply 'find-eoutput-reuse (format "*wget: %s*" url) `(insert (find-wget00 ,url)) rest)) ;; «find-gitk» (to ".find-gitk") ;; Example: (find-eev-install-intro "find-gitk") ;; (defun find-gitk (dir) "Run gitk in the directory DIR." (ee-at0 dir '(find-bgprocess "gitk --all --date-order"))) ;; «find-tkdiff» (to ".find-tkdiff") (defun find-tkdiff (f1 f2) (find-bgprocess `("tkdiff" ,f1 ,f2))) (provide 'eev-plinks) ;; Local Variables: ;; coding: utf-8-unix ;; no-byte-compile: t ;; End: