diff options
author | Yoni Rabkin <yoni@rabkins.net> | 2020-11-16 20:52:16 -0500 |
---|---|---|
committer | Yoni Rabkin <yoni@rabkins.net> | 2020-11-16 20:52:16 -0500 |
commit | 0ee9eba3a41a1dfc5c79abf5df2439ba5e497030 (patch) | |
tree | b70f39076e921e5d06bf045eed8a82a12f3a5e01 | |
parent | 12d16aa7cccca1a25e7bcd7a41dc7d4755813a3b (diff) |
New file: rt-liberation-viewer
Move the viewer code to its own file.
-rw-r--r-- | rt-liberation-viewer.el | 251 | ||||
-rw-r--r-- | rt-liberation.el | 228 |
2 files changed, 257 insertions, 222 deletions
diff --git a/rt-liberation-viewer.el b/rt-liberation-viewer.el new file mode 100644 index 0000000..e3b6309 --- /dev/null +++ b/rt-liberation-viewer.el @@ -0,0 +1,251 @@ +;;; rt-liberation-viewer.el --- Emacs interface to RT -*- lexical-binding: t; -*- + +;; Copyright (C) 2020 Free Software Foundation, Inc. +;; +;; Authors: Yoni Rabkin <yrk@gnu.org> +;; +;; This file is a part of rt-liberation. +;; +;; This program is free software; you can redistribute it and/or +;; modify it under the terms of the GNU General Public License as +;; published by the Free Software Foundation; either version 3 of the +;; License, or (at your option) any later version. +;; +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public +;; License along with this program; if not, write to the Free +;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +;; MA 02111-1307, USA. + + +;;; Comments: +;; By the end of 2020 is was clear that a more robust way of viewing +;; tickets was preferable. + + +;;; Code: +(require 'rt-liberation) + + +(defconst rt-liber-viewer-font-lock-keywords + (let ((header-regexp (regexp-opt '("id: " "Ticket: " "TimeTaken: " + "Type: " "Field: " "OldValue: " + "NewValue: " "Data: " + "Description: " "Created: " + "Creator: " "Attachments: ") t))) + (list + (list (concat "^" header-regexp ".*$") 0 + 'font-lock-comment-face))) + "Expressions to font-lock for RT ticket viewer.") + + +(defun rt-liber-jump-to-latest-correspondence () + "Move point to the newest correspondence section." + (interactive) + (let (latest-point) + (save-excursion + (goto-char (point-max)) + (when (re-search-backward rt-liber-correspondence-regexp + (point-min) t) + (setq latest-point (point)))) + (if latest-point + (progn + (goto-char latest-point) + (rt-liber-next-section-in-viewer)) + (message "no correspondence found")))) + +(defun rt-liber-viewer-visit-in-browser () + "Visit this ticket in the RT Web interface." + (interactive) + (let ((id (rt-liber-ticket-id-only rt-liber-ticket-local))) + (if id + (browse-url + (concat rt-liber-base-url "Ticket/Display.html?id=" id)) + (error "no ticket currently in view")))) + +(defun rt-liber-display-ticket-history (ticket-alist &optional assoc-browser) + "Display history for ticket. + +TICKET-ALIST alist of ticket data. +ASSOC-BROWSER if non-nil should be a ticket browser." + (let* ((ticket-id (rt-liber-ticket-id-only ticket-alist)) + (contents (rt-liber-rest-run-ticket-history-base-query ticket-id)) + (new-ticket-buffer (get-buffer-create + (concat "*RT Ticket #" ticket-id "*")))) + (with-current-buffer new-ticket-buffer + (let ((inhibit-read-only t)) + (erase-buffer) + (insert contents) + (goto-char (point-min)) + (rt-liber-viewer-mode) + (set + (make-local-variable 'rt-liber-ticket-local) + ticket-alist) + (when assoc-browser + (set + (make-local-variable 'rt-liber-assoc-browser) + assoc-browser)) + (set-buffer-modified-p nil) + (setq buffer-read-only t))) + (switch-to-buffer new-ticket-buffer))) + +(defun rt-liber-viewer-mode-quit () + "Bury the ticket viewer." + (interactive) + (bury-buffer)) + +(defun rt-liber-viewer-show-ticket-browser () + "Return to the ticket browser buffer." + (interactive) + (let ((id (rt-liber-ticket-id-only rt-liber-ticket-local))) + (if id + (let ((target-buffer + (if rt-liber-assoc-browser + (buffer-name rt-liber-assoc-browser) + (buffer-name rt-liber-browser-buffer-name)))) + (if target-buffer + (switch-to-buffer target-buffer) + (error "associated ticket browser buffer no longer exists")) + (rt-liber-browser-move-point-to-ticket id)) + (error "no ticket currently in view")))) + +(defun rt-liber-next-section-in-viewer () + "Move point to next section." + (interactive) + (forward-line 1) + (when (not (re-search-forward rt-liber-content-regexp (point-max) t)) + (message "no next section")) + (goto-char (point-at-bol))) + +(defun rt-liber-previous-section-in-viewer () + "Move point to previous section." + (interactive) + (forward-line -1) + (when (not (re-search-backward rt-liber-content-regexp (point-min) t)) + (message "no previous section")) + (goto-char (point-at-bol))) + +(defconst rt-liber-viewer-mode-map + (let ((map (make-sparse-keymap))) + (define-key map (kbd "q") 'rt-liber-viewer-mode-quit) + (define-key map (kbd "n") 'rt-liber-next-section-in-viewer) + (define-key map (kbd "N") 'rt-liber-jump-to-latest-correspondence) + (define-key map (kbd "p") 'rt-liber-previous-section-in-viewer) + (define-key map (kbd "V") 'rt-liber-viewer-visit-in-browser) + (define-key map (kbd "m") 'rt-liber-viewer-answer) + (define-key map (kbd "M") 'rt-liber-viewer-answer-this) + (define-key map (kbd "t") 'rt-liber-viewer-answer-provisionally) + (define-key map (kbd "T") 'rt-liber-viewer-answer-provisionally-this) + (define-key map (kbd "F") 'rt-liber-viewer-answer-verbatim-this) + (define-key map (kbd "c") 'rt-liber-viewer-comment) + (define-key map (kbd "C") 'rt-liber-viewer-comment-this) + (define-key map (kbd "g") 'revert-buffer) + (define-key map (kbd "SPC") 'scroll-up) + (define-key map (kbd "DEL") 'scroll-down) + (define-key map (kbd "h") 'rt-liber-viewer-show-ticket-browser) + map) + "Key map for ticket viewer.") + +(define-derived-mode rt-liber-viewer-mode nil + "RT Liberation Viewer" + "Major Mode for viewing RT tickets. +\\{rt-liber-viewer-mode-map}" + (set + (make-local-variable 'font-lock-defaults) + '((rt-liber-viewer-font-lock-keywords))) + (set (make-local-variable 'revert-buffer-function) + #'rt-liber-refresh-ticket-history) + (set (make-local-variable 'buffer-stale-function) + (lambda (&optional _noconfirm) 'slow)) + (when rt-liber-jump-to-latest + (rt-liber-jump-to-latest-correspondence)) + (run-hooks 'rt-liber-viewer-hook)) + +(defun rt-liber-refresh-ticket-history (&optional _ignore-auto _noconfirm) + (interactive) + (if rt-liber-ticket-local + (rt-liber-display-ticket-history rt-liber-ticket-local + rt-liber-assoc-browser) + (error "not viewing a ticket"))) + +;; wrapper functions around specific functions provided by a backend + +(declare-function + rt-liber-gnus-compose-reply-to-requestor + "rt-liberation-gnus.el") +(declare-function + rt-liber-gnus-compose-reply-to-requestor-to-this + "rt-liberation-gnus.el") +(declare-function + rt-liber-gnus-compose-reply-to-requestor-verbatim-this + "rt-liberation-gnus.el") +(declare-function + rt-liber-gnus-compose-provisional + "rt-liberation-gnus.el") +(declare-function + rt-liber-gnus-compose-provisional-to-this + "rt-liberation-gnus.el") +(declare-function + rt-liber-gnus-compose-comment + "rt-liberation-gnus.el") +(declare-function + rt-liber-gnus-compose-comment-this + "rt-liberation-gnus.el") + +(defun rt-liber-viewer-answer () + "Answer the ticket." + (interactive) + (cond ((featurep 'rt-liberation-gnus) + (rt-liber-gnus-compose-reply-to-requestor)) + (t (error "no function defined")))) + +(defun rt-liber-viewer-answer-this () + "Answer the ticket using the current context." + (interactive) + (cond ((featurep 'rt-liberation-gnus) + (rt-liber-gnus-compose-reply-to-requestor-to-this)) + (t (error "no function defined")))) + +(defun rt-liber-viewer-answer-verbatim-this () + "Answer the ticket using the current context verbatim." + (interactive) + (cond ((featurep 'rt-liberation-gnus) + (rt-liber-gnus-compose-reply-to-requestor-verbatim-this)) + (t (error "no function defined")))) + +(defun rt-liber-viewer-answer-provisionally () + "Provisionally answer the ticket." + (interactive) + (cond ((featurep 'rt-liberation-gnus) + (rt-liber-gnus-compose-provisional)) + (t (error "no function defined")))) + +(defun rt-liber-viewer-answer-provisionally-this () + "Provisionally answer the ticket using the current context." + (interactive) + (cond ((featurep 'rt-liberation-gnus) + (rt-liber-gnus-compose-provisional-to-this)) + (t (error "no function defined")))) + +(defun rt-liber-viewer-comment () + "Comment on the ticket." + (interactive) + (cond ((featurep 'rt-liberation-gnus) + (rt-liber-gnus-compose-comment)) + (t (error "no function defined")))) + +(defun rt-liber-viewer-comment-this () + "Comment on the ticket using the current context." + (interactive) + (cond ((featurep 'rt-liberation-gnus) + (rt-liber-gnus-compose-comment-this)) + (t (error "no function defined")))) + + +(provide 'rt-liberation-viewer) + +;;; rt-liberation-viewer.el ends here. diff --git a/rt-liberation.el b/rt-liberation.el index 086e14f..ef3c84f 100644 --- a/rt-liberation.el +++ b/rt-liberation.el @@ -45,6 +45,8 @@ (require 'rt-liberation-rest) +(declare-function rt-liber-display-ticket-history "rt-liberation-viewer.el" (ticket-alist &optional assoc-browser)) + (defgroup rt-liber nil "*rt-liberation, the Emacs interface to RT" @@ -163,17 +165,6 @@ function returns a truth value.") (t (:background "Black"))) "Face for high priority tickets in browser buffer.") -(defconst rt-liber-viewer-font-lock-keywords - (let ((header-regexp (regexp-opt '("id: " "Ticket: " "TimeTaken: " - "Type: " "Field: " "OldValue: " - "NewValue: " "Data: " - "Description: " "Created: " - "Creator: " "Attachments: ") t))) - (list - (list (concat "^" header-regexp ".*$") 0 - 'font-lock-comment-face))) - "Expressions to font-lock for RT ticket viewer.") - (defvar rt-liber-browser-do-refresh t "When t, run `rt-liber-browser-refresh' otherwise disable it.") @@ -445,26 +436,6 @@ AFTER date after predicate." (<= rt-liber-ticket-old-threshold (rt-liber-ticket-days-old ticket-alist))) - -;;; -------------------------------------------------------- -;;; Ticket viewer -;;; -------------------------------------------------------- - -(defun rt-liber-jump-to-latest-correspondence () - "Move point to the newest correspondence section." - (interactive) - (let (latest-point) - (save-excursion - (goto-char (point-max)) - (when (re-search-backward rt-liber-correspondence-regexp - (point-min) t) - (setq latest-point (point)))) - (if latest-point - (progn - (goto-char latest-point) - (rt-liber-next-section-in-viewer)) - (message "no correspondence found")))) - (defun rt-liber-ticket-id-only (ticket-alist) "Return numerical portion of ticket number from TICKET-ALIST." (if ticket-alist @@ -480,11 +451,6 @@ AFTER date after predicate." nil)) nil)) -(defun rt-liber-get-field-string (field-symbol) - (when (not field-symbol) - (error "null field symbol")) - (cdr (assoc field-symbol rt-liber-field-dictionary))) - (defun rt-liber-ticket-owner-only (ticket-alist) "Return the string value of the ticket owner." (when (not ticket-alist) @@ -492,192 +458,10 @@ AFTER date after predicate." (cdr (assoc (rt-liber-get-field-string 'owner) ticket-alist))) -(defun rt-liber-viewer-visit-in-browser () - "Visit this ticket in the RT Web interface." - (interactive) - (let ((id (rt-liber-ticket-id-only rt-liber-ticket-local))) - (if id - (browse-url - (concat rt-liber-base-url "Ticket/Display.html?id=" id)) - (error "no ticket currently in view")))) - -(defun rt-liber-viewer-mode-quit () - "Bury the ticket viewer." - (interactive) - (bury-buffer)) - -(defun rt-liber-viewer-show-ticket-browser () - "Return to the ticket browser buffer." - (interactive) - (let ((id (rt-liber-ticket-id-only rt-liber-ticket-local))) - (if id - (let ((target-buffer - (if rt-liber-assoc-browser - (buffer-name rt-liber-assoc-browser) - (buffer-name rt-liber-browser-buffer-name)))) - (if target-buffer - (switch-to-buffer target-buffer) - (error "associated ticket browser buffer no longer exists")) - (rt-liber-browser-move-point-to-ticket id)) - (error "no ticket currently in view")))) - -(defun rt-liber-next-section-in-viewer () - "Move point to next section." - (interactive) - (forward-line 1) - (when (not (re-search-forward rt-liber-content-regexp (point-max) t)) - (message "no next section")) - (goto-char (point-at-bol))) - -(defun rt-liber-previous-section-in-viewer () - "Move point to previous section." - (interactive) - (forward-line -1) - (when (not (re-search-backward rt-liber-content-regexp (point-min) t)) - (message "no previous section")) - (goto-char (point-at-bol))) - -(defconst rt-liber-viewer-mode-map - (let ((map (make-sparse-keymap))) - (define-key map (kbd "q") 'rt-liber-viewer-mode-quit) - (define-key map (kbd "n") 'rt-liber-next-section-in-viewer) - (define-key map (kbd "N") 'rt-liber-jump-to-latest-correspondence) - (define-key map (kbd "p") 'rt-liber-previous-section-in-viewer) - (define-key map (kbd "V") 'rt-liber-viewer-visit-in-browser) - (define-key map (kbd "m") 'rt-liber-viewer-answer) - (define-key map (kbd "M") 'rt-liber-viewer-answer-this) - (define-key map (kbd "t") 'rt-liber-viewer-answer-provisionally) - (define-key map (kbd "T") 'rt-liber-viewer-answer-provisionally-this) - (define-key map (kbd "F") 'rt-liber-viewer-answer-verbatim-this) - (define-key map (kbd "c") 'rt-liber-viewer-comment) - (define-key map (kbd "C") 'rt-liber-viewer-comment-this) - (define-key map (kbd "g") 'revert-buffer) - (define-key map (kbd "SPC") 'scroll-up) - (define-key map (kbd "DEL") 'scroll-down) - (define-key map (kbd "h") 'rt-liber-viewer-show-ticket-browser) - map) - "Key map for ticket viewer.") - -(define-derived-mode rt-liber-viewer-mode nil - "RT Liberation Viewer" - "Major Mode for viewing RT tickets. -\\{rt-liber-viewer-mode-map}" - (set - (make-local-variable 'font-lock-defaults) - '((rt-liber-viewer-font-lock-keywords))) - (set (make-local-variable 'revert-buffer-function) - #'rt-liber-refresh-ticket-history) - (set (make-local-variable 'buffer-stale-function) - (lambda (&optional _noconfirm) 'slow)) - (when rt-liber-jump-to-latest - (rt-liber-jump-to-latest-correspondence)) - (run-hooks 'rt-liber-viewer-hook)) - -(defun rt-liber-display-ticket-history (ticket-alist &optional assoc-browser) - "Display history for ticket. - -TICKET-ALIST alist of ticket data. -ASSOC-BROWSER if non-nil should be a ticket browser." - (let* ((ticket-id (rt-liber-ticket-id-only ticket-alist)) - (contents (rt-liber-rest-run-ticket-history-base-query ticket-id)) - (new-ticket-buffer (get-buffer-create - (concat "*RT Ticket #" ticket-id "*")))) - (with-current-buffer new-ticket-buffer - (let ((inhibit-read-only t)) - (erase-buffer) - (insert contents) - (goto-char (point-min)) - (rt-liber-viewer-mode) - (set - (make-local-variable 'rt-liber-ticket-local) - ticket-alist) - (when assoc-browser - (set - (make-local-variable 'rt-liber-assoc-browser) - assoc-browser)) - (set-buffer-modified-p nil) - (setq buffer-read-only t))) - (switch-to-buffer new-ticket-buffer))) - -(defun rt-liber-refresh-ticket-history (&optional _ignore-auto _noconfirm) - (interactive) - (if rt-liber-ticket-local - (rt-liber-display-ticket-history rt-liber-ticket-local - rt-liber-assoc-browser) - (error "not viewing a ticket"))) - -;; wrapper functions around specific functions provided by a backend - -(declare-function - rt-liber-gnus-compose-reply-to-requestor - "rt-liberation-gnus.el") -(declare-function - rt-liber-gnus-compose-reply-to-requestor-to-this - "rt-liberation-gnus.el") -(declare-function - rt-liber-gnus-compose-reply-to-requestor-verbatim-this - "rt-liberation-gnus.el") -(declare-function - rt-liber-gnus-compose-provisional - "rt-liberation-gnus.el") -(declare-function - rt-liber-gnus-compose-provisional-to-this - "rt-liberation-gnus.el") -(declare-function - rt-liber-gnus-compose-comment - "rt-liberation-gnus.el") -(declare-function - rt-liber-gnus-compose-comment-this - "rt-liberation-gnus.el") - -(defun rt-liber-viewer-answer () - "Answer the ticket." - (interactive) - (cond ((featurep 'rt-liberation-gnus) - (rt-liber-gnus-compose-reply-to-requestor)) - (t (error "no function defined")))) - -(defun rt-liber-viewer-answer-this () - "Answer the ticket using the current context." - (interactive) - (cond ((featurep 'rt-liberation-gnus) - (rt-liber-gnus-compose-reply-to-requestor-to-this)) - (t (error "no function defined")))) - -(defun rt-liber-viewer-answer-verbatim-this () - "Answer the ticket using the current context verbatim." - (interactive) - (cond ((featurep 'rt-liberation-gnus) - (rt-liber-gnus-compose-reply-to-requestor-verbatim-this)) - (t (error "no function defined")))) - -(defun rt-liber-viewer-answer-provisionally () - "Provisionally answer the ticket." - (interactive) - (cond ((featurep 'rt-liberation-gnus) - (rt-liber-gnus-compose-provisional)) - (t (error "no function defined")))) - -(defun rt-liber-viewer-answer-provisionally-this () - "Provisionally answer the ticket using the current context." - (interactive) - (cond ((featurep 'rt-liberation-gnus) - (rt-liber-gnus-compose-provisional-to-this)) - (t (error "no function defined")))) - -(defun rt-liber-viewer-comment () - "Comment on the ticket." - (interactive) - (cond ((featurep 'rt-liberation-gnus) - (rt-liber-gnus-compose-comment)) - (t (error "no function defined")))) - -(defun rt-liber-viewer-comment-this () - "Comment on the ticket using the current context." - (interactive) - (cond ((featurep 'rt-liberation-gnus) - (rt-liber-gnus-compose-comment-this)) - (t (error "no function defined")))) +(defun rt-liber-get-field-string (field-symbol) + (when (not field-symbol) + (error "null field symbol")) + (cdr (assoc field-symbol rt-liber-field-dictionary))) ;;; -------------------------------------------------------- |