From a8312b07d225900f3b45bf030dd72369d7477fdb Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Mon, 24 Nov 2014 10:35:24 +0000 Subject: Refactor question-list as a generic backend. --- sx-question-list.el | 162 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 112 insertions(+), 50 deletions(-) diff --git a/sx-question-list.el b/sx-question-list.el index 9e94536..ffbb584 100644 --- a/sx-question-list.el +++ b/sx-question-list.el @@ -92,11 +92,116 @@ "" :group 'sx-question-list-faces) + +;;; Backend variables +(defvar sx-question-list--print-function #'sx-question-list--print-info + "Function to convert a question alist into a tabulated-list entry. +Used by `sx-question-list-mode', the default value is +`sx-question-list--print-info'. + +If this is set to a different value, it may be necessary to +change `tabulated-list-format' accordingly.") +(make-variable-buffer-local 'sx-question-list--print-function) + +(defun sx-question-list--print-info (question-data) + "Convert `json-read' QUESTION-DATA into tabulated-list format. + +This is the default printer used by `sx-question-list'. It +assumes QUESTION-DATA is an alist containing (at least) the +elements: + `site', `score', `upvoted', `answer_count', `title', + `last_activity_date', `tags', `uestion_id'. + +Also 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"))))))) + +(defvar sx-question-list--refresh-function + (lambda () + (sx-question-get-questions + sx-question-list--current-site)) + "Function used to refresh the list of questions to be displayed. +Used by `sx-question-list-mode', this is a function, called with +no arguments, which returns a list questions to be displayed, +like the one returned by `sx-question-get-questions'. + +If this is not set, the value of `sx-question-list--dataset' is +used, and the list is simply redisplayed.") +(make-variable-buffer-local 'sx-question-list--refresh-function) + +(defvar sx-question-list--next-page-function nil + "Function used to fetch the next page of questions to be displayed. +Used by `sx-question-list-mode'. This is a function, called with +no arguments, which returns a list questions to be displayed, +like the one returned by `sx-question-get-questions'. + +This function will be called when the user presses \\\\[sx-question-list-next] at the end +of the question list. It should either return nil (indicating +\"no more questions\") or return a list of questions which will +appended to the currently displayed list. + +If this is not set, it's the same as a function which always +returns nil.") +(make-variable-buffer-local 'sx-question-list--next-page-function) + +(defvar sx-question-list--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. + +This is ignored if `sx-question-list--refresh-function' is set.") +(make-variable-buffer-local 'sx-question-list--dataset) + ;;; Mode Definition -(define-derived-mode sx-question-list-mode tabulated-list-mode "Question List" +(define-derived-mode sx-question-list-mode + tabulated-list-mode "Question List" "Major mode for browsing a list of questions from StackExchange. Letters do not insert themselves; instead, they are commands. + +To use this mode, activate it and then optionally set some of the +following variables: + + - `sx-question-list--print-function' + - `sx-question-list--refresh-function' or `sx-question-list--dataset' + - `sx-question-list--next-page-function' + +If none of these is configured, the behaviour is that of a +\"Frontpage\", for the site given by +`sx-question-list--current-site'. + \\ \\{sx-question-list}" (hl-line-mode 1) @@ -209,11 +314,6 @@ Non-interactively, DATA is a question alist." (defvar sx-question-list--current-site "emacs" "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. If REDISPLAY is non-nil (or if interactive), also call `tabulated-list-print'. @@ -223,14 +323,14 @@ a new list before redisplaying." ;; Reset the mode-line unread count (we rebuild it here). (setq sx-question-list--unread-count 0) (let ((question-list - (if (and no-update sx-question-list--current-dataset) - sx-question-list--current-dataset - (sx-question-get-questions - sx-question-list--current-site)))) - (setq sx-question-list--current-dataset question-list) + (if (or no-update + (null (functionp sx-question-list--refresh-function))) + sx-question-list--dataset + (funcall sx-question-list--refresh-function)))) + (setq sx-question-list--dataset question-list) ;; Print the result. (setq tabulated-list-entries - (mapcar #'sx-question-list--print-info + (mapcar sx-question-list--print-function (cl-remove-if #'sx-question--hidden-p question-list)))) (when redisplay (tabulated-list-print 'remember))) @@ -251,44 +351,6 @@ Used in the questions list to indicate a question was updated :type 'string :group 'sx-question-list) -(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) "Move cursor up N questions up and display this question. Displayed in `sx-question-mode--window', replacing any question -- cgit v1.2.3 From 315c8ad1673e5925a67dcf8b821917a623660603 Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Mon, 24 Nov 2014 10:43:13 +0000 Subject: Moving above the top or below the end refreshes --- sx-question-list.el | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/sx-question-list.el b/sx-question-list.el index ffbb584..6775a27 100644 --- a/sx-question-list.el +++ b/sx-question-list.el @@ -370,7 +370,29 @@ that may currently be there." "Move cursor down N questions. This does not update `sx-question-mode--window'." (interactive "p") - (forward-line n)) + (if (and (< n 0) (bobp)) + (sx-question-list-refresh 'redisplay) + (let ((line (line-number-at-pos (point)))) + (forward-line n) + ;; If we were trying to move forward, but we hit the end. + (when (and (> n 0) (= line (line-number-at-pos (point)))) + ;; Try to get more questions. + (sx-question-list-next-page))))) + +(defun sx-question-list-next-page () + "Fetch and display the next page of questions." + (interactive) + (let ((list (when sx-question-list--next-page-function + (funcall sx-question-list--next-page-function)))) + (if (null list) + (progn (message "No further questions.") + (forward-line 0)) + ;; Try to be at the right place. + (goto-char (point-max)) + (setq sx-question-list--dataset + (append sx-question-list--dataset list)) + (sx-question-list-refresh 'redisplay 'no-update) + (forward-line 1)))) (defun sx-question-list-previous (n) "Move cursor up N questions. -- cgit v1.2.3 From b7e0d1d8c292706962d45606c9eb4f922c82df6a Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Mon, 24 Nov 2014 10:49:35 +0000 Subject: Refactor list-questions into sx-view-frontpage. --- sx-question-list.el | 25 ++-------------- sx-view.el | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+), 22 deletions(-) create mode 100644 sx-view.el diff --git a/sx-question-list.el b/sx-question-list.el index 6775a27..45982a4 100644 --- a/sx-question-list.el +++ b/sx-question-list.el @@ -446,30 +446,11 @@ completions from `sx-site-get-api-tokens'. Sets `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) - (lambda (site) - (not (equal site sx-question-list--current-site))) - t))) + "Switch to site: " (sx-site-get-api-tokens) + (lambda (site) (not (equal site sx-question-list--current-site))) + t))) (setq sx-question-list--current-site site) (sx-question-list-refresh 'redisplay)) -(defvar sx-question-list--buffer nil - "Buffer where the list of questions is displayed.") - -(defun list-questions (no-update) - "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) - (setq sx-question-list--buffer - (generate-new-buffer "*question-list*"))) - (with-current-buffer sx-question-list--buffer - (sx-question-list-mode) - (sx-question-list-refresh 'redisplay no-update)) - (switch-to-buffer sx-question-list--buffer)) - -(defalias 'sx-list-questions #'list-questions) - (provide 'sx-question-list) ;;; sx-question-list.el ends here diff --git a/sx-view.el b/sx-view.el new file mode 100644 index 0000000..74dde25 --- /dev/null +++ b/sx-view.el @@ -0,0 +1,82 @@ +;;; sx-view.el --- User-level functions for viewing frontpages. -*- lexical-binding: t; -*- + +;; Copyright (C) 2014 Artur Malabarba + +;; Author: Artur Malabarba + +;; 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, see . + +;;; Commentary: + +;; + + +;;; Code: + +(require 'sx) +(require 'sx-question-list) + +(defcustom sx-view-default-site "emacs" + "Name of the site to use by default when listing questions." + :type 'string + :group 'stack-exchange) + +(defmacro sx-view--define-page (page) + "Define a stack-exchange page called PAGE. +Page is a capitalized string. + +This defines a command `sx-view-PAGE' for displaying the page, +and a variable `sx-view--PAGE-buffer' for holding the bufer." + (declare (indent 1) (debug t)) + (let ((name (downcase page)) + (buffer-variable + (intern (concat "sx-view--" name "-buffer")))) + `(progn + (defvar ,buffer-variable nil + ,(format "Buffer where the %s questions are displayed." + page)) + (defun + ,(intern (concat "sx-view-" name)) + (&optional no-update site) + ,(format "Display a list of %s questions for SITE. + +NO-UPDATE (the prefix arg) is passed to `sx-question-list-refresh'. +If SITE is nil, use `sx-view-default-site'." + page) + (interactive + (list current-prefix-arg + (funcall (if ido-mode #'ido-completing-read #'completing-read) + (format "Site (%s): " sx-view-default-site) + (sx-site-get-api-tokens) nil t nil + sx-view-default-site))) + (sx-initialize) + (unless site (setq site sx-view-default-site)) + ;; Create the buffer + (unless (buffer-live-p ,buffer-variable) + (setq ,buffer-variable + (generate-new-buffer "*question-list*"))) + ;; Fill the buffer with content. + (with-current-buffer ,buffer-variable + (sx-question-list-mode) + (setq sx-question-list--current-site site) + (setq sx-question-list--current-page ,page) + (sx-question-list-refresh 'redisplay no-update)) + (switch-to-buffer ,buffer-variable))))) + + +;;; FrontPage +(sx-view--define-page "FrontPage") + +(provide 'sx-view) +;;; sx-view.el ends here -- cgit v1.2.3 From 413f850fff7ca23a0818a64dac4941d87d007a2c Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Mon, 24 Nov 2014 10:55:53 +0000 Subject: Accept empty input on switch-site --- sx-question-list.el | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/sx-question-list.el b/sx-question-list.el index 45982a4..e1ea349 100644 --- a/sx-question-list.el +++ b/sx-question-list.el @@ -440,17 +440,18 @@ relevant window." (defun sx-question-list-switch-site (site) "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 +Use `ido-completing-read' if variable `ido-mode' is active. +Retrieve completions from `sx-site-get-api-tokens'. +Sets `sx-question-list--current-site' and then call `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) (lambda (site) (not (equal site sx-question-list--current-site))) t))) - (setq sx-question-list--current-site site) - (sx-question-list-refresh 'redisplay)) + (when (and (stringp site) (> (length site) 0)) + (setq sx-question-list--current-site site) + (sx-question-list-refresh 'redisplay))) (provide 'sx-question-list) ;;; sx-question-list.el ends here -- cgit v1.2.3 From e83683bceaeaccafbab9506ace21bff261f9564c Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Mon, 24 Nov 2014 10:56:06 +0000 Subject: Fix let bug --- sx-view.el | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sx-view.el b/sx-view.el index 74dde25..faad8be 100644 --- a/sx-view.el +++ b/sx-view.el @@ -39,9 +39,9 @@ Page is a capitalized string. This defines a command `sx-view-PAGE' for displaying the page, and a variable `sx-view--PAGE-buffer' for holding the bufer." (declare (indent 1) (debug t)) - (let ((name (downcase page)) - (buffer-variable - (intern (concat "sx-view--" name "-buffer")))) + (let* ((name (downcase page)) + (buffer-variable + (intern (concat "sx-view--" name "-buffer")))) `(progn (defvar ,buffer-variable nil ,(format "Buffer where the %s questions are displayed." -- cgit v1.2.3 From ee0e3d9973be059e8615db11d9ea997b989d6242 Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Mon, 24 Nov 2014 11:00:43 +0000 Subject: Fix ido bug --- sx-view.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sx-view.el b/sx-view.el index faad8be..69060ea 100644 --- a/sx-view.el +++ b/sx-view.el @@ -58,7 +58,7 @@ If SITE is nil, use `sx-view-default-site'." (list current-prefix-arg (funcall (if ido-mode #'ido-completing-read #'completing-read) (format "Site (%s): " sx-view-default-site) - (sx-site-get-api-tokens) nil t nil + (sx-site-get-api-tokens) nil t nil nil sx-view-default-site))) (sx-initialize) (unless site (setq site sx-view-default-site)) -- cgit v1.2.3 From c7a76fffce768c2bdc94f165041a8dc254994ef9 Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Mon, 24 Nov 2014 11:39:34 +0000 Subject: Improve question-list-mode doc --- sx-question-list.el | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/sx-question-list.el b/sx-question-list.el index e1ea349..7af8b0f 100644 --- a/sx-question-list.el +++ b/sx-question-list.el @@ -194,16 +194,27 @@ Letters do not insert themselves; instead, they are commands. To use this mode, activate it and then optionally set some of the following variables: - - `sx-question-list--print-function' - - `sx-question-list--refresh-function' or `sx-question-list--dataset' - - `sx-question-list--next-page-function' - + 1. `sx-question-list--print-function' + 2. `sx-question-list--refresh-function' + 3. `sx-question-list--dataset' + 4. `sx-question-list--next-page-function' +\\ If none of these is configured, the behaviour is that of a \"Frontpage\", for the site given by `sx-question-list--current-site'. -\\ -\\{sx-question-list}" +As long as one of 2, 3, or 4 is provided, the other are entirely +optional. + - If function 2 is not given, the value of 3 is used instead. + - If 3 is also not given, it is populated by calling 4. + - If 4 is also not given, the page will display nothing. + +For beter integration, items 2 and 4 should take into +consideration the variable `sx-question-list--current-site'. If +the application in question has no use for this variable, it +should unbind \\[sx-question-list-switch-site]. + +\\{sx-question-list-mode-map}" (hl-line-mode 1) (sx-question-list--update-mode-line) (setq tabulated-list-format -- cgit v1.2.3 From 71b822c3aa4a175a00379bc9e92f9fa27f08bccb Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Mon, 24 Nov 2014 11:46:37 +0000 Subject: Add far movement commands, --- sx-question-list.el | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/sx-question-list.el b/sx-question-list.el index 7af8b0f..0234d62 100644 --- a/sx-question-list.el +++ b/sx-question-list.el @@ -244,6 +244,8 @@ should unbind \\[sx-question-list-switch-site]. sx-question-list-date-sort-method (car x) (car y) #'>)) + +;;; Keybinds (mapc (lambda (x) (define-key sx-question-list-mode-map (car x) (cadr x))) @@ -251,6 +253,10 @@ should unbind \\[sx-question-list-switch-site]. ("p" sx-question-list-previous) ("j" sx-question-list-view-next) ("k" sx-question-list-view-previous) + ("N" sx-question-list-next-far) + ("P" sx-question-list-previous-far) + ("J" sx-question-list-next-far) + ("K" sx-question-list-previous-far) ("g" sx-question-list-refresh) (":" sx-question-list-switch-site) ("v" sx-question-list-visit) @@ -411,6 +417,24 @@ This does not update `sx-question-mode--window'." (interactive "p") (sx-question-list-next (- n))) +(defcustom sx-question-list-far-step-size 5 + "How many questions `sx-question-list-next-far' skips." + :type 'integer + :group 'sx-question-list + :package-version '(sx-question-list . "")) + +(defun sx-question-list-next-far (n) + "Move cursor up N*`sx-question-list-far-step-size' questions. +This does not update `sx-question-mode--window'." + (interactive "p") + (sx-question-list-next (* n sx-question-list-far-step-size))) + +(defun sx-question-list-previous-far (n) + "Move cursor up N questions. +This does not update `sx-question-mode--window'." + (interactive "p") + (sx-question-list-next-far (- n))) + (defun sx-question-list-display-question (&optional data focus) "Display question given by DATA. When DATA is nil, display question under point. When FOCUS is -- cgit v1.2.3 From e63350ce3940cf673211a25daf2e8858bbe8a7a4 Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Mon, 24 Nov 2014 12:39:28 +0000 Subject: Implement paging --- sx-question-list.el | 57 +++++++++++++++++++++++++++++++++++++---------------- sx-view.el | 16 +++++++++++++-- 2 files changed, 54 insertions(+), 19 deletions(-) diff --git a/sx-question-list.el b/sx-question-list.el index 0234d62..026eff8 100644 --- a/sx-question-list.el +++ b/sx-question-list.el @@ -148,10 +148,12 @@ Also see `sx-question-list-refresh'." 'face 'sx-question-list-tags) (propertize " " 'display "\n"))))))) -(defvar sx-question-list--refresh-function - (lambda () - (sx-question-get-questions - sx-question-list--current-site)) +(defvar sx-question-list--pages-so-far 0 + "Number of pages currently being displayed. +This variable gets reset to 0 before every refresh. +It should be used by `sx-question-list--next-page-function'.") + +(defvar sx-question-list--refresh-function nil "Function used to refresh the list of questions to be displayed. Used by `sx-question-list-mode', this is a function, called with no arguments, which returns a list questions to be displayed, @@ -161,7 +163,14 @@ If this is not set, the value of `sx-question-list--dataset' is used, and the list is simply redisplayed.") (make-variable-buffer-local 'sx-question-list--refresh-function) -(defvar sx-question-list--next-page-function nil +(defvar sx-question-list--next-page-function + (lambda () + (or (sx-question-get-questions + sx-question-list--current-site + (cl-incf sx-question-list--pages-so-far)) + ;; If the `get' failed, don't increment. + (and (cl-decf sx-question-list--pages-so-far) + nil))) "Function used to fetch the next page of questions to be displayed. Used by `sx-question-list-mode'. This is a function, called with no arguments, which returns a list questions to be displayed, @@ -196,27 +205,38 @@ following variables: 1. `sx-question-list--print-function' 2. `sx-question-list--refresh-function' - 3. `sx-question-list--dataset' - 4. `sx-question-list--next-page-function' + 3. `sx-question-list--next-page-function' + 4. `sx-question-list--dataset' \\ If none of these is configured, the behaviour is that of a \"Frontpage\", for the site given by `sx-question-list--current-site'. -As long as one of 2, 3, or 4 is provided, the other are entirely -optional. - - If function 2 is not given, the value of 3 is used instead. - - If 3 is also not given, it is populated by calling 4. - - If 4 is also not given, the page will display nothing. +Function 1 is mandatory, but it also has a sane default which is +usually enough. + +As long as one of 2, 3, or 4 is provided, the other two are +entirely optional. Populating or refreshing the list of questions +is done in the following way: + - Set `sx-question-list--pages-so-far' to 0. + - Call function 2. + - If function 2 is not given, call function 3 instead. + - If 3 is also not given, it has a safe default (see the doc). + - If 3 is set to nil use the value of 4. -For beter integration, items 2 and 4 should take into +For better integration, items 2 and 3 should take into consideration the variable `sx-question-list--current-site'. If the application in question has no use for this variable, it should unbind \\[sx-question-list-switch-site]. +Function 3 should probably use the value of +`sx-question-list--pages-so-far'. If it does, it needs to update +the value manually. + \\{sx-question-list-mode-map}" (hl-line-mode 1) (sx-question-list--update-mode-line) + (setq sx-question-list--pages-so-far 0) (setq tabulated-list-format [(" V" 3 t :right-align t) (" A" 3 t :right-align t) @@ -339,11 +359,14 @@ a new list before redisplaying." (interactive "p\nP") ;; Reset the mode-line unread count (we rebuild it here). (setq sx-question-list--unread-count 0) + (setq sx-question-list--pages-so-far 0) (let ((question-list - (if (or no-update - (null (functionp sx-question-list--refresh-function))) - sx-question-list--dataset - (funcall sx-question-list--refresh-function)))) + (or (and no-update sx-question-list--dataset) + (and (functionp sx-question-list--refresh-function) + (funcall sx-question-list--refresh-function)) + (and (functionp sx-question-list--next-page-function) + (funcall sx-question-list--next-page-function)) + sx-question-list--dataset))) (setq sx-question-list--dataset question-list) ;; Print the result. (setq tabulated-list-entries diff --git a/sx-view.el b/sx-view.el index 69060ea..9a7c3fd 100644 --- a/sx-view.el +++ b/sx-view.el @@ -32,12 +32,18 @@ :type 'string :group 'stack-exchange) -(defmacro sx-view--define-page (page) +(defmacro sx-view--define-page (page &optional printer refresher pager) "Define a stack-exchange page called PAGE. Page is a capitalized string. This defines a command `sx-view-PAGE' for displaying the page, -and a variable `sx-view--PAGE-buffer' for holding the bufer." +and a variable `sx-view--PAGE-buffer' for holding the bufer. + +The arguments PRINTER, REFRESHER, and PAGER, if non-nil, are +respectively used to set the value of the variables +`sx-question-list--print-function', +`sx-question-list--refresh-function', and +`sx-question-list--next-page-function'." (declare (indent 1) (debug t)) (let* ((name (downcase page)) (buffer-variable @@ -69,6 +75,12 @@ If SITE is nil, use `sx-view-default-site'." ;; Fill the buffer with content. (with-current-buffer ,buffer-variable (sx-question-list-mode) + (when printer + (setq sx-question-list--next-page-function printer)) + (when refresher + (setq sx-question-list--refresh-function refresher)) + (when pager + (setq sx-question-list--print-function pager)) (setq sx-question-list--current-site site) (setq sx-question-list--current-page ,page) (sx-question-list-refresh 'redisplay no-update)) -- cgit v1.2.3 From 84a1d8a3676c040090ae9ab61e73e6d982bbc5bf Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Mon, 24 Nov 2014 12:41:53 +0000 Subject: Refactor view to tab --- sx-tab.el | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ sx-view.el | 94 -------------------------------------------------------------- 2 files changed, 94 insertions(+), 94 deletions(-) create mode 100644 sx-tab.el delete mode 100644 sx-view.el diff --git a/sx-tab.el b/sx-tab.el new file mode 100644 index 0000000..74d308e --- /dev/null +++ b/sx-tab.el @@ -0,0 +1,94 @@ +;;; sx-tab.el --- User-level functions for viewing frontpages. -*- lexical-binding: t; -*- + +;; Copyright (C) 2014 Artur Malabarba + +;; Author: Artur Malabarba + +;; 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, see . + +;;; Commentary: + +;; + + +;;; Code: + +(require 'sx) +(require 'sx-question-list) + +(defcustom sx-tab-default-site "emacs" + "Name of the site to use by default when listing questions." + :type 'string + :group 'stack-exchange) + +(defmacro sx-tab--define (page &optional printer refresher pager) + "Define a stack-exchange page called PAGE. +Page is a capitalized string. + +This defines a command `sx-tab-PAGE' for displaying the page, +and a variable `sx-tab--PAGE-buffer' for holding the bufer. + +The arguments PRINTER, REFRESHER, and PAGER, if non-nil, are +respectively used to set the value of the variables +`sx-question-list--print-function', +`sx-question-list--refresh-function', and +`sx-question-list--next-page-function'." + (declare (indent 1) (debug t)) + (let* ((name (downcase page)) + (buffer-variable + (intern (concat "sx-tab--" name "-buffer")))) + `(progn + (defvar ,buffer-variable nil + ,(format "Buffer where the %s questions are displayed." + page)) + (defun + ,(intern (concat "sx-tab-" name)) + (&optional no-update site) + ,(format "Display a list of %s questions for SITE. + +NO-UPDATE (the prefix arg) is passed to `sx-question-list-refresh'. +If SITE is nil, use `sx-tab-default-site'." + page) + (interactive + (list current-prefix-arg + (funcall (if ido-mode #'ido-completing-read #'completing-read) + (format "Site (%s): " sx-tab-default-site) + (sx-site-get-api-tokens) nil t nil nil + sx-tab-default-site))) + (sx-initialize) + (unless site (setq site sx-tab-default-site)) + ;; Create the buffer + (unless (buffer-live-p ,buffer-variable) + (setq ,buffer-variable + (generate-new-buffer "*question-list*"))) + ;; Fill the buffer with content. + (with-current-buffer ,buffer-variable + (sx-question-list-mode) + (when printer + (setq sx-question-list--next-page-function printer)) + (when refresher + (setq sx-question-list--refresh-function refresher)) + (when pager + (setq sx-question-list--print-function pager)) + (setq sx-question-list--current-site site) + (setq sx-question-list--current-page ,page) + (sx-question-list-refresh 'redisplay no-update)) + (switch-to-buffer ,buffer-variable))))) + + +;;; FrontPage +(sx-tab--define-tab "FrontPage") + +(provide 'sx-tab) +;;; sx-tab.el ends here diff --git a/sx-view.el b/sx-view.el deleted file mode 100644 index 9a7c3fd..0000000 --- a/sx-view.el +++ /dev/null @@ -1,94 +0,0 @@ -;;; sx-view.el --- User-level functions for viewing frontpages. -*- lexical-binding: t; -*- - -;; Copyright (C) 2014 Artur Malabarba - -;; Author: Artur Malabarba - -;; 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, see . - -;;; Commentary: - -;; - - -;;; Code: - -(require 'sx) -(require 'sx-question-list) - -(defcustom sx-view-default-site "emacs" - "Name of the site to use by default when listing questions." - :type 'string - :group 'stack-exchange) - -(defmacro sx-view--define-page (page &optional printer refresher pager) - "Define a stack-exchange page called PAGE. -Page is a capitalized string. - -This defines a command `sx-view-PAGE' for displaying the page, -and a variable `sx-view--PAGE-buffer' for holding the bufer. - -The arguments PRINTER, REFRESHER, and PAGER, if non-nil, are -respectively used to set the value of the variables -`sx-question-list--print-function', -`sx-question-list--refresh-function', and -`sx-question-list--next-page-function'." - (declare (indent 1) (debug t)) - (let* ((name (downcase page)) - (buffer-variable - (intern (concat "sx-view--" name "-buffer")))) - `(progn - (defvar ,buffer-variable nil - ,(format "Buffer where the %s questions are displayed." - page)) - (defun - ,(intern (concat "sx-view-" name)) - (&optional no-update site) - ,(format "Display a list of %s questions for SITE. - -NO-UPDATE (the prefix arg) is passed to `sx-question-list-refresh'. -If SITE is nil, use `sx-view-default-site'." - page) - (interactive - (list current-prefix-arg - (funcall (if ido-mode #'ido-completing-read #'completing-read) - (format "Site (%s): " sx-view-default-site) - (sx-site-get-api-tokens) nil t nil nil - sx-view-default-site))) - (sx-initialize) - (unless site (setq site sx-view-default-site)) - ;; Create the buffer - (unless (buffer-live-p ,buffer-variable) - (setq ,buffer-variable - (generate-new-buffer "*question-list*"))) - ;; Fill the buffer with content. - (with-current-buffer ,buffer-variable - (sx-question-list-mode) - (when printer - (setq sx-question-list--next-page-function printer)) - (when refresher - (setq sx-question-list--refresh-function refresher)) - (when pager - (setq sx-question-list--print-function pager)) - (setq sx-question-list--current-site site) - (setq sx-question-list--current-page ,page) - (sx-question-list-refresh 'redisplay no-update)) - (switch-to-buffer ,buffer-variable))))) - - -;;; FrontPage -(sx-view--define-page "FrontPage") - -(provide 'sx-view) -;;; sx-view.el ends here -- cgit v1.2.3 From 53ca78edba5cd1210a2996fc29716cf75eafa032 Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Mon, 24 Nov 2014 12:51:07 +0000 Subject: Refactor page to tab --- sx-question-list.el | 6 +++--- sx-tab.el | 24 ++++++++++++------------ 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/sx-question-list.el b/sx-question-list.el index 026eff8..68bb55b 100644 --- a/sx-question-list.el +++ b/sx-question-list.el @@ -307,10 +307,10 @@ Non-interactively, DATA is a question alist." (when (called-interactively-p 'any) (sx-question-list-refresh 'redisplay 'noupdate))) -(defvar sx-question-list--current-page "Latest" +(defvar sx-question-list--current-tab "Latest" ;; @TODO Other values (once we implement them) are "Top Voted", ;; "Unanswered", etc. - "Variable describing current page being viewed.") + "Variable describing current tab being viewed.") (defvar sx-question-list--unread-count 0 "Holds the number of unread questions in the current buffer.") @@ -324,7 +324,7 @@ Non-interactively, DATA is a question alist." '(" " mode-name " " - (:propertize sx-question-list--current-page + (:propertize sx-question-list--current-tab face mode-line-buffer-id) " [" "Unread: " diff --git a/sx-tab.el b/sx-tab.el index 74d308e..eb8d02e 100644 --- a/sx-tab.el +++ b/sx-tab.el @@ -1,4 +1,4 @@ -;;; sx-tab.el --- User-level functions for viewing frontpages. -*- lexical-binding: t; -*- +;;; sx-tab.el --- Functions for viewing different tabs. -*- lexical-binding: t; -*- ;; Copyright (C) 2014 Artur Malabarba @@ -32,12 +32,12 @@ :type 'string :group 'stack-exchange) -(defmacro sx-tab--define (page &optional printer refresher pager) - "Define a stack-exchange page called PAGE. -Page is a capitalized string. +(defmacro sx-tab--define (tab &optional printer refresher pager) + "Define a stack-exchange tab called TAB. +TAB is a capitalized string. -This defines a command `sx-tab-PAGE' for displaying the page, -and a variable `sx-tab--PAGE-buffer' for holding the bufer. +This defines a command `sx-tab-TAB' for displaying the tab, +and a variable `sx-tab--TAB-buffer' for holding the bufer. The arguments PRINTER, REFRESHER, and PAGER, if non-nil, are respectively used to set the value of the variables @@ -45,13 +45,13 @@ respectively used to set the value of the variables `sx-question-list--refresh-function', and `sx-question-list--next-page-function'." (declare (indent 1) (debug t)) - (let* ((name (downcase page)) + (let* ((name (downcase tab)) (buffer-variable (intern (concat "sx-tab--" name "-buffer")))) `(progn (defvar ,buffer-variable nil ,(format "Buffer where the %s questions are displayed." - page)) + tab)) (defun ,(intern (concat "sx-tab-" name)) (&optional no-update site) @@ -59,7 +59,7 @@ respectively used to set the value of the variables NO-UPDATE (the prefix arg) is passed to `sx-question-list-refresh'. If SITE is nil, use `sx-tab-default-site'." - page) + tab) (interactive (list current-prefix-arg (funcall (if ido-mode #'ido-completing-read #'completing-read) @@ -76,13 +76,13 @@ If SITE is nil, use `sx-tab-default-site'." (with-current-buffer ,buffer-variable (sx-question-list-mode) (when printer - (setq sx-question-list--next-page-function printer)) + (setq sx-question-list--print-function printer)) (when refresher (setq sx-question-list--refresh-function refresher)) (when pager - (setq sx-question-list--print-function pager)) + (setq sx-question-list--next-page-function pager)) (setq sx-question-list--current-site site) - (setq sx-question-list--current-page ,page) + (setq sx-question-list--current-tab ,tab) (sx-question-list-refresh 'redisplay no-update)) (switch-to-buffer ,buffer-variable))))) -- cgit v1.2.3 From dce1f846b63d029a3f4175e5fb95513e2e355bbc Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Mon, 24 Nov 2014 12:54:42 +0000 Subject: Fix next-page logic --- sx-question-list.el | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/sx-question-list.el b/sx-question-list.el index 68bb55b..708c6eb 100644 --- a/sx-question-list.el +++ b/sx-question-list.el @@ -412,23 +412,23 @@ This does not update `sx-question-mode--window'." (interactive "p") (if (and (< n 0) (bobp)) (sx-question-list-refresh 'redisplay) - (let ((line (line-number-at-pos (point)))) - (forward-line n) - ;; If we were trying to move forward, but we hit the end. - (when (and (> n 0) (= line (line-number-at-pos (point)))) - ;; Try to get more questions. - (sx-question-list-next-page))))) + (forward-line n) + ;; If we were trying to move forward, but we hit the end. + (when (eobp) + ;; Try to get more questions. + (sx-question-list-next-page)))) (defun sx-question-list-next-page () "Fetch and display the next page of questions." (interactive) (let ((list (when sx-question-list--next-page-function (funcall sx-question-list--next-page-function)))) + ;; Try to be at the right place. + (goto-char (point-max)) + (forward-line -1) (if (null list) - (progn (message "No further questions.") - (forward-line 0)) - ;; Try to be at the right place. - (goto-char (point-max)) + (message "No further questions.") + ;; @TODO: Check for duplicates. (setq sx-question-list--dataset (append sx-question-list--dataset list)) (sx-question-list-refresh 'redisplay 'no-update) -- cgit v1.2.3 From 59b91fde7dd9bd6d9a389494e0af2cd7d162c5fe Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Mon, 24 Nov 2014 14:56:02 +0000 Subject: Fix next-page bug --- sx-question-list.el | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sx-question-list.el b/sx-question-list.el index 708c6eb..4719d84 100644 --- a/sx-question-list.el +++ b/sx-question-list.el @@ -152,6 +152,7 @@ Also see `sx-question-list-refresh'." "Number of pages currently being displayed. This variable gets reset to 0 before every refresh. It should be used by `sx-question-list--next-page-function'.") +(make-variable-buffer-local 'sx-question-list--pages-so-far) (defvar sx-question-list--refresh-function nil "Function used to refresh the list of questions to be displayed. @@ -244,7 +245,7 @@ the value manually. (setq tabulated-list-padding 1) ;; Sorting by title actually sorts by date. It's what we want, but ;; it's not terribly intuitive. - (setq tabulated-list-sort-key '("Title" . nil)) + (setq tabulated-list-sort-key nil) (add-hook 'tabulated-list-revert-hook #'sx-question-list-refresh nil t) (add-hook 'tabulated-list-revert-hook @@ -359,7 +360,8 @@ a new list before redisplaying." (interactive "p\nP") ;; Reset the mode-line unread count (we rebuild it here). (setq sx-question-list--unread-count 0) - (setq sx-question-list--pages-so-far 0) + (unless no-update + (setq sx-question-list--pages-so-far 0)) (let ((question-list (or (and no-update sx-question-list--dataset) (and (functionp sx-question-list--refresh-function) -- cgit v1.2.3 From 3268a30caac379f2168c60c49f1a72edd60151fc Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Mon, 24 Nov 2014 14:56:13 +0000 Subject: Fix macro bugs --- sx-tab.el | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sx-tab.el b/sx-tab.el index eb8d02e..29398d2 100644 --- a/sx-tab.el +++ b/sx-tab.el @@ -75,12 +75,12 @@ If SITE is nil, use `sx-tab-default-site'." ;; Fill the buffer with content. (with-current-buffer ,buffer-variable (sx-question-list-mode) - (when printer - (setq sx-question-list--print-function printer)) - (when refresher - (setq sx-question-list--refresh-function refresher)) - (when pager - (setq sx-question-list--next-page-function pager)) + ,(when printer + `(setq sx-question-list--print-function ,printer)) + ,(when refresher + `(setq sx-question-list--refresh-function ,refresher)) + ,(when pager + `(setq sx-question-list--next-page-function ,pager)) (setq sx-question-list--current-site site) (setq sx-question-list--current-tab ,tab) (sx-question-list-refresh 'redisplay no-update)) @@ -88,7 +88,7 @@ If SITE is nil, use `sx-tab-default-site'." ;;; FrontPage -(sx-tab--define-tab "FrontPage") +(sx-tab--define "FrontPage") (provide 'sx-tab) ;;; sx-tab.el ends here -- cgit v1.2.3 From 9f3cc0190f844d13f4770d50e444fd64ce635b2f Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Mon, 24 Nov 2014 15:03:18 +0000 Subject: Fix test --- test/tests.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/tests.el b/test/tests.el index c76e137..c6e38e7 100644 --- a/test/tests.el +++ b/test/tests.el @@ -100,7 +100,7 @@ (ert-deftest question-list-display () (cl-letf (((symbol-function #'sx-request-make) (lambda (&rest _) sx-test-data-questions))) - (list-questions nil) + (sx-tab-frontpage nil "emacs") (switch-to-buffer "*question-list*") (goto-char (point-min)) (should (equal (buffer-name) "*question-list*")) -- cgit v1.2.3 From 93ab8319ee5657cd0c2e227c693bafb78812e19b Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Mon, 24 Nov 2014 16:21:55 +0000 Subject: Streamline the refactoring --- sx-question-list.el | 106 +++++++++++++++++++++++++++++----------------------- sx-question-mode.el | 3 +- sx-tab.el | 18 ++++++--- 3 files changed, 73 insertions(+), 54 deletions(-) diff --git a/sx-question-list.el b/sx-question-list.el index 4719d84..4d80305 100644 --- a/sx-question-list.el +++ b/sx-question-list.el @@ -164,14 +164,7 @@ If this is not set, the value of `sx-question-list--dataset' is used, and the list is simply redisplayed.") (make-variable-buffer-local 'sx-question-list--refresh-function) -(defvar sx-question-list--next-page-function - (lambda () - (or (sx-question-get-questions - sx-question-list--current-site - (cl-incf sx-question-list--pages-so-far)) - ;; If the `get' failed, don't increment. - (and (cl-decf sx-question-list--pages-so-far) - nil))) +(defvar sx-question-list--next-page-function nil "Function used to fetch the next page of questions to be displayed. Used by `sx-question-list-mode'. This is a function, called with no arguments, which returns a list questions to be displayed, @@ -201,38 +194,52 @@ This is ignored if `sx-question-list--refresh-function' is set.") "Major mode for browsing a list of questions from StackExchange. Letters do not insert themselves; instead, they are commands. -To use this mode, activate it and then optionally set some of the -following variables: - - 1. `sx-question-list--print-function' - 2. `sx-question-list--refresh-function' - 3. `sx-question-list--next-page-function' - 4. `sx-question-list--dataset' +The recommended way of using this mode is to activate it and then +set `sx-question-list--next-page-function'. The return value of +this function is mapped with `sx-question-list--print-function', +so you may need to customize the latter if the former does not +return a list of questions. + +The full list of variables which can be set is: + 1. `sx-question-list--site' + Set this to the name of the site if that makes sense. If it + doesn't leave it as nil. + 2. `sx-question-list--print-function' + Change this if the data you're dealing with is not strictly a + list of questions (see the doc for details). + 3. `sx-question-list--refresh-function' + This is used to populate the initial list. It is only necessary + if item 4 does not fit your needs. + 4. `sx-question-list--next-page-function' + This is used to fetch further questions. If item 3 is nil, it is + also used to populate the initial list. + 5. `sx-question-list--dataset' + This is only used if both 3 and 4 are nil. It can be used to + display a static list. \\ If none of these is configured, the behaviour is that of a \"Frontpage\", for the site given by -`sx-question-list--current-site'. +`sx-question-list--site'. -Function 1 is mandatory, but it also has a sane default which is +Item 2 is mandatory, but it also has a sane default which is usually enough. -As long as one of 2, 3, or 4 is provided, the other two are +As long as one of 3, 4, or 5 is provided, the other two are entirely optional. Populating or refreshing the list of questions is done in the following way: - - Set `sx-question-list--pages-so-far' to 0. + - Set `sx-question-list--pages-so-far' to 1. - Call function 2. - - If function 2 is not given, call function 3 instead. - - If 3 is also not given, it has a safe default (see the doc). - - If 3 is set to nil use the value of 4. + - If function 2 is not given, call function 3 with argument 1. + - If 3 is not given use the value of 4. -For better integration, items 2 and 3 should take into -consideration the variable `sx-question-list--current-site'. If -the application in question has no use for this variable, it -should unbind \\[sx-question-list-switch-site]. +Adding further questions to the bottom of the list is done by: + - Increment `sx-question-list--pages-so-far'. + - Call function 3 with argument `sx-question-list--pages-so-far'. + - If it returns anything, append to the dataset and refresh the + display; otherwise, decrement `sx-question-list--pages-so-far'. -Function 3 should probably use the value of -`sx-question-list--pages-so-far'. If it does, it needs to update -the value manually. +If `sx-question-list--site' is given, items 3 and 4 should take it +into consideration. \\{sx-question-list-mode-map}" (hl-line-mode 1) @@ -349,7 +356,7 @@ Non-interactively, DATA is a question alist." (setq sx-question-list--total-count (length tabulated-list-entries)))) -(defvar sx-question-list--current-site "emacs" +(defvar sx-question-list--site nil "Site being displayed in the *question-list* buffer.") (defun sx-question-list-refresh (&optional redisplay no-update) @@ -361,13 +368,13 @@ a new list before redisplaying." ;; Reset the mode-line unread count (we rebuild it here). (setq sx-question-list--unread-count 0) (unless no-update - (setq sx-question-list--pages-so-far 0)) + (setq sx-question-list--pages-so-far 1)) (let ((question-list (or (and no-update sx-question-list--dataset) (and (functionp sx-question-list--refresh-function) (funcall sx-question-list--refresh-function)) (and (functionp sx-question-list--next-page-function) - (funcall sx-question-list--next-page-function)) + (funcall sx-question-list--next-page-function 1)) sx-question-list--dataset))) (setq sx-question-list--dataset question-list) ;; Print the result. @@ -423,18 +430,23 @@ This does not update `sx-question-mode--window'." (defun sx-question-list-next-page () "Fetch and display the next page of questions." (interactive) - (let ((list (when sx-question-list--next-page-function - (funcall sx-question-list--next-page-function)))) - ;; Try to be at the right place. - (goto-char (point-max)) - (forward-line -1) - (if (null list) - (message "No further questions.") - ;; @TODO: Check for duplicates. - (setq sx-question-list--dataset - (append sx-question-list--dataset list)) - (sx-question-list-refresh 'redisplay 'no-update) - (forward-line 1)))) + ;; Stay at the last line. + (goto-char (point-max)) + (forward-line -1) + (when (functionp sx-question-list--next-page-function) + ;; Try to get more questions + (let ((list (funcall sx-question-list--next-page-function + (1+ sx-question-list--pages-so-far)))) + (if (null list) + (message "No further questions.") + ;; If it worked, increment the variable. + (cl-incf sx-question-list--pages-so-far) + ;; And update the dataset. + ;; @TODO: Check for duplicates. + (setq sx-question-list--dataset + (append sx-question-list--dataset list)) + (sx-question-list-refresh 'redisplay 'no-update) + (forward-line 1))))) (defun sx-question-list-previous (n) "Move cursor up N questions. @@ -502,15 +514,15 @@ relevant window." "Switch the current site to SITE and display its questions. Use `ido-completing-read' if variable `ido-mode' is active. Retrieve completions from `sx-site-get-api-tokens'. -Sets `sx-question-list--current-site' and then call +Sets `sx-question-list--site' and then call `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) - (lambda (site) (not (equal site sx-question-list--current-site))) + (lambda (site) (not (equal site sx-question-list--site))) t))) (when (and (stringp site) (> (length site) 0)) - (setq sx-question-list--current-site site) + (setq sx-question-list--site site) (sx-question-list-refresh 'redisplay))) (provide 'sx-question-list) diff --git a/sx-question-mode.el b/sx-question-mode.el index f1705a5..a9e14e7 100644 --- a/sx-question-mode.el +++ b/sx-question-mode.el @@ -604,8 +604,7 @@ comments, and redisplays it." (sx-question-mode--ensure-mode) (sx-assoc-let sx-question-mode--data (sx-question-mode--display - (sx-question-get-question - sx-question-list--current-site .question_id) + (sx-question-get-question .site .question_id) (selected-window)))) (defun sx-question-mode--ensure-mode () diff --git a/sx-tab.el b/sx-tab.el index 29398d2..8a51236 100644 --- a/sx-tab.el +++ b/sx-tab.el @@ -32,18 +32,22 @@ :type 'string :group 'stack-exchange) -(defmacro sx-tab--define (tab &optional printer refresher pager) +(defmacro sx-tab--define (tab pager &optional printer refresher + &rest body) "Define a stack-exchange tab called TAB. TAB is a capitalized string. This defines a command `sx-tab-TAB' for displaying the tab, and a variable `sx-tab--TAB-buffer' for holding the bufer. -The arguments PRINTER, REFRESHER, and PAGER, if non-nil, are +The arguments PAGER, PRINTER, and REFRESHER, if non-nil, are respectively used to set the value of the variables `sx-question-list--print-function', `sx-question-list--refresh-function', and -`sx-question-list--next-page-function'." +`sx-question-list--next-page-function'. + +BODY is evaluated after activating the mode and setting these +variables, but before refreshing the display." (declare (indent 1) (debug t)) (let* ((name (downcase tab)) (buffer-variable @@ -81,14 +85,18 @@ If SITE is nil, use `sx-tab-default-site'." `(setq sx-question-list--refresh-function ,refresher)) ,(when pager `(setq sx-question-list--next-page-function ,pager)) - (setq sx-question-list--current-site site) + (setq sx-question-list--site site) (setq sx-question-list--current-tab ,tab) + ,@body (sx-question-list-refresh 'redisplay no-update)) (switch-to-buffer ,buffer-variable))))) ;;; FrontPage -(sx-tab--define "FrontPage") +(sx-tab--define "FrontPage" + (lambda (page) + (sx-question-get-questions + sx-question-list--site page))) (provide 'sx-tab) ;;; sx-tab.el ends here -- cgit v1.2.3 From eaf2e6d6f89d46190c2ed8b3971c39e69c908294 Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Mon, 24 Nov 2014 16:25:55 +0000 Subject: Fix test --- test/tests.el | 1 + 1 file changed, 1 insertion(+) diff --git a/test/tests.el b/test/tests.el index c6e38e7..75238fe 100644 --- a/test/tests.el +++ b/test/tests.el @@ -48,6 +48,7 @@ (require 'sx) (require 'sx-question) (require 'sx-question-list) +(require 'sx-tab) (ert-deftest test-basic-request () "Test basic request functionality" -- cgit v1.2.3 From 7513e83bd978dbd06b7298d32db71dce43d47c3e Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Mon, 24 Nov 2014 16:39:56 +0000 Subject: Mention sx-tab-frontpage --- sx.org | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/sx.org b/sx.org index b646b2c..cb1c109 100644 --- a/sx.org +++ b/sx.org @@ -66,11 +66,16 @@ a cache file. ** Browsing Questions To browse a list of questions retrieved from the site, use -~list-questions~. This pulls the first page of questions from the -current site and displays them in a list. Refresh the page with =g=, -use =n= and =p= to navigate without viewing the question, =j= and =k= -to do the same /with/ viewing the question, and =RET= to visit the -question at point. +~sx-tab-frontpage~. This queries for a site, pulls the first page of +questions for that site, and displays them in a list. + +- Refresh the page with =g= or by scrolling past the top. +- Use =n=, =p=, =N=, =P= to navigate without viewing the question. +- =j=, =k=, =J=, =K= to do the same /with/ viewing the question. +- =RET= to open the question with Emacs. +- =v= to visit it with a browser. + +Scrolling past the bottom of the list fetches more questions. * List of Hooks :PROPERTIES: @@ -123,4 +128,5 @@ The language for Emacs Lisp source code blocks should be given as # Local Variables: # org-export-date-timestamp-format: "$B %e %Y" +# sentence-end-double-space: t # End: -- cgit v1.2.3