(require 'url) (defconst bugzilla-show-bug-url-format "https://bugzilla.mozilla.org/show_bug.cgi?id=%s") (defvar bugzilla-previous-buffer nil) (defun bugzilla-get-bug (n) (if (buffer-live-p bugzilla-previous-buffer) (kill-buffer bugzilla-previous-buffer)) (setq bugzilla-previous-buffer (url-retrieve-synchronously (format bugzilla-show-bug-url-format n)))) (defun bugzilla-bug-number (prompt) "Prompt for a bug number, defaulting to the number near point (if any)." (let ((default (save-excursion (unless (looking-at "\\<") (backward-word)) (when (looking-at "\\<[0-9]+\\>") (string-to-number (match-string 0)))))) (read-number (concat prompt ": ") default))) (defun bugzilla-bug-title (n) "Return the title of Bugzilla bug N." (let ((buffer (bugzilla-get-bug n))) (save-excursion (set-buffer buffer) (goto-char (point-min)) (re-search-forward "") (let ((start (point))) (re-search-forward "") (narrow-to-region start (match-beginning 0)) (goto-char (point-min)) (while (re-search-forward "&\\([a-z]+\\);" nil t) (let* ((name (match-string 1)) (def (assoc name '(("quot" . "\"") ("ndash" . " -- ") ("gt" . ">") ("lt" . "<") ("amp" . "&"))))) (when def (delete-region (match-beginning 0) (match-end 0)) (insert (cdr def))))) (goto-char (point-min)) (while (re-search-forward "&#\\([0-9a-z]+\\);" nil t) (let ((code (string-to-number (match-string 1)))) (delete-region (match-beginning 0) (match-end 0)) (insert-char code 1))) (buffer-substring (point-min) (point-max)))))) (defun bugzilla-insert-heading (omit-url n) "Insert a bug header for a 1-on-1 notes message. With a prefix argument, omit the URL." (interactive (list current-prefix-arg (bugzilla-bug-number "Bug number"))) (let ((title (bugzilla-bug-title n))) (push-mark (point)) (insert title "\n") (if (not omit-url) (insert (format bugzilla-show-bug-url-format n) "\n")))) (provide 'bugzilla)