]> code.delx.au - gnu-emacs-elpa/blobdiff - packages/debbugs/debbugs-gnu.el
(debbugs-toggle-sort): Use `debbugs-current-id'.
[gnu-emacs-elpa] / packages / debbugs / debbugs-gnu.el
index 287041c172ed80bb90b86018a3c4a0aee9670423..e8496d003f8054072dc7228a770dfc22399bf520 100644 (file)
@@ -27,6 +27,7 @@
 ;;; Code:
 
 (require 'debbugs)
+(require 'widget)
 (eval-when-compile (require 'cl))
 
 (autoload 'gnus-read-ephemeral-emacs-bug-group "gnus-group")
 (defface debbugs-done '((t (:foreground "DarkGrey")))
   "Face for closed bug reports.")
 
+(defvar debbugs-widget-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map "\r" 'widget-button-press)
+    map))
+
 (defun debbugs-emacs (severities &optional package suppress-done archivedp)
   "List all outstanding Emacs bugs."
   (interactive
                     nil t "normal")))
   (unless (consp severities)
     (setq severities (list severities)))
-  (pop-to-buffer (get-buffer-create "*Emacs Bugs*"))
-  (debbugs-mode)
   (let ((debbugs-port "gnu.org")
-       (buffer-read-only nil)
-       (ids nil)
-       (default 500))
+       (default 500)
+       ids widgets)
     (dolist (severity severities)
       (setq ids (nconc ids
                       (debbugs-get-bugs :package (or package "emacs")
                                         :severity severity
                                         :archive (if archivedp
                                                      "1" "0")))))
+    (setq ids (sort ids '<))
+
+    (if (> (length ids) default)
+       (let ((cursor-in-echo-area nil))
+         (setq default
+               (string-to-number
+                (read-string
+                 (format
+                  "How many reports (available %d, default %d): "
+                  (length ids) default)
+                 nil
+                 nil
+                 (number-to-string default))))))
+
+    (if (> (length ids) default)
+       (let ((i 0)
+             curr-ids)
+         (while ids
+           (setq i (1+ i)
+                 curr-ids (butlast ids (- (length ids) default))
+                 widgets (append
+                          widgets
+                          (list
+                           (widget-convert
+                            'push-button
+                            :follow-link 'mouse-face
+                            :notify (lambda (widget &rest ignore)
+                                      (debbugs-show-reports
+                                       (widget-get widget :suppress-done)
+                                       widget
+                                       (widget-get widget :widgets)))
+                            :keymap debbugs-widget-map
+                            :suppress-done suppress-done
+                            :buffer-name (format "*Emacs Bugs*<%d>" i)
+                            :bug-ids (butlast ids (- (length ids) default))
+                            (format " %d" i))))
+                 ids (last ids (- (length ids) default))))
+         (debbugs-show-reports suppress-done (car widgets) widgets))
+
+      (debbugs-show-reports suppress-done
+                           (widget-convert
+                            'const
+                            :buffer-name "*Emacs Bugs*"
+                            :bug-ids ids)
+                           nil))))
+
+(defun debbugs-show-reports (suppress-done widget widgets)
+  "Show bug reports as given in WIDGET property :bug-ids."
+  (pop-to-buffer (get-buffer-create (widget-get widget :buffer-name)))
+  (debbugs-mode)
+  (let ((inhibit-read-only t))
     (erase-buffer)
 
-    (when (> (length ids) default)
-      (let* ((cursor-in-echo-area nil)
-            (input
-             (read-string
-              (format
-               "How many reports (available %d, default %d): "
-               (length ids) default)
-              nil
-              nil
-              (number-to-string default))))
-       (setq ids (last (sort ids '<) (string-to-number input)))))
-
-    (dolist (status (sort (apply 'debbugs-get-status ids)
+    (when widgets
+      (widget-insert "Page:")
+      (mapc
+       (lambda (obj)
+        (widget-insert " ")
+        (widget-put obj :widgets widgets)
+        (if (eq obj widget)
+            (widget-put obj :button-face 'widget-button-pressed)
+          (widget-put obj :button-face 'widget-button-face))
+        (widget-apply obj :create))
+       widgets)
+      (widget-insert "\n\n"))
+
+    (dolist (status (sort (apply 'debbugs-get-status
+                                (widget-get widget :bug-ids))
                          (lambda (s1 s2)
                            (< (cdr (assq 'id s1))
                               (cdr (assq 'id s2))))))
                        (decode-coding-string (cdr (assq 'originator status))
                                              'utf-8)))
              (subject (decode-coding-string (cdr (assq 'subject status))
-                                            'utf-8)))
+                                            'utf-8))
+             merged)
          (setq address
                ;; Prefer the name over the address.
                (or (cdr address)
                     (unless (equal (cdr (assq 'pending status)) "pending")
                       (setq words
                             (concat words "," (cdr (assq 'pending status)))))
+                    (when (setq merged (cdr (assq 'mergedwith status)))
+                      (setq words (format "%s,%s"
+                                          (if (numberp merged)
+                                              merged
+                                            (mapconcat 'number-to-string merged
+                                                       ","))
+                                          words)))
                     (if (> (length words) 20)
                         (propertize (substring words 0 20) 'help-echo words)
                       words))
                     address)
                   (propertize subject 'help-echo subject)))
          (forward-line -1)
+         (put-text-property (point) (1+ (point))
+                            'debbugs-status status)
          (put-text-property
           (+ (point) 5) (+ (point) 26)
           'face
             'debbugs-handled)
            (t
             'debbugs-stale)))
-         (forward-line 1)))))
-  (goto-char (point-min)))
+         (forward-line 1))))
+
+    (when widgets
+      (widget-insert "\nPage:")
+      (mapc
+       (lambda (obj)
+        (widget-insert " ")
+        (widget-put obj :widgets widgets)
+        (if (eq obj widget)
+            (widget-put obj :button-face 'widget-button-pressed)
+          (widget-put obj :button-face 'widget-button-face))
+        (widget-apply obj :create))
+       widgets)
+      (widget-setup))
 
-(defvar debbugs-mode-map nil)
-(unless debbugs-mode-map
-  (setq debbugs-mode-map (make-sparse-keymap))
-  (define-key debbugs-mode-map "\r" 'debbugs-select-report)
-  (define-key debbugs-mode-map "q"  'kill-buffer))
+    (goto-char (point-min))))
+
+(defvar debbugs-mode-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map "\r" 'debbugs-select-report)
+    (define-key map "q" 'kill-buffer)
+    (define-key map "s" 'debbugs-toggle-sort)
+    (define-key map "d" 'debbugs-display-status)
+    map))
+
+(defvar debbugs-sort-state 'number)
 
 (defun debbugs-mode ()
   "Major mode for listing bug reports.
@@ -154,24 +238,86 @@ The following commands are available:
   (setq major-mode 'debbugs-mode)
   (setq mode-name "Debbugs")
   (use-local-map debbugs-mode-map)
+  (set (make-local-variable 'debbugs-sort-state)
+       'number)
   (buffer-disable-undo)
   (setq truncate-lines t)
   (setq buffer-read-only t))
 
-(defun debbugs-select-report ()
-  "Select the report on the current line."
+(defvar debbugs-state-preference
+  '((debbugs-new . 1)
+    (debbugs-stale . 2)
+    (debbugs-handled . 3)
+    (debbugs-done . 4)))
+
+(defun debbugs-toggle-sort ()
+  "Toggle sorting by age and by state."
   (interactive)
-  (let (id)
-    (save-excursion
-      (beginning-of-line)
-      (if (not (looking-at " *\\([0-9]+\\)"))
-         (error "No bug report on the current line")
-       (setq id (string-to-number (match-string 1)))))
-    (gnus-read-ephemeral-emacs-bug-group
-     id (cons (current-buffer)
-             (current-window-configuration)))
-    (with-current-buffer (window-buffer (selected-window))
-      (debbugs-summary-mode 1))))
+  (beginning-of-line)
+  (let ((buffer-read-only nil)
+       (before-change-functions nil)
+       (current-bug (debbugs-current-id t)))
+    (setq debbugs-sort-state
+         (if (eq debbugs-sort-state 'number)
+             'state
+           'number))
+    (goto-char (point-min))
+    (while (and (not (eobp))
+               (not (get-text-property (point) 'debbugs-status)))
+      (forward-line 1))
+    (save-restriction
+      (narrow-to-region
+       (point)
+       (progn
+        (goto-char (point-max))
+        (beginning-of-line)
+        (while (and (not (bobp))
+                    (not (get-text-property (point) 'debbugs-status)))
+          (forward-line -1))
+        (forward-line 1)
+        (point)))
+      (goto-char (point-min))
+      (sort-subr
+       nil (lambda () (forward-line 1)) 'end-of-line
+       (lambda ()
+        (if (eq debbugs-sort-state 'number)
+            (debbugs-current-id)
+          (or (cdr (assq (get-text-property (+ (point) 7) 'face)
+                         debbugs-state-preference))
+              10)))))
+    (if (not current-bug)
+       (goto-char (point-max))
+      (goto-char (point-min))
+      (re-search-forward (format "^%d" current-bug) nil t))))
+
+(defvar debbugs-bug-number nil)
+
+(defun debbugs-current-id (&optional noerror)
+  (or (cdr (assq 'id (get-text-property (line-beginning-position)
+                                       'debbugs-status)))
+      (and (not noerror)
+          (error "No bug on the current line"))))
+
+(defun debbugs-display-status (id)
+  "Display the status of the report on the current line."
+  (interactive (list (debbugs-current-id)))
+  (let ((status (get-text-property (line-beginning-position)
+                                  'debbugs-status)))
+    (pop-to-buffer "*Bug Status*")
+    (erase-buffer)
+    (pp status (current-buffer))
+    (goto-char (point-min))))
+
+(defun debbugs-select-report (id)
+  "Select the report on the current line."
+  (interactive (list (debbugs-current-id)))
+  ;; We open the report messages.
+  (gnus-read-ephemeral-emacs-bug-group
+   id (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)))
 
 (defvar debbugs-summary-mode-map
   (let ((map (make-sparse-keymap)))
@@ -212,11 +358,7 @@ fixed, and then closed."
            "merge" "forcemerge"
            "patch" "wontfix" "moreinfo" "unreproducible" "fixed" "notabug")
          nil t)))
-  (let* ((subject (mail-header-subject (gnus-summary-article-header)))
-        (id
-         (if (string-match "bug#\\([0-9]+\\)" subject)
-             (string-to-number (match-string 1 subject))
-           (error "No bug number present")))
+  (let* ((id debbugs-bug-number)       ; Set on group entry.
         (version
          (when (member message '("close" "done"))
            (read-string