aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sx-question-list.el15
-rw-r--r--sx-question.el52
-rw-r--r--sx.el15
3 files changed, 78 insertions, 4 deletions
diff --git a/sx-question-list.el b/sx-question-list.el
index dead68f..7dd0d00 100644
--- a/sx-question-list.el
+++ b/sx-question-list.el
@@ -138,8 +138,20 @@ 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)
([?\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)))
+
(defvar sx-question-list--current-page "Latest"
;; Other values (once we implement them) are "Top Voted",
;; "Unanswered", etc.
@@ -203,7 +215,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)
diff --git a/sx-question.el b/sx-question.el
index 6ef9484..972e9d9 100644
--- a/sx-question.el
+++ b/sx-question.el
@@ -68,6 +68,7 @@
;;; Question Properties
+;;;; Read/unread
(defvar sx-question--user-read-list nil
"Alist of questions read by the user.
Each element has the form (SITE . QUESTION-LIST).
@@ -78,7 +79,7 @@ And each element in QUESTION-LIST has the form (QUESTION_ID . LAST-VIEWED-DATE).
If no cache exists for it, initialize one with SITE."
(unless sx-question--user-read-list
(setq sx-question--user-read-list
- (sx-cache-get 'read-questions `(list ,site)))))
+ (sx-cache-get 'read-questions `'((,site))))))
(defun sx-question--read-p (question)
"Non-nil if QUESTION has been read since last updated."
@@ -104,13 +105,58 @@ If no cache exists for it, initialize one with SITE."
((setq cell (assoc .question_id site-cell))
(setcdr cell .last_activity_date))
;; Question wasn't present.
- (t
- (setcdr site-cell (cons q-cell (cdr site-cell)))))))
+ (t
+ (sx-sorted-insert-skip-first
+ q-cell site-cell (lambda (x y) (> (car x) (car y))))))))
;; This causes a small lag on `j' and `k' as the list gets large.
;; Should we do this on a timer?
;; Save the results.
(sx-cache-set 'read-questions sx-question--user-read-list))
+
+;;;; Hidden
+(defvar sx-question--user-hidden-list nil
+ "Alist of questions hidden by the user.
+Each element has the form (SITE . QUESTION-LIST).
+And each element in QUESTION-LIST has the form (QUESTION_ID . LAST-VIEWED-DATE).")
+
+(defun sx-question--ensure-hidden-list (site)
+ "Ensure the `sx-question--user-hidden-list' has been read from cache.
+If no cache exists for it, initialize one with SITE."
+ (unless sx-question--user-hidden-list
+ (setq sx-question--user-hidden-list
+ (sx-cache-get 'hidden-questions `'((,site))))))
+
+(defun sx-question--hidden-p (question)
+ "Non-nil if QUESTION has been hidden."
+ (sx-assoc-let question
+ (sx-question--ensure-hidden-list .site)
+ (let ((ql (cdr (assoc .site sx-question--user-hidden-list))))
+ (and ql (memq .question_id ql)))))
+
+(defun sx-question--mark-hidden (question)
+ "Mark QUESTION as being hidden."
+ (sx-assoc-let question
+ (sx-question--ensure-hidden-list .site)
+ (let ((site-cell (assoc .site sx-question--user-hidden-list))
+ cell)
+ ;; If question already hidden, do nothing.
+ (unless (memq .question_id site-cell)
+ ;; First question from this site.
+ (if (null site-cell)
+ (push (list .site .question_id) sx-question--user-hidden-list)
+ ;; Question wasn't present.
+ ;; Add it in, but make sure it's sorted (just in case we need
+ ;; it later).
+ (sx-sorted-insert-skip-first .question_id site-cell >))
+ ;; This causes a small lag on `j' and `k' as the list gets large.
+ ;; Should we do this on a timer?
+ ;; Save the results.
+ (sx-cache-set 'hidden-questions sx-question--user-hidden-list)))))
+
+
+;;;; Other data
+
(defun sx-question--accepted-answer-id (question)
"Return accepted answer in QUESTION, or nil if none."
(sx-assoc-let question
diff --git a/sx.el b/sx.el
index 64c555c..387c6bb 100644
--- a/sx.el
+++ b/sx.el
@@ -27,6 +27,21 @@
;;; Utility Functions
+(defmacro sx-sorted-insert-skip-first (newelt list &optional predicate)
+ "Inserted NEWELT into LIST sorted by PREDICATE.
+This is designed for the (site id id ...) lists. So the first car
+is intentionally skipped."
+ `(let ((tail ,list)
+ (x ,newelt))
+ ;; The first element is never less-than.
+ (while (and
+ ;; We're at the end.
+ (cdr-safe tail)
+ ;; We're at the right place.
+ (,(or predicate #'<) x (cadr tail)))
+ (setq tail (cdr tail)))
+ (setcdr tail (cons x (cdr tail)))))
+
(defun sx-message (format-string &rest args)
"Display a message"
(message "[stack] %s" (apply #'format format-string args)))