From 48273879d34d6027d9edd623e9f946ef819d363e Mon Sep 17 00:00:00 2001 From: Sean Allred Date: Fri, 2 Jan 2015 19:30:37 -0500 Subject: Fix sx-tag-filter It wasn't returning any .items because it wasn't included in the filter. This commit also introduces a convenience macro in sx-filter to avoid this scenario in the future. --- sx-filter.el | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) (limited to 'sx-filter.el') diff --git a/sx-filter.el b/sx-filter.el index 8c00c12..ad37e67 100644 --- a/sx-filter.el +++ b/sx-filter.el @@ -41,7 +41,40 @@ Structure: ...)") -;;; Compilation +;;; Creation + +(defmacro sx-filter-from-nil (included) + "Creates a filter data structure with INCLUDED fields. +All wrapper fields are included by default." + ;; @OTODO: it would be neat to have syntax like + ;; + ;; (field-a + ;; field-b + ;; (object-a subfield) + ;; field-c + ;; (object-b subfield-a subfield-b)) + ;; + ;; expand into + ;; + ;; (field-a + ;; field-b + ;; object-a.subfield + ;; field-c + ;; object-b.subfield-a object-b.subfield-b) + `(quote ((,@included + .backoff + .error_id + .error_message + .error_name + .has_more + .items + .page + .page_size + .quota_max + .quota_remaining + .total + .type) + nil none))) ;;; @TODO allow BASE to be a precompiled filter name (defun sx-filter-compile (&optional include exclude base) -- cgit v1.2.3 From 59327f6f9c6ba419543c47670a62af0aa41271ca Mon Sep 17 00:00:00 2001 From: Sean Allred Date: Sun, 4 Jan 2015 11:41:30 -0500 Subject: Tree-style specification for filter-from-nil Instead of saying (field-a field-b object-a.subfield field-c object-b.subfield-a object-b.subfield-b) you can rather say (field-a field-b (object-a subfield) field-c (object-b subfield-a subfield-b)) To avoid a dependency loop, sx-browse-filter has been moved to sx-filter.el. --- sx-filter.el | 87 +++++++++++++++++++++++++++++++++++------------------ sx-networks.el | 26 ++++++++-------- sx-site.el | 12 ++++---- sx.el | 61 ++++++++++++------------------------- test/test-macros.el | 22 ++++++++++++++ test/test-util.el | 14 +++++++++ 6 files changed, 132 insertions(+), 90 deletions(-) (limited to 'sx-filter.el') diff --git a/sx-filter.el b/sx-filter.el index ad37e67..d484f43 100644 --- a/sx-filter.el +++ b/sx-filter.el @@ -42,39 +42,26 @@ Structure: ;;; Creation - (defmacro sx-filter-from-nil (included) "Creates a filter data structure with INCLUDED fields. All wrapper fields are included by default." - ;; @OTODO: it would be neat to have syntax like - ;; - ;; (field-a - ;; field-b - ;; (object-a subfield) - ;; field-c - ;; (object-b subfield-a subfield-b)) - ;; - ;; expand into - ;; - ;; (field-a - ;; field-b - ;; object-a.subfield - ;; field-c - ;; object-b.subfield-a object-b.subfield-b) - `(quote ((,@included - .backoff - .error_id - .error_message - .error_name - .has_more - .items - .page - .page_size - .quota_max - .quota_remaining - .total - .type) - nil none))) + `(quote + ((,@(sx--tree-expand + (lambda (path) + (intern (mapconcat #'symbol-name path "."))) + included) + .backoff + .error_id + .error_message + .error_name + .has_more + .items + .page + .page_size + .quota_max + .quota_remaining + .total) + nil none))) ;;; @TODO allow BASE to be a precompiled filter name (defun sx-filter-compile (&optional include exclude base) @@ -114,6 +101,46 @@ return the compiled filter." (sx-cache-set 'filter sx--filter-alist) filter)))) + +;;; Browsing filter +(defvar sx-browse-filter + (sx-filter-from-nil + ((question body_markdown + comments + answers + last_editor + last_activity_date + accepted_answer_id + link + upvoted + downvoted + question_id + share_link) + (user display_name) + (comment owner + body_markdown + body + link + edited + creation_date + upvoted + score + post_type + post_id + comment_id) + (answer answer_id + last_editor + last_activity_date + link + share_link + owner + body_markdown + upvoted + downvoted + comments))) + "The filter applied when retrieving question data. +See `sx-question-get-questions' and `sx-question-get-question'.") + (provide 'sx-filter) ;;; sx-filter.el ends here diff --git a/sx-networks.el b/sx-networks.el index 20ac65c..58ebff5 100644 --- a/sx-networks.el +++ b/sx-networks.el @@ -28,19 +28,19 @@ (defvar sx-network--user-filter (sx-filter-from-nil - (badge_count.bronze - badge_count.silver - badge_count.gold - network_user.account_id - network_user.answer_count - network_user.badge_counts - network_user.creation_date - network_user.last_access_date - network_user.reputation - network_user.site_name - network_user.site_url - network_user.user_id - network_user.user_type))) + ((badge_count bronze + silver + gold) + (network_user account_id + answer_count + badge_counts + creation_date + last_access_date + reputation + site_name + site_url + user_id + user_type)))) (defun sx-network--get-associated () "Retrieve cached information for network user. diff --git a/sx-site.el b/sx-site.el index 1bc86a6..2f0a31d 100644 --- a/sx-site.el +++ b/sx-site.el @@ -27,12 +27,12 @@ (defvar sx-site-browse-filter (sx-filter-from-nil - (site.site_type - site.name - site.api_site_parameter - site.related_sites - related_site.api_site_parameter - related_site.relation)) + ((site site_type + name + api_site_parameter + related_sites) + (related_site api_site_parameter + relation))) "Filter for browsing sites.") (defun sx-site--get-site-list () diff --git a/sx.el b/sx.el index 3aa87e7..f77b313 100644 --- a/sx.el +++ b/sx.el @@ -136,6 +136,26 @@ with a `link' property)." result)) result)) +(defun sx--tree-paths (tree) + "Return a list of all paths in TREE. +Adapted from http://stackoverflow.com/q/3019250." + (if (atom tree) + (list (list tree)) + (apply #'append + (mapcar (lambda (node) + (mapcar (lambda (path) + (cons (car tree) path)) + (sx--tree-paths node))) + (cdr tree))))) + +(defun sx--tree-expand (path-func tree) + "Apply PATH-FUNC to every path in TREE. +Return the result. See `sx--tree-paths'." + (mapcar path-func + (apply #'append + (mapcar #'sx--tree-paths + tree)))) + (defmacro sx-assoc-let (alist &rest body) "Use ALIST with `let-alist' to execute BODY. `.site_par' has a special meaning, thanks to `sx--ensure-site'. @@ -148,47 +168,6 @@ If ALIST doesn't have a `site' property, one is created using the ,(macroexpand `(let-alist ,alist ,@body)))) - -;;; Browsing filter -(defvar sx-browse-filter - ;; @TODO: Use `sx-filter-from-nil' - '((question.body_markdown - question.comments - question.answers - question.last_editor - question.last_activity_date - question.accepted_answer_id - question.link - question.upvoted - question.downvoted - question.question_id - question.share_link - user.display_name - comment.owner - comment.body_markdown - comment.body - comment.link - comment.edited - comment.creation_date - comment.upvoted - comment.score - comment.post_type - comment.post_id - comment.comment_id - answer.answer_id - answer.last_editor - answer.last_activity_date - answer.link - answer.share_link - answer.owner - answer.body_markdown - answer.upvoted - answer.downvoted - answer.comments) - (user.profile_image shallow_user.profile_image)) - "The filter applied when retrieving question data. -See `sx-question-get-questions' and `sx-question-get-question'.") - ;;; Utility Functions (defun sx-completing-read (&rest args) diff --git a/test/test-macros.el b/test/test-macros.el index b6bf20b..1634603 100644 --- a/test/test-macros.el +++ b/test/test-macros.el @@ -20,3 +20,25 @@ (should (equal (sx-assoc-let data (cons .test-one .test-two)) '(1 . 2))))) + +(ert-deftest macro-test--sx-filter-from-nil () + "Test `sx-filter-from-nil'" + (should + (equal + (sx-filter-from-nil + (one two (three four five) (six seven) + (a b c d e))) + '((one two three.four three.five six.seven + a.b a.c a.d a.e + .backoff + .error_id + .error_message + .error_name + .has_more + .items + .page + .page_size + .quota_max + .quota_remaining + .total) + nil none)))) diff --git a/test/test-util.el b/test/test-util.el index 5db1691..1e3dc2b 100644 --- a/test/test-util.el +++ b/test/test-util.el @@ -29,3 +29,17 @@ (string= (sx--thing-as-string 'test& nil t) "test%26"))) + +(ert-deftest tree () + (should + (equal + (sx--tree-expand + (lambda (path) (mapconcat #'symbol-name path ".")) + '(a b (c d (e f g) h i (j k) l) m (n o) p)) + '("a" "b" "c.d" "c.e.f" "c.e.g" "c.h" "c.i" "c.j.k" "c.l" "m" "n.o" "p"))) + (should + (equal + (sx--tree-expand + (lambda (path) (intern (mapconcat #'symbol-name path "/"))) + '(a b (c d (e f g) h i (j k) l) m (n o) p)) + '(a b c/d c/e/f c/e/g c/h c/i c/j/k c/l m n/o p)))) -- cgit v1.2.3 From e8a2b48d09e22cf5dca446e70d1428ae4561fd42 Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Sun, 4 Jan 2015 17:50:35 -0200 Subject: Display bounty --- sx-filter.el | 1 + sx-question-list.el | 13 ++++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) (limited to 'sx-filter.el') diff --git a/sx-filter.el b/sx-filter.el index d484f43..1cf010f 100644 --- a/sx-filter.el +++ b/sx-filter.el @@ -106,6 +106,7 @@ return the compiled filter." (defvar sx-browse-filter (sx-filter-from-nil ((question body_markdown + bounty_amount comments answers last_editor diff --git a/sx-question-list.el b/sx-question-list.el index ee7d6b1..81e5ab0 100644 --- a/sx-question-list.el +++ b/sx-question-list.el @@ -104,6 +104,11 @@ "" :group 'sx-question-list-faces) +(defface sx-question-list-bounty + '((t :inherit font-lock-warning-face)) + "" + :group 'sx-question-list-faces) + ;;; Backend variables (defvar sx-question-list--print-function #'sx-question-list--print-info @@ -150,9 +155,11 @@ Also see `sx-question-list-refresh'." (propertize " " 'display "\n ") ;; Second line (propertize favorite 'face 'sx-question-list-favorite) - " " - (propertize (concat (sx-time-since .last_activity_date) - sx-question-list-ago-string) + (if (and (numberp .bounty_amount) (> .bounty_amount 0)) + (propertize (format "%4d" .bounty_amount) + 'face 'sx-question-list-bounty) + " ") + " " 'face 'sx-question-list-date) " " (propertize (mapconcat #'sx-question--tag-format .tags " ") -- cgit v1.2.3 From df4a8bba9b720357008423b8f91657a8a311607a Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Sun, 4 Jan 2015 18:09:26 -0200 Subject: Display user --- sx-filter.el | 5 ++++- sx-question-list.el | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) (limited to 'sx-filter.el') diff --git a/sx-filter.el b/sx-filter.el index 1cf010f..15bd8a1 100644 --- a/sx-filter.el +++ b/sx-filter.el @@ -117,7 +117,10 @@ return the compiled filter." downvoted question_id share_link) - (user display_name) + (user display_name + reputation) + (shallow_user display_name + reputation) (comment owner body_markdown body diff --git a/sx-question-list.el b/sx-question-list.el index 1342e76..40b72b9 100644 --- a/sx-question-list.el +++ b/sx-question-list.el @@ -109,6 +109,16 @@ "" :group 'sx-question-list-faces) +(defface sx-question-list-reputation + '((t :inherit sx-question-list-date)) + "" + :group 'sx-question-list-faces) + +(defface sx-question-list-user + '((t :inherit font-lock-builtin-face)) + "" + :group 'sx-question-list-faces) + ;;; Backend variables (defvar sx-question-list--print-function #'sx-question-list--print-info @@ -169,6 +179,12 @@ Also see `sx-question-list-refresh'." ;; the whole thing customizable) (propertize (format "%-40s" (mapconcat #'sx-question--tag-format .tags " ")) 'face 'sx-question-list-tags) + " " + (let-alist .owner + (format "%15s %5s" + (propertize .display_name 'face 'sx-question-list-user) + (propertize (number-to-string .reputation) + 'face 'sx-question-list-reputation))) (propertize " " 'display "\n"))))))) (defvar sx-question-list--pages-so-far 0 -- cgit v1.2.3