aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSean Allred <code@seanallred.com>2014-11-15 06:58:47 -0500
committerSean Allred <code@seanallred.com>2014-11-15 06:58:47 -0500
commitf2ebbd3aa4916a27b2368a56046c33eea88058b7 (patch)
tree089262aa9f9705eba643d722bd220f0b886a4827
parentec23bfbfe7509757686d2d6f07c30b4f26eb7973 (diff)
parenta4ea5464e2141c7d5e2ff3692313a8bdf1177757 (diff)
Merge pull request #55 from vermiculus/real-scores
Use real data for mark-as-read
-rw-r--r--sx-question-list.el33
-rw-r--r--sx-question-mode.el5
-rw-r--r--sx-question.el64
3 files changed, 76 insertions, 26 deletions
diff --git a/sx-question-list.el b/sx-question-list.el
index c6d298a..b220097 100644
--- a/sx-question-list.el
+++ b/sx-question-list.el
@@ -51,11 +51,7 @@
:group 'sx-question-list-faces)
(defface sx-question-list-answers-accepted
- '((((background light)) :background "YellowGreen"
- :inherit sx-question-list-answers)
- (((background dark)) :background "DarkOliveGreen"
- :inherit sx-question-list-answers)
- (t :inherit sx-question-list-answers))
+ '((t :underline t :overline t :inherit sx-question-list-answers))
""
:group 'sx-question-list-faces)
@@ -187,10 +183,10 @@ Letters do not insert themselves; instead, they are commands.
(defun sx-question-list-refresh (&optional redisplay no-update)
"Update the list of questions.
-If REDISPLAY is non-nil, also call `tabulated-list-print'.
+If REDISPLAY is non-nil (or if interactive), also call `tabulated-list-print'.
If the prefix argument NO-UPDATE is nil, query StackExchange for
a new list before redisplaying."
- (interactive "pP")
+ (interactive "p\nP")
;; Reset the mode-line unread count (we rebuild it here).
(setq sx-question-list--unread-count 0)
(let ((question-list
@@ -210,7 +206,9 @@ a new list before redisplaying."
(unless data (setq data (tabulated-list-get-id)))
(unless data (error "No question here!"))
(sx-assoc-let data
- (browse-url .link)))
+ (browse-url .link))
+ (sx-question--mark-read data)
+ (sx-question-list-refresh 'redisplay 'no-update))
(defcustom sx-question-list-ago-string " ago"
"String appended to descriptions of the time since something happened.
@@ -228,13 +226,13 @@ Used in the questions list to indicate a question was updated \"4d ago\"."
'face (if .upvoted 'sx-question-list-score-upvoted
'sx-question-list-score))
(list (int-to-string .answer_count)
- 'face (if (sx-question--accepted-answer .data)
+ '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)
+ '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)
@@ -278,14 +276,15 @@ focus the relevant window."
(interactive '(nil t))
(unless data (setq data (tabulated-list-get-id)))
(unless data (error "No question here!"))
- (when (sx-question--read-p data)
+ (unless (sx-question--read-p data)
(cl-decf sx-question-list--unread-count)
- (sx-question--mark-read data))
+ (sx-question--mark-read data)
+ (sx-question-list-refresh 'redisplay 'no-update))
(unless (and (window-live-p sx-question-mode--window)
(null (equal sx-question-mode--window (selected-window))))
(setq sx-question-mode--window
(condition-case er
- (split-window-below sx-question-list-height)
+ (split-window (selected-window) sx-question-list-height 'below)
(error
;; If the window is too small to split, use current one.
(if (string-match
@@ -293,7 +292,15 @@ focus the relevant window."
(car (cdr-safe er)))
nil
(error (cdr er)))))))
+ ;; Display the question.
(sx-question-mode--display data sx-question-mode--window)
+ ;; Configure the window to be closed on `q'.
+ (set-window-prev-buffers sx-question-mode--window nil)
+ (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
+ `(window window ,(selected-window) ,sx-question-mode--buffer))
(when focus
(if sx-question-mode--window
(select-window sx-question-mode--window)
diff --git a/sx-question-mode.el b/sx-question-mode.el
index 39d352e..32cd112 100644
--- a/sx-question-mode.el
+++ b/sx-question-mode.el
@@ -526,6 +526,11 @@ If DIRECTION is negative, move backwards instead."
Letters do not insert themselves; instead, they are commands.
\\<sx-question-mode>
\\{sx-question-mode}"
+ ;; Determine how to close this window.
+ (unless (window-parameter nil 'quit-restore)
+ (set-window-parameter
+ nil 'quit-restore
+ `(other window nil ,(current-buffer))))
;; We call font-lock-region manually. See `sx-question-mode--fill-and-fontify'
(font-lock-mode -1)
(remove-hook 'after-change-functions 'markdown-check-change-for-wiki-link t)
diff --git a/sx-question.el b/sx-question.el
index 2fa9d2b..fc44bd8 100644
--- a/sx-question.el
+++ b/sx-question.el
@@ -33,6 +33,7 @@
question.comments
question.answers
question.last_editor
+ question.accepted_answer_id
user.display_name
comment.owner
comment.body_markdown
@@ -45,11 +46,13 @@
(defun sx-question-get-questions (site &optional page)
"Get the page PAGE of questions from SITE."
- (sx-method-call
- "questions"
- `((site . ,site)
- (page . ,page))
- sx-question-browse-filter))
+ (mapcar
+ (lambda (question) (cons (cons 'site site) question))
+ (sx-method-call
+ "questions"
+ `((site . ,site)
+ (page . ,page))
+ sx-question-browse-filter)))
(defun sx-question-get-question (site id)
"Get the question ID from SITE."
@@ -63,19 +66,54 @@
;;; Question Properties
+(defvar sx-question--user-read-list nil
+ "Alist of questions read 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-read-list (site)
+ "Ensure the `sx-question--user-read-list' has been read from cache.
+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)))))
+
(defun sx-question--read-p (question)
"Non-nil if QUESTION has been read since last updated."
- ;; @TODO:
- (cl-evenp (random)))
-
-(defun sx-question--accepted-answer (question)
- "Return accepted answer in QUESTION, or nil if none."
- ;; @TODO:
- (cl-evenp (random)))
+ (sx-assoc-let question
+ (sx-question--ensure-read-list .site)
+ (let ((ql (cdr (assoc .site sx-question--user-read-list))))
+ (and ql
+ (>= (or (cdr (assoc .question_id ql)) 0)
+ .last_activity_date)))))
(defun sx-question--mark-read (question)
"Mark QUESTION as being read, until it is updated again."
- nil)
+ (sx-assoc-let question
+ (sx-question--ensure-read-list .site)
+ (let ((site-cell (assoc .site sx-question--user-read-list))
+ (q-cell (cons .question_id .last_activity_date))
+ cell)
+ (cond
+ ;; First question from this site.
+ ((null site-cell)
+ (push (list .site q-cell) sx-question--user-read-list))
+ ;; Question already has an older time.
+ ((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)))))))
+ ;; 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))
+
+(defun sx-question--accepted-answer-id (question)
+ "Return accepted answer in QUESTION, or nil if none."
+ (sx-assoc-let question
+ (and (integerp .accepted_answer_id)
+ .accepted_answer_id)))
(defun sx-question--tag-format (tag)
"Formats TAG for display"