diff options
-rw-r--r-- | sx-question-mode.el | 114 | ||||
-rw-r--r-- | sx.el | 35 |
2 files changed, 76 insertions, 73 deletions
diff --git a/sx-question-mode.el b/sx-question-mode.el index a9e14e7..abea6bf 100644 --- a/sx-question-mode.el +++ b/sx-question-mode.el @@ -84,10 +84,6 @@ If WINDOW is given, use that to display the buffer." ;;; Printing a question's content ;;;; Faces and Variables -(defvar sx-question-mode--overlays nil - "Question mode overlays.") -(make-variable-buffer-local 'sx-question-mode--overlays) - (defface sx-question-mode-header '((t :inherit font-lock-variable-name-face)) "Face used on the question headers in the question buffer." @@ -194,12 +190,12 @@ replaced with the comment." 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) + (mapc #'delete-overlay sx--overlays) + (setq sx--overlays nil) ;; Print everything (sx-question-mode--print-section question) (sx-assoc-let question - (mapc #'sx-question-mode--print-section .answers)) + (mapc #'sx-question-mode--print-section .answers)) (goto-char (point-min)) (with-selected-window sx-question-mode--window (sx-question-mode-next-section))) @@ -222,10 +218,10 @@ QUESTION must be a data structure returned by `json-read'." "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 + ;; `(get-text-property (point) 'sx--data-here)' + (sx-assoc-let data + (sx--wrap-in-text-property + (list 'sx--data-here data) (insert sx-question-mode-header-title (apply #'propertize @@ -238,7 +234,7 @@ DATA can represent a question or an answer." ;; face, action and help-echo sx-question-mode--title-properties)) ;; Sections can be hidden with overlays - (sx-question-mode--wrap-in-overlay + (sx--wrap-in-overlay '(sx-question-mode--section-content t) (sx-question-mode--insert-header ;; Author @@ -265,28 +261,29 @@ DATA can represent a question or an answer." (propertize sx-question-mode-separator 'face 'sx-question-mode-header 'sx-question-mode--section 4)) - (sx-question-mode--wrap-in-overlay + (sx--wrap-in-overlay '(face sx-question-mode-content-face) (insert "\n" (sx-question-mode--fill-and-fontify .body_markdown) "\n" (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))))))) + 'face 'sx-question-mode-header))))) + ;; Comments have their own `sx--data-here' property (so they can + ;; be upvoted too). + (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--wrap-in-overlay + '(sx-question-mode--section-content t) + (insert "\n") + (sx--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." @@ -298,46 +295,21 @@ DATA can represent a question or an answer." "Print the comment described by alist COMMENT-DATA. The comment is indented, filled, and then printed according to `sx-question-mode-comments-format'." - (sx-assoc-let comment-data - (insert - (format - sx-question-mode-comments-format - (sx-question-mode--propertize-display-name .owner) - (substring - ;; We fill with three spaces at the start, so the comment is - ;; slightly indented. - (sx-question-mode--fill-and-fontify - (concat " " .body_markdown)) - ;; Then we remove the spaces from the first line, since we'll - ;; add the username there anyway. - 3))))) - -(defmacro sx-question-mode--wrap-in-overlay (properties &rest body) - "Start a scope with overlay PROPERTIES and execute BODY. -Overlay is pushed on `sx-question-mode--overlays' and given -PROPERTIES. - -Return the result of BODY." - (declare (indent 1) - (debug t)) - `(let ((p (point-marker)) - (result (progn ,@body))) - (let ((ov (make-overlay p (point))) - (props ,properties)) - (while props - (overlay-put ov (pop props) (pop props))) - (push ov sx-question-mode--overlays)) - result)) - -(defmacro sx-question-mode--wrap-in-text-property (properties &rest body) - "Start a scope with PROPERTIES and execute BODY. -Return the result of BODY." - (declare (indent 1) - (debug t)) - `(let ((p (point-marker)) - (result (progn ,@body))) - (add-text-properties p (point) ,properties) - result)) + (sx--wrap-in-text-property + (list 'sx--data-here comment-data) + (sx-assoc-let comment-data + (insert + (format + sx-question-mode-comments-format + (sx-question-mode--propertize-display-name .owner) + (substring + ;; We fill with three spaces at the start, so the comment is + ;; slightly indented. + (sx-question-mode--fill-and-fontify + (concat " " .body_markdown)) + ;; Then we remove the spaces from the first line, since we'll + ;; add the username there anyway. + 3)))))) (defun sx-question-mode--insert-header (&rest args) "Insert propertized ARGS. @@ -345,9 +317,7 @@ ARGS is a list of repeating values -- `header', `value', and `face'. `header' is given `sx-question-mode-header' as a face, where `value' is given `face' as its face. -Syntax: - - \(fn HEADER VALUE FACE [HEADER VALUE FACE] [HEADER VALUE FACE] ...)" +\(fn HEADER VALUE FACE [HEADER VALUE FACE] [HEADER VALUE FACE] ...)" (while args (insert (propertize (pop args) 'face 'sx-question-mode-header) @@ -592,7 +562,7 @@ Letters do not insert themselves; instead, they are commands. ;; 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) + (append (get-text-property (point) 'sx--data-here) sx-question-mode--data) (browse-url .link))) @@ -129,7 +129,40 @@ would yield data)))) -;;; Interpreting request data +;;; Printing request data +(defvar sx--overlays nil + "Overlays created by sx on this buffer.") +(make-variable-buffer-local 'sx--overlays) + +(defmacro sx--wrap-in-overlay (properties &rest body) + "Start a scope with overlay PROPERTIES and execute BODY. +Overlay is pushed on the buffer-local variable `sx--overlays' and +given PROPERTIES. + +Return the result of BODY." + (declare (indent 1) + (debug t)) + `(let ((p (point-marker)) + (result (progn ,@body))) + (let ((ov (make-overlay p (point))) + (props ,properties)) + (while props + (overlay-put ov (pop props) (pop props))) + (push ov sx--overlays)) + result)) + +(defmacro sx--wrap-in-text-property (properties &rest body) + "Start a scope with PROPERTIES and execute BODY. +Return the result of BODY." + (declare (indent 1) + (debug t)) + `(let ((p (point-marker)) + (result (progn ,@body))) + (add-text-properties p (point) ,properties) + result)) + + +;;; Assoc-let (defun sx--deep-dot-search (data) "Find symbols somewhere inside DATA which start with a `.'. Returns a list where each element is a cons cell. The car is the |