diff options
| author | Roland Winkler | 2008-03-26 02:15:28 +0000 |
|---|---|---|
| committer | Roland Winkler | 2008-03-26 02:15:28 +0000 |
| commit | 37e4d8ed4fa32f2392755c70906bd8dbbad19807 (patch) | |
| tree | 0cc02469cfcf7ed63eaa1e0ab0a39f01bba25b66 | |
| parent | 9e60aa0b8c833ee810cb2976ad00a260113ad7bf (diff) | |
| download | emacs-37e4d8ed4fa32f2392755c70906bd8dbbad19807.tar.gz emacs-37e4d8ed4fa32f2392755c70906bd8dbbad19807.zip | |
proced.el: New file.
| -rw-r--r-- | lisp/ChangeLog | 4 | ||||
| -rw-r--r-- | lisp/proced.el | 452 |
2 files changed, 456 insertions, 0 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index c61f36dbfb4..f64c3ae9e21 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,7 @@ | |||
| 1 | 2008-03-25 Roland Winkler <Roland.Winkler@physik.uni-erlangen.de> | ||
| 2 | |||
| 3 | * proced.el: New file. | ||
| 4 | |||
| 1 | 2008-03-25 Tetsurou Okazaki <okazaki@be.to> (tiny change) | 5 | 2008-03-25 Tetsurou Okazaki <okazaki@be.to> (tiny change) |
| 2 | 6 | ||
| 3 | * emacs-lisp/byte-opt.el (side-effect-free-fns): Fix typo. | 7 | * emacs-lisp/byte-opt.el (side-effect-free-fns): Fix typo. |
diff --git a/lisp/proced.el b/lisp/proced.el new file mode 100644 index 00000000000..1edc0108565 --- /dev/null +++ b/lisp/proced.el | |||
| @@ -0,0 +1,452 @@ | |||
| 1 | ;;; proced.el --- operate on processes like dired | ||
| 2 | |||
| 3 | ;; Copyright (C) 2008 Roland Winkler | ||
| 4 | ;; Author: Roland Winkler <Roland.Winkler@physik.uni-erlangen.de> | ||
| 5 | ;; Version: 0.5 | ||
| 6 | ;; Keywords: Processes, Unix | ||
| 7 | |||
| 8 | ;; This program is free software; you can redistribute it and/or | ||
| 9 | ;; modify it under the terms of the GNU General Public License as | ||
| 10 | ;; published by the Free Software Foundation; either version 2, or (at | ||
| 11 | ;; your option) any later version. | ||
| 12 | |||
| 13 | ;; This program is distributed in the hope that it will be useful, but | ||
| 14 | ;; WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 16 | ;; General Public License for more details. | ||
| 17 | |||
| 18 | ;; You should have received a copy of the GNU General Public License | ||
| 19 | ;; along with this program ; see the file COPYING. If not, write to | ||
| 20 | ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
| 21 | ;; Boston, MA 02110-1301, USA. | ||
| 22 | |||
| 23 | ;;; Commentary: | ||
| 24 | |||
| 25 | ;; Proced makes an Emacs buffer containing a listing of the current processes | ||
| 26 | ;; (using ps(1)). You can use the normal Emacs commands to move around in | ||
| 27 | ;; this buffer, and special Proced commands to operate on the processes listed. | ||
| 28 | ;; | ||
| 29 | ;; To autoload, use | ||
| 30 | ;; (autoload 'proced "proced" nil t) | ||
| 31 | ;; in your .emacs file. | ||
| 32 | ;; | ||
| 33 | ;; Is there a need for additional features like: | ||
| 34 | ;; - automatic update of process list | ||
| 35 | ;; - sort by CPU time or other criteria | ||
| 36 | ;; - filter by user name or other criteria | ||
| 37 | |||
| 38 | ;;; Code: | ||
| 39 | |||
| 40 | (defgroup proced nil | ||
| 41 | "Proced mode." | ||
| 42 | :group 'processes | ||
| 43 | :group 'unix | ||
| 44 | :prefix "proced-") | ||
| 45 | |||
| 46 | (defcustom proced-procname-column-regexp "\\b\\(CMD\\|COMMAND\\)\\b" | ||
| 47 | "If non-nil, regexp that defines the `proced-procname-column'." | ||
| 48 | :group 'proced | ||
| 49 | :type '(choice (const :tag "none" nil) | ||
| 50 | (regexp :tag "regexp"))) | ||
| 51 | |||
| 52 | (defcustom proced-command-alist | ||
| 53 | (cond ((memq system-type '(berkeley-unix netbsd)) | ||
| 54 | '(("user" ("ps" "-uxgww") 2) | ||
| 55 | ("user-running" ("ps" "-uxrgww") 2) | ||
| 56 | ("all" ("ps" "-auxgww") 2) | ||
| 57 | ("all-running" ("ps" "-auxrgww") 2))) | ||
| 58 | ((memq system-type '(linux lignux gnu/linux)) | ||
| 59 | `(("user" ("ps" "uxwww") 2) | ||
| 60 | ("user-running" ("ps" "uxrwww") 2) | ||
| 61 | ("all" ("ps" "auxwww") 2) | ||
| 62 | ("all-running" ("ps" "auxrwww") 2) | ||
| 63 | ("emacs" ("ps" "--pid" ,(number-to-string (emacs-pid)) | ||
| 64 | "--ppid" ,(number-to-string (emacs-pid)) | ||
| 65 | "uwww") 2))) | ||
| 66 | (t ; standard syntax doesn't allow us to list running processes only | ||
| 67 | `(("user" ("ps" "-fu" ,(number-to-string (user-uid))) 2) | ||
| 68 | ("all" ("ps" "-ef") 2)))) | ||
| 69 | "Alist of commands to get list of processes. | ||
| 70 | Each element has the form (NAME COMMAND PID-COLUMN SORT-COLUMN). | ||
| 71 | NAME is a shorthand name to select the type of listing. | ||
| 72 | COMMAND is a list (COMMAND-NAME ARG1 ARG2 ...), | ||
| 73 | where COMMAND-NAME is the command to generate the listing (usually \"ps\"). | ||
| 74 | ARG1, ARG2, ... are arguments passed to COMMAND-NAME to generate | ||
| 75 | a particular listing. These arguments differ under various operating systems. | ||
| 76 | PID-COLUMN is the column number (starting from 1) of the process ID. | ||
| 77 | SORT-COLUMN is the column number used for sorting the process listing | ||
| 78 | \(must be a numeric field). If nil, the process listing is not sorted." | ||
| 79 | :group 'proced | ||
| 80 | :type '(repeat (group (string :tag "name") | ||
| 81 | (cons (string :tag "command") | ||
| 82 | (repeat (string :tag "option"))) | ||
| 83 | (integer :tag "PID column") | ||
| 84 | (option (integer :tag "sort column"))))) | ||
| 85 | |||
| 86 | (defcustom proced-command (if (zerop (user-real-uid)) "all" "user") | ||
| 87 | "Name of process listing. | ||
| 88 | Must be the car of an element of `proced-command-alist'." | ||
| 89 | :group 'proced | ||
| 90 | :type '(string :tag "name")) | ||
| 91 | |||
| 92 | (defcustom proced-kill-program "kill" | ||
| 93 | "Name of kill command (usually `kill')." | ||
| 94 | :group 'proced | ||
| 95 | :type '(string :tag "command")) | ||
| 96 | |||
| 97 | (defcustom proced-signal-list | ||
| 98 | '(("HUP (1. Hangup)") | ||
| 99 | ("INT (2. Terminal interrupt)") | ||
| 100 | ("QUIT (3. Terminal quit)") | ||
| 101 | ("ABRT (6. Process abort)") | ||
| 102 | ("KILL (9. Kill -- cannot be caught or ignored)") | ||
| 103 | ("ALRM (14. Alarm Clock)") | ||
| 104 | ("TERM (15. Termination)")) | ||
| 105 | "List of signals, used for minibuffer completion." | ||
| 106 | :group 'proced | ||
| 107 | :type '(repeat (string :tag "signal"))) | ||
| 108 | |||
| 109 | (defvar proced-marker-char ?* ; the answer is 42 | ||
| 110 | "In proced, the current mark character.") | ||
| 111 | |||
| 112 | ;; face and font-lock code taken from dired | ||
| 113 | (defgroup proced-faces nil | ||
| 114 | "Faces used by Proced." | ||
| 115 | :group 'proced | ||
| 116 | :group 'faces) | ||
| 117 | |||
| 118 | (defface proced-header | ||
| 119 | '((t (:inherit font-lock-type-face))) | ||
| 120 | "Face used for proced headers." | ||
| 121 | :group 'proced-faces) | ||
| 122 | (defvar proced-header-face 'proced-header | ||
| 123 | "Face name used for proced headers.") | ||
| 124 | |||
| 125 | (defface proced-mark | ||
| 126 | '((t (:inherit font-lock-constant-face))) | ||
| 127 | "Face used for proced marks." | ||
| 128 | :group 'proced-faces) | ||
| 129 | (defvar proced-mark-face 'proced-mark | ||
| 130 | "Face name used for proced marks.") | ||
| 131 | |||
| 132 | (defface proced-marked | ||
| 133 | '((t (:inherit font-lock-warning-face))) | ||
| 134 | "Face used for marked processes." | ||
| 135 | :group 'proced-faces) | ||
| 136 | (defvar proced-marked-face 'proced-marked | ||
| 137 | "Face name used for marked processes.") | ||
| 138 | |||
| 139 | (defvar proced-re-mark "^[^ \n]" | ||
| 140 | "Regexp matching a marked line. | ||
| 141 | Important: the match ends just after the marker.") | ||
| 142 | |||
| 143 | (defvar proced-header-regexp "\\`.*$" | ||
| 144 | "Regexp matching a header line.") | ||
| 145 | |||
| 146 | (defvar proced-procname-column nil | ||
| 147 | "Proced command column. | ||
| 148 | Initialized based on `proced-procname-column-regexp'.") | ||
| 149 | |||
| 150 | (defvar proced-font-lock-keywords | ||
| 151 | (list | ||
| 152 | ;; | ||
| 153 | ;; Process listing headers. | ||
| 154 | (list proced-header-regexp '(0 proced-header-face)) | ||
| 155 | ;; | ||
| 156 | ;; Proced marks. | ||
| 157 | (list proced-re-mark '(0 proced-mark-face)) | ||
| 158 | ;; | ||
| 159 | ;; Marked files. | ||
| 160 | (list (concat "^[" (char-to-string proced-marker-char) "]") | ||
| 161 | '(".+" (proced-move-to-procname) nil (0 proced-marked-face))))) | ||
| 162 | |||
| 163 | (defvar proced-mode-map | ||
| 164 | (let ((km (make-sparse-keymap))) | ||
| 165 | (define-key km " " 'next-line) | ||
| 166 | (define-key km "n" 'next-line) | ||
| 167 | (define-key km "p" 'previous-line) | ||
| 168 | (define-key km "\C-?" 'previous-line) | ||
| 169 | (define-key km "h" 'describe-mode) | ||
| 170 | (define-key km "?" 'proced-help) | ||
| 171 | (define-key km "d" 'proced-mark) ; Dired compatibility | ||
| 172 | (define-key km "m" 'proced-mark) | ||
| 173 | (define-key km "M" 'proced-mark-all) | ||
| 174 | (define-key km "g" 'revert-buffer) ; Dired compatibility | ||
| 175 | (define-key km "q" 'quit-window) | ||
| 176 | (define-key km "u" 'proced-unmark) | ||
| 177 | (define-key km "U" 'proced-unmark-all) | ||
| 178 | (define-key km "x" 'proced-send-signal) ; Dired compatibility | ||
| 179 | (define-key km "k" 'proced-send-signal) ; kill processes | ||
| 180 | (define-key km "l" 'proced-listing-type) | ||
| 181 | (define-key km [remap undo] 'proced-undo) | ||
| 182 | (define-key km [remap advertised-undo] 'proced-undo) | ||
| 183 | km) | ||
| 184 | "Keymap for proced commands") | ||
| 185 | |||
| 186 | (easy-menu-define | ||
| 187 | proced-menu proced-mode-map "Proced Menu" | ||
| 188 | '("Proced" | ||
| 189 | ["Mark" proced-mark t] | ||
| 190 | ["Unmark" proced-unmark t] | ||
| 191 | ["Mark All" proced-mark-all t] | ||
| 192 | ["Unmark All" proced-unmark-all t] | ||
| 193 | "--" | ||
| 194 | ["Revert" revert-buffer t] | ||
| 195 | ["Send signal" proced-send-signal t] | ||
| 196 | ["Change listing" proced-listing-type t])) | ||
| 197 | |||
| 198 | (defconst proced-help-string | ||
| 199 | "(n)ext, (p)revious, (m)ark, (u)nmark, (k)ill, (q)uit (type ? for more help)" | ||
| 200 | "Help string for proced.") | ||
| 201 | |||
| 202 | (defun proced-mode (&optional arg) | ||
| 203 | "Mode for displaying UNIX processes and sending signals to them. | ||
| 204 | Type \\[proced-mark-process] to mark a process for later commands. | ||
| 205 | Type \\[proced-send-signal] to send signals to marked processes. | ||
| 206 | |||
| 207 | If invoked with optional ARG the window displaying the process | ||
| 208 | information will be displayed but not selected. | ||
| 209 | |||
| 210 | \\{proced-mode-map}" | ||
| 211 | (interactive "P") | ||
| 212 | (let ((proced-buffer (get-buffer-create "*Process Info*")) new) | ||
| 213 | (set-buffer proced-buffer) | ||
| 214 | (setq new (zerop (buffer-size))) | ||
| 215 | (when new | ||
| 216 | (kill-all-local-variables) | ||
| 217 | (use-local-map proced-mode-map) | ||
| 218 | (abbrev-mode 0) | ||
| 219 | (auto-fill-mode 0) | ||
| 220 | (setq buffer-read-only t | ||
| 221 | truncate-lines t | ||
| 222 | major-mode 'proced-mode | ||
| 223 | mode-name "Proced") | ||
| 224 | (set (make-local-variable 'revert-buffer-function) 'proced-revert) | ||
| 225 | (set (make-local-variable 'font-lock-defaults) | ||
| 226 | '(proced-font-lock-keywords t nil nil beginning-of-line))) | ||
| 227 | |||
| 228 | (if (or new arg) | ||
| 229 | (proced-update)) | ||
| 230 | |||
| 231 | (if arg | ||
| 232 | (display-buffer proced-buffer) | ||
| 233 | (pop-to-buffer proced-buffer) | ||
| 234 | (message (substitute-command-keys | ||
| 235 | "type \\[quit-window] to quit, \\[proced-help] for help"))) | ||
| 236 | (if new (run-mode-hooks 'proced-mode-hook)))) | ||
| 237 | |||
| 238 | ;; Proced mode is suitable only for specially formatted data. | ||
| 239 | (put 'proced-mode 'mode-class 'special) | ||
| 240 | |||
| 241 | (fset 'proced 'proced-mode) | ||
| 242 | |||
| 243 | (defun proced-move-to-procname () | ||
| 244 | "Move to the beginning of the process name on the current line. | ||
| 245 | Return the position of the beginning of the process name, or nil if none found." | ||
| 246 | (beginning-of-line) | ||
| 247 | (if proced-procname-column | ||
| 248 | (forward-char proced-procname-column) | ||
| 249 | (forward-char 2))) | ||
| 250 | |||
| 251 | (defun proced-mark (&optional count) | ||
| 252 | "Mark the current (or next COUNT) processes." | ||
| 253 | (interactive "p") | ||
| 254 | (proced-do-mark t count)) | ||
| 255 | |||
| 256 | (defun proced-unmark (&optional count) | ||
| 257 | "Unmark the current (or next COUNT) processes." | ||
| 258 | (interactive "p") | ||
| 259 | (proced-do-mark nil count)) | ||
| 260 | |||
| 261 | (defun proced-do-mark (mark &optional count) | ||
| 262 | "Mark the current (or next ARG) processes using MARK." | ||
| 263 | (or count (setq count 1)) | ||
| 264 | (let ((n (if (<= 0 count) 1 -1)) | ||
| 265 | (line (line-number-at-pos)) | ||
| 266 | buffer-read-only) | ||
| 267 | ;; do nothing in the first line | ||
| 268 | (unless (= line 1) | ||
| 269 | (setq count (1+ (cond ((<= 0 count) count) | ||
| 270 | ((< (abs count) line) (abs count)) | ||
| 271 | (t (1- line))))) | ||
| 272 | (beginning-of-line) | ||
| 273 | (while (not (or (zerop (setq count (1- count))) (eobp))) | ||
| 274 | (proced-insert-mark mark n)) | ||
| 275 | (proced-move-to-procname)))) | ||
| 276 | |||
| 277 | (defun proced-mark-all () | ||
| 278 | "Mark all processes." | ||
| 279 | (interactive) | ||
| 280 | (proced-do-mark-all t)) | ||
| 281 | |||
| 282 | (defun proced-unmark-all () | ||
| 283 | "Unmark all processes." | ||
| 284 | (interactive) | ||
| 285 | (proced-do-mark-all nil)) | ||
| 286 | |||
| 287 | (defun proced-do-mark-all (mark) | ||
| 288 | "Mark all processes using MARK." | ||
| 289 | (save-excursion | ||
| 290 | (let (buffer-read-only) | ||
| 291 | (goto-line 2) | ||
| 292 | (while (not (eobp)) | ||
| 293 | (proced-insert-mark mark 1))))) | ||
| 294 | |||
| 295 | (defun proced-insert-mark (mark n) | ||
| 296 | "If MARK is non-nil, insert `proced-marker-char', move N lines." | ||
| 297 | ;; Do we need other marks besides `proced-marker-char'? | ||
| 298 | (insert (if mark proced-marker-char ?\s)) | ||
| 299 | (delete-char 1) | ||
| 300 | (forward-line n)) | ||
| 301 | |||
| 302 | (defun proced-listing-type (command) | ||
| 303 | "Select `proced' listing type COMMAND from `proced-command-alist'." | ||
| 304 | (interactive | ||
| 305 | (list (completing-read "Listing type: " proced-command-alist nil t))) | ||
| 306 | (setq proced-command command) | ||
| 307 | (proced-update)) | ||
| 308 | |||
| 309 | (defsubst proced-skip-regexp () | ||
| 310 | "Regexp to skip in process listing." | ||
| 311 | (apply 'concat (make-list (1- (nth 2 (assoc proced-command | ||
| 312 | proced-command-alist))) | ||
| 313 | "\\s-+\\S-+"))) | ||
| 314 | |||
| 315 | (defun proced-update (&optional quiet) | ||
| 316 | "Update the `proced' process information. Preserves point and marks." | ||
| 317 | (interactive) | ||
| 318 | (or quiet (message "Updating process information...")) | ||
| 319 | (let* ((command (cdr (assoc proced-command proced-command-alist))) | ||
| 320 | (regexp (concat (proced-skip-regexp) "\\s-+\\([0-9]+\\>\\)")) | ||
| 321 | (old-pos (if (save-excursion | ||
| 322 | (beginning-of-line) | ||
| 323 | (looking-at (concat "^[* ]" regexp))) | ||
| 324 | (cons (match-string-no-properties 1) | ||
| 325 | (current-column)))) | ||
| 326 | buffer-read-only plist) | ||
| 327 | (goto-char (point-min)) | ||
| 328 | ;; remember marked processes (whatever the mark was) | ||
| 329 | (while (re-search-forward (concat "^\\(\\S-\\)" regexp) nil t) | ||
| 330 | (push (cons (match-string-no-properties 2) | ||
| 331 | (match-string-no-properties 1)) plist)) | ||
| 332 | ;; generate new listing | ||
| 333 | (erase-buffer) | ||
| 334 | (apply 'call-process (caar command) nil t nil (cdar command)) | ||
| 335 | (goto-char (point-min)) | ||
| 336 | (while (not (eobp)) | ||
| 337 | (insert " ") | ||
| 338 | (forward-line)) | ||
| 339 | ;; (delete-trailing-whitespace) | ||
| 340 | (goto-char (point-min)) | ||
| 341 | (while (re-search-forward "[ \t\r]+$" nil t) | ||
| 342 | (delete-region (match-beginning 0) (match-end 0))) | ||
| 343 | ;; set `proced-procname-column' | ||
| 344 | (goto-char (point-min)) | ||
| 345 | (and proced-procname-column-regexp | ||
| 346 | (re-search-forward proced-procname-column-regexp nil t) | ||
| 347 | (setq proced-procname-column (1- (match-beginning 0)))) | ||
| 348 | ;; sort fields | ||
| 349 | (goto-line 2) | ||
| 350 | (if (nth 2 command) | ||
| 351 | (sort-numeric-fields (nth 2 command) (point) (point-max))) | ||
| 352 | (set-buffer-modified-p nil) | ||
| 353 | ;; restore process marks | ||
| 354 | (if plist | ||
| 355 | (save-excursion | ||
| 356 | (goto-line 2) | ||
| 357 | (let (mark) | ||
| 358 | (while (re-search-forward (concat "^" regexp) nil t) | ||
| 359 | (if (setq mark (assoc (match-string-no-properties 1) plist)) | ||
| 360 | (save-excursion | ||
| 361 | (beginning-of-line) | ||
| 362 | (insert (cdr mark)) | ||
| 363 | (delete-char 1))))))) | ||
| 364 | ;; restore buffer position (if possible) | ||
| 365 | (goto-line 2) | ||
| 366 | (if (and old-pos | ||
| 367 | (re-search-forward | ||
| 368 | (concat "^[* ]" (proced-skip-regexp) "\\s-+" (car old-pos) "\\>") | ||
| 369 | nil t)) | ||
| 370 | (progn | ||
| 371 | (beginning-of-line) | ||
| 372 | (forward-char (cdr old-pos))) | ||
| 373 | (proced-move-to-procname)) | ||
| 374 | (or quiet (input-pending-p) | ||
| 375 | (message "Updating process information...done.")))) | ||
| 376 | |||
| 377 | (defun proced-revert (&rest args) | ||
| 378 | "Analog of `revert-buffer'." | ||
| 379 | (proced-update)) | ||
| 380 | |||
| 381 | ;; I do not want to reinvent the wheel | ||
| 382 | (autoload 'dired-pop-to-buffer "dired") | ||
| 383 | |||
| 384 | (defun proced-send-signal (&optional signal) | ||
| 385 | "Send a SIGNAL to the marked processes. | ||
| 386 | SIGNAL may be a string (HUP, INT, TERM, etc.) or a number. | ||
| 387 | If SIGNAL is nil display marked processes and query interactively for SIGNAL." | ||
| 388 | (interactive) | ||
| 389 | (let ((regexp (concat "^\\*" (proced-skip-regexp) "\\s-+\\([0-9]+\\>\\).*$")) | ||
| 390 | plist) | ||
| 391 | ;; collect marked processes | ||
| 392 | (save-excursion | ||
| 393 | (goto-char (point-min)) | ||
| 394 | (while (re-search-forward regexp nil t) | ||
| 395 | (push (cons (match-string-no-properties 1) | ||
| 396 | (substring (match-string-no-properties 0) 2)) | ||
| 397 | plist))) | ||
| 398 | (if (not plist) | ||
| 399 | (message "No processes marked") | ||
| 400 | (unless signal | ||
| 401 | ;; Display marked processes (code taken from `dired-mark-pop-up'). | ||
| 402 | ;; We include all process information to distinguish multiple | ||
| 403 | ;; instances of the same program. | ||
| 404 | (let ((bufname " *Marked Processes*") | ||
| 405 | (header (save-excursion | ||
| 406 | (goto-char (+ 2 (point-min))) | ||
| 407 | (buffer-substring-no-properties | ||
| 408 | (point) (line-end-position))))) | ||
| 409 | (with-current-buffer (get-buffer-create bufname) | ||
| 410 | (setq truncate-lines t) | ||
| 411 | (erase-buffer) | ||
| 412 | (insert header "\n") | ||
| 413 | (dolist (proc plist) | ||
| 414 | (insert (cdr proc) "\n")) | ||
| 415 | (save-window-excursion | ||
| 416 | (dired-pop-to-buffer bufname) ; all we need | ||
| 417 | (let* ((completion-ignore-case t) | ||
| 418 | ;; The following is an ugly hack. Is there a better way | ||
| 419 | ;; to help people like me to remember the signals and | ||
| 420 | ;; their meanings? | ||
| 421 | (tmp (completing-read "Signal (default TERM): " | ||
| 422 | proced-signal-list | ||
| 423 | nil nil nil nil "TERM"))) | ||
| 424 | (setq signal (if (string-match "^\\(\\S-+\\)\\s-" tmp) | ||
| 425 | (match-string 1 tmp) tmp)))))) | ||
| 426 | ;; send signal | ||
| 427 | (apply 'call-process proced-kill-program nil 0 nil | ||
| 428 | (concat "-" (if (numberp signal) | ||
| 429 | (number-to-string signal) signal)) | ||
| 430 | (mapcar 'car plist)) | ||
| 431 | (run-hooks 'proced-after-send-signal-hook))))) | ||
| 432 | |||
| 433 | (defun proced-help () | ||
| 434 | "Provide help for the `proced' user." | ||
| 435 | (interactive) | ||
| 436 | (if (eq last-command 'proced-help) | ||
| 437 | (describe-mode) | ||
| 438 | (message proced-help-string))) | ||
| 439 | |||
| 440 | (defun proced-undo () | ||
| 441 | "Undo in a proced buffer. | ||
| 442 | This doesn't recover killed processes, it just undoes changes in the proced | ||
| 443 | buffer. You can use it to recover marks." | ||
| 444 | (interactive) | ||
| 445 | (let (buffer-read-only) | ||
| 446 | (undo)) | ||
| 447 | (message "Change in proced buffer undone. | ||
| 448 | Killed processes cannot be recovered by Emacs.")) | ||
| 449 | |||
| 450 | (provide 'proced) | ||
| 451 | |||
| 452 | ;;; proced.el ends here. | ||