diff options
Diffstat (limited to 'sx-question-list.el')
-rw-r--r-- | sx-question-list.el | 141 |
1 files changed, 97 insertions, 44 deletions
diff --git a/sx-question-list.el b/sx-question-list.el index 72eabd3..9e94536 100644 --- a/sx-question-list.el +++ b/sx-question-list.el @@ -28,6 +28,7 @@ (require 'sx-site) (require 'sx-question) (require 'sx-question-mode) +(require 'sx-favorites) ;;; Customization @@ -86,6 +87,11 @@ "" :group 'sx-question-list-faces) +(defface sx-question-list-favorite + '((t :inherit sx-question-list-score-upvoted)) + "" + :group 'sx-question-list-faces) + ;;; Mode Definition (define-derived-mode sx-question-list-mode tabulated-list-mode "Question List" @@ -132,10 +138,35 @@ Letters do not insert themselves; instead, they are commands. ("g" sx-question-list-refresh) (":" sx-question-list-switch-site) ("v" sx-question-list-visit) + ("h" sx-question-list-hide) + ("m" sx-question-list-mark-read) ([?\r] sx-question-list-display-question))) +(defun sx-question-list-hide (data) + "Hide question under point. +Non-interactively, DATA is a question alist." + (interactive + (list (if (derived-mode-p 'sx-question-list-mode) + (tabulated-list-get-id) + (user-error "Not in `sx-question-list-mode'")))) + (sx-question--mark-hidden data) + (when (called-interactively-p 'any) + (sx-question-list-refresh 'redisplay 'noupdate))) + +(defun sx-question-list-mark-read (data) + "Mark as read question under point. +Non-interactively, DATA is a question alist." + (interactive + (list (if (derived-mode-p 'sx-question-list-mode) + (tabulated-list-get-id) + (user-error "Not in `sx-question-list-mode'")))) + (sx-question--mark-read data) + (sx-question-list-next 1) + (when (called-interactively-p 'any) + (sx-question-list-refresh 'redisplay 'noupdate))) + (defvar sx-question-list--current-page "Latest" - ;; Other values (once we implement them) are "Top Voted", + ;; @TODO Other values (once we implement them) are "Top Voted", ;; "Unanswered", etc. "Variable describing current page being viewed.") @@ -179,7 +210,9 @@ Letters do not insert themselves; instead, they are commands. "Site being displayed in the *question-list* buffer.") (defvar sx-question-list--current-dataset nil - "") + "The logical data behind the displayed list of questions. +This dataset contains even questions that are hidden by the user, +and thus not displayed in the list of questions.") (defun sx-question-list-refresh (&optional redisplay no-update) "Update the list of questions. @@ -197,7 +230,8 @@ a new list before redisplaying." (setq sx-question-list--current-dataset question-list) ;; Print the result. (setq tabulated-list-entries - (mapcar #'sx-question-list--print-info question-list))) + (mapcar #'sx-question-list--print-info + (cl-remove-if #'sx-question--hidden-p question-list)))) (when redisplay (tabulated-list-print 'remember))) (defun sx-question-list-visit (&optional data) @@ -212,67 +246,81 @@ a new list before redisplaying." (defcustom sx-question-list-ago-string " ago" "String appended to descriptions of the time since something happened. -Used in the questions list to indicate a question was updated \"4d ago\"." +Used in the questions list to indicate a question was updated +\"4d ago\"." :type 'string :group 'sx-question-list) -(defun sx-question-list--print-info (data) - "Convert `json-read' DATA into tabulated-list format." - (sx-assoc-let data - (list - data - (vector - (list (int-to-string .score) - 'face (if .upvoted 'sx-question-list-score-upvoted - 'sx-question-list-score)) - (list (int-to-string .answer_count) - 'face (if (sx-question--accepted-answer-id data) - 'sx-question-list-answers-accepted - 'sx-question-list-answers)) - (concat - (propertize - .title - 'face (if (sx-question--read-p data) - 'sx-question-list-read-question - ;; Increment `sx-question-list--unread-count' for the mode-line. - (cl-incf sx-question-list--unread-count) - 'sx-question-list-unread-question)) - (propertize " " 'display "\n ") - (propertize (concat (sx-time-since .last_activity_date) - sx-question-list-ago-string) - 'face 'sx-question-list-date) - " " - (propertize (mapconcat #'sx-question--tag-format .tags " ") - 'face 'sx-question-list-tags) - (propertize " " 'display "\n")))))) +(defun sx-question-list--print-info (question-data) + "Convert `json-read' QUESTION-DATA into tabulated-list format. +See `sx-question-list-refresh'." + (sx-assoc-let question-data + (let ((favorite (if (member .question_id + (assoc .site + sx-favorites--user-favorite-list)) + (if (char-displayable-p ?\x2b26) "\x2b26" "*") " "))) + (list + question-data + (vector + (list (int-to-string .score) + 'face (if .upvoted 'sx-question-list-score-upvoted + 'sx-question-list-score)) + (list (int-to-string .answer_count) + 'face (if (sx-question--accepted-answer-id question-data) + 'sx-question-list-answers-accepted + 'sx-question-list-answers)) + (concat + (propertize + .title + 'face (if (sx-question--read-p question-data) + 'sx-question-list-read-question + ;; Increment `sx-question-list--unread-count' for + ;; the mode-line. + (cl-incf sx-question-list--unread-count) + 'sx-question-list-unread-question)) + (propertize " " 'display "\n ") + (propertize favorite 'face 'sx-question-list-favorite) + " " + (propertize (concat (sx-time-since .last_activity_date) + sx-question-list-ago-string) + 'face 'sx-question-list-date) + " " + (propertize (mapconcat #'sx-question--tag-format .tags " ") + 'face 'sx-question-list-tags) + (propertize " " 'display "\n"))))))) (defun sx-question-list-view-previous (n) - "Hide this question, move to previous one, display it." + "Move cursor up N questions up and display this question. +Displayed in `sx-question-mode--window', replacing any question +that may currently be there." (interactive "p") (sx-question-list-view-next (- n))) (defun sx-question-list-view-next (n) - "Hide this question, move to next one, display it." + "Move cursor down N questions and display this question. +Displayed in `sx-question-mode--window', replacing any question +that may currently be there." (interactive "p") (sx-question-list-next n) (sx-question-list-display-question)) (defun sx-question-list-next (n) - "Move to the next entry." + "Move cursor down N questions. +This does not update `sx-question-mode--window'." (interactive "p") (forward-line n)) (defun sx-question-list-previous (n) - "Move to the previous entry." + "Move cursor up N questions. +This does not update `sx-question-mode--window'." (interactive "p") (sx-question-list-next (- n))) (defun sx-question-list-display-question (&optional data focus) "Display question given by DATA. -If called interactively (or with DATA being nil), display -question under point. -Also when called interactively (or when FOCUS is non-nil), also -focus the relevant window." +When DATA is nil, display question under point. When FOCUS is +non-nil (the default when called interactively), also focus the +relevant window." (interactive '(nil t)) (unless data (setq data (tabulated-list-get-id))) (unless data (error "No question here!")) @@ -299,7 +347,7 @@ focus the relevant window." (set-window-parameter sx-question-mode--window 'quit-restore - ;; See https://www.gnu.org/software/emacs/manual/html_node/elisp/Window-Parameters.html#Window-Parameters + ;; See (info "(elisp) Window Parameters") `(window window ,(selected-window) ,sx-question-mode--buffer)) (when focus (if sx-question-mode--window @@ -307,7 +355,11 @@ focus the relevant window." (switch-to-buffer sx-question-mode--buffer)))) (defun sx-question-list-switch-site (site) - "Switch the current site to SITE and display its questions" + "Switch the current site to SITE and display its questions. +Uses `ido-completing-read' if variable `ido-mode' is active. Retrieves +completions from `sx-site-get-api-tokens'. Sets +`sx-question-list--current-site' and then +`sx-question-list-refresh' with `redisplay'." (interactive (list (funcall (if ido-mode #'ido-completing-read #'completing-read) "Switch to site: " (sx-site-get-api-tokens) @@ -321,7 +373,8 @@ focus the relevant window." "Buffer where the list of questions is displayed.") (defun list-questions (no-update) - "Display a list of StackExchange questions." + "Display a list of StackExchange questions. +NO-UPDATE is passed to `sx-question-list-refresh'." (interactive "P") (sx-initialize) (unless (buffer-live-p sx-question-list--buffer) |