diff options
Diffstat (limited to 'sx-interaction.el')
-rw-r--r-- | sx-interaction.el | 112 |
1 files changed, 100 insertions, 12 deletions
diff --git a/sx-interaction.el b/sx-interaction.el index b67e0df..9a5bbcb 100644 --- a/sx-interaction.el +++ b/sx-interaction.el @@ -19,6 +19,21 @@ ;;; Commentary: +;; This file holds a series of functions for performing arbitrary +;; interactions with arbitrary objects (objects here always mean the +;; alist of a question, answer, or comment). All commands take at +;; least a DATA argument corresponding to the object which, when +;; called interactively, is always derived from the context at point +;; (usually using the `sx--data-here' function). +;; +;; Interactions represented here involve voting, commenting, asking, +;; answering, editing. +;; +;; These are commands are meant to be available throughout the +;; interface. So it didn't make sense to put them in a specific +;; module. They also rely on a lot of dependencies, so they couldn't +;; be put in sx.el. + ;;; Code: @@ -26,6 +41,8 @@ (require 'sx-question) (require 'sx-question-mode) (require 'sx-question-list) +(require 'sx-compose) +(require 'sx-tab) ;;; Using data in buffer @@ -44,13 +61,15 @@ it throws an error." (and (null noerror) (error "No question data found here")))) -(defun sx--maybe-update-display () - "Refresh the question list if we're inside it." - (cond - ((derived-mode-p 'sx-question-list-mode) - (sx-question-list-refresh 'redisplay 'no-update)) - ((derived-mode-p 'sx-question-mode) - (sx-question-mode-refresh 'no-update)))) +(defun sx--maybe-update-display (&optional buffer) + "Refresh whatever is displayed in BUFFER or the current buffer. +If BUFFER is not live, nothing is done." + (setq buffer (or buffer (current-buffer))) + (when (buffer-live-p buffer) + (cond ((derived-mode-p 'sx-question-list-mode) + (sx-question-list-refresh 'redisplay 'no-update)) + ((derived-mode-p 'sx-question-mode) + (sx-question-mode-refresh 'no-update))))) (defun sx--copy-data (from to) "Copy all fields of alist FORM onto TO. @@ -75,7 +94,7 @@ If DATA is a question, also mark it as read." (let ((link (when (stringp .link) (funcall (if copy-as-kill #'kill-new #'browse-url) - .link)))) + .link)))) (when (and (called-interactively-p 'any) copy-as-kill) (message "Copied: %S" link))) (when (and .title (not copy-as-kill)) @@ -222,13 +241,82 @@ OBJECT can be a question or an answer." (setcdr com-cell (apply #'vector - (append - (cl-map 'list #'identity - (cdr com-cell)) - (list comment))))) + (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]))))) + +;;; Editing +(defun sx-edit (data) + "Start editing an answer or question given by DATA. +DATA is an answer or question alist. Interactively, it is guessed +from context at point." + ;; Answering doesn't really make sense from anywhere other than + ;; inside a question. So we don't need `sx--data-here' here. + (interactive (list (sx--data-here))) + ;; If we ever make an "Edit" button, first arg is a marker. + (when (markerp data) (setq data (sx--data-here))) + (sx-assoc-let data + (when .comment_id (user-error "Editing comments is not supported yet")) + (let ((buffer (current-buffer))) + (pop-to-buffer + (sx-compose-create + .site data nil + ;; After send functions + (list (lambda (_ res) + (sx--copy-data (elt res 0) data) + (sx--maybe-update-display buffer)))))))) + + +;;; Asking +(defun sx-ask (site) + "Start composing a question for SITE. +SITE is a string, indicating where the question will be posted." + ;; Answering doesn't really make sense from anywhere other than + ;; inside a question. So we don't need `sx--data-here' here. + (interactive (list (sx-tab--interactive-site-prompt))) + (let ((buffer (current-buffer))) + (pop-to-buffer + (sx-compose-create + site nil nil + ;; After send functions + (list (lambda (_ res) (sx--maybe-update-display buffer))))))) + + +;;; Answering +(defun sx-answer (data) + "Start composing an answer for question given by DATA. +DATA is a question alist. Interactively, it is guessed from +context at point. " + ;; Answering doesn't really make sense from anywhere other than + ;; inside a question. So we don't need `sx--data-here' here. + (interactive (list sx-question-mode--data)) + ;; When clicking the "Write an Answer" button, first arg is a marker. + (when (markerp data) (setq data (sx--data-here))) + (let ((buffer (current-buffer))) + (sx-assoc-let data + (pop-to-buffer + (sx-compose-create + .site .question_id nil + ;; After send functions + (list (lambda (_ res) + (sx--add-answer-to-question-object + (elt res 0) sx-question-mode--data) + (sx--maybe-update-display buffer)))))))) + +(defun sx--add-answer-to-question-object (answer question) + "Add alist ANSWER to alist QUESTION in the right place." + (let ((cell (assoc 'answers question))) + (if cell + (setcdr cell (apply #'vector + (append (cdr cell) (list answer)))) + ;; No previous comments, add it manually. + (setcdr question (cons (car question) (cdr question))) + (setcar question `(answers . [,answer]))))) + (provide 'sx-interaction) ;;; sx-interaction.el ends here |