diff options
| author | Roland Winkler | 2012-09-23 07:34:23 -0500 |
|---|---|---|
| committer | Roland Winkler | 2012-09-23 07:34:23 -0500 |
| commit | bc7be45dbd90145b9bc76dbff349bf51a8315211 (patch) | |
| tree | 1450740aab38912e484e5707a01105a0d75cffe2 | |
| parent | 6fab02746b865525b6fae7d16a4d3ed990f81723 (diff) | |
| download | emacs-bc7be45dbd90145b9bc76dbff349bf51a8315211.tar.gz emacs-bc7be45dbd90145b9bc76dbff349bf51a8315211.zip | |
lisp/proced.el: new command proced-renice
| -rw-r--r-- | etc/NEWS | 2 | ||||
| -rw-r--r-- | lisp/proced.el | 296 |
2 files changed, 195 insertions, 103 deletions
| @@ -411,6 +411,8 @@ server properties. | |||
| 411 | ** In Perl mode, new option `perl-indent-parens-as-block' causes non-block | 411 | ** In Perl mode, new option `perl-indent-parens-as-block' causes non-block |
| 412 | closing brackets to be aligned with the line of the opening bracket. | 412 | closing brackets to be aligned with the line of the opening bracket. |
| 413 | 413 | ||
| 414 | ** In Proced mode, new command `proced-renice' renices selected processes. | ||
| 415 | |||
| 414 | ** Python mode | 416 | ** Python mode |
| 415 | 417 | ||
| 416 | A new version of python.el, which provides several new features, including: | 418 | A new version of python.el, which provides several new features, including: |
diff --git a/lisp/proced.el b/lisp/proced.el index d98bf7d2c5b..be6cae2ef08 100644 --- a/lisp/proced.el +++ b/lisp/proced.el | |||
| @@ -28,8 +28,11 @@ | |||
| 28 | ;; listed. See `proced-mode' for getting started. | 28 | ;; listed. See `proced-mode' for getting started. |
| 29 | ;; | 29 | ;; |
| 30 | ;; To do: | 30 | ;; To do: |
| 31 | ;; - interactive temporary customizability of flags in `proced-grammar-alist' | 31 | ;; - Interactive temporary customizability of flags in `proced-grammar-alist' |
| 32 | ;; - allow "sudo kill PID", "renice PID" | 32 | ;; - Allow "sudo kill PID", "sudo renice PID" |
| 33 | ;; `proced-send-signal' operates on multiple processes one by one. | ||
| 34 | ;; With "sudo" we want to execute one "kill" or "renice" command | ||
| 35 | ;; for all marked processes. Is there a `sudo-call-process'? | ||
| 33 | ;; | 36 | ;; |
| 34 | ;; Thoughts and Ideas | 37 | ;; Thoughts and Ideas |
| 35 | ;; - Currently, `process-attributes' returns the list of | 38 | ;; - Currently, `process-attributes' returns the list of |
| @@ -62,6 +65,11 @@ the external command (usually \"kill\")." | |||
| 62 | :type '(choice (function :tag "function") | 65 | :type '(choice (function :tag "function") |
| 63 | (string :tag "command"))) | 66 | (string :tag "command"))) |
| 64 | 67 | ||
| 68 | (defcustom proced-renice-command "renice" | ||
| 69 | "Name of renice command." | ||
| 70 | :group 'proced | ||
| 71 | :type '(string :tag "command")) | ||
| 72 | |||
| 65 | (defcustom proced-signal-list | 73 | (defcustom proced-signal-list |
| 66 | '( ;; signals supported on all POSIX compliant systems | 74 | '( ;; signals supported on all POSIX compliant systems |
| 67 | ("HUP" . " (1. Hangup)") | 75 | ("HUP" . " (1. Hangup)") |
| @@ -491,6 +499,7 @@ Important: the match ends just after the marker.") | |||
| 491 | (define-key km "o" 'proced-omit-processes) | 499 | (define-key km "o" 'proced-omit-processes) |
| 492 | (define-key km "x" 'proced-send-signal) ; Dired compatibility | 500 | (define-key km "x" 'proced-send-signal) ; Dired compatibility |
| 493 | (define-key km "k" 'proced-send-signal) ; kill processes | 501 | (define-key km "k" 'proced-send-signal) ; kill processes |
| 502 | (define-key km "r" 'proced-renice) ; renice processes | ||
| 494 | ;; misc | 503 | ;; misc |
| 495 | (define-key km "h" 'describe-mode) | 504 | (define-key km "h" 'describe-mode) |
| 496 | (define-key km "?" 'proced-help) | 505 | (define-key km "?" 'proced-help) |
| @@ -561,8 +570,11 @@ Important: the match ends just after the marker.") | |||
| 561 | :style toggle | 570 | :style toggle |
| 562 | :selected (eval proced-auto-update-flag) | 571 | :selected (eval proced-auto-update-flag) |
| 563 | :help "Auto Update of Proced Buffer"] | 572 | :help "Auto Update of Proced Buffer"] |
| 573 | "--" | ||
| 564 | ["Send signal" proced-send-signal | 574 | ["Send signal" proced-send-signal |
| 565 | :help "Send Signal to Marked Processes"])) | 575 | :help "Send Signal to Marked Processes"] |
| 576 | ["Renice" proced-renice | ||
| 577 | :help "Renice Marked Processes"])) | ||
| 566 | 578 | ||
| 567 | ;; helper functions | 579 | ;; helper functions |
| 568 | (defun proced-marker-regexp () | 580 | (defun proced-marker-regexp () |
| @@ -1686,14 +1698,11 @@ After updating a displayed Proced buffer run the normal hook | |||
| 1686 | Preserves point and marks." | 1698 | Preserves point and marks." |
| 1687 | (proced-update t)) | 1699 | (proced-update t)) |
| 1688 | 1700 | ||
| 1689 | (defun proced-send-signal (&optional signal) | 1701 | (defun proced-marked-processes () |
| 1690 | "Send a SIGNAL to the marked processes. | 1702 | "Return marked processes as alist of PIDs. |
| 1691 | If no process is marked, operate on current process. | 1703 | If no process is marked return alist with the PID of the process point is on. |
| 1692 | SIGNAL may be a string (HUP, INT, TERM, etc.) or a number. | 1704 | The cdrs of the alist are the text strings displayed by Proced for these |
| 1693 | If SIGNAL is nil display marked processes and query interactively for SIGNAL. | 1705 | processes. They are used for error messages." |
| 1694 | After sending the signal, this command runs the normal hook | ||
| 1695 | `proced-after-send-signal-hook'." | ||
| 1696 | (interactive) | ||
| 1697 | (let ((regexp (proced-marker-regexp)) | 1706 | (let ((regexp (proced-marker-regexp)) |
| 1698 | process-alist) | 1707 | process-alist) |
| 1699 | ;; collect marked processes | 1708 | ;; collect marked processes |
| @@ -1706,102 +1715,183 @@ After sending the signal, this command runs the normal hook | |||
| 1706 | (+ 2 (line-beginning-position)) | 1715 | (+ 2 (line-beginning-position)) |
| 1707 | (line-end-position))) | 1716 | (line-end-position))) |
| 1708 | process-alist))) | 1717 | process-alist))) |
| 1709 | (setq process-alist | 1718 | (if process-alist |
| 1710 | (if process-alist | 1719 | (nreverse process-alist) |
| 1711 | (nreverse process-alist) | 1720 | ;; take current process |
| 1712 | ;; take current process | 1721 | (let ((pid (proced-pid-at-point))) |
| 1713 | (list (cons (proced-pid-at-point) | 1722 | (if pid |
| 1723 | (list (cons pid | ||
| 1714 | (buffer-substring-no-properties | 1724 | (buffer-substring-no-properties |
| 1715 | (+ 2 (line-beginning-position)) | 1725 | (+ 2 (line-beginning-position)) |
| 1716 | (line-end-position)))))) | 1726 | (line-end-position))))))))) |
| 1727 | |||
| 1728 | (defmacro proced-with-processes-buffer (process-alist &rest body) | ||
| 1729 | "Execute the forms in BODY in a temporary buffer displaying PROCESS-ALIST. | ||
| 1730 | PROCESS-ALIST is an alist of process PIDs as in `proced-process-alist'. | ||
| 1731 | The value returned is the value of the last form in BODY." | ||
| 1732 | (declare (indent 1) (debug t)) | ||
| 1733 | ;; Use leading space in buffer name to make this buffer ephemeral | ||
| 1734 | `(let ((bufname " *Marked Processes*") | ||
| 1735 | (header-line (substring-no-properties proced-header-line))) | ||
| 1736 | (with-current-buffer (get-buffer-create bufname) | ||
| 1737 | (setq truncate-lines t | ||
| 1738 | proced-header-line header-line ; inherit header line | ||
| 1739 | header-line-format '(:eval (proced-header-line))) | ||
| 1740 | (add-hook 'post-command-hook 'force-mode-line-update nil t) | ||
| 1741 | (let ((inhibit-read-only t)) | ||
| 1742 | (erase-buffer) | ||
| 1743 | (buffer-disable-undo) | ||
| 1744 | (setq buffer-read-only t) | ||
| 1745 | (dolist (process ,process-alist) | ||
| 1746 | (insert " " (cdr process) "\n")) | ||
| 1747 | (delete-char -1) | ||
| 1748 | (goto-char (point-min))) | ||
| 1749 | (save-window-excursion | ||
| 1750 | ;; Analogous to `dired-pop-to-buffer' | ||
| 1751 | ;; Don't split window horizontally. (Bug#1806) | ||
| 1752 | (let (split-width-threshold) | ||
| 1753 | (pop-to-buffer (current-buffer))) | ||
| 1754 | (fit-window-to-buffer (get-buffer-window) nil 1) | ||
| 1755 | ,@body)))) | ||
| 1756 | |||
| 1757 | (defun proced-send-signal (&optional signal process-alist) | ||
| 1758 | "Send a SIGNAL to processes in PROCESS-ALIST. | ||
| 1759 | PROCESS-ALIST is an alist as returned by `proced-marked-processes'. | ||
| 1760 | Interactively, PROCESS-ALIST contains the marked processes. | ||
| 1761 | If no process is marked, it contains the process point is on, | ||
| 1762 | SIGNAL may be a string (HUP, INT, TERM, etc.) or a number. | ||
| 1763 | After sending SIGNAL to all processes in PROCESS-ALIST, this command | ||
| 1764 | runs the normal hook `proced-after-send-signal-hook'. | ||
| 1765 | |||
| 1766 | For backward compatibility SIGNAL and PROCESS-ALIST may be nil. | ||
| 1767 | Then PROCESS-ALIST contains the marked processes or the process point is on | ||
| 1768 | and SIGNAL is queried interactively. This noninteractive usage is still | ||
| 1769 | supported but discouraged. It will be removed in a future version of Emacs." | ||
| 1770 | (interactive | ||
| 1771 | (let* ((process-alist (proced-marked-processes)) | ||
| 1772 | (pnum (if (= 1 (length process-alist)) | ||
| 1773 | "1 process" | ||
| 1774 | (format "%d processes" (length process-alist)))) | ||
| 1775 | (completion-ignore-case t) | ||
| 1776 | (completion-extra-properties | ||
| 1777 | '(:annotation-function | ||
| 1778 | (lambda (s) (cdr (assoc s proced-signal-list)))))) | ||
| 1779 | (proced-with-processes-buffer process-alist | ||
| 1780 | (list (completing-read (concat "Send signal [" pnum | ||
| 1781 | "] (default TERM): ") | ||
| 1782 | proced-signal-list | ||
| 1783 | nil nil nil nil "TERM") | ||
| 1784 | process-alist)))) | ||
| 1785 | |||
| 1786 | (unless (and signal process-alist) | ||
| 1787 | ;; Discouraged usge (supported for backward compatibility): | ||
| 1788 | ;; The new calling sequence separates more cleanly between the parts | ||
| 1789 | ;; of the code required for interactive and noninteractive calls so that | ||
| 1790 | ;; the command can be used more flexibly in noninteractive ways, too. | ||
| 1791 | (unless (get 'proced-send-signal 'proced-outdated) | ||
| 1792 | (put 'proced-send-signal 'proced-outdated t) | ||
| 1793 | (message "Outdated usage of `proced-send-signal'") | ||
| 1794 | (sit-for 2)) | ||
| 1795 | (setq process-alist (proced-marked-processes)) | ||
| 1717 | (unless signal | 1796 | (unless signal |
| 1718 | ;; Display marked processes (code taken from `dired-mark-pop-up'). | 1797 | (let ((pnum (if (= 1 (length process-alist)) |
| 1719 | (let ((bufname " *Marked Processes*") ; use leading space in buffer name | 1798 | "1 process" |
| 1720 | ; to make this buffer ephemeral | 1799 | (format "%d processes" (length process-alist)))) |
| 1721 | (header-line (substring-no-properties proced-header-line))) | 1800 | (completion-ignore-case t) |
| 1722 | (with-current-buffer (get-buffer-create bufname) | 1801 | (completion-extra-properties |
| 1723 | (setq truncate-lines t | 1802 | '(:annotation-function |
| 1724 | proced-header-line header-line ; inherit header line | 1803 | (lambda (s) (cdr (assoc s proced-signal-list)))))) |
| 1725 | header-line-format '(:eval (proced-header-line))) | 1804 | (proced-with-processes-buffer process-alist |
| 1726 | (add-hook 'post-command-hook 'force-mode-line-update nil t) | 1805 | (setq signal (completing-read (concat "Send signal [" pnum |
| 1727 | (let ((inhibit-read-only t)) | 1806 | "] (default TERM): ") |
| 1728 | (erase-buffer) | 1807 | proced-signal-list |
| 1729 | (buffer-disable-undo) | 1808 | nil nil nil nil "TERM")))))) |
| 1730 | (setq buffer-read-only t) | 1809 | |
| 1731 | (dolist (process process-alist) | 1810 | (let (failures) |
| 1732 | (insert " " (cdr process) "\n")) | 1811 | ;; Why not always use `signal-process'? See |
| 1733 | (delete-char -1) | 1812 | ;; http://lists.gnu.org/archive/html/emacs-devel/2008-03/msg02955.html |
| 1734 | (goto-char (point-min))) | 1813 | (if (functionp proced-signal-function) |
| 1735 | (save-window-excursion | 1814 | ;; use built-in `signal-process' |
| 1736 | ;; Analogous to `dired-pop-to-buffer' | 1815 | (let ((signal (if (stringp signal) |
| 1737 | ;; Don't split window horizontally. (Bug#1806) | 1816 | (if (string-match "\\`[0-9]+\\'" signal) |
| 1738 | (let (split-width-threshold) | 1817 | (string-to-number signal) |
| 1739 | (pop-to-buffer (current-buffer))) | 1818 | (make-symbol signal)) |
| 1740 | (fit-window-to-buffer (get-buffer-window) nil 1) | 1819 | signal))) ; number |
| 1741 | (let* ((completion-ignore-case t) | ||
| 1742 | (pnum (if (= 1 (length process-alist)) | ||
| 1743 | "1 process" | ||
| 1744 | (format "%d processes" (length process-alist)))) | ||
| 1745 | (completion-extra-properties | ||
| 1746 | '(:annotation-function | ||
| 1747 | (lambda (s) (cdr (assoc s proced-signal-list)))))) | ||
| 1748 | (setq signal | ||
| 1749 | (completing-read (concat "Send signal [" pnum | ||
| 1750 | "] (default TERM): ") | ||
| 1751 | proced-signal-list | ||
| 1752 | nil nil nil nil "TERM"))))))) | ||
| 1753 | ;; send signal | ||
| 1754 | (let ((count 0) | ||
| 1755 | failures) | ||
| 1756 | ;; Why not always use `signal-process'? See | ||
| 1757 | ;; http://lists.gnu.org/archive/html/emacs-devel/2008-03/msg02955.html | ||
| 1758 | (if (functionp proced-signal-function) | ||
| 1759 | ;; use built-in `signal-process' | ||
| 1760 | (let ((signal (if (stringp signal) | ||
| 1761 | (if (string-match "\\`[0-9]+\\'" signal) | ||
| 1762 | (string-to-number signal) | ||
| 1763 | (make-symbol signal)) | ||
| 1764 | signal))) ; number | ||
| 1765 | (dolist (process process-alist) | ||
| 1766 | (condition-case err | ||
| 1767 | (if (zerop (funcall | ||
| 1768 | proced-signal-function (car process) signal)) | ||
| 1769 | (setq count (1+ count)) | ||
| 1770 | (proced-log "%s\n" (cdr process)) | ||
| 1771 | (push (cdr process) failures)) | ||
| 1772 | (error ; catch errors from failed signals | ||
| 1773 | (proced-log "%s\n" err) | ||
| 1774 | (proced-log "%s\n" (cdr process)) | ||
| 1775 | (push (cdr process) failures))))) | ||
| 1776 | ;; use external system call | ||
| 1777 | (let ((signal (concat "-" (if (numberp signal) | ||
| 1778 | (number-to-string signal) signal)))) | ||
| 1779 | (dolist (process process-alist) | 1820 | (dolist (process process-alist) |
| 1780 | (with-temp-buffer | 1821 | (condition-case err |
| 1781 | (condition-case nil | 1822 | (unless (zerop (funcall |
| 1782 | (if (zerop (call-process | 1823 | proced-signal-function (car process) signal)) |
| 1783 | proced-signal-function nil t nil | 1824 | (proced-log "%s\n" (cdr process)) |
| 1784 | signal (number-to-string (car process)))) | 1825 | (push (cdr process) failures)) |
| 1785 | (setq count (1+ count)) | 1826 | (error ; catch errors from failed signals |
| 1786 | (proced-log (current-buffer)) | 1827 | (proced-log "%s\n" err) |
| 1787 | (proced-log "%s\n" (cdr process)) | 1828 | (proced-log "%s\n" (cdr process)) |
| 1788 | (push (cdr process) failures)) | 1829 | (push (cdr process) failures))))) |
| 1789 | (error ; catch errors from failed signals | 1830 | ;; use external system call |
| 1790 | (proced-log (current-buffer)) | 1831 | (let ((signal (format "-%s" signal))) |
| 1791 | (proced-log "%s\n" (cdr process)) | 1832 | (dolist (process process-alist) |
| 1792 | (push (cdr process) failures))))))) | 1833 | (with-temp-buffer |
| 1793 | (if failures | 1834 | (condition-case nil |
| 1794 | ;; Proced error message are not always very precise. | 1835 | (unless (zerop (call-process |
| 1795 | ;; Can we issue a useful one-line summary in the | 1836 | proced-signal-function nil t nil |
| 1796 | ;; message area (using FAILURES) if only one signal failed? | 1837 | signal (number-to-string (car process)))) |
| 1797 | (proced-log-summary | 1838 | (proced-log (current-buffer)) |
| 1798 | signal | 1839 | (proced-log "%s\n" (cdr process)) |
| 1799 | (format "%d of %d signal%s failed" | 1840 | (push (cdr process) failures)) |
| 1800 | (length failures) (length process-alist) | 1841 | (error ; catch errors from failed signals |
| 1801 | (if (= 1 (length process-alist)) "" "s"))) | 1842 | (proced-log (current-buffer)) |
| 1802 | (proced-success-message "Sent signal to" count))) | 1843 | (proced-log "%s\n" (cdr process)) |
| 1803 | ;; final clean-up | 1844 | (push (cdr process) failures))))))) |
| 1804 | (run-hooks 'proced-after-send-signal-hook))) | 1845 | (if failures |
| 1846 | ;; Proced error message are not always very precise. | ||
| 1847 | ;; Can we issue a useful one-line summary in the | ||
| 1848 | ;; message area (using FAILURES) if only one signal failed? | ||
| 1849 | (proced-log-summary | ||
| 1850 | (format "Signal %s" signal) | ||
| 1851 | (format "%d of %d signal%s failed" | ||
| 1852 | (length failures) (length process-alist) | ||
| 1853 | (if (= 1 (length process-alist)) "" "s"))) | ||
| 1854 | (proced-success-message "Sent signal to" (length process-alist)))) | ||
| 1855 | ;; final clean-up | ||
| 1856 | (run-hooks 'proced-after-send-signal-hook)) | ||
| 1857 | |||
| 1858 | (defun proced-renice (priority process-alist) | ||
| 1859 | "Renice the processes in PROCESS-ALIST to PRIORITY. | ||
| 1860 | PROCESS-ALIST is an alist as returned by `proced-marked-processes'. | ||
| 1861 | Interactively, PROCESS-ALIST contains the marked processes. | ||
| 1862 | If no process is marked, it contains the process point is on, | ||
| 1863 | After renicing all processes in PROCESS-ALIST, this command runs | ||
| 1864 | the normal hook `proced-after-send-signal-hook'." | ||
| 1865 | (interactive | ||
| 1866 | (let ((process-alist (proced-marked-processes))) | ||
| 1867 | (proced-with-processes-buffer process-alist | ||
| 1868 | (list (read-number "New priority: ") | ||
| 1869 | process-alist)))) | ||
| 1870 | (if (numberp priority) | ||
| 1871 | (setq priority (number-to-string priority))) | ||
| 1872 | (let (failures) | ||
| 1873 | (dolist (process process-alist) | ||
| 1874 | (with-temp-buffer | ||
| 1875 | (condition-case nil | ||
| 1876 | (unless (zerop (call-process | ||
| 1877 | proced-renice-command nil t nil | ||
| 1878 | priority (number-to-string (car process)))) | ||
| 1879 | (proced-log (current-buffer)) | ||
| 1880 | (proced-log "%s\n" (cdr process)) | ||
| 1881 | (push (cdr process) failures)) | ||
| 1882 | (error ; catch errors from failed renice | ||
| 1883 | (proced-log (current-buffer)) | ||
| 1884 | (proced-log "%s\n" (cdr process)) | ||
| 1885 | (push (cdr process) failures))))) | ||
| 1886 | (if failures | ||
| 1887 | (proced-log-summary | ||
| 1888 | (format "Renice %s" priority) | ||
| 1889 | (format "%d of %d renice%s failed" | ||
| 1890 | (length failures) (length process-alist) | ||
| 1891 | (if (= 1 (length process-alist)) "" "s"))) | ||
| 1892 | (proced-success-message "Reniced" (length process-alist)))) | ||
| 1893 | ;; final clean-up | ||
| 1894 | (run-hooks 'proced-after-send-signal-hook)) | ||
| 1805 | 1895 | ||
| 1806 | ;; similar to `dired-why' | 1896 | ;; similar to `dired-why' |
| 1807 | (defun proced-why () | 1897 | (defun proced-why () |