diff options
-rw-r--r-- | sx-question-list.el | 1 | ||||
-rw-r--r-- | sx-question-mode.el | 1 | ||||
-rw-r--r-- | sx-search.el | 112 | ||||
-rw-r--r-- | sx.el | 19 |
4 files changed, 133 insertions, 0 deletions
diff --git a/sx-question-list.el b/sx-question-list.el index d84d1ea..0856e2a 100644 --- a/sx-question-list.el +++ b/sx-question-list.el @@ -317,6 +317,7 @@ into consideration. (":" sx-question-list-switch-site) ("t" sx-tab-switch) ("a" sx-ask) + ("s" sx-search) ("v" sx-visit-externally) ("u" sx-toggle-upvote) ("d" sx-toggle-downvote) diff --git a/sx-question-mode.el b/sx-question-mode.el index a60cf3a..05b8984 100644 --- a/sx-question-mode.el +++ b/sx-question-mode.el @@ -231,6 +231,7 @@ Letters do not insert themselves; instead, they are commands. (" " scroll-up-command) ("a" sx-answer) ("e" sx-edit) + ("s" sx-search) (,(kbd "S-SPC") scroll-down-command) ([backspace] scroll-down-command) ([tab] forward-button) diff --git a/sx-search.el b/sx-search.el new file mode 100644 index 0000000..928db5d --- /dev/null +++ b/sx-search.el @@ -0,0 +1,112 @@ +;;; sx-search.el --- Searching for questions. -*- lexical-binding: t; -*- + +;; Copyright (C) 2014 Artur Malabarba + +;; Author: Artur Malabarba <bruce.connor.am@gmail.com> + +;; 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 <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;; Implements sarch functionality. The basic function is +;; `sx-search-get-questions', which returns an array of questions +;; according to a search term. +;; +;; This also defines a user-level command, `sx-search', which is an +;; interactive wrapper around `sx-search-get-questions' and +;; `sx-question-list-mode'. + + +;;; Code: + +(require 'sx) +(require 'sx-question-list) + +(defvar sx-search--query-history nil + "Query history for interactive prompts.") + +(defvar sx-search--tag-history nil + "Tags history for interactive prompts.") + + +;;; Basic function +(defun sx-search-get-questions (site page query &optional tags excluded-tags keywords) + "Like `sx-question-get-questions', but restrict results by a search. + +Perform search on SITE. PAGE is an integer indicating which page +of results to return. QUERY, TAGS, and EXCLUDED-TAGS restrict the +possible returned questions as per `sx-search'. + +Either QUERY or TAGS must be non-nil, or the search will +fail. EXCLUDED-TAGS is only is used if TAGS is also provided. + +KEYWORDS is passed to `sx-method-call'." + (sx-method-call 'search + :keywords `((page . ,page) + (sort . activity) + (intitle . ,query) + (tagged . ,tags) + (nottagged . ,excluded-tags) + ,@keywords) + :site site + :auth t + :filter sx-browse-filter)) + + +;;; User command +(defun sx-search (site query &optional tags excluded-tags) + "Display search on SITE for question titles containing QUERY. +When TAGS is given, it is a lists of tags, one of which must +match. When EXCLUDED-TAGS is given, it is a list of tags, none +of which is allowed to match. + +Interactively, the user is asked for SITE and QUERY. With a +prefix argument, the user is asked for everything." + (interactive + (let ((site (sx--interactive-site-prompt)) + (query (read-string + (format "Query (%s): " + (if current-prefix-arg "optional" "mandatory")) + "" + 'sx-search--query-history)) + tags excluded-tags) + (when (string= query "") + (setq query nil)) + (when current-prefix-arg + (setq tags (sx--multiple-read + (format "Tags (%s)" + (if query "optional" "mandatory")) + 'sx-search--tag-history)) + (when (and (not query) (string= "" tags)) + (sx-user-error "Must supply either QUERY or TAGS")) + (setq excluded-tags + (sx--multiple-read + "Excluded tags (optional)" 'sx-search--tag-history))) + (list site query tags excluded-tags))) + + ;; Here starts the actual function + (sx-initialize) + (with-current-buffer (get-buffer-create "*sx-search-result*") + (sx-question-list-mode) + (setq sx-question-list--next-page-function + (lambda (page) + (sx-search-get-questions + sx-question-list--site page + query tags excluded-tags))) + (setq sx-question-list--site site) + (sx-question-list-refresh 'redisplay) + (switch-to-buffer (current-buffer)))) + +(provide 'sx-search) +;;; sx-search.el ends here @@ -190,6 +190,25 @@ All ARGS are passed to `completing-read' or `ido-completing-read'." (apply (if ido-mode #'ido-completing-read #'completing-read) args)) +(defun sx--multiple-read (prompt hist-var) + "Interactively query gthe user for a list of strings. +Call `read-string' multiple times, until the input is empty. + +PROMPT is a string displayed to the user. and should not +end with a space nor a colon. +HIST-VAR is a quoted symbol, indicating a list in which to store +input history." + (let (list input) + (while (not (string= + "" + (setq input (read-string + (concat prompt " [" + (mapconcat #'identity list ",") + "]: ") + "" hist-var)))) + (push input list)) + list)) + (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 |