aboutsummaryrefslogtreecommitdiff
path: root/sx-question-mode.el
diff options
context:
space:
mode:
authorSean Allred <code@seanallred.com>2014-11-18 23:49:07 -0500
committerSean Allred <code@seanallred.com>2014-11-19 00:00:42 -0500
commit0dd95e3a3d4ee52f52a585388c3ba65e045c305b (patch)
treef8c4497519cf6f741ea7ec379c537f4b71a4de88 /sx-question-mode.el
parent20dd7254da8e95bd01ce57f806733dee20005039 (diff)
parent681319aeb250a83d982d1e3e02264a7af0ae4120 (diff)
Merge branch 'master' into documentation
Conflicts: sx-method.el sx-question-list.el sx-question-mode.el sx-question.el sx-request.el sx.el
Diffstat (limited to 'sx-question-mode.el')
-rw-r--r--sx-question-mode.el164
1 files changed, 99 insertions, 65 deletions
diff --git a/sx-question-mode.el b/sx-question-mode.el
index d971a49..627081b 100644
--- a/sx-question-mode.el
+++ b/sx-question-mode.el
@@ -199,6 +199,7 @@ replaced with the comment."
"Print a buffer describing QUESTION.
QUESTION must be a data structure returned by `json-read'."
+ (setq sx-question-mode--data question)
;; Clear the overlays
(mapc #'delete-overlay sx-question-mode--overlays)
(setq sx-question-mode--overlays nil)
@@ -224,71 +225,75 @@ QUESTION must be a data structure returned by `json-read'."
follow-link t)
"")
-(defun sx-question-mode--print-section (question-data)
- "Print a section corresponding to QUESTION-DATA.
-
-QUESTION-DATA can represent a question or an answer."
- (sx-assoc-let question-data
- (insert sx-question-mode-header-title
- (apply
- #'propertize
- ;; Questions have title
- (or .title
- ;; Answers don't
- sx-question-mode-answer-title)
- ;; Section level
- 'sx-question-mode--section (if .title 1 2)
- ;; face, action and help-echo
- sx-question-mode--title-properties))
- ;; Sections can be hidden with overlays
- (sx-question-mode--wrap-in-overlay
- '(sx-question-mode--section-content t)
- (sx-question-mode--insert-header
- ;; Author
- sx-question-mode-header-author
- (sx-question-mode--propertize-display-name .owner)
- 'sx-question-mode-author
- ;; Date
- sx-question-mode-header-date
- (concat
- (sx-time-seconds-to-date .creation_date)
- (when .last_edit_date
- (format sx-question-mode-last-edit-format
- (sx-time-since .last_edit_date)
- (sx-question-mode--propertize-display-name .last_editor))))
- 'sx-question-mode-date)
- (when .title
- ;; Tags
- (sx-question-mode--insert-header
- sx-question-mode-header-tags
- (mapconcat #'sx-question--tag-format .tags " ")
- 'sx-question-mode-tags))
- ;; Body
- (insert "\n"
- (propertize sx-question-mode-separator
- 'face 'sx-question-mode-header
- 'sx-question-mode--section 4))
+(defun sx-question-mode--print-section (data)
+ "Print a section corresponding to DATA.
+
+DATA can represent a question or an answer."
+ ;; This makes `data' accessible through
+ ;; `(get-text-property (point) 'sx-question-mode--data-here)'
+ (sx-question-mode--wrap-in-text-property
+ (list 'sx-question-mode--data-here data)
+ (sx-assoc-let data
+ (insert sx-question-mode-header-title
+ (apply
+ #'propertize
+ ;; Questions have title
+ (or .title
+ ;; Answers don't
+ sx-question-mode-answer-title)
+ ;; Section level
+ 'sx-question-mode--section (if .title 1 2)
+ ;; face, action and help-echo
+ sx-question-mode--title-properties))
+ ;; Sections can be hidden with overlays
(sx-question-mode--wrap-in-overlay
- '(face sx-question-mode-content-face)
+ '(sx-question-mode--section-content t)
+ (sx-question-mode--insert-header
+ ;; Author
+ sx-question-mode-header-author
+ (sx-question-mode--propertize-display-name .owner)
+ 'sx-question-mode-author
+ ;; Date
+ sx-question-mode-header-date
+ (concat
+ (sx-time-seconds-to-date .creation_date)
+ (when .last_edit_date
+ (format sx-question-mode-last-edit-format
+ (sx-time-since .last_edit_date)
+ (sx-question-mode--propertize-display-name .last_editor))))
+ 'sx-question-mode-date)
+ (when .title
+ ;; Tags
+ (sx-question-mode--insert-header
+ sx-question-mode-header-tags
+ (mapconcat #'sx-question--tag-format .tags " ")
+ 'sx-question-mode-tags))
+ ;; Body
(insert "\n"
- (sx-question-mode--fill-and-fontify
- .body_markdown)
(propertize sx-question-mode-separator
- 'face 'sx-question-mode-header))))
- ;; Comments
- (when .comments
- (insert "\n"
- (apply #'propertize
- sx-question-mode-comments-title
- 'face 'sx-question-mode-title-comments
- 'sx-question-mode--section 3
- sx-question-mode--title-properties))
- (sx-question-mode--wrap-in-overlay
- '(sx-question-mode--section-content t)
- (insert "\n")
+ 'face 'sx-question-mode-header
+ 'sx-question-mode--section 4))
(sx-question-mode--wrap-in-overlay
'(face sx-question-mode-content-face)
- (mapc #'sx-question-mode--print-comment .comments))))))
+ (insert "\n"
+ (sx-question-mode--fill-and-fontify
+ .body_markdown)
+ (propertize sx-question-mode-separator
+ 'face 'sx-question-mode-header))))
+ ;; Comments
+ (when .comments
+ (insert "\n"
+ (apply #'propertize
+ sx-question-mode-comments-title
+ 'face 'sx-question-mode-title-comments
+ 'sx-question-mode--section 3
+ sx-question-mode--title-properties))
+ (sx-question-mode--wrap-in-overlay
+ '(sx-question-mode--section-content t)
+ (insert "\n")
+ (sx-question-mode--wrap-in-overlay
+ '(face sx-question-mode-content-face)
+ (mapc #'sx-question-mode--print-comment .comments)))))))
(defun sx-question-mode--propertize-display-name (author)
"Return display_name of AUTHOR with `sx-question-mode-author' face."
@@ -333,6 +338,17 @@ Return the result of BODY."
(push ov sx-question-mode--overlays))
result))
+(defmacro sx-question-mode--wrap-in-text-property (properties &rest body)
+ "Execute BODY and PROPERTIES to any inserted text.
+
+Return the result of BODY."
+ (declare (indent 1)
+ (debug t))
+ `(let ((p (point-marker))
+ (result (progn ,@body)))
+ (add-text-properties p (point) ,properties)
+ result))
+
(defun sx-question-mode--insert-header (&rest args)
"Insert propertized ARGS.
@@ -364,11 +380,11 @@ Use as (fn header value face
(when sx-question-mode-bullet-appearance
(font-lock-add-keywords ;; Bullet items.
nil
- `(((rx line-start (0+ blank) (group-n 1 (any "*+-")) blank)
+ `((,(rx line-start (0+ blank) (group-n 1 (any "*+-")) blank)
1 '(face nil display ,sx-question-mode-bullet-appearance) prepend))))
(font-lock-add-keywords ;; Highlight usernames.
nil
- `(((rx (or blank line-start)
+ `((,(rx (or blank line-start)
(group-n 1 (and "@" (1+ (or (syntax word) (syntax symbol)))))
symbol-end)
1 font-lock-builtin-face)))
@@ -449,7 +465,7 @@ If ID is nil, use FALLBACK-ID instead."
(save-match-data
(goto-char (point-min))
(when (search-forward-regexp
- (format (rx line-start (0+ blank) "[%s]:" (1+ blank)
+ (format (rx line-start (0+ blank) "[%s]:" (0+ blank)
(group-n 1 (1+ (not blank))))
(or id fallback-id))
nil t)
@@ -573,6 +589,7 @@ Letters do not insert themselves; instead, they are commands.
`(("n" sx-question-mode-next-section)
("p" sx-question-mode-previous-section)
("g" sx-question-mode-refresh)
+ ("v" sx-question-mode-visit)
("q" quit-window)
(" " scroll-up-command)
(,(kbd "S-SPC") scroll-down-command)
@@ -583,19 +600,36 @@ Letters do not insert themselves; instead, they are commands.
(,(kbd "<backtab>") backward-button)
([return] push-button)))
+(defun sx-question-mode-visit ()
+ "Visit the currently displayed question."
+ (interactive)
+ (sx-question-mode--ensure-mode)
+ (sx-assoc-let
+ ;; This allows us to visit the thing-at-point. Which could be a
+ ;; question or an answer. We use `append', so that if one
+ ;; doesn't have a `link' item we can fallback to
+ ;; `sx-question-mode--data'.
+ (append (get-text-property (point) 'sx-question-mode--data-here)
+ sx-question-mode--data)
+ (browse-url .link)))
+
(defun sx-question-mode-refresh ()
"Refresh currently displayed question.
Queries the API for any changes to the question or its answers or
comments, and redisplays it."
(interactive)
- (unless (derived-mode-p 'sx-question-mode)
- (error "Not in `sx-question-mode'"))
+ (sx-question-mode--ensure-mode)
(sx-assoc-let sx-question-mode--data
(sx-question-mode--display
(sx-question-get-question
sx-question-list--current-site .question_id)
(selected-window))))
+(defun sx-question-mode--ensure-mode ()
+ "Ensures we are in question mode, erroring otherwise."
+ (unless (derived-mode-p 'sx-question-mode)
+ (error "Not in `sx-question-mode'")))
+
(provide 'sx-question-mode)
;;; sx-question-mode.el ends here