aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sx-button.el34
-rw-r--r--sx-compose.el6
-rw-r--r--sx-inbox.el6
-rw-r--r--sx-question-list.el39
-rw-r--r--sx-question-print.el131
-rw-r--r--sx-question.el6
-rw-r--r--sx-request.el23
-rw-r--r--sx-search.el20
-rw-r--r--sx-tag.el38
-rw-r--r--sx.el7
-rw-r--r--test/test-api.el23
-rw-r--r--test/test-printing.el20
12 files changed, 249 insertions, 104 deletions
diff --git a/sx-button.el b/sx-button.el
index 5a2f052..d32314d 100644
--- a/sx-button.el
+++ b/sx-button.el
@@ -77,30 +77,35 @@ This is usually a link's URL, or the content of a code block."
(point) 'sx-button-copy-type)
content)))))
-(defun sx-button-edit-this (text-or-marker &optional major-mode)
- "Open a temp buffer populated with the string TEXT-OR-MARKER using MAJOR-MODE.
+(defun sx-button-edit-this (text-or-marker &optional majormode)
+ "Open a temp buffer populated with the string TEXT-OR-MARKER using MAJORMODE.
When given a marker (or interactively), use the 'sx-button-copy
and the 'sx-mode text-properties under the marker. These are
usually part of a code-block."
(interactive (list (point-marker)))
;; Buttons receive markers.
(when (markerp text-or-marker)
- (setq major-mode (get-text-property text-or-marker 'sx-mode))
+ (setq majormode (get-text-property text-or-marker 'sx-mode))
(unless (setq text-or-marker
(get-text-property text-or-marker 'sx-button-copy))
(sx-message "Nothing of interest here.")))
(with-current-buffer (pop-to-buffer (generate-new-buffer
"*sx temp buffer*"))
(insert text-or-marker)
- (when major-mode
- (funcall major-mode))))
+ (when majormode
+ (funcall majormode))))
(defun sx-button-follow-link (&optional pos)
"Follow link at POS. If POS is nil, use `point'."
(interactive)
- (browse-url
- (or (get-text-property (or pos (point)) 'sx-button-url)
- (sx-user-error "No url under point: %s" (or pos (point))))))
+ (let ((url (or (get-text-property (or pos (point)) 'sx-button-url)
+ (sx-user-error "No url under point: %s" (or pos (point))))))
+ ;; If we didn't recognize the link, this errors immediately. If
+ ;; we mistakenly recognize it, it will error when we try to fetch
+ ;; whatever we thought it was.
+ (condition-case nil (sx-open-link url)
+ ;; When it errors, don't blame the user, just visit externally.
+ (error (sx-visit-externally url)))))
;;; Help-echo definitions
@@ -117,6 +122,12 @@ usually part of a code-block."
"link")
"Help echoed in the minibuffer when point is on a user.")
+(defconst sx-button--tag-help-echo
+ (format sx-button--help-echo
+ "Tag search"
+ "tag")
+ "Help echoed in the minibuffer when point is on a tag.")
+
(defconst sx-button--question-title-help-echo
(format sx-button--help-echo
"hide content"
@@ -158,6 +169,13 @@ usually part of a code-block."
'face 'sx-user-name
:supertype 'sx-button)
+(declare-function sx-search-tag-at-point "sx-search")
+(define-button-type 'sx-button-tag
+ 'action #'sx-search-tag-at-point
+ 'help-echo sx-button--tag-help-echo
+ 'face 'sx-tag
+ :supertype 'sx-button)
+
(define-button-type 'sx-button-comment
'help-echo (concat "mouse-1, RET"
(propertize ": write a comment"
diff --git a/sx-compose.el b/sx-compose.el
index eb5e2eb..ae13fb6 100644
--- a/sx-compose.el
+++ b/sx-compose.el
@@ -193,8 +193,7 @@ tags. Return a list of already inserted tags."
'noerror)
(error "No Tags header found"))
(save-match-data
- (split-string (match-string 1) (rx (any space ",;"))
- 'omit-nulls (rx space))))
+ (sx--split-string (match-string 1) (rx (any space ",;")))))
(defun sx-compose--check-tags ()
"Check if tags in current compose buffer are valid."
@@ -313,8 +312,7 @@ other keywords are read from the header "
(unless (search-forward-regexp "^Tags : *\\([^[:space:]].*\\) *$"
header-end 'noerror)
(error "No Tags header found"))
- (push (cons 'tags (split-string (match-string 1)
- "[[:space:],;]" 'omit-nulls))
+ (push (cons 'tags (sx--split-string (match-string 1) "[[:space:],;]"))
keywords)
;; And erase the header so it doesn't get sent.
(delete-region
diff --git a/sx-inbox.el b/sx-inbox.el
index 21589fb..3048509 100644
--- a/sx-inbox.el
+++ b/sx-inbox.el
@@ -127,11 +127,7 @@ These are identified by their links.")
(setq tabulated-list-format
[("Type" 30 t nil t) ("Date" 10 t :right-align t) ("Title" 0)])
(setq mode-line-format sx-inbox--mode-line)
- (setq header-line-format sx-inbox--header-line)
- ;; @TODO: This will no longer be necessary once we properly
- ;; refactor sx-question-list-mode.
- (remove-hook 'tabulated-list-revert-hook
- #'sx-question-list--update-mode-line t))
+ (setq header-line-format sx-inbox--header-line))
;;; Keybinds
diff --git a/sx-question-list.el b/sx-question-list.el
index 7757503..def490b 100644
--- a/sx-question-list.el
+++ b/sx-question-list.el
@@ -27,6 +27,7 @@
(require 'sx)
(require 'sx-time)
+(require 'sx-tag)
(require 'sx-site)
(require 'sx-question)
(require 'sx-question-mode)
@@ -81,11 +82,6 @@
""
:group 'sx-question-list-faces)
-(defface sx-question-list-tags
- '((t :inherit sx-question-mode-tags))
- ""
- :group 'sx-question-list-faces)
-
(defface sx-question-list-date
'((t :inherit font-lock-comment-face))
""
@@ -170,8 +166,7 @@ Also see `sx-question-list-refresh'."
" "
;; @TODO: Make this width customizable. (Or maybe just make
;; the whole thing customizable)
- (propertize (format "%-40s" (mapconcat #'sx-question--tag-format .tags " "))
- 'face 'sx-question-list-tags)
+ (format "%-40s" (sx-tag--format-tags .tags sx-question-list--site))
" "
(sx-user--format "%15d %4r" .owner)
(propertize " " 'display "\n")))))))
@@ -308,7 +303,8 @@ into consideration. The same holds for `sx-question-list--order'.
\\{sx-question-list-mode-map}"
(hl-line-mode 1)
- (sx-question-list--update-mode-line)
+ (setq mode-line-format
+ sx-question-list--mode-line-format)
(setq sx-question-list--pages-so-far 0)
(setq tabulated-list-format
[(" V" 3 t :right-align t)
@@ -320,8 +316,6 @@ into consideration. The same holds for `sx-question-list--order'.
(setq tabulated-list-sort-key nil)
(add-hook 'tabulated-list-revert-hook
#'sx-question-list-refresh nil t)
- (add-hook 'tabulated-list-revert-hook
- #'sx-question-list--update-mode-line nil t)
(setq header-line-format sx-question-list--header-line))
(defcustom sx-question-list-date-sort-method 'last_activity_date
@@ -400,14 +394,14 @@ Non-interactively, DATA is a question alist."
;; "Unanswered", etc.
"Variable describing current tab being viewed.")
-(defvar sx-question-list--total-count 0
- "Holds the total number of questions in the current buffer.")
-(make-variable-buffer-local 'sx-question-list--total-count)
-
(defconst sx-question-list--mode-line-format
- '(" "
- mode-name
- " "
+ '(" "
+ (:propertize
+ (:eval (mapconcat #'capitalize
+ (split-string sx-question-list--site "\\.")
+ " "))
+ face mode-line-buffer-id)
+ " " mode-name ": "
(:propertize sx-question-list--current-tab
face mode-line-buffer-id)
" ["
@@ -418,7 +412,7 @@ Non-interactively, DATA is a question alist."
", "
"Total: "
(:propertize
- (:eval (int-to-string sx-question-list--total-count))
+ (:eval (int-to-string (length tabulated-list-entries)))
face mode-line-buffer-id)
"] ")
"Mode-line construct to use in question-list buffers.")
@@ -429,15 +423,6 @@ Non-interactively, DATA is a question alist."
(cl-count-if-not
#'sx-question--read-p sx-question-list--dataset)))
-(defun sx-question-list--update-mode-line ()
- "Fill the mode-line with useful information."
- ;; All the data we need is right in the buffer.
- (when (derived-mode-p 'sx-question-list-mode)
- (setq mode-line-format
- sx-question-list--mode-line-format)
- (setq sx-question-list--total-count
- (length tabulated-list-entries))))
-
(defvar sx-question-list--site nil
"Site being displayed in the *question-list* buffer.")
(make-variable-buffer-local 'sx-question-list--site)
diff --git a/sx-question-print.el b/sx-question-print.el
index 4f50560..c350d8c 100644
--- a/sx-question-print.el
+++ b/sx-question-print.el
@@ -79,11 +79,6 @@ Some faces of this mode might be defined in the `sx-user' group."
:type 'string
:group 'sx-question-mode)
-(defface sx-question-mode-tags
- '((t :underline nil :inherit font-lock-function-name-face))
- "Face used on the question tags in the question buffer."
- :group 'sx-question-mode-faces)
-
(defface sx-question-mode-score
'((t))
"Face used for the score in the question buffer."
@@ -173,6 +168,21 @@ replaced with the comment."
sx-question-mode--sort-methods))
:group 'sx-question-mode)
+(defcustom sx-question-mode-use-images
+ (eval-when-compile
+ (image-type-available-p 'imagemagick))
+ "Non-nil if SX should download and display images.
+By default, this is `t' if the `imagemagick' image type is
+available (checked with `image-type-available-p'). If this image
+type is not available, images won't work."
+ :type 'boolean
+ :group 'sx-question-mode)
+
+(defcustom sx-question-mode-image-max-width 550
+ "Maximum width, in pixels, of images in the question buffer."
+ :type 'integer
+ :group 'sx-question-mode)
+
;;; Functions
;;;; Printing the general structure
@@ -239,8 +249,8 @@ DATA can represent a question or an answer."
;; Tags
(sx-question-mode--insert-header
sx-question-mode-header-tags
- (mapconcat #'sx-question--tag-format .tags " ")
- 'sx-question-mode-tags))
+ (sx-tag--format-tags .tags .site_par)
+ nil))
;; Body
(insert "\n"
(propertize sx-question-mode-separator
@@ -315,7 +325,10 @@ where `value' is given `face' as its face.
(while args
(insert
(propertize (pop args) 'face 'sx-question-mode-header)
- (propertize (pop args) 'face (pop args)))))
+ (let ((header (pop args))
+ (face (pop args)))
+ (if face (propertize header 'face face)
+ header)))))
;;;; Printing and Font-locking the content (body)
@@ -326,14 +339,16 @@ where `value' is given `face' as its face.
(defconst sx-question-mode--reference-regexp
(rx line-start (0+ blank) "[%s]:" (0+ blank)
- (group-n 1 (1+ (not blank))))
+ (group-n 1 (1+ (not (any blank "\n\r")))))
"Regexp used to find the url of labeled links.
E.g.:
[1]: https://...")
(defconst sx-question-mode--link-regexp
;; Done at compile time.
- (rx (or (and "[" (group-n 1 (1+ (not (any "]")))) "]"
+ (rx (or (and "[" (optional (group-n 6 "meta-")) "tag:"
+ (group-n 5 (+ (not (any " ]")))) "]")
+ (and (opt "!") "[" (group-n 1 (1+ (not (any "]")))) "]"
(or (and "(" (group-n 2 (1+ (not (any ")")))) ")")
(and "[" (group-n 3 (1+ (not (any "]")))) "]")))
(group-n 4 (and (and "http" (opt "s") "://") ""
@@ -377,37 +392,79 @@ E.g.:
;;; Handling links
(defun sx-question-mode--process-links-in-buffer ()
- "Turn all markdown links in this buffer into compact format."
+ "Turn all markdown links in this buffer into compact format.
+Image links are downloaded and displayed, if
+`sx-question-mode-use-images' is non-nil."
(save-excursion
(goto-char (point-min))
(while (search-forward-regexp sx-question-mode--link-regexp nil t)
- (let* ((text (match-string-no-properties 1))
- (url (or (match-string-no-properties 2)
- (match-string-no-properties 4)
- (sx-question-mode-find-reference
- (match-string-no-properties 3)
- text)))
- (full-text (match-string-no-properties 0)))
- (when (stringp url)
- (replace-match "")
- (sx-question-mode--insert-link
- (or (if sx-question-mode-pretty-links text full-text) url)
- url))))))
-
-(defun sx-question-mode--insert-link (text url)
- "Return a link propertized version of string TEXT.
+ ;; Tags are tag-buttons.
+ (let ((tag (match-string-no-properties 5)))
+ (if (and tag (> (length tag) 0))
+ (progn (replace-match "")
+ ;; `match-string' 6 is the "meta-" prefix.
+ (sx-tag--insert tag (match-string 6)))
+ ;; Other links are link-buttons.
+ (let* ((text (match-string-no-properties 1))
+ (url (or (match-string-no-properties 2)
+ (match-string-no-properties 4)
+ (sx-question-mode-find-reference
+ (match-string-no-properties 3)
+ text)))
+ (full-text (match-string-no-properties 0)))
+ (when (stringp url)
+ (replace-match "")
+ (sx-question-mode--insert-link
+ (if (and sx-question-mode-use-images (eq ?! (elt full-text 0)))
+ ;; Is it an image?
+ (sx-question-mode--create-image url)
+ ;; Or a regular link
+ (or (if sx-question-mode-pretty-links text full-text) url))
+ url))))))))
+
+(defun sx-question-mode--create-image (url)
+ "Get and create an image from URL.
+Its size is bound by `sx-question-mode-image-max-width' and
+`window-body-width'."
+ (let* ((image
+ (create-image (sx-request-get-url url) 'imagemagick t))
+ (image-width (car (image-size image 'pixels))))
+ (append image
+ (list :width (min sx-question-mode-image-max-width
+ (window-body-width nil 'pixel)
+ image-width)))))
+
+(defun sx-question-mode--insert-link (text-or-image url)
+ "Return a link propertized version of TEXT-OR-IMAGE.
URL is used as 'help-echo and 'url properties."
- (insert-text-button
- text
- ;; Mouse-over
- 'help-echo
- (format sx-button--link-help-echo
- (propertize (sx--shorten-url url)
- 'face 'font-lock-function-name-face))
- ;; For visiting and stuff.
- 'sx-button-url url
- 'sx-button-copy url
- :type 'sx-button-link))
+ ;; For now, the only way to handle nested links is to remove them.
+ (when (eq (char-before) ?\[)
+ (insert "a")
+ (forward-char -2)
+ (if (looking-at sx-question-mode--link-regexp)
+ (replace-match "")
+ (forward-char 1)
+ (delete-char 1)))
+ (let ((imagep (not (stringp text-or-image))))
+ ;; Images need to be at the start of a line.
+ (when (and imagep (not (looking-at-p "^")))
+ (insert "\n"))
+ (apply #'insert-text-button
+ (if imagep " " text-or-image)
+ ;; Mouse-over
+ 'help-echo
+ (format sx-button--link-help-echo
+ (propertize (sx--shorten-url url)
+ 'face 'font-lock-function-name-face))
+ ;; For visiting and stuff.
+ 'sx-button-url url
+ 'sx-button-copy url
+ :type 'sx-button-link
+ ;; The last argument of `apply' is a list.
+ (when imagep
+ `(face default display ,text-or-image)))
+ ;; Images need to be at the end of a line too.
+ (insert "\n")))
(defun sx-question-mode-find-reference (id &optional fallback-id)
"Find url identified by reference ID in current buffer.
diff --git a/sx-question.el b/sx-question.el
index 1fde1aa..1162eb9 100644
--- a/sx-question.el
+++ b/sx-question.el
@@ -197,20 +197,14 @@ If no cache exists for it, initialize one with SITE."
;;;; Other data
-
(defun sx-question--accepted-answer-id (question)
"Return accepted answer in QUESTION or nil if none exists."
(sx-assoc-let question
(and (integerp .accepted_answer_id)
.accepted_answer_id)))
-(defun sx-question--tag-format (tag)
- "Formats TAG for display."
- (concat "[" tag "]"))
-
;;; Question Mode Answer-Sorting Functions
-
(sx--create-comparator sx-answer-higher-score-p
"Return t if answer A has a higher score than answer B."
#'> (lambda (x) (cdr (assq 'score x))))
diff --git a/sx-request.el b/sx-request.el
index 8f672ec..d7fd058 100644
--- a/sx-request.el
+++ b/sx-request.el
@@ -221,29 +221,34 @@ Currently returns nil."
"https://raw.githubusercontent.com/vermiculus/sx.el/data/data/%s.el"
"Url of the \"data\" directory inside the SX `data' branch.")
-(defun sx-request-get-data (file)
- "Fetch and return data stored online by SX.
-FILE is a string or symbol, the name of the file which holds the
-desired data, relative to `sx-request--data-url-format'. For
-instance, `tags/emacs' returns the list of tags on Emacs.SE."
+(defun sx-request-get-url (url)
+ "Fetch and return data stored online at URL."
(let* ((url-automatic-caching t)
(url-inhibit-uncompression t)
- (request-url (format sx-request--data-url-format file))
(url-request-method "GET")
(url-request-extra-headers
'(("Content-Type" . "application/x-www-form-urlencoded")))
- (response-buffer (url-retrieve-synchronously request-url)))
+ (response-buffer (url-retrieve-synchronously url)))
(if (not response-buffer)
(error "Something went wrong in `url-retrieve-synchronously'")
(with-current-buffer response-buffer
(progn
(goto-char (point-min))
+ (unless (string-match "200" (thing-at-point 'line))
+ (error "Page not found."))
(if (not (search-forward "\n\n" nil t))
(error "Headers missing; response corrupt")
- (when (looking-at-p "Not Found") (error "Page not found."))
- (prog1 (read (current-buffer))
+ (prog1 (buffer-substring (point) (point-max))
(kill-buffer (current-buffer)))))))))
+(defun sx-request-get-data (file)
+ "Fetch and return data stored online by SX.
+FILE is a string or symbol, the name of the file which holds the
+desired data, relative to `sx-request--data-url-format'. For
+instance, `tags/emacs' returns the list of tags on Emacs.SE."
+ (read (sx-request-get-url
+ (format sx-request--data-url-format file))))
+
;;; Support Functions
(defun sx-request--build-keyword-arguments (alist &optional kv-sep)
diff --git a/sx-search.el b/sx-search.el
index 55964b9..b245cbe 100644
--- a/sx-search.el
+++ b/sx-search.el
@@ -32,6 +32,7 @@
(require 'sx)
(require 'sx-question-list)
+(require 'sx-question-mode)
(require 'sx-tag)
(defvar sx-search--query-history nil
@@ -117,6 +118,25 @@ prefix argument, the user is asked for everything."
(sx-question-list-refresh 'redisplay)
(switch-to-buffer (current-buffer))))
+
+;;; Tag
+(defun sx-search-tag-at-point (&optional pos)
+ "Follow tag under position POS or point."
+ (interactive)
+ (let ((tag (save-excursion
+ (when pos (goto-char pos))
+ (or (get-text-property (point) 'sx-tag)
+ (thing-at-point 'symbol))))
+ (meta (save-excursion
+ (when pos (goto-char pos))
+ (get-text-property (point) 'sx-tag-meta)))
+ (site (replace-regexp-in-string
+ (rx string-start "meta.") ""
+ (or sx-question-list--site
+ (sx-assoc-let sx-question-mode--data .site_par)))))
+ (sx-search (concat (when meta "meta.") site)
+ nil tag)))
+
(provide 'sx-search)
;;; sx-search.el ends here
diff --git a/sx-tag.el b/sx-tag.el
index b2ad375..3c00ae2 100644
--- a/sx-tag.el
+++ b/sx-tag.el
@@ -23,6 +23,13 @@
(require 'sx)
(require 'sx-method)
+(require 'sx-button)
+
+(defface sx-tag
+ '((t :underline nil :inherit font-lock-function-name-face))
+ "Face used on the question tags in the question buffer."
+ :group 'sx-question-mode-faces
+ :group 'sx-question-list-faces)
;;; Getting the list from a site
@@ -133,6 +140,37 @@ tags."
(push input list))
(reverse list)))
+
+;;; Printing
+(defun sx-tag--format (tag &optional meta)
+ "Format and return TAG for display.
+If META is non-nil, the tag is for the meta site."
+ (with-temp-buffer
+ (sx-tag--insert tag meta)
+ (buffer-string)))
+
+(defun sx-tag--insert (tag &optional meta)
+ "Insert TAG button.
+If META is non-nil, the tag is for the meta site."
+ (insert-text-button (concat "[" tag "]")
+ 'sx-button-copy tag
+ 'sx-tag tag
+ 'sx-tag-meta meta
+ :type 'sx-button-tag))
+
+(defun sx-tag--format-tags (tags &optional site)
+ "Format and concatenate a sequence of TAGS.
+Returns a string of all tags in TAGS, separated by a space.
+
+SITE is the site to which the tags refer, it is only used to
+decide whether they are main or meta tags. SITE can also be t or
+nil, which respectively indicate meta and main."
+ (let ((is-meta
+ (if (stringp site) (string-match (rx string-start "meta.") site)
+ site)))
+ (mapconcat (lambda (tag) (sx-tag--format tag is-meta))
+ tags " ")))
+
(provide 'sx-tag)
;;; sx-tag.el ends here
diff --git a/sx.el b/sx.el
index 381f78e..501f1e0 100644
--- a/sx.el
+++ b/sx.el
@@ -189,6 +189,11 @@ If ALIST doesn't have a `site' property, one is created using the
;;; Utility Functions
+(defun sx--split-string (string &optional separators)
+ "Split STRING into substrings bounded by matches for SEPARATORS."
+ (mapcar (lambda (s) (replace-regexp-in-string "\\` +\\| +\\'" "" s))
+ (split-string string separators 'omit-nulls)))
+
(defun sx-completing-read (&rest args)
"Like `completing-read', but possibly use ido.
All ARGS are passed to `completing-read' or `ido-completing-read'."
@@ -204,7 +209,7 @@ is intentionally skipped."
(while (and ;; We're not at the end.
(cdr-safe tail)
;; We're not at the right place.
- (,(or predicate #'<) x (cadr tail)))
+ (funcall (or ,predicate #'<) x (cadr tail)))
(setq tail (cdr tail)))
(setcdr tail (cons x (cdr tail)))))
diff --git a/test/test-api.el b/test/test-api.el
index b7d5dbb..faf2e0a 100644
--- a/test/test-api.el
+++ b/test/test-api.el
@@ -14,3 +14,26 @@
(ert-deftest test-method-get-all ()
"Tests sx-method interface to `sx-request-all-items'"
(should (< 250 (length (sx-method-call 'sites :get-all t)))))
+
+(ert-deftest request-get-url ()
+ (should (sx-request-get-url "http://google.com"))
+ (should-error (sx-request-get-url "http://github.com/Bruce-Connor/does-not-exist"))
+ (when sx-question-mode-use-images
+ (should
+ ;; If image is not recognized, this returns nil.
+ (create-image (sx-request-get-url "https://raw.githubusercontent.com/vermiculus/sx.el/master/list-and-question.png")
+ 'imagemagick t
+ :width sx-question-mode-image-max-width)))
+ ;; In case imagemacgick is not available, let's try png so we at
+ ;; least test the function.
+ (when (image-type-available-p 'png)
+ (should
+ (create-image (sx-request-get-url "https://raw.githubusercontent.com/vermiculus/sx.el/master/list-and-question.png")
+ 'png t
+ :width sx-question-mode-image-max-width))))
+
+(ert-deftest request-get-data ()
+ (should-error (sx-request-get-data "tags/emacs-does-not-exist"))
+ (let ((emacs-tags (sx-request-get-data 'tags/emacs)))
+ (should (> (length emacs-tags) 450))
+ (should (not (cl-remove-if #'stringp emacs-tags)))))
diff --git a/test/test-printing.el b/test/test-printing.el
index bcc3dd9..8016444 100644
--- a/test/test-printing.el
+++ b/test/test-printing.el
@@ -13,7 +13,7 @@
(defmacro question-list-regex (title votes answers &rest tags)
"Construct a matching regexp for TITLE, VOTES, and ANSWERS.
Each element of TAGS is appended at the end of the expression
-after being run through `sx-question--tag-format'."
+after being run through `sx-tag--format'."
`(rx line-start
(+ whitespace) ,(number-to-string votes)
(+ whitespace) ,(number-to-string answers)
@@ -22,8 +22,7 @@ after being run through `sx-question--tag-format'."
(+ (any whitespace digit))
(or "y" "d" "h" "m" "mo" "s") " ago"
(+ whitespace)
- (eval (mapconcat #'sx-question--tag-format
- (list ,@tags) " "))))
+ (eval (mapconcat #'sx-tag--format (list ,@tags) " "))))
;;; Tests
@@ -40,11 +39,18 @@ after being run through `sx-question--tag-format'."
(sx-time-since 1420105000.)))))
(ert-deftest question-list-tag ()
- "Test `sx-question--tag-format'."
+ "Test `sx-tag--format'."
(should
- (string=
- (sx-question--tag-format "tag")
- "[tag]")))
+ (string= (sx-tag--format "tag") "[tag]"))
+ (with-temp-buffer
+ (insert (sx-tag--format "tag"))
+ (should (get-char-property (point-min) 'button))
+ (should
+ (eq (get-char-property (point-min) 'face) 'sx-tag))
+ (should
+ (string= (get-char-property (point-min) 'sx-tag) "tag"))
+ (should
+ (string= (get-char-property (point-min) 'sx-button-copy) "tag"))))
(ert-deftest question-list-display ()
(cl-letf (((symbol-function #'sx-request-make)