diff options
Diffstat (limited to 'sx.el')
-rw-r--r-- | sx.el | 182 |
1 files changed, 92 insertions, 90 deletions
@@ -51,6 +51,96 @@ (browse-url "https://github.com/vermiculus/sx.el/issues/new")) +;;; Site +(defun sx--site (data) + "Get the site in which DATA belongs. +DATA can be a question, answer, comment, or user (or any object +with a `link' property). +DATA can also be the link itself." + (let ((link (if (stringp data) data + (cdr (assoc 'link data))))) + (when (stringp link) + (replace-regexp-in-string + (rx line-start "http" (optional "s") "://" + (or + (sequence + (group-n 1 (+ (not (any "/")))) + ".stackexchange") + (group-n 2 (+ (not (any "/"))))) + "." (+ (not (any "."))) + "/" (* any) + line-end) + "\\1\\2" link)))) + +(defun sx--ensure-site (data) + "Add a `site' property to DATA if it doesn't have one. Return DATA. +DATA can be a question, answer, comment, or user (or any object +with a `link' property)." + (when data + (unless (assq 'site data) + (setcdr data (cons (cons 'site (sx--site data)) + (cdr data)))) + data)) + +(defun sx--link-to-data (link) + "Convert string LINK into data that can be displayed." + (let ((result (list (cons 'site (sx--site link))))) + ;; Try to strip a question or answer ID + (when (or + ;; Answer + (and (or (string-match + ;; From 'Share' button + (rx "/a/" + ;; Question ID + (group (+ digit)) + ;; User ID + "/" (+ digit) + ;; Answer ID + (group (or (sequence "#" (* any)) "")) + string-end) link) + (string-match + ;; From URL + (rx "/questions/" (+ digit) "/" + (+ (not (any "/"))) "/" + ;; User ID + (optional (group (+ digit))) + (optional "/") + (group (or (sequence "#" (* any)) "")) + string-end) link)) + (push '(type . answer) result)) + ;; Question + (and (or (string-match + ;; From 'Share' button + (rx "/q/" + ;; Question ID + (group (+ digit)) + ;; User ID + (optional "/" (+ digit)) + ;; Answer or Comment ID + (group (or (sequence "#" (* any)) "")) + string-end) link) + (string-match + ;; From URL + (rx "/questions/" + ;; Question ID + (group (+ digit)) + "/") link)) + (push '(type . question) result))) + (push (cons 'id (string-to-number (match-string-no-properties 1 link))) + result)) + result)) + +(defmacro sx-assoc-let (alist &rest body) + "Identical to `let-alist', except `.site' has a special meaning. +If ALIST doesn't have a `site' property, one is created using the +`link' property." + (declare (indent 1) (debug t)) + `(progn + (require 'let-alist) + (sx--ensure-site ,alist) + (let-alist ,alist ,@body))) + + ;;; Browsing filter (defvar sx-browse-filter '((question.body_markdown @@ -107,7 +197,8 @@ is intentionally skipped." (defun sx-user-error (format-string &rest args) "Like `user-error', but prepend FORMAT-STRING with \"[sx]\". See `format'." - (signal 'user-error (list (apply #'format (concat "[sx] " format) args)))) + (signal 'user-error + (list (apply #'format (concat "[sx] " format-string) args)))) (defun sx-message (format-string &rest args) "Display FORMAT-STRING as a message with ARGS. @@ -284,95 +375,6 @@ removed from the display name before it is returned." string)) -;;; Site -(defun sx--site (data) - "Get the site in which DATA belongs. -DATA can be a question, answer, comment, or user (or any object -with a `link' property). -DATA can also be the link itself." - (let ((link (if (stringp data) data - (cdr (assoc 'link data))))) - (when (stringp link) - (replace-regexp-in-string - (rx line-start "http" (optional "s") "://" - (or - (sequence - (group-n 1 (+ (not (any "/")))) - ".stackexchange") - (group-n 2 (+ (not (any "/"))))) - "." (+ (not (any "."))) - "/" (* any) - line-end) - "\\1\\2" link)))) - -(defun sx--ensure-site (data) - "Add a `site' property to DATA if it doesn't have one. Return DATA. -DATA can be a question, answer, comment, or user (or any object -with a `link' property)." - (when data - (unless (assq 'site data) - (setcdr data (cons (cons 'site (sx--site data)) - (cdr data)))) - data)) - -(defmacro sx-assoc-let (alist &rest body) - "Identical to `let-alist', except `.site' has a special meaning. -If ALIST doesn't have a `site' property, one is created using the -`link' property." - (declare (indent 1) (debug t)) - `(progn - (require 'let-alist) - (sx--ensure-site ,alist) - (let-alist ,alist ,@body))) - -(defun sx--link-to-data (link) - "Convert string LINK into data that can be displayed." - (let ((result (list (cons 'site (sx--site link))))) - ;; Try to strip a question or answer ID - (when (or - ;; Answer - (and (or (string-match - ;; From 'Share' button - (rx "/a/" - ;; Question ID - (group (+ digit)) - ;; User ID - "/" (+ digit) - ;; Answer ID - (group (or (sequence "#" (* any)) "")) - string-end) link) - (string-match - ;; From URL - (rx "/questions/" (+ digit) "/" - (+ (not (any "/"))) "/" - ;; User ID - (optional (group (+ digit))) - (optional "/") - (group (or (sequence "#" (* any)) "")) - string-end) link)) - (push '(type . answer) result)) - ;; Question - (and (or (string-match - ;; From 'Share' button - (rx "/q/" - ;; Question ID - (group (+ digit)) - ;; User ID - (optional "/" (+ digit)) - ;; Answer or Comment ID - (group (or (sequence "#" (* any)) "")) - string-end) link) - (string-match - ;; From URL - (rx "/questions/" - ;; Question ID - (group (+ digit)) - "/") link)) - (push '(type . question) result))) - (push (cons 'id (string-to-number (match-string-no-properties 1 link))) - result)) - result)) - (defcustom sx-init-hook nil "Hook run when SX initializes. Run after `sx-init--internal-hook'." |