aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSean Allred <code@seanallred.com>2014-11-25 21:55:46 -0500
committerSean Allred <code@seanallred.com>2014-11-25 21:55:46 -0500
commit07a1456fe7a91d1589f689d40ac4391f35e695b9 (patch)
tree1c79f7808dc280e29ca2ca93dc57792ba8286d4f
parent56c95d4670f97c66e9cfcf52b6209f954a284b21 (diff)
parent977182943de4e3824a9178f3f3c114648b227265 (diff)
Merge pull request #95 from vermiculus/commenting
Commenting
-rw-r--r--sx-interaction.el80
-rw-r--r--sx-question-list.el9
-rw-r--r--sx-question-mode.el12
-rw-r--r--sx-question.el2
-rw-r--r--sx.el12
5 files changed, 106 insertions, 9 deletions
diff --git a/sx-interaction.el b/sx-interaction.el
index a9203bd..404fb56 100644
--- a/sx-interaction.el
+++ b/sx-interaction.el
@@ -106,5 +106,85 @@ changes."
;; Display the changes in `data'.
(sx--maybe-update-display))))
+
+;;; Commenting
+(defun sx-comment (data text)
+ "Post a comment on DATA given by TEXT.
+DATA can be a question, an answer, or a comment. Interactively,
+it is guessed from context at point.
+If DATA is a comment, the comment is posted as a reply to it.
+
+TEXT is a string. Interactively, it is read from the minibufer."
+ (interactive
+ (list (sx--data-here) 'query))
+ (sx-assoc-let data
+ ;; Get the comment text
+ (when (eq text 'query)
+ (setq text (read-string
+ "Comment text: "
+ (when .comment_id
+ (sx--user-@name .owner))))
+ (while (< (string-width text) 15)
+ (setq text (read-string "Comment text (at least 15 characters): " text))))
+ ;; If non-interactive, `text' could be anything.
+ (unless (stringp text)
+ (error "Comment body must be a string"))
+ ;; And post
+ (let ((result
+ (sx-method-call 'posts
+ :id (or .post_id .answer_id .question_id)
+ :submethod "comments/add"
+ :auth 'warn
+ :url-method "POST"
+ :filter sx-browse-filter
+ :site .site
+ :keywords `((body ,text)))))
+ ;; The api returns the new DATA.
+ (when (> (length result) 0)
+ (sx--add-comment-to-object
+ (elt result 0)
+ (if .post_id
+ (sx--get-post .post_type .site .post_id)
+ data))
+ ;; Display the changes in `data'.
+ (sx--maybe-update-display)))))
+
+(defun sx--get-post (type site id)
+ "Find in the database a post identified by TYPE, SITE and ID.
+TYPE is `question' or `answer'.
+SITE is a string.
+ID is an integer."
+ (let ((db (cons sx-question-mode--data
+ sx-question-list--dataset)))
+ (setq db
+ (cond
+ ((string= type "question") db)
+ ((string= type "answer")
+ (apply #'cl-map 'list #'identity
+ (mapcar (lambda (x) (cdr (assoc 'answers x))) db)))))
+ (car (cl-member-if
+ (lambda (x) (sx-assoc-let x
+ (and (equal (or .answer_id .question_id) id)
+ (equal .site site))))
+ db))))
+
+(defun sx--add-comment-to-object (comment object)
+ "Add COMMENT to OBJECT's `comments' property.
+OBJECT can be a question or an answer."
+ (let ((com-cell (assoc 'comments object))
+ (count-cell (assoc 'comment_count object)))
+ (if com-cell
+ (progn
+ (setcdr
+ com-cell
+ (apply #'vector
+ (append
+ (cl-map 'list #'identity
+ (cdr com-cell))
+ (list comment)))))
+ ;; No previous comments, add it manually.
+ (setcdr object (cons (car object) (cdr object)))
+ (setcar object `(comments . [,comment])))))
+
(provide 'sx-interaction)
;;; sx-interaction.el ends here
diff --git a/sx-question-list.el b/sx-question-list.el
index 4d7681b..2965ede 100644
--- a/sx-question-list.el
+++ b/sx-question-list.el
@@ -427,8 +427,10 @@ This does not update `sx-question-mode--window'."
(forward-line -1)
(when (functionp sx-question-list--next-page-function)
;; Try to get more questions
- (let ((list (funcall sx-question-list--next-page-function
- (1+ sx-question-list--pages-so-far))))
+ (let ((list
+ (cl-map 'list #'identity
+ (funcall sx-question-list--next-page-function
+ (1+ sx-question-list--pages-so-far)))))
(if (null list)
(message "No further questions.")
;; If it worked, increment the variable.
@@ -436,7 +438,8 @@ This does not update `sx-question-mode--window'."
;; And update the dataset.
;; @TODO: Check for duplicates.
(setq sx-question-list--dataset
- (append sx-question-list--dataset list))
+ (append sx-question-list--dataset
+ list))
(sx-question-list-refresh 'redisplay 'no-update)
(forward-line 1)))))
diff --git a/sx-question-mode.el b/sx-question-mode.el
index f1a8cc0..70b8866 100644
--- a/sx-question-mode.el
+++ b/sx-question-mode.el
@@ -499,11 +499,12 @@ Prefix argument N moves N sections down or up."
(unless (and (overlayp ov)
(overlay-get ov 'invisible))
(cl-decf count)))))
- (when sx-question-mode-recenter-line
- (let ((ov (car-safe (sx-question-mode--section-overlays-at (line-end-position)))))
- (when (and (overlayp ov) (> (overlay-end ov) (window-end)))
- (recenter sx-question-mode-recenter-line))))
- (sx-message-help-echo))
+ (when (equal (selected-window) (get-buffer-window))
+ (when sx-question-mode-recenter-line
+ (let ((ov (car-safe (sx-question-mode--section-overlays-at (line-end-position)))))
+ (when (and (overlayp ov) (> (overlay-end ov) (window-end)))
+ (recenter sx-question-mode-recenter-line))))
+ (sx-message-help-echo)))
(defun sx-question-mode-previous-section (&optional n)
"Move down to previous section (question or answer) of this buffer.
@@ -571,6 +572,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)
+ ("c" sx-comment)
("v" sx-visit)
("u" sx-toggle-upvote)
("d" sx-toggle-downvote)
diff --git a/sx-question.el b/sx-question.el
index de07c94..a7aadb2 100644
--- a/sx-question.el
+++ b/sx-question.el
@@ -43,7 +43,7 @@ property.
"Query SITE for a QUESTION-ID and return it.
If QUESTION-ID doesn't exist on SITE, raise an error."
(let ((res (sx-method-call 'questions
- :id id
+ :id question-id
:site site
:auth t
:filter sx-browse-filter)))
diff --git a/sx.el b/sx.el
index e5f81a4..d4c3ac2 100644
--- a/sx.el
+++ b/sx.el
@@ -56,6 +56,7 @@
question.link
question.upvoted
question.downvoted
+ question.question_id
user.display_name
comment.owner
comment.body_markdown
@@ -65,6 +66,10 @@
comment.creation_date
comment.upvoted
comment.score
+ comment.post_type
+ comment.post_id
+ comment.comment_id
+ answer.answer_id
answer.last_editor
answer.link
answer.owner
@@ -193,6 +198,13 @@ Return the result of BODY."
(add-text-properties p (point) ,properties)
result))
+(defun sx--user-@name (user)
+ "Get the `display_name' of USER prepended with @."
+ (sx-assoc-let user
+ (when (stringp .display_name)
+ (concat "@" .display_name))))
+
+
;;; Assoc-let
(defun sx--site (data)
"Get the site in which DATA belongs.