aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sx-question-print.el84
-rw-r--r--sx-request.el23
-rw-r--r--test/test-api.el23
3 files changed, 104 insertions, 26 deletions
diff --git a/sx-question-print.el b/sx-question-print.el
index 190c924..9f51b4c 100644
--- a/sx-question-print.el
+++ b/sx-question-print.el
@@ -157,6 +157,21 @@ replaced with the comment."
(const :tag "More active first" sx-answer-more-active-p))
: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
@@ -313,7 +328,7 @@ 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://...")
@@ -321,7 +336,7 @@ E.g.:
(defconst sx-question-mode--link-regexp
;; Done at compile time.
(rx (or (and "[tag:" (group-n 5 (+ (not (any " ]")))) "]")
- (and "[" (group-n 1 (1+ (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") "://") ""
@@ -365,7 +380,9 @@ 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)
@@ -385,23 +402,56 @@ E.g.:
(when (stringp url)
(replace-match "")
(sx-question-mode--insert-link
- (or (if sx-question-mode-pretty-links text full-text) url)
+ (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--insert-link (text url)
- "Return a link propertized version of string TEXT.
+(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-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/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)))))