From 1e847ec274fc5e3bd799128f79b4f38a6c126f94 Mon Sep 17 00:00:00 2001 From: Frank Halasz Date: Sun, 8 Oct 2023 19:34:43 -0700 Subject: [PATCH] Add ShellOpen (and ShellOpener) to UNIXUTILS; fix small bug in UNIX-FILE-NAME (#1341) * Add ShellOpener and ShellOpen to UNIXUTILS - used to open a file using the generic opener on this machine. Adapted ShellBrowse and ShellBrowser accordingly; fixed bug in UNIX-FILE-NAME where it fails if file does not exist and COPY is non-NIL and access is INPUT * Add return of error strings to ShellOpen --- library/UNIXUTILS | 189 +++++++++++++++++++++++++++++----------- library/UNIXUTILS.DFASL | Bin 4896 -> 6443 bytes 2 files changed, 137 insertions(+), 52 deletions(-) diff --git a/library/UNIXUTILS b/library/UNIXUTILS index 0758f19f..2150c55e 100644 --- a/library/UNIXUTILS +++ b/library/UNIXUTILS @@ -1,12 +1,12 @@ (DEFINE-FILE-INFO PACKAGE "INTERLISP" READTABLE "INTERLISP" BASE 10) -(FILECREATED " 2-Oct-2023 12:54:58" {WMEDLEY}UNIXUTILS.;10 10535 +(FILECREATED " 8-Oct-2023 15:06:52" {DSK}frank>il>medley>gmedley>library>UNIXUTILS.;15 14696 - :EDIT-BY rmk + :CHANGES-TO (FNS ShellOpen UNIX-FILE-NAME ShellBrowser ShellBrowse ShellOpener) + (VARS UNIXUTILSCOMS) - :CHANGES-TO (FUNCTIONS ShellWhich) - - :PREVIOUS-DATE " 1-Oct-2023 20:52:23" {WMEDLEY}UNIXUTILS.;9) + :PREVIOUS-DATE " 8-Oct-2023 02:35:47" {DSK}frank>il>medley>gmedley>library>UNIXUTILS.;14 +) (PRETTYCOMPRINT UNIXUTILSCOMS) @@ -15,10 +15,11 @@ ((DECLARE%: EVAL@COMPILE DONTCOPY (* ; "For PROCESS-COMMAND") (FILES (FROM LOADUPS) EXPORTS.ALL)) - (GLOBALVARS ShellBrowser) - (INITVARS (ShellBrowser)) + (GLOBALVARS ShellBrowser ShellOpener) + (INITVARS (ShellBrowser) + (ShellOpener)) (FUNCTIONS ShellCommand ShellWhich) - (FNS ShellBrowser ShellBrowse PROCESS-COMMAND SLASHIT UNIX-FILE-NAME) + (FNS ShellBrowser ShellBrowse ShellOpener ShellOpen PROCESS-COMMAND SLASHIT UNIX-FILE-NAME) (PROPS (UNIXUTILS FILETYPE)))) (DECLARE%: EVAL@COMPILE DONTCOPY @@ -27,11 +28,13 @@ ) (DECLARE%: DOEVAL@COMPILE DONTCOPY -(GLOBALVARS ShellBrowser) +(GLOBALVARS ShellBrowser ShellOpener) ) (RPAQ? ShellBrowser ) +(RPAQ? ShellOpener ) + (CL:DEFUN ShellCommand (Cmd &OPTIONAL (Output T)) (CL:WITH-OPEN-STREAM (s (CREATE-PROCESS-STREAM Cmd)) (CL:TAGBODY [SETFILEINFO s 'ENDOFSTREAMOP #'(CL:LAMBDA (s) @@ -55,50 +58,44 @@ (ShellBrowser [LAMBDA NIL (* ; "Edited 18-Jan-2023 20:30 by FGH") - (OR ShellBrowser (SETQ ShellBrowser (LET (CMDPATH) - (if (STRPOS "darwin" (OR (UNIX-GETENV "OSTYPE") - (UNIX-GETENV "PATH"))) - then - (* ;; " MacOS") - "open" - elseif (SETQ CMDPATH (ShellWhich "wslview")) - then - (* ;; "windows with WSL") + (* ;; "Figure out the browser to use for the ShellOpen/ShellBrowse functions. ") - CMDPATH - elseif (SETQ CMDPATH (ShellWhich "xdg-open")) - then - (* ;; "Linux systems with xdg-utils installed ") + (* ;; " Ordinarily, this would be the same as the generic ShellOpener.") - CMDPATH - elseif (SETQ CMDPATH (ShellWhich "git")) - then - (* ;; " Systems with git installed") + (* ;; " But if a generic ShellOpener is not found, then there are some additional") - (CONCAT CMDPATH " web--browse") - (* ; "") - elseif (SETQ CMDPATH (ShellWhich "lynx")) - then - (* ;; " Systems with lynx installed") + (* ;; " possibilities that will work for http/https URLs. If one of these exists return it.") - (LET (CMDPATH2) - (if (SETQ CMDPATH2 (ShellWhich "xterm")) - then (CONCAT CMDPATH2 " -e " CMDPATH) - else (LIST CMDPATH))) - else - (* ;; - " Out of ideas - just return a dummy function") + (OR ShellBrowser (SETQ ShellBrowser + (if (NOT (STREQUAL (ShellOpener) + "true")) + then ShellOpener + else (LET (CMDPATH) + (if (SETQ CMDPATH (ShellWhich "git")) + then + (* ;; " Systems with git installed") - "true"]) + CMDPATH + elseif (SETQ CMDPATH (ShellWhich "lynx")) + then + (* ;; " Systems with lynx installed") + + (LET (CMDPATH2) + (if (SETQ CMDPATH2 (ShellWhich "xterm")) + then (CONCAT CMDPATH2 " -e " CMDPATH) + else (LIST CMDPATH))) + else + (* ;; " Out of ideas - just return a dummy function") + + "true"]) (ShellBrowse [LAMBDA (URL) (* ; "Edited 18-Jan-2023 20:32 by FGH") (* ;; " Open the web page specified by URL using an external browser via shell call") - (* ;; - " URL must start with http:// or https:// (case ireelevant) or this function will just return NIL.") + (* ;; " URL must start with http:// or https:// or file:/// (case ireelevant) or this function will just return NIL.") (* ;; " Returns T otherwise.") @@ -106,15 +103,102 @@ (if (OR (EQ (STRPOS "http://" (L-CASE URL)) 1) (EQ (STRPOS "https://" (L-CASE URL)) + 1) + (EQ (STRPOS "file:///" (L-CASE URL)) + 1)) + then (ShellOpen URL) + else NIL]) + +(ShellOpener + [LAMBDA NIL + + (* ;; "Find an %"opener%" that will open files (and URLs) using the appropriate/default app on this machine") + + (OR ShellOpener (SETQ ShellOpener (LET (CMDPATH) + (if (SETQ CMDPATH (ShellWhich "wslview")) + then + (* ;; "windows with WSL") + + CMDPATH + elseif (SETQ CMDPATH (ShellWhich "cygstart")) + then + (* ;; "windows with cygwin") + + CMDPATH + elseif (SETQ CMDPATH (ShellWhich "xdg-open")) + then + (* ;; "Linux systems with xdg-utils installed ") + + CMDPATH + elseif (SETQ CMDPATH (ShellWhich "open")) + then + (* ;; " MacOS open") + + CMDPATH + else + (* ;; + " Out of ideas - just return a dummy function") + + "true"]) + +(ShellOpen + [LAMBDA (FilenameOrURL) + + (* ;; "Open the file or URL using the generic %"opener%" for this machine via a shell call.") + + (* ;; " If FilenameOrURL starts with %"http://%" or %"https://%" or %"file:///%", then we use (ShellBrowser) as") + + (* ;; " the %"opener%" (which includes some browsers on a machine without a generic opener).") + + (* ;; + " Otherwise FilenameOrURL is assumed to be a filename and will be opened using (ShellOpener).") + + (* ;; " Returns T is all goes well; returns an error string if all does not go well") + + (SETQ FilenameOrURL (MKSTRING FilenameOrURL)) + (if (OR (EQ (STRPOS "http://" (L-CASE FilenameOrURL)) + 1) + (EQ (STRPOS "https://" (L-CASE FilenameOrURL)) + 1) + (EQ (STRPOS "file://" (L-CASE FilenameOrURL)) 1)) then (LET ((BROWSER (ShellBrowser))) - (if (LISTP BROWSER) - then (CHAT 'SHELL NIL (CONCAT (CAR BROWSER) - " '" URL "'")) - else (ShellCommand (CONCAT BROWSER " '" URL "'" - " >>/tmp/ShellBrowser-warnings-$$.txt"))) - T) - else NIL]) + (if (NOT (STREQUAL BROWSER "true")) + then (if (LISTP BROWSER) + then (CHAT 'SHELL NIL (CONCAT (CAR BROWSER) + " '" FilenameOrURL "'")) + else (ShellCommand (CONCAT BROWSER " '" FilenameOrURL "'" + " >>/tmp/ShellBrowser-warnings-$$.txt")) + T) + else (CONCAT "Unable to find a browser to open: " FilenameOrURL))) + else + (LET ((OPENER (ShellOpener)) + (UNIXFILE (UNIX-FILE-NAME FilenameOrURL 'INPUT T))) + (if (NOT UNIXFILE) + then (CONCAT "File not found: " FilenameOrURL) + elseif (NOT (STREQUAL OPENER "true")) + then (CL:WITH-OPEN-STREAM + (SHELLSTREAM (OPENSTREAM (CONCAT "{CORE}SHELLOUT" (RAND)) + 'BOTH)) + (ShellCommand (CONCAT OPENER " '" UNIXFILE "'" + " >>/tmp/ShellOpener-warnings-$$.txt") + SHELLSTREAM) + (if (EQ (GETFILEPTR SHELLSTREAM) + 0) + then T + else (LET* ((OUTSTRING (ALLOCSTRING (GETFILEPTR SHELLSTREAM) + " "))) + (CL:WITH-OPEN-STREAM (STRINGSTREAM (OPENSTRINGSTREAM OUTSTRING + 'OUTPUT)) + (SETFILEPTR SHELLSTREAM 0) + (CL:TAGBODY [SETFILEINFO SHELLSTREAM 'ENDOFSTREAMOP + #'(CL:LAMBDA (s) + (GO OUT] + (CL:LOOP (PRINTCCODE (READCCODE SHELLSTREAM) + STRINGSTREAM)) + OUT)) + OUTSTRING))) + else (CONCAT "Unable to find a file opener to open: " FilenameOrURL]) (PROCESS-COMMAND [LAMBDA (CMD) (* ; "Edited 17-Jul-2022 08:17 by rmk") @@ -183,7 +267,8 @@ "") "~" VERSION "~") FILE))) - (CL:WHEN (AND COPY (EQ ACCESS 'INPUT)) + (CL:WHEN (AND COPY (EQ ACCESS 'INPUT) + FILE) (RESETLST (CL:WHEN (\GETSTREAM FILE 'INPUT T) (* ; "Hope is randaccess") [RESETSAVE (GETFILEPTR FILE) @@ -200,7 +285,7 @@ (PUTPROPS UNIXUTILS FILETYPE CL:COMPILE-FILE) (DECLARE%: DONTCOPY - (FILEMAP (NIL (927 1300 (ShellCommand 927 . 1300)) (1302 1699 (ShellWhich 1302 . 1699)) (1700 10457 ( -ShellBrowser 1710 . 4233) (ShellBrowse 4235 . 5227) (PROCESS-COMMAND 5229 . 5842) (SLASHIT 5844 . 7886 -) (UNIX-FILE-NAME 7888 . 10455))))) + (FILEMAP (NIL (1144 1517 (ShellCommand 1144 . 1517)) (1519 1916 (ShellWhich 1519 . 1916)) (1917 14618 +(ShellBrowser 1927 . 3675) (ShellBrowse 3677 . 4362) (ShellOpener 4364 . 6052) (ShellOpen 6054 . 9357) + (PROCESS-COMMAND 9359 . 9972) (SLASHIT 9974 . 12016) (UNIX-FILE-NAME 12018 . 14616))))) STOP diff --git a/library/UNIXUTILS.DFASL b/library/UNIXUTILS.DFASL index e9cb27338f7ba39d2606d35dfbdcd0bd0f7fceb3..8cfdae7d1b4ad2fefc52a2506d71c8d3a74f770c 100644 GIT binary patch delta 3294 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