| 1 | ;;; -*- Log: hemlock.log; Package: Hemlock -*-
|
|---|
| 2 | ;;;
|
|---|
| 3 | ;;; **********************************************************************
|
|---|
| 4 | ;;; This code was written as part of the CMU Common Lisp project at
|
|---|
| 5 | ;;; Carnegie Mellon University, and has been placed in the public domain.
|
|---|
| 6 | ;;;
|
|---|
| 7 | #+CMU (ext:file-comment
|
|---|
| 8 | "$Header$")
|
|---|
| 9 | ;;;
|
|---|
| 10 | ;;; **********************************************************************
|
|---|
| 11 | ;;;
|
|---|
| 12 | ;;;
|
|---|
| 13 | ;;; This file contains Commands useful when running on a Unix box. Hopefully
|
|---|
| 14 | ;;; there are no CMU Unix dependencies though there are probably CMU Common
|
|---|
| 15 | ;;; Lisp dependencies, such as RUN-PROGRAM.
|
|---|
| 16 | ;;;
|
|---|
| 17 | ;;; Written by Christopher Hoover.
|
|---|
| 18 |
|
|---|
| 19 | (in-package :hemlock)
|
|---|
| 20 |
|
|---|
| 21 |
|
|---|
| 22 | |
|---|
| 23 |
|
|---|
| 24 | ;;;; Region and File printing commands.
|
|---|
| 25 |
|
|---|
| 26 | (defhvar "Print Utility"
|
|---|
| 27 | "UNIX(tm) program to invoke (via EXT:RUN-PROGRAM) to do printing.
|
|---|
| 28 | The program should act like lpr: if a filename is given as an argument,
|
|---|
| 29 | it should print that file, and if no name appears, standard input should
|
|---|
| 30 | be assumed."
|
|---|
| 31 | :value "lpr")
|
|---|
| 32 |
|
|---|
| 33 | (defhvar "Print Utility Switches"
|
|---|
| 34 | "Switches to pass to the \"Print Utility\" program. This should be a list
|
|---|
| 35 | of strings."
|
|---|
| 36 | :value ())
|
|---|
| 37 |
|
|---|
| 38 |
|
|---|
| 39 | ;;; PRINT-SOMETHING calls RUN-PROGRAM on the utility-name and args. Output
|
|---|
| 40 | ;;; and error output are done to the echo area, and errors are ignored for
|
|---|
| 41 | ;;; now. Run-program-keys are other keywords to pass to RUN-PROGRAM in
|
|---|
| 42 | ;;; addition to :wait, :output, and :error.
|
|---|
| 43 | ;;;
|
|---|
| 44 | (defmacro print-something (&optional (run-program-keys)
|
|---|
| 45 | (utility-name '(value print-utility))
|
|---|
| 46 | (args '(value print-utility-switches)))
|
|---|
| 47 | (let ((pid (gensym))
|
|---|
| 48 | (error-code (gensym)))
|
|---|
| 49 | `(multiple-value-bind (,pid ,error-code)
|
|---|
| 50 | (ext:run-program ,utility-name ,args
|
|---|
| 51 | ,@run-program-keys
|
|---|
| 52 | :wait t
|
|---|
| 53 | :output *echo-area-stream*
|
|---|
| 54 | :error *echo-area-stream*)
|
|---|
| 55 | (declare (ignore ,pid ,error-code))
|
|---|
| 56 | (force-output *echo-area-stream*)
|
|---|
| 57 | ;; Keep the echo area from being cleared at the top of the command loop.
|
|---|
| 58 | (setf (buffer-modified *echo-area-buffer*) nil))))
|
|---|
| 59 |
|
|---|
| 60 |
|
|---|
| 61 | ;;; PRINT-REGION -- Interface
|
|---|
| 62 | ;;;
|
|---|
| 63 | ;;; Takes a region and outputs the text to the program defined by
|
|---|
| 64 | ;;; the hvar "Print Utility" with options form the hvar "Print
|
|---|
| 65 | ;;; Utility Options" using PRINT-SOMETHING.
|
|---|
| 66 | ;;;
|
|---|
| 67 | (defun print-region (region)
|
|---|
| 68 | (with-input-from-region (s region)
|
|---|
| 69 | (print-something (:input s))))
|
|---|
| 70 |
|
|---|
| 71 |
|
|---|
| 72 | (defcommand "Print Buffer" (p)
|
|---|
| 73 | "Prints the current buffer using the program defined by the hvar
|
|---|
| 74 | \"Print Utility\" with the options from the hvar \"Print Utility
|
|---|
| 75 | Options\". Errors appear in the echo area."
|
|---|
| 76 | "Prints the contents of the buffer."
|
|---|
| 77 | (declare (ignore p))
|
|---|
| 78 | (message "Printing buffer...~%")
|
|---|
| 79 | (print-region (buffer-region (current-buffer))))
|
|---|
| 80 |
|
|---|
| 81 | (defcommand "Print Region" (p)
|
|---|
| 82 | "Prints the current region using the program defined by the hvar
|
|---|
| 83 | \"Print Utility\" with the options from the hvar \"Print Utility
|
|---|
| 84 | Options\". Errors appear in the echo area."
|
|---|
| 85 | "Prints the current region."
|
|---|
| 86 | (declare (ignore p))
|
|---|
| 87 | (message "Printing region...~%")
|
|---|
| 88 | (print-region (current-region)))
|
|---|
| 89 |
|
|---|
| 90 | (defcommand "Print File" (p)
|
|---|
| 91 | "Prompts for a file and prints it usings the program defined by
|
|---|
| 92 | the hvar \"Print Utility\" with the options from the hvar \"Print
|
|---|
| 93 | Utility Options\". Errors appear in the echo area."
|
|---|
| 94 | "Prints a file."
|
|---|
| 95 | (declare (ignore p))
|
|---|
| 96 | (let* ((pn (prompt-for-file :prompt "File to print: "
|
|---|
| 97 | :help "Name of file to print."
|
|---|
| 98 | :default (buffer-default-pathname (current-buffer))
|
|---|
| 99 | :must-exist t))
|
|---|
| 100 | (ns (namestring (truename pn))))
|
|---|
| 101 | (message "Printing file...~%")
|
|---|
| 102 | (print-something () (value print-utility)
|
|---|
| 103 | (append (value print-utility-switches) (list ns)))))
|
|---|
| 104 |
|
|---|
| 105 | |
|---|
| 106 |
|
|---|
| 107 | ;;;; Scribe.
|
|---|
| 108 |
|
|---|
| 109 | (defcommand "Scribe File" (p)
|
|---|
| 110 | "Scribe a file with the default directory set to the directory of the
|
|---|
| 111 | specified file. The output from running Scribe is sent to the
|
|---|
| 112 | \"Scribe Warnings\" buffer. See \"Scribe Utility\" and \"Scribe Utility
|
|---|
| 113 | Switches\"."
|
|---|
| 114 | "Scribe a file with the default directory set to the directory of the
|
|---|
| 115 | specified file."
|
|---|
| 116 | (declare (ignore p))
|
|---|
| 117 | (scribe-file (prompt-for-file :prompt "Scribe file: "
|
|---|
| 118 | :default
|
|---|
| 119 | (buffer-default-pathname (current-buffer)))))
|
|---|
| 120 |
|
|---|
| 121 | (defhvar "Scribe Buffer File Confirm"
|
|---|
| 122 | "When set, \"Scribe Buffer File\" prompts for confirmation before doing
|
|---|
| 123 | anything."
|
|---|
| 124 | :value t)
|
|---|
| 125 |
|
|---|
| 126 | (defcommand "Scribe Buffer File" (p)
|
|---|
| 127 | "Scribe the file associated with the current buffer. The default directory
|
|---|
| 128 | set to the directory of the file. The output from running Scribe is sent to
|
|---|
| 129 | the \"Scribe Warnings\" buffer. See \"Scribe Utility\" and \"Scribe Utility
|
|---|
| 130 | Switches\". Before doing anything the user is asked to confirm saving and
|
|---|
| 131 | Scribe'ing the file. This prompting can be inhibited by with \"Scribe Buffer
|
|---|
| 132 | File Confirm\"."
|
|---|
| 133 | "Scribe a file with the default directory set to the directory of the
|
|---|
| 134 | specified file."
|
|---|
| 135 | (declare (ignore p))
|
|---|
| 136 | (let* ((buffer (current-buffer))
|
|---|
| 137 | (pathname (buffer-pathname buffer))
|
|---|
| 138 | (modified (buffer-modified buffer)))
|
|---|
| 139 | (when (or (not (value scribe-buffer-file-confirm))
|
|---|
| 140 | (prompt-for-y-or-n
|
|---|
| 141 | :default t :default-string "Y"
|
|---|
| 142 | :prompt (list "~:[S~;Save and s~]cribe file ~A? "
|
|---|
| 143 | modified (namestring pathname))))
|
|---|
| 144 | (when modified (write-buffer-file buffer pathname))
|
|---|
| 145 | (scribe-file pathname))))
|
|---|
| 146 |
|
|---|
| 147 | (defhvar "Scribe Utility"
|
|---|
| 148 | "Program name to invoke (via EXT:RUN-PROGRAM) to do text formatting."
|
|---|
| 149 | :value "scribe")
|
|---|
| 150 |
|
|---|
| 151 | (defhvar "Scribe Utility Switches"
|
|---|
| 152 | "Switches to pass to the \"Scribe Utility\" program. This should be a list
|
|---|
| 153 | of strings."
|
|---|
| 154 | :value ())
|
|---|
| 155 |
|
|---|
| 156 | (defun scribe-file (pathname)
|
|---|
| 157 | (let* ((pathname (truename pathname))
|
|---|
| 158 | (out-buffer (or (getstring "Scribe Warnings" *buffer-names*)
|
|---|
| 159 | (make-buffer "Scribe Warnings")))
|
|---|
| 160 | (out-point (buffer-end (buffer-point out-buffer)))
|
|---|
| 161 | (stream (make-hemlock-output-stream out-point :line))
|
|---|
| 162 | (orig-cwd (default-directory)))
|
|---|
| 163 | (buffer-end out-point)
|
|---|
| 164 | (insert-character out-point #\newline)
|
|---|
| 165 | (insert-character out-point #\newline)
|
|---|
| 166 | (unwind-protect
|
|---|
| 167 | (progn
|
|---|
| 168 | (setf (default-directory) (directory-namestring pathname))
|
|---|
| 169 | (ext:run-program (namestring (value scribe-utility))
|
|---|
| 170 | (list* (namestring pathname)
|
|---|
| 171 | (value scribe-utility-switches))
|
|---|
| 172 | :output stream :error stream
|
|---|
| 173 | :wait nil))
|
|---|
| 174 | (setf (default-directory) orig-cwd))))
|
|---|
| 175 |
|
|---|
| 176 | |
|---|
| 177 |
|
|---|
| 178 | ;;;; UNIX Filter Region
|
|---|
| 179 |
|
|---|
| 180 | (defcommand "Unix Filter Region" (p)
|
|---|
| 181 | "Unix Filter Region prompts for a UNIX program and then passes the current
|
|---|
| 182 | region to the program as standard input. The standard output from the
|
|---|
| 183 | program is used to replace the region. This command is undo-able."
|
|---|
| 184 | "UNIX-FILTER-REGION-COMMAND is not intended to be called from normal
|
|---|
| 185 | Hemlock commands; use UNIX-FILTER-REGION instead."
|
|---|
| 186 | (declare (ignore p))
|
|---|
| 187 | (let* ((region (current-region))
|
|---|
| 188 | (filter-and-args (prompt-for-string
|
|---|
| 189 | :prompt "Filter: "
|
|---|
| 190 | :help "Unix program to filter the region through."))
|
|---|
| 191 | (filter-and-args-list (listify-unix-filter-string filter-and-args))
|
|---|
| 192 | (filter (car filter-and-args-list))
|
|---|
| 193 | (args (cdr filter-and-args-list))
|
|---|
| 194 | (new-region (unix-filter-region region filter args))
|
|---|
| 195 | (start (copy-mark (region-start region) :right-inserting))
|
|---|
| 196 | (end (copy-mark (region-end region) :left-inserting))
|
|---|
| 197 | (old-region (region start end))
|
|---|
| 198 | (undo-region (delete-and-save-region old-region)))
|
|---|
| 199 | (ninsert-region end new-region)
|
|---|
| 200 | (make-region-undo :twiddle "Unix Filter Region" old-region undo-region)))
|
|---|
| 201 |
|
|---|
| 202 | (defun unix-filter-region (region command args)
|
|---|
| 203 | "Passes the region REGION as standard input to the program COMMAND
|
|---|
| 204 | with arguments ARGS and returns the standard output as a freshly
|
|---|
| 205 | cons'ed region."
|
|---|
| 206 | (let ((new-region (make-empty-region)))
|
|---|
| 207 | (with-input-from-region (input region)
|
|---|
| 208 | (with-output-to-mark (output (region-end new-region) :full)
|
|---|
| 209 | (ext:run-program command args
|
|---|
| 210 | :input input
|
|---|
| 211 | :output output
|
|---|
| 212 | :error output)))
|
|---|
| 213 | new-region))
|
|---|
| 214 |
|
|---|
| 215 | (defun listify-unix-filter-string (str)
|
|---|
| 216 | (declare (simple-string str))
|
|---|
| 217 | (let ((result nil)
|
|---|
| 218 | (lastpos 0))
|
|---|
| 219 | (loop
|
|---|
| 220 | (let ((pos (position #\Space str :start lastpos :test #'char=)))
|
|---|
| 221 | (push (subseq str lastpos pos) result)
|
|---|
| 222 | (unless pos
|
|---|
| 223 | (return))
|
|---|
| 224 | (setf lastpos (1+ pos))))
|
|---|
| 225 | (nreverse result)))
|
|---|
| 226 |
|
|---|
| 227 |
|
|---|
| 228 | |
|---|
| 229 |
|
|---|
| 230 | ;;;; Man pages.
|
|---|
| 231 |
|
|---|
| 232 | (defcommand "Manual Page" (p)
|
|---|
| 233 | "Read the Unix manual pages in a View buffer.
|
|---|
| 234 | If given an argument, this will put the man page in a Pop-up display."
|
|---|
| 235 | "Read the Unix manual pages in a View buffer.
|
|---|
| 236 | If given an argument, this will put the man page in a Pop-up display."
|
|---|
| 237 | (let ((topic (prompt-for-string :prompt "Man topic: ")))
|
|---|
| 238 | (if p
|
|---|
| 239 | (with-pop-up-display (stream)
|
|---|
| 240 | (execute-man topic stream))
|
|---|
| 241 | (let* ((buf-name (format nil "Man Page ~a" topic))
|
|---|
| 242 | (new-buffer (make-buffer buf-name :modes '("Fundamental" "View")))
|
|---|
| 243 | (buffer (or new-buffer (getstring buf-name *buffer-names*)))
|
|---|
| 244 | (point (buffer-point buffer)))
|
|---|
| 245 | (change-to-buffer buffer)
|
|---|
| 246 | (when new-buffer
|
|---|
| 247 | (setf (value view-return-function) #'(lambda ()))
|
|---|
| 248 | (with-writable-buffer (buffer)
|
|---|
| 249 | (with-output-to-mark (s point :full)
|
|---|
| 250 | (execute-man topic s))))
|
|---|
| 251 | (buffer-start point buffer)))))
|
|---|
| 252 |
|
|---|
| 253 | (defun execute-man (topic stream)
|
|---|
| 254 | (ext:run-program
|
|---|
| 255 | "/bin/sh"
|
|---|
| 256 | (list "-c"
|
|---|
| 257 | (format nil "man ~a| ul -t adm3" topic))
|
|---|
| 258 | :output stream))
|
|---|