From 3de378c215fdfa82df821df1339b0f1504d4a469 Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Wed, 17 Dec 2014 12:36:11 -0200 Subject: Support editing comments. --- sx-interaction.el | 1 - 1 file changed, 1 deletion(-) (limited to 'sx-interaction.el') diff --git a/sx-interaction.el b/sx-interaction.el index ea494eb..da08581 100644 --- a/sx-interaction.el +++ b/sx-interaction.el @@ -304,7 +304,6 @@ from context at point." ;; 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 (sx-user-error "Editing comments is not supported yet")) (let ((buffer (current-buffer))) (pop-to-buffer (sx-compose-create -- cgit v1.2.3 From 5c965d196ff4dcd043577ecdacdd75b21482ea9c Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Wed, 17 Dec 2014 12:36:37 -0200 Subject: Fix buffer not updating after posting answers/edits. --- sx-interaction.el | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'sx-interaction.el') diff --git a/sx-interaction.el b/sx-interaction.el index da08581..177a054 100644 --- a/sx-interaction.el +++ b/sx-interaction.el @@ -93,10 +93,11 @@ If it's not a question, or if it is read, return DATA." 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))))) + (with-current-buffer 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. -- cgit v1.2.3 From ad3849d4b4d946bc186473718ccd50953a94c143 Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Wed, 17 Dec 2014 12:53:25 -0200 Subject: Refactor comment validity checking --- sx-interaction.el | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'sx-interaction.el') diff --git a/sx-interaction.el b/sx-interaction.el index 177a054..9af9ac6 100644 --- a/sx-interaction.el +++ b/sx-interaction.el @@ -234,8 +234,8 @@ TEXT is a string. Interactively, it is read from the minibufer." "Comment text: " (when .comment_id (concat (sx--user-@name .owner) " ")))) - (while (< (string-width text) 15) - (setq text (read-string "Comment text (at least 15 characters): " text)))) + (while (not (sx--comment-valid-p text 'silent)) + (setq text (read-string "Comment text (between 16 and 600 characters): " text)))) ;; If non-interactive, `text' could be anything. (unless (stringp text) (error "Comment body must be a string")) @@ -259,6 +259,18 @@ TEXT is a string. Interactively, it is read from the minibufer." ;; Display the changes in `data'. (sx--maybe-update-display))))) +(defun sx--comment-valid-p (&optional text silent) + "Non-nil if TEXT fits stack exchange comment length limits. +If TEXT is nil, use `buffer-string'. Must have more than 15 and +less than 601 characters. +If SILENT is nil, message the user about this limit." + (let ((w (string-width (or text (buffer-string))))) + (if (and (< 15 w) (< w 601)) + t + (unless silent + (message "Comments must be within 16 and 600 characters.")) + nil))) + (defun sx--get-post (type site id) "Find in the database a post identified by TYPE, SITE and ID. TYPE is `question' or `answer'. -- cgit v1.2.3 From 8142023ef51a90fdb5fe094bd9861308cb39452d Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Wed, 17 Dec 2014 12:53:35 -0200 Subject: Do comment validity checking on edits too --- sx-interaction.el | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'sx-interaction.el') diff --git a/sx-interaction.el b/sx-interaction.el index 9af9ac6..2768c8d 100644 --- a/sx-interaction.el +++ b/sx-interaction.el @@ -320,7 +320,9 @@ from context at point." (let ((buffer (current-buffer))) (pop-to-buffer (sx-compose-create - .site data nil + .site data + ;; Before send hook + (when .comment_id (list #'sx--comment-valid-p)) ;; After send functions (list (lambda (_ res) (sx--copy-data (elt res 0) data) -- cgit v1.2.3 From d51791fb6ae69e3b426f7d598920b4349858908f Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Mon, 22 Dec 2014 11:37:35 -0200 Subject: Refactor .site to .site_par It turns out some api objects do have a site property, except its value is not a string, it is another object. The actual string we've been referring to as .site is the .site.api_site_parameter To avoid conflicts, I've renamed all our uses of .site to .site_par, and sx-assoc-let now makes sure the object has a .site_par value, instead of a .site value (which it may or may not have now, and is the same object that the api refers to as site). --- sx-interaction.el | 18 +++++++++--------- sx-question-list.el | 2 +- sx-question-mode.el | 2 +- sx-question.el | 18 +++++++++--------- sx.el | 9 ++++++--- 5 files changed, 26 insertions(+), 23 deletions(-) (limited to 'sx-interaction.el') diff --git a/sx-interaction.el b/sx-interaction.el index 2768c8d..342ae1c 100644 --- a/sx-interaction.el +++ b/sx-interaction.el @@ -142,10 +142,10 @@ Element can be a question, answer, or comment." (cl-case .type (answer (sx-display-question - (sx-question-get-from-answer .site .id) 'focus)) + (sx-question-get-from-answer .site_par .id) 'focus)) (question (sx-display-question - (sx-question-get-question .site .id) 'focus)))))) + (sx-question-get-question .site_par .id) 'focus)))))) ;;; Displaying @@ -206,7 +206,7 @@ changes." :auth 'warn :url-method "POST" :filter sx-browse-filter - :site .site)))) + :site .site_par)))) ;; The api returns the new DATA. (when (> (length result) 0) (sx--copy-data (elt result 0) data) @@ -247,14 +247,14 @@ TEXT is a string. Interactively, it is read from the minibufer." :auth 'warn :url-method "POST" :filter sx-browse-filter - :site .site + :site .site_par :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) + (sx--get-post .post_type .site_par .post_id) data)) ;; Display the changes in `data'. (sx--maybe-update-display))))) @@ -287,7 +287,7 @@ ID is an integer." (car (cl-member-if (lambda (x) (sx-assoc-let x (and (equal (or .answer_id .question_id) id) - (equal .site site)))) + (equal .site_par site)))) db)))) (defun sx--add-comment-to-object (comment object) @@ -320,7 +320,7 @@ from context at point." (let ((buffer (current-buffer))) (pop-to-buffer (sx-compose-create - .site data + .site_par data ;; Before send hook (when .comment_id (list #'sx--comment-valid-p)) ;; After send functions @@ -338,7 +338,7 @@ from context at point." (defun sx--interactive-site-prompt () "Query the user for a site." (let ((default (or sx-question-list--site - (sx-assoc-let sx-question-mode--data .site) + (sx-assoc-let sx-question-mode--data .site_par) sx-default-site))) (funcall (if ido-mode #'ido-completing-read #'completing-read) (format "Site (%s): " default) @@ -372,7 +372,7 @@ context at point. " (sx-assoc-let data (pop-to-buffer (sx-compose-create - .site .question_id nil + .site_par .question_id nil ;; After send functions (list (lambda (_ res) (sx--add-answer-to-question-object diff --git a/sx-question-list.el b/sx-question-list.el index 62ce032..4b6c4ef 100644 --- a/sx-question-list.el +++ b/sx-question-list.el @@ -127,7 +127,7 @@ elements: Also see `sx-question-list-refresh'." (sx-assoc-let question-data (let ((favorite (if (member .question_id - (assoc .site + (assoc .site_par sx-favorites--user-favorite-list)) (if (char-displayable-p ?\x2b26) "\x2b26" "*") " "))) (list diff --git a/sx-question-mode.el b/sx-question-mode.el index a60cf3a..7d61167 100644 --- a/sx-question-mode.el +++ b/sx-question-mode.el @@ -254,7 +254,7 @@ query the api." (if no-update sx-question-mode--data (sx-assoc-let sx-question-mode--data - (sx-question-get-question .site .question_id)))) + (sx-question-get-question .site_par .question_id)))) (goto-char point) (when (equal (selected-window) (get-buffer-window (current-buffer))) diff --git a/sx-question.el b/sx-question.el index 801384a..3fcc438 100644 --- a/sx-question.el +++ b/sx-question.el @@ -94,8 +94,8 @@ If no cache exists for it, initialize one with SITE." "Non-nil if QUESTION has been read since last updated. See `sx-question--user-read-list'." (sx-assoc-let question - (sx-question--ensure-read-list .site) - (let ((ql (cdr (assoc .site sx-question--user-read-list)))) + (sx-question--ensure-read-list .site_par) + (let ((ql (cdr (assoc .site_par sx-question--user-read-list)))) (and ql (>= (or (cdr (assoc .question_id ql)) 0) .last_activity_date))))) @@ -107,14 +107,14 @@ read, i.e., if it was `sx-question--read-p'. See `sx-question--user-read-list'." (prog1 (sx-assoc-let question - (sx-question--ensure-read-list .site) - (let ((site-cell (assoc .site sx-question--user-read-list)) + (sx-question--ensure-read-list .site_par) + (let ((site-cell (assoc .site_par sx-question--user-read-list)) (q-cell (cons .question_id .last_activity_date)) cell) (cond ;; First question from this site. ((null site-cell) - (push (list .site q-cell) sx-question--user-read-list)) + (push (list .site_par q-cell) sx-question--user-read-list)) ;; Question already present. ((setq cell (assoc .question_id site-cell)) ;; Current version is newer than cached version. @@ -149,18 +149,18 @@ If no cache exists for it, initialize one with SITE." (defun sx-question--hidden-p (question) "Non-nil if QUESTION has been hidden." (sx-assoc-let question - (sx-question--ensure-hidden-list .site) - (let ((ql (cdr (assoc .site sx-question--user-hidden-list)))) + (sx-question--ensure-hidden-list .site_par) + (let ((ql (cdr (assoc .site_par sx-question--user-hidden-list)))) (and ql (memq .question_id ql))))) (defun sx-question--mark-hidden (question) "Mark QUESTION as being hidden." (sx-assoc-let question - (let ((site-cell (assoc .site sx-question--user-hidden-list))) + (let ((site-cell (assoc .site_par sx-question--user-hidden-list))) ;; If question already hidden, do nothing. (unless (memq .question_id site-cell) ;; First question from this site. - (push (list .site .question_id) sx-question--user-hidden-list) + (push (list .site_par .question_id) sx-question--user-hidden-list) ;; Question wasn't present. ;; Add it in, but make sure it's sorted (just in case we need ;; it later). diff --git a/sx.el b/sx.el index cda1acd..78995a8 100644 --- a/sx.el +++ b/sx.el @@ -303,9 +303,12 @@ DATA can also be the link itself." DATA can be a question, answer, comment, or user (or any object with a `link' property)." (when data - (unless (assq 'site data) - (setcdr data (cons (cons 'site (sx--site data)) - (cdr data)))) + (let-alist data + (unless .site_par + (setcdr data (cons (cons 'site_par + (or .site.api_site_parameter + (sx--site data))) + (cdr data))))) data)) (defmacro sx-assoc-let (alist &rest body) -- cgit v1.2.3 From 5493c6f7d1105810e5133e26c838e6d2cfe50055 Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Mon, 22 Dec 2014 11:41:29 -0200 Subject: sx-display-question should only take questions --- sx-interaction.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sx-interaction.el') diff --git a/sx-interaction.el b/sx-interaction.el index 342ae1c..965a996 100644 --- a/sx-interaction.el +++ b/sx-interaction.el @@ -157,7 +157,7 @@ relevant window. If WINDOW nil, the window is decided by `sx-question-mode-display-buffer-function'." - (interactive (list (sx--data-here) t)) + (interactive (list (sx--data-here 'question) t)) (when (sx-question--mark-read data) (sx--maybe-update-display)) ;; Display the question. -- cgit v1.2.3 From 293aa1850a00dfe42549b7f4b7373057aaaa21d9 Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Mon, 22 Dec 2014 11:53:38 -0200 Subject: Generalize sx-display-question to sx-display --- sx-interaction.el | 20 +++++++++++++++++++- sx-question-list.el | 2 +- 2 files changed, 20 insertions(+), 2 deletions(-) (limited to 'sx-interaction.el') diff --git a/sx-interaction.el b/sx-interaction.el index 965a996..181632e 100644 --- a/sx-interaction.el +++ b/sx-interaction.el @@ -149,9 +149,27 @@ Element can be a question, answer, or comment." ;;; Displaying +(defun sx-display (&optional data) + "Display object given by DATA. +Interactively, display object under point. Object can be a +question, an answer, or an inbox_item. + +This is meant for interactive use. In lisp code, use +object-specific functions such as `sx-display-question' and the +likes." + (interactive (list (sx--data-here) t)) + (sx-assoc-let data + (cond + (.item_type (sx-open-link .link)) + (.answer_id + (sx-display-question + (sx-question-get-from-answer .site_par .id) 'focus)) + (.title + (sx-display-question data 'focus))))) + (defun sx-display-question (&optional data focus window) "Display question given by DATA, on WINDOW. -When DATA is nil, display question under point. When FOCUS is +Interactively, display question under point. When FOCUS is non-nil (the default when called interactively), also focus the relevant window. diff --git a/sx-question-list.el b/sx-question-list.el index 4b6c4ef..4f71251 100644 --- a/sx-question-list.el +++ b/sx-question-list.el @@ -322,7 +322,7 @@ into consideration. ("d" sx-toggle-downvote) ("h" sx-question-list-hide) ("m" sx-question-list-mark-read) - ([?\r] sx-display-question) + ([?\r] sx-display) )) (defun sx-question-list-hide (data) -- cgit v1.2.3 From 69f081af1461fb70858a29f7426a758ecc10bafe Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Mon, 22 Dec 2014 13:21:41 -0200 Subject: Viewing and visiting doesn't work on inbox. --- sx-interaction.el | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'sx-interaction.el') diff --git a/sx-interaction.el b/sx-interaction.el index 181632e..619f259 100644 --- a/sx-interaction.el +++ b/sx-interaction.el @@ -119,15 +119,14 @@ Interactively, this is specified with a prefix argument. If DATA is a question, also mark it as read." (interactive (list (sx--data-here) current-prefix-arg)) (sx-assoc-let data - (let ((link - (when (stringp .link) - (funcall (if copy-as-kill #'kill-new #'browse-url) - .link)))) + (if (not (stringp .link)) + (sx-message "Nothing to visit here.") + (funcall (if copy-as-kill #'kill-new #'browse-url) .link) (when (and (called-interactively-p 'any) copy-as-kill) - (message "Copied: %S" link))) - (when (and .title (not copy-as-kill)) - (sx-question--mark-read data) - (sx--maybe-update-display)))) + (message "Copied: %S" .link)) + (when (and .title (not copy-as-kill)) + (sx-question--mark-read data) + (sx--maybe-update-display))))) (defun sx-open-link (link) "Visit element given by LINK inside Emacs. @@ -157,9 +156,11 @@ question, an answer, or an inbox_item. This is meant for interactive use. In lisp code, use object-specific functions such as `sx-display-question' and the likes." - (interactive (list (sx--data-here) t)) + (interactive (list (sx--data-here))) (sx-assoc-let data (cond + (.notification_type + (sx-message "Viewing notifications is not yet implemented")) (.item_type (sx-open-link .link)) (.answer_id (sx-display-question -- cgit v1.2.3 From b87903a14b5b6da5b847ed64de34df00971cbb4a Mon Sep 17 00:00:00 2001 From: Sean Allred Date: Fri, 2 Jan 2015 09:00:27 -0500 Subject: Introduce convencience function for site prompting Arose from comment discussion at [1]. This function allows for simplified syntax when the use case wants to retrieve a site token in an interactive context. See docstring for details. [1]: https://github.com/vermiculus/sx.el/pull/183/files#r22403919 --- sx-interaction.el | 12 ++++++++++++ sx-search.el | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) (limited to 'sx-interaction.el') diff --git a/sx-interaction.el b/sx-interaction.el index 9ced1ab..d814485 100644 --- a/sx-interaction.el +++ b/sx-interaction.el @@ -345,6 +345,18 @@ from context at point." (sx-site-get-api-tokens) nil t nil nil default))) +(defun sx--maybe-site-prompt (arg) + "Get a site token conditionally in an interactive context. +If PREFIX-ARG is non-nil, use `sx--interactive-site-prompt'. +Otherwise, use `sx-question-list--site' if non-nil. If nil, +use `sx--interactive-site-prompt' anyway." + ;; This could eventually be generalized into (sx--maybe-prompt + ;; prefix-arg value-if-non-nil #'prompt-function). + (if arg + (sx--interactive-site-prompt) + (or sx-question-list--site + (sx--interactive-site-prompt)))) + ;;;###autoload (defun sx-ask (site) "Start composing a question for SITE. diff --git a/sx-search.el b/sx-search.el index 928db5d..2633da9 100644 --- a/sx-search.el +++ b/sx-search.el @@ -74,7 +74,7 @@ of which is allowed to match. Interactively, the user is asked for SITE and QUERY. With a prefix argument, the user is asked for everything." (interactive - (let ((site (sx--interactive-site-prompt)) + (let ((site (sx--maybe-site-prompt current-prefix-arg)) (query (read-string (format "Query (%s): " (if current-prefix-arg "optional" "mandatory")) -- cgit v1.2.3 From 57a784d6810ab19771db46d9339b73ab27240b87 Mon Sep 17 00:00:00 2001 From: Sean Allred Date: Fri, 2 Jan 2015 10:54:26 -0500 Subject: Fix bad docstring Branch: search --- sx-interaction.el | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sx-interaction.el') diff --git a/sx-interaction.el b/sx-interaction.el index d814485..be9d664 100644 --- a/sx-interaction.el +++ b/sx-interaction.el @@ -347,9 +347,9 @@ from context at point." (defun sx--maybe-site-prompt (arg) "Get a site token conditionally in an interactive context. -If PREFIX-ARG is non-nil, use `sx--interactive-site-prompt'. -Otherwise, use `sx-question-list--site' if non-nil. If nil, -use `sx--interactive-site-prompt' anyway." +If ARG is non-nil, use `sx--interactive-site-prompt'. +Otherwise, use `sx-question-list--site' if non-nil. +If nil, use `sx--interactive-site-prompt' anyway." ;; This could eventually be generalized into (sx--maybe-prompt ;; prefix-arg value-if-non-nil #'prompt-function). (if arg -- cgit v1.2.3