;;; Commentary:
+;; This package provides an interface to bug reports which are located
+;; on the GNU bug tracker debbugs.gnu.org. It's main purpose is to
+;; show and manipulate bug reports from Emacs, but it could be used
+;; also for other GNU projects which use the same bug tracker.
+
+;; If you have `debbugs-gnu.el' in your load-path, you could enable
+;; the bug tracker command by the following line in your ~/.emacs
+;;
+;; (autoload 'debbugs-gnu "debbugs-gnu" "" 'interactive)
+
+;; The bug tracker is called interactively by
+;;
+;; M-x debbugs-gnu
+
+;; It asks for the severities, for which bugs shall be shown. This can
+;; be either just one severity, or a list of severities, separated by
+;; comma. Valid severities are "important", "normal", "minor" or
+;; "wishlist". There is also the pseudo severity "tagged", which
+;; selects locally tagged bugs.
+
+;; If a prefix is given, more search parameters are asked for, like
+;; packages (also a comma separated list, "emacs" is the default),
+;; whether archived bugs shall be shown, and whether closed bugs shall
+;; be shown.
+
+;; The bug reports are downloaded from the bug tracker. In order to
+;; not generate too much load of the server, up to 500 bugs will be
+;; downloaded at once. If there are more hits, you will be asked to
+;; change this limit, but please don't increase this number too much.
+
+;; These default values could be changed also by customer options
+;; `debbugs-gnu-default-severities', `debbugs-gnu-default-packages'
+;; and `debbugs-gnu-default-hits-per-page'.
+
+;; The command creates one or more pages of bug lists. Every bug is
+;; shown in one line, including the bug number, the status (combining
+;; merged bug numbers, keywords and severities), the name of the
+;; submitter, and the title of the bug. On every bug line you could
+;; apply the following actions by the following keystrokes:
+
+;; RET: Show corresponding messages in Gnus
+;; "C": Send a control message
+;; "t": Mark the bug locally as tagged
+;; "d": Show bug attributes
+
+;; Furthermore, you could apply the global actions
+
+;; "s": Toggle bug sorting
+;; "g": Rescan bugs
+;; "x": Suppress closed bugs
+;; "q": Quit the buffer
+
+;; When you visit the related bug messages in Gnus, you could also
+;; send control messages by keystroke "C".
+
;;; Code:
(require 'debbugs)
(defgroup debbugs-gnu ()
"UI for the debbugs.gnu.org bug tracker."
- :group 'debbugs)
-
-(defface debbugs-new '((t (:foreground "red")))
+ :group 'debbugs
+ :version "24.1")
+
+(defcustom debbugs-gnu-default-severities '("normal")
+ "*The list severities bugs are searched for.
+\"tagged\" is not a severity but marks locally tagged bugs."
+ :group 'debbugs-gnu
+ :type '(set (const "important")
+ (const "normal")
+ (const "minor")
+ (const "wishlist")
+ (const "tagged"))
+ :version "24.1")
+
+(defcustom debbugs-gnu-default-packages '("emacs")
+ "*The list of packages to be searched for."
+ :group 'debbugs-gnu
+ :type '(set (const "automake")
+ (const "coreutils")
+ (const "emacs")
+ (const "gnus")
+ (const "libtool"))
+ :version "24.1")
+
+(defcustom debbugs-gnu-default-hits-per-page 500
+ "*The number of bugs shown per page."
+ :group 'debbugs-gnu
+ :type 'integer
+ :version "24.1")
+
+(defface debbugs-gnu-new '((t (:foreground "red")))
"Face for new reports that nobody has answered.")
-(defface debbugs-handled '((t (:foreground "ForestGreen")))
+(defface debbugs-gnu-handled '((t (:foreground "ForestGreen")))
"Face for new reports that have been modified recently.")
-(defface debbugs-stale '((t (:foreground "orange")))
+(defface debbugs-gnu-stale '((t (:foreground "orange")))
"Face for new reports that nobody has answered.")
-(defface debbugs-done '((t (:foreground "DarkGrey")))
+(defface debbugs-gnu-done '((t (:foreground "DarkGrey")))
"Face for closed bug reports.")
-(defface debbugs-tagged '((t (:foreground "red")))
+(defface debbugs-gnu-tagged '((t (:foreground "red")))
"Face for reports that have been tagged locally.")
-(defvar debbugs-widgets nil)
+(defvar debbugs-gnu-widgets nil)
-(defvar debbugs-widget-map
+(defvar debbugs-gnu-widget-map
(let ((map (make-sparse-keymap)))
(define-key map "\r" 'widget-button-press)
(define-key map [mouse-1] 'widget-button-press)
(define-key map [mouse-2] 'widget-button-press)
map))
-(defvar debbugs-local-tags nil
+(defvar debbugs-gnu-local-tags nil
"List of bug numbers tagged locally, and kept persistent.")
-(defvar debbugs-persistency-file
+(defvar debbugs-gnu-persistency-file
(expand-file-name (locate-user-emacs-file "debbugs"))
"File name of a persistency store for debbugs variables")
-(defun debbugs-dump-persistency-file ()
+(defun debbugs-gnu-dump-persistency-file ()
"Function to store debbugs variables persistently."
- (ignore-errors
- (with-temp-buffer
- (insert
- ";; -*- emacs-lisp -*-\n"
- ";; Debbugs tags connection history. Don't change this file.\n\n"
- (format "(setq debbugs-local-tags '%S)"
- (sort (copy-sequence debbugs-local-tags) '<)))
- (write-region
- (point-min) (point-max) debbugs-persistency-file))))
-
-;; Save variables.
-(unless noninteractive
- (add-hook 'kill-emacs-hook 'debbugs-dump-persistency-file))
-
-(defvar debbugs-package nil
- "The package name to be searched for.")
-
-(defvar debbugs-severities nil
+ (with-temp-file debbugs-gnu-persistency-file
+ (insert
+ ";; -*- emacs-lisp -*-\n"
+ ";; Debbugs tags connection history. Don't change this file.\n\n"
+ (format "(setq debbugs-gnu-local-tags '%S)"
+ (sort (copy-sequence debbugs-gnu-local-tags) '<)))))
+
+(defvar debbugs-gnu-current-severities nil
"The severities strings to be searched for.")
-(defvar debbugs-archive nil
- "The archive flag to be searched for.")
+(defvar debbugs-gnu-current-packages nil
+ "The package names to be searched for.")
-(defun debbugs-emacs (severities &optional package suppress-done archivedp)
+(defvar debbugs-gnu-current-archive nil
+ "Whether to search in the archive.")
+
+(defun debbugs-gnu (severities &optional packages archivedp suppress-done)
"List all outstanding Emacs bugs."
(interactive
- (list
- (completing-read "Severity: "
- '("important" "normal" "minor" "wishlist")
- nil t "normal")))
+ (let (archivedp)
+ (list
+ (completing-read-multiple
+ "Severity: "
+ (mapcar 'cadr (cdr (get 'debbugs-gnu-default-severities 'custom-type)))
+ nil t (mapconcat 'identity debbugs-gnu-default-severities ","))
+ ;; The optional parameters are asked only when there is a prefix.
+ (if current-prefix-arg
+ (completing-read-multiple
+ "Packages: "
+ (mapcar 'cadr (cdr (get 'debbugs-gnu-default-packages 'custom-type)))
+ nil t (mapconcat 'identity debbugs-gnu-default-packages ","))
+ debbugs-gnu-default-packages)
+ (when current-prefix-arg
+ (setq archivedp (y-or-n-p "Show archived bugs?")))
+ (when (and current-prefix-arg (not archivedp))
+ (y-or-n-p "Suppress closed bugs?")))))
+
;; Initialize variables.
- (when (and (file-exists-p debbugs-persistency-file)
- (not debbugs-local-tags))
+ (when (and (file-exists-p debbugs-gnu-persistency-file)
+ (not debbugs-gnu-local-tags))
(with-temp-buffer
- (insert-file-contents debbugs-persistency-file)
+ (insert-file-contents debbugs-gnu-persistency-file)
(eval (read (current-buffer)))))
+ ;; Set lists.
(unless (consp severities)
(setq severities (list severities)))
+ (unless (consp packages)
+ (setq packages (list packages)))
- (setq debbugs-package (or package "emacs")
- debbugs-severities severities
- debbugs-archive (if archivedp "1" "0")
- debbugs-widgets nil)
+ (setq debbugs-gnu-current-severities severities
+ debbugs-gnu-current-packages packages
+ debbugs-gnu-current-archive (if archivedp "1" "0")
+ debbugs-gnu-widgets nil)
- (let ((debbugs-port "gnu.org")
- (default 500)
- ids)
- (dolist (severity debbugs-severities)
- (setq ids (nconc ids
- (debbugs-get-bugs :package debbugs-package
- :severity severity
- :archive debbugs-archive))))
- (setq ids (sort ids '<))
-
- (if (> (length ids) default)
+ (let ((hits debbugs-gnu-default-hits-per-page)
+ (ids (debbugs-gnu-get-bugs)))
+
+ (if (> (length ids) hits)
(let ((cursor-in-echo-area nil))
- (setq default
+ (setq hits
(string-to-number
(read-string
(format
"How many reports (available %d, default %d): "
- (length ids) default)
+ (length ids) hits)
nil
nil
- (number-to-string default))))))
+ (number-to-string hits))))))
- (if (> (length ids) default)
+ (if (> (length ids) hits)
(let ((i 0)
curr-ids)
(while ids
(setq i (1+ i)
- curr-ids (butlast ids (- (length ids) default)))
+ curr-ids (butlast ids (- (length ids) hits)))
(add-to-list
- 'debbugs-widgets
+ 'debbugs-gnu-widgets
(widget-convert
'push-button
:follow-link 'mouse-face
:notify (lambda (widget &rest ignore)
- (debbugs-show-reports widget))
- :keymap debbugs-widget-map
+ (debbugs-gnu-show-reports widget))
+ :keymap debbugs-gnu-widget-map
:suppress-done suppress-done
:buffer-name (format "*Emacs Bugs*<%d>" i)
:bug-ids curr-ids
:format " %[%v%]"
(number-to-string i))
'append)
- (setq ids (last ids (- (length ids) default))))
- (debbugs-show-reports (car debbugs-widgets)))
+ (setq ids (last ids (- (length ids) hits))))
+ (debbugs-gnu-show-reports (car debbugs-gnu-widgets)))
- (debbugs-show-reports
+ (debbugs-gnu-show-reports
(widget-convert
'const
:suppress-done suppress-done
:buffer-name "*Emacs Bugs*"
:bug-ids ids)))))
-(defvar debbugs-current-widget nil)
+(defun debbugs-gnu-get-bugs ()
+ "Retrieve bugs numbers from debbugs.gnu.org according search criteria."
+ (let ((debbugs-port "gnu.org")
+ ids)
+ (dolist (severity debbugs-gnu-current-severities)
+ (if (string-equal severity "tagged")
+ (setq ids (nconc ids (copy-sequence debbugs-gnu-local-tags)))
+ (dolist (package debbugs-gnu-current-packages)
+ (setq ids
+ (nconc ids
+ (debbugs-get-bugs
+ :package package
+ :severity severity
+ :archive debbugs-gnu-current-archive))))))
+ (sort ids '<)))
+
+(defvar debbugs-gnu-current-widget nil)
(defvar widget-mouse-face)
-(defun debbugs-show-reports (widget)
+(defun debbugs-gnu-show-reports (widget)
"Show bug reports as given in WIDGET property :bug-ids."
(pop-to-buffer (get-buffer-create (widget-get widget :buffer-name)))
- (debbugs-mode)
+ (debbugs-gnu-mode)
(let ((inhibit-read-only t)
+ (debbugs-port "gnu.org")
(suppress-done (widget-get widget :suppress-done)))
(erase-buffer)
- (when debbugs-widgets
+ (when debbugs-gnu-widgets
(widget-insert "Page:")
(mapc
(lambda (obj)
(widget-put obj :button-face 'widget-button-pressed)
(widget-put obj :button-face 'widget-button-face))
(widget-apply obj :create))
- debbugs-widgets)
+ debbugs-gnu-widgets)
(widget-insert "\n\n"))
(dolist (status (sort (apply 'debbugs-get-status
","))
(face (cond
((equal (cdr (assq 'pending status)) "done")
- 'debbugs-done)
+ 'debbugs-gnu-done)
((= (cdr (assq 'date status))
(cdr (assq 'log_modified status)))
- 'debbugs-new)
+ 'debbugs-gnu-new)
((< (- (float-time)
(cdr (assq 'log_modified status)))
(* 60 60 24 4))
- 'debbugs-handled)
+ 'debbugs-gnu-handled)
(t
- 'debbugs-stale)))
+ 'debbugs-gnu-stale)))
(address (mail-header-parse-address
(decode-coding-string (cdr (assq 'originator status))
'utf-8)))
;; Mark own submitted bugs.
(if (and (stringp (car address))
(string-equal (car address) user-mail-address))
- 'debbugs-tagged
+ 'debbugs-gnu-tagged
'default)))
(insert
(format "%5d %-20s [%-23s] %s\n"
(if (and (stringp owner)
(string-equal owner user-mail-address))
(propertize subject
- 'face 'debbugs-tagged 'help-echo subject)
+ 'face 'debbugs-gnu-tagged 'help-echo subject)
(propertize subject 'help-echo subject))))
(forward-line -1)
- (put-text-property (point) (1+ (point)) 'debbugs-status status)
+ (put-text-property (point) (1+ (point)) 'debbugs-gnu-status status)
(put-text-property
(point-at-bol) (point-at-eol) 'mouse-face widget-mouse-face)
- (when (memq id debbugs-local-tags)
+ (when (memq id debbugs-gnu-local-tags)
(put-text-property
(+ (point) (- 5 (length (number-to-string id)))) (+ (point) 5)
- 'face 'debbugs-tagged))
+ 'face 'debbugs-gnu-tagged))
(forward-line 1))))
- (when debbugs-widgets
+ (when debbugs-gnu-widgets
(widget-insert "\nPage:")
- (mapc (lambda (obj) (widget-apply obj :create)) debbugs-widgets)
+ (mapc (lambda (obj) (widget-apply obj :create)) debbugs-gnu-widgets)
(widget-setup))
(set-buffer-modified-p nil)
- (set (make-local-variable 'debbugs-current-widget)
+ (set (make-local-variable 'debbugs-gnu-current-widget)
widget)
(goto-char (point-min))))
-(defvar debbugs-mode-map
+(defvar debbugs-gnu-mode-map
(let ((map (make-sparse-keymap)))
- (define-key map "\r" 'debbugs-select-report)
- (define-key map [mouse-1] 'debbugs-select-report)
- (define-key map [mouse-2] 'debbugs-select-report)
- (define-key map "q" 'kill-buffer)
- (define-key map "s" 'debbugs-toggle-sort)
- (define-key map "t" 'debbugs-toggle-tag)
- (define-key map "d" 'debbugs-display-status)
- (define-key map "g" 'debbugs-rescan)
- (define-key map "x" 'debbugs-suppress-done)
- (define-key map "C" 'debbugs-send-control-message)
+ (define-key map "\r" 'debbugs-gnu-select-report)
+ (define-key map [mouse-1] 'debbugs-gnu-select-report)
+ (define-key map [mouse-2] 'debbugs-gnu-select-report)
+ (define-key map "q" 'bury-buffer)
+ (define-key map "s" 'debbugs-gnu-toggle-sort)
+ (define-key map "t" 'debbugs-gnu-toggle-tag)
+ (define-key map "d" 'debbugs-gnu-display-status)
+ (define-key map "g" 'debbugs-gnu-rescan)
+ (define-key map "x" 'debbugs-gnu-suppress-done)
+ (define-key map "C" 'debbugs-gnu-send-control-message)
map))
-(defun debbugs-rescan ()
+(defun debbugs-gnu-rescan ()
"Rescan the current set of bug reports."
(interactive)
;; The last page will be provided with new bug ids.
;; TODO: Do it also for the other pages.
- (when (and debbugs-widgets
- (eq debbugs-current-widget (car (last debbugs-widgets))))
- (let ((debbugs-port "gnu.org")
- (first-id (car (widget-get debbugs-current-widget :bug-ids)))
- (last-id (car (last (widget-get debbugs-current-widget :bug-ids))))
- ids)
- (dolist (severity debbugs-severities)
- (setq ids (nconc ids
- (debbugs-get-bugs :package debbugs-package
- :severity severity
- :archive debbugs-archive))))
- (setq ids (sort ids '<))
+ (when (and debbugs-gnu-widgets
+ (eq debbugs-gnu-current-widget (car (last debbugs-gnu-widgets))))
+ (let ((first-id (car (widget-get debbugs-gnu-current-widget :bug-ids)))
+ (last-id (car
+ (last (widget-get debbugs-gnu-current-widget :bug-ids))))
+ (ids (debbugs-gnu-get-bugs)))
(while (and (<= first-id last-id) (not (memq first-id ids)))
(setq first-id (1+ first-id)))
(when (<= first-id last-id)
- (widget-put debbugs-current-widget :bug-ids (memq first-id ids)))))
+ (widget-put debbugs-gnu-current-widget :bug-ids (memq first-id ids)))))
;; Refresh the buffer. `save-excursion' does not work, so we
;; remember the position.
(let ((pos (point)))
- (debbugs-show-reports debbugs-current-widget)
+ (debbugs-gnu-show-reports debbugs-gnu-current-widget)
(goto-char pos)))
-(defvar debbugs-sort-state 'number)
+(defvar debbugs-gnu-sort-state 'number)
-(defun debbugs-mode ()
+(defun debbugs-gnu-mode ()
"Major mode for listing bug reports.
All normal editing commands are switched off.
-\\<debbugs-mode-map>
+\\<debbugs-gnu-mode-map>
The following commands are available:
-\\{debbugs-mode-map}"
+\\{debbugs-gnu-mode-map}"
(interactive)
(kill-all-local-variables)
- (setq major-mode 'debbugs-mode)
+ (setq major-mode 'debbugs-gnu-mode)
(setq mode-name "Debbugs")
- (use-local-map debbugs-mode-map)
- (set (make-local-variable 'debbugs-sort-state)
+ (use-local-map debbugs-gnu-mode-map)
+ (set (make-local-variable 'debbugs-gnu-sort-state)
'number)
(buffer-disable-undo)
(setq truncate-lines t)
(setq buffer-read-only t))
-(defvar debbugs-state-preference
- '((debbugs-new . 1)
- (debbugs-stale . 2)
- (debbugs-handled . 3)
- (debbugs-done . 4)))
+(defvar debbugs-gnu-state-preference
+ '((debbugs-gnu-new . 1)
+ (debbugs-gnu-stale . 2)
+ (debbugs-gnu-handled . 3)
+ (debbugs-gnu-done . 4)))
-(defun debbugs-toggle-sort ()
+(defun debbugs-gnu-toggle-sort ()
"Toggle sorting by age and by state."
(interactive)
(beginning-of-line)
(let ((buffer-read-only nil)
(before-change-functions nil)
- (current-bug (debbugs-current-id t))
+ (current-bug (debbugs-gnu-current-id t))
(start-point (point)))
- (setq debbugs-sort-state
- (if (eq debbugs-sort-state 'number)
+ (setq debbugs-gnu-sort-state
+ (if (eq debbugs-gnu-sort-state 'number)
'state
'number))
(goto-char (point-min))
(while (and (not (eobp))
- (not (get-text-property (point) 'debbugs-status)))
+ (not (get-text-property (point) 'debbugs-gnu-status)))
(forward-line 1))
(save-restriction
(narrow-to-region
(goto-char (point-max))
(beginning-of-line)
(while (and (not (bobp))
- (not (get-text-property (point) 'debbugs-status)))
+ (not (get-text-property (point) 'debbugs-gnu-status)))
(forward-line -1))
(forward-line 1)
(point)))
(sort-subr
nil (lambda () (forward-line 1)) 'end-of-line
(lambda ()
- (let ((id (debbugs-current-id)))
- (if (eq debbugs-sort-state 'number)
+ (let ((id (debbugs-gnu-current-id)))
+ (if (eq debbugs-gnu-sort-state 'number)
id
;; Sort the tagged ones at the end.
- (or (and (memq id debbugs-local-tags)
+ (or (and (memq id debbugs-gnu-local-tags)
20)
(cdr (assq (get-text-property (+ (point) 7) 'face)
- debbugs-state-preference))
+ debbugs-gnu-state-preference))
10))))))
(if (not current-bug)
(goto-char start-point)
(goto-char (point-min))
(re-search-forward (format "^%d" current-bug) nil t))))
-(defun debbugs-toggle-tag ()
+(defun debbugs-gnu-toggle-tag ()
"Toggle tag of the report in the current line."
(interactive)
(save-excursion
(beginning-of-line)
(let ((inhibit-read-only t)
- (id (debbugs-current-id)))
- (if (memq id debbugs-local-tags)
+ (id (debbugs-gnu-current-id)))
+ (if (memq id debbugs-gnu-local-tags)
(progn
- (setq debbugs-local-tags (delq id debbugs-local-tags))
+ (setq debbugs-gnu-local-tags (delq id debbugs-gnu-local-tags))
(put-text-property (point) (+ (point) 5) 'face 'default))
- (add-to-list 'debbugs-local-tags id)
+ (add-to-list 'debbugs-gnu-local-tags id)
(put-text-property
(+ (point) (- 5 (length (number-to-string id)))) (+ (point) 5)
- 'face 'debbugs-tagged)))))
+ 'face 'debbugs-gnu-tagged))))
+ (debbugs-gnu-dump-persistency-file))
-(defun debbugs-suppress-done ()
+(defun debbugs-gnu-suppress-done ()
"Suppress bugs marked as done."
(interactive)
(save-excursion
- (unless (widget-get debbugs-current-widget :suppress-done)
+ (unless (widget-get debbugs-gnu-current-widget :suppress-done)
(let ((inhibit-read-only t))
- (widget-put debbugs-current-widget :suppress-done t)
+ (widget-put debbugs-gnu-current-widget :suppress-done t)
(goto-char (point-min))
(while (and (not (eobp))
- (not (get-text-property (point) 'debbugs-status)))
+ (not (get-text-property (point) 'debbugs-gnu-status)))
(forward-line 1))
(while (and (not (eobp))
- (get-text-property (point) 'debbugs-status))
- (if (equal (cdr (assq 'pending (debbugs-current-status))) "done")
+ (get-text-property (point) 'debbugs-gnu-status))
+ (if (equal (cdr (assq 'pending (debbugs-gnu-current-status))) "done")
(kill-region (point) (progn (forward-line 1) (point)))
(forward-line 1)))))))
-(defvar debbugs-bug-number nil)
+(defvar debbugs-gnu-bug-number nil)
-(defun debbugs-current-id (&optional noerror)
- (or (cdr (assq 'id (debbugs-current-status)))
+(defun debbugs-gnu-current-id (&optional noerror)
+ (or (cdr (assq 'id (debbugs-gnu-current-status)))
(and (not noerror)
(error "No bug on the current line"))))
-(defun debbugs-current-status ()
+(defun debbugs-gnu-current-status ()
(get-text-property (line-beginning-position)
- 'debbugs-status))
+ 'debbugs-gnu-status))
-(defun debbugs-display-status (status)
+(defun debbugs-gnu-display-status (status)
"Display the status of the report on the current line."
- (interactive (list (debbugs-current-status)))
+ (interactive (list (debbugs-gnu-current-status)))
(pop-to-buffer "*Bug Status*")
(erase-buffer)
(pp status (current-buffer))
(goto-char (point-min)))
-(defun debbugs-select-report ()
+(defun debbugs-gnu-select-report ()
"Select the report on the current line."
(interactive)
;; We open the report messages.
- (let* ((status (debbugs-current-status))
+ (let* ((status (debbugs-gnu-current-status))
(id (cdr (assq 'id status)))
(merged (cdr (assq 'mergedwith status))))
(gnus-read-ephemeral-emacs-bug-group
(cons (current-buffer)
(current-window-configuration)))
(with-current-buffer (window-buffer (selected-window))
- (debbugs-summary-mode 1)
- (set (make-local-variable 'debbugs-bug-number) id))))
+ (debbugs-gnu-summary-mode 1)
+ (set (make-local-variable 'debbugs-gnu-bug-number) id))))
-(defvar debbugs-summary-mode-map
+(defvar debbugs-gnu-summary-mode-map
(let ((map (make-sparse-keymap)))
- (define-key map "C" 'debbugs-send-control-message)
+ (define-key map "C" 'debbugs-gnu-send-control-message)
map))
(defvar gnus-posting-styles)
-(define-minor-mode debbugs-summary-mode
+(define-minor-mode debbugs-gnu-summary-mode
"Minor mode for providing a debbugs interface in Gnus summary buffers.
-\\{debbugs-summary-mode-map}"
- :lighter " Debbugs" :keymap debbugs-summary-mode-map
+\\{debbugs-gnu-summary-mode-map}"
+ :lighter " Debbugs" :keymap debbugs-gnu-summary-mode-map
(set (make-local-variable 'gnus-posting-styles)
'((".*"
(eval
(set (make-local-variable 'message-prune-recipient-rules)
'((".*@debbugs.*" "emacs-pretest-bug")
(".*@debbugs.*" "bug-gnu-emacs")
- ("[0-9]+@debbugs.*" "submit@debbugs.gnu.org")))
+ ("[0-9]+@debbugs.*" "submit@debbugs.gnu.org")
+ ("[0-9]+@debbugs.*" "quiet@debbugs.gnu.org")))
(set (make-local-variable 'message-alter-recipients-function)
(lambda (address)
(if (string-match "\\([0-9]+\\)@donarmstrong" (car address))
(cons new new))
address)))))))))
-(defun debbugs-send-control-message (message)
+(defun debbugs-gnu-send-control-message (message &optional reverse)
"Send a control message for the current bug report.
You can set the severity or add a tag, or close the report. If
you use the special \"done\" MESSAGE, the report will be marked as
-fixed, and then closed."
+fixed, and then closed.
+
+If given a prefix, and given a tag to set, the tag will be
+removed instead."
(interactive
(list (completing-read
"Control message: "
'("important" "normal" "minor" "wishlist"
- "done"
+ "done" "donenotabug" "donewontfix"
"unarchive" "reopen" "close"
"merge" "forcemerge"
"owner" "noowner"
"patch" "wontfix" "moreinfo" "unreproducible" "fixed" "notabug")
- nil t)))
- (let* ((id (or debbugs-bug-number ; Set on group entry.
- (debbugs-current-id)))
+ nil t)
+ current-prefix-arg))
+ (let* ((id (or debbugs-gnu-bug-number ; Set on group entry.
+ (debbugs-gnu-current-id)))
(version
(when (member message '("close" "done"))
(read-string
(format "close %d %s\n" id version))
((equal message "done")
(format "tags %d fixed\nclose %d %s\n" id id version))
+ ((member message '("donenotabug" "donewontfix"))
+ (format "tags %d %s\nclose %d\n" id (substring message 4) id))
((member message '("important" "normal" "minor" "wishlist"))
(format "severity %d %s\n" id message))
(t
- (format "tags %d %s\n" id message))))
+ (format "tags %d%s %s\n"
+ id (if reverse " -" "")
+ message))))
(funcall send-mail-function))))
(provide 'debbugs-gnu)