From f924a9c58ce30dc62fc61382b1933d8ef51189b5 Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Sun, 14 Dec 2014 12:59:17 +0000 Subject: Fix dependency order. sx-tab now requires sx-interaction --- sx-interaction.el | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'sx-interaction.el') diff --git a/sx-interaction.el b/sx-interaction.el index 9b63e0a..0411410 100644 --- a/sx-interaction.el +++ b/sx-interaction.el @@ -44,7 +44,6 @@ (require 'sx-question-mode) (require 'sx-question-list) (require 'sx-compose) -(require 'sx-tab) ;;; Using data in buffer @@ -299,6 +298,21 @@ from context at point." ;;; Asking +(defcustom sx-default-site "emacs" + "Name of the site to use by default when listing questions." + :type 'string + :group 'sx) + +(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-default-site))) + (funcall (if ido-mode #'ido-completing-read #'completing-read) + (format "Site (%s): " default) + (sx-site-get-api-tokens) nil t nil nil + default))) + (defun sx-ask (site) "Start composing a question for SITE. SITE is a string, indicating where the question will be posted." @@ -308,7 +322,7 @@ SITE is a string, indicating where the question will be posted." (sx-compose-create site nil nil ;; After send functions - (list (lambda (_ res) (sx--maybe-update-display buffer))))))) + (list (lambda (_b _res) (sx--maybe-update-display buffer))))))) ;;; Answering -- cgit v1.2.3 From 65a66c266a10bda3843fbf02eb13789e0f1dc9c7 Mon Sep 17 00:00:00 2001 From: Sean Allred Date: Mon, 15 Dec 2014 11:35:40 -0500 Subject: Hotfix undefined function Related in conversation: #151 Branch: master --- 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 0411410..38520a7 100644 --- a/sx-interaction.el +++ b/sx-interaction.el @@ -316,7 +316,7 @@ from context at point." (defun sx-ask (site) "Start composing a question for SITE. SITE is a string, indicating where the question will be posted." - (interactive (list (sx-tab--interactive-site-prompt))) + (interactive (list (sx--interactive-site-prompt))) (let ((buffer (current-buffer))) (pop-to-buffer (sx-compose-create -- cgit v1.2.3 From 6956c17e1e7ef2899026ad365a0acdd4ce63cb80 Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Mon, 15 Dec 2014 18:27:33 -0200 Subject: user-error is "not known to be defined" in emacs 24.2 --- sx-button.el | 2 +- sx-interaction.el | 4 ++-- sx-method.el | 2 +- sx-question-list.el | 4 ++-- sx.el | 5 +++++ 5 files changed, 11 insertions(+), 6 deletions(-) (limited to 'sx-interaction.el') diff --git a/sx-button.el b/sx-button.el index dbadc2e..1727a3d 100644 --- a/sx-button.el +++ b/sx-button.el @@ -96,7 +96,7 @@ code-block." (interactive) (browse-url (or (get-text-property (or pos (point)) 'sx-button-url) - (user-error "No url under point: %s" (or pos (point)))))) + (sx-user-error "No url under point: %s" (or pos (point)))))) ;;; Help-echo definitions diff --git a/sx-interaction.el b/sx-interaction.el index 38520a7..7d32094 100644 --- a/sx-interaction.el +++ b/sx-interaction.el @@ -85,7 +85,7 @@ If it's not a question, or if it is read, return DATA." ;; If we found a question, we may need to check if it's read. (if (and (assoc 'title data) (null (sx-question--read-p data))) - (user-error "Question not yet read. View it before acting on it") + (sx-user-error "Question not yet read. View it before acting on it") data)) (defun sx--maybe-update-display (&optional buffer) @@ -286,7 +286,7 @@ 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 (user-error "Editing comments is not supported yet")) + (when .comment_id (sx-user-error "Editing comments is not supported yet")) (let ((buffer (current-buffer))) (pop-to-buffer (sx-compose-create diff --git a/sx-method.el b/sx-method.el index 4575b0f..1078014 100644 --- a/sx-method.el +++ b/sx-method.el @@ -90,7 +90,7 @@ Return the entire response as a complex alist." (cond ;; 1. Need auth and warn user (interactive use) ((and method-auth (equal 'warn auth)) - (user-error + (sx-user-error "This request requires authentication. Please run `M-x sx-authenticate' and try again.")) ;; 2. Need auth to populate UI, cannot provide subset ((and method-auth auth) diff --git a/sx-question-list.el b/sx-question-list.el index f23310c..e94c689 100644 --- a/sx-question-list.el +++ b/sx-question-list.el @@ -331,7 +331,7 @@ Non-interactively, DATA is a question alist." (interactive (list (if (derived-mode-p 'sx-question-list-mode) (tabulated-list-get-id) - (user-error "Not in `sx-question-list-mode'")))) + (sx-user-error "Not in `sx-question-list-mode'")))) (sx-question--mark-hidden data) (when (called-interactively-p 'any) (sx-question-list-refresh 'redisplay 'noupdate))) @@ -342,7 +342,7 @@ Non-interactively, DATA is a question alist." (interactive (list (if (derived-mode-p 'sx-question-list-mode) (tabulated-list-get-id) - (user-error "Not in `sx-question-list-mode'")))) + (sx-user-error "Not in `sx-question-list-mode'")))) (sx-question--mark-read data) (sx-question-list-next 1) (when (called-interactively-p 'any) diff --git a/sx.el b/sx.el index 096e20b..c8d4e5b 100644 --- a/sx.el +++ b/sx.el @@ -104,6 +104,11 @@ is intentionally skipped." (setq tail (cdr tail))) (setcdr tail (cons x (cdr tail))))) +(defun sx-user-error (format-string &rest args) + "Like `user-error', but prepend FORMAT-STRING with \"[sx]\". +See `format'." + (signal 'user-error (list (apply #'format (concat "[sx] " format) args)))) + (defun sx-message (format-string &rest args) "Display FORMAT-STRING as a message with ARGS. See `format'." -- cgit v1.2.3 From 6d8a8d5dc07fb8a58344775632716dbe781479a3 Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Tue, 16 Dec 2014 12:00:32 -0200 Subject: Hotfix wrong variable --- 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 7d32094..e7a4d94 100644 --- a/sx-interaction.el +++ b/sx-interaction.el @@ -60,7 +60,7 @@ If no object of the requested type could be returned, an error is thrown unless NOERROR is non-nil." (or (let ((data (get-char-property (point) 'sx--data-here))) (if (null type) data - (sx-assoc-let type + (sx-assoc-let data ;; Is data of the right type? (cl-case type (question (when .title data)) -- cgit v1.2.3 From 6b370f8dfc9ffbef757230732f5d158707d7f6e0 Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Wed, 17 Dec 2014 12:36:11 -0200 Subject: Support editing comments. --- sx-compose.el | 18 +++++++++++++----- sx-interaction.el | 1 - 2 files changed, 13 insertions(+), 6 deletions(-) (limited to 'sx-interaction.el') diff --git a/sx-compose.el b/sx-compose.el index 96f47f3..af9d861 100644 --- a/sx-compose.el +++ b/sx-compose.el @@ -146,19 +146,22 @@ respectively added locally to `sx-compose-before-send-hook' and (error "Invalid PARENT")) (let ((is-question (and (listp parent) - (null (cdr (assoc 'answer_id parent)))))) + (cdr (assoc 'title parent))))) (with-current-buffer (sx-compose--get-buffer-create site parent) (sx-compose-mode) (setq sx-compose--send-function (if (consp parent) (sx-assoc-let parent - (lambda () (sx-method-call (if .title 'questions 'answers) + (lambda () (sx-method-call (cond + (.title 'questions) + (.comment_id 'comments) + (t 'answers)) :auth 'warn :url-method "POST" :filter sx-browse-filter :site site :keywords (sx-compose--generate-keywords is-question) - :id (or .answer_id .question_id) + :id (or .comment_id .answer_id .question_id) :submethod 'edit))) (lambda () (sx-method-call 'questions :auth 'warn @@ -256,8 +259,13 @@ the id property." site data))) (t (get-buffer-create - (format "*sx draft edit %s %s*" - site (sx-assoc-let data (or .answer_id .question_id))))))) + (sx-assoc-let data + (format "*sx draft edit %s %s %s*" + site + (cond (.title "question") + (.comment_id "comment") + (t "answer")) + (or .comment_id .answer_id .question_id))))))) (provide 'sx-compose) ;;; sx-compose.el ends here diff --git a/sx-interaction.el b/sx-interaction.el index e7a4d94..1e14062 100644 --- a/sx-interaction.el +++ b/sx-interaction.el @@ -286,7 +286,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 d202e1ebeddf98d3109c8f7352fceb8dd5c07eb7 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 1e14062..92f0a63 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 cd28aeb50a49a625047f9a3d7eb20694955f87aa 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 92f0a63..8aa82a2 100644 --- a/sx-interaction.el +++ b/sx-interaction.el @@ -216,8 +216,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")) @@ -241,6 +241,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 34753b9cb10beaa529f9f56cbc5bea3d11960ea3 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 8aa82a2..c6f2639 100644 --- a/sx-interaction.el +++ b/sx-interaction.el @@ -302,7 +302,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 e39a909dc722dfdb48ecc4533cf061dbb209abf1 Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Wed, 17 Dec 2014 15:35:54 -0200 Subject: Implement identifying type, id, and site of a link. --- sx-interaction.el | 1 + sx.el | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) (limited to 'sx-interaction.el') diff --git a/sx-interaction.el b/sx-interaction.el index e7a4d94..2c392e1 100644 --- a/sx-interaction.el +++ b/sx-interaction.el @@ -128,6 +128,7 @@ If DATA is a question, also mark it as read." (sx-question--mark-read data) (sx--maybe-update-display)))) + ;;; Displaying (defun sx-display-question (&optional data focus window) diff --git a/sx.el b/sx.el index 4ad0fd5..7d67835 100644 --- a/sx.el +++ b/sx.el @@ -317,6 +317,22 @@ If ALIST doesn't have a `site' property, one is created using the (sx--ensure-site ,alist) (let-alist ,alist ,@body))) +(defun sx--link-to-data (link) + "Convert string LINK into data that can be displayed." + (let ((result (list (cons 'site (sx--site link))))) + (when (or + ;; Answer + (and (or (string-match "/a/\\([0-9]+\\)/[0-9]+\\(#.*\\|\\)\\'" link) + (string-match "/questions/[0-9]+/[^/]+/\\([0-9]\\)/?\\(#.*\\|\\)\\'" link)) + (push (cons 'type 'answer) result)) + ;; Question + (and (or (string-match "/q/\\([0-9]+\\)/[0-9]+\\(#.*\\|\\)\\'" link) + (string-match "/questions/\\([0-9]+\\)/" link)) + (push (cons 'type 'question) result))) + (push (cons 'id (string-to-number (match-string-no-properties 1 link))) + result)) + result)) + (defcustom sx-init-hook nil "Hook run when SX initializes. Run after `sx-init--internal-hook'." -- cgit v1.2.3 From 8d1c9e8a29e890d1d37c5caa649a0861b1621bfa Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Wed, 17 Dec 2014 15:44:45 -0200 Subject: sx-open-link: command to visit links inside SX --- sx-interaction.el | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'sx-interaction.el') diff --git a/sx-interaction.el b/sx-interaction.el index 2c392e1..38efe5d 100644 --- a/sx-interaction.el +++ b/sx-interaction.el @@ -128,6 +128,19 @@ If DATA is a question, also mark it as read." (sx-question--mark-read data) (sx--maybe-update-display)))) +(defun sx-open-link (link) + "Visit element given by LINK inside Emacs. +Element can be a question, answer, or comment." + (interactive "sLink: ") + (let ((data (sx--link-to-data link))) + (sx-assoc-let data + (cl-case .type + (answer + (sx-display-question + (sx-question-get-from-answer .site .id) 'focus)) + (question + (sx-display-question + (sx-question-get-question .site .id) 'focus)))))) ;;; Displaying -- cgit v1.2.3 From abaad8b3c57355be672e13a2f5cdff3d651e91d0 Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Sat, 20 Dec 2014 16:59:09 -0200 Subject: Refactor sx-visit to sx-visit-externally --- sx-interaction.el | 2 +- sx-question-list.el | 2 +- sx-question-mode.el | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'sx-interaction.el') diff --git a/sx-interaction.el b/sx-interaction.el index 38efe5d..ed8891b 100644 --- a/sx-interaction.el +++ b/sx-interaction.el @@ -106,7 +106,7 @@ Only fields contained in TO are copied." ;;; Visiting -(defun sx-visit (data &optional copy-as-kill) +(defun sx-visit-externally (data &optional copy-as-kill) "Visit DATA in a web browser. DATA can be a question, answer, or comment. Interactively, it is derived from point position. diff --git a/sx-question-list.el b/sx-question-list.el index 94b5be4..f6a82e2 100644 --- a/sx-question-list.el +++ b/sx-question-list.el @@ -317,7 +317,7 @@ into consideration. (":" sx-question-list-switch-site) ("t" sx-question-list-switch-tab) ("a" sx-ask) - ("v" sx-visit) + ("v" sx-visit-externally) ("u" sx-toggle-upvote) ("d" sx-toggle-downvote) ("h" sx-question-list-hide) diff --git a/sx-question-mode.el b/sx-question-mode.el index b376616..807eeea 100644 --- a/sx-question-mode.el +++ b/sx-question-mode.el @@ -224,7 +224,7 @@ Letters do not insert themselves; instead, they are commands. ("p" sx-question-mode-previous-section) ("g" sx-question-mode-refresh) ("c" sx-comment) - ("v" sx-visit) + ("v" sx-visit-externally) ("u" sx-toggle-upvote) ("d" sx-toggle-downvote) ("q" quit-window) -- cgit v1.2.3 From 72cdd44dbfe6266f33471012091b58f85d5b7d88 Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Sat, 20 Dec 2014 17:03:59 -0200 Subject: sx-open-link takes link from clipboard by default --- sx-interaction.el | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'sx-interaction.el') diff --git a/sx-interaction.el b/sx-interaction.el index ed8891b..2b41b35 100644 --- a/sx-interaction.el +++ b/sx-interaction.el @@ -131,7 +131,11 @@ If DATA is a question, also mark it as read." (defun sx-open-link (link) "Visit element given by LINK inside Emacs. Element can be a question, answer, or comment." - (interactive "sLink: ") + (interactive + (let ((def (with-temp-buffer + (save-excursion (yank)) + (thing-at-point 'url)))) + (list (read-string (concat "Link (" def "): ") nil nil def)))) (let ((data (sx--link-to-data link))) (sx-assoc-let data (cl-case .type -- cgit v1.2.3 From fb52d842299e1826915bcae5c6fbb6e0e1f617ec Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Sat, 20 Dec 2014 17:04:20 -0200 Subject: whitespace --- 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 2b41b35..ea494eb 100644 --- a/sx-interaction.el +++ b/sx-interaction.el @@ -152,7 +152,7 @@ Element can be a question, answer, or comment." "Display question given by DATA, on WINDOW. When DATA is nil, display question under point. When FOCUS is non-nil (the default when called interactively), also focus the -relevant window. +relevant window. If WINDOW nil, the window is decided by `sx-question-mode-display-buffer-function'." @@ -260,13 +260,13 @@ TEXT is a string. Interactively, it is read from the minibufer." (defun sx--get-post (type site id) "Find in the database a post identified by TYPE, SITE and ID. -TYPE is `question' or `answer'. +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 + (cond ((string= type "question") db) ((string= type "answer") (apply #'cl-map 'list #'identity -- cgit v1.2.3 From 60bed65f15505261dd297fcf4ad2c71a7c76dbeb Mon Sep 17 00:00:00 2001 From: Sean Allred Date: Sat, 27 Dec 2014 09:56:03 -0500 Subject: Add autoload cookie to `sx-ask' --- sx-interaction.el | 1 + 1 file changed, 1 insertion(+) (limited to 'sx-interaction.el') diff --git a/sx-interaction.el b/sx-interaction.el index c6f2639..baf8c13 100644 --- a/sx-interaction.el +++ b/sx-interaction.el @@ -327,6 +327,7 @@ from context at point." (sx-site-get-api-tokens) nil t nil nil default))) +;;;###autoload (defun sx-ask (site) "Start composing a question for SITE. SITE is a string, indicating where the question will be posted." -- cgit v1.2.3 From c37022ffbc52b900d81eee05f3c2c3d5fe6fee01 Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Sat, 27 Dec 2014 23:06:00 -0200 Subject: Initial implementation of sx-completing-read --- sx-interaction.el | 8 ++++---- sx-question-list.el | 3 +-- sx-tab.el | 8 ++++---- sx.el | 5 +++++ 4 files changed, 14 insertions(+), 10 deletions(-) (limited to 'sx-interaction.el') diff --git a/sx-interaction.el b/sx-interaction.el index 372a5b1..9ced1ab 100644 --- a/sx-interaction.el +++ b/sx-interaction.el @@ -340,10 +340,10 @@ from context at point." (let ((default (or sx-question-list--site (sx-assoc-let sx-question-mode--data .site) sx-default-site))) - (funcall (if ido-mode #'ido-completing-read #'completing-read) - (format "Site (%s): " default) - (sx-site-get-api-tokens) nil t nil nil - default))) + (sx-completing-read + (format "Site (%s): " default) + (sx-site-get-api-tokens) nil t nil nil + default))) ;;;###autoload (defun sx-ask (site) diff --git a/sx-question-list.el b/sx-question-list.el index 4bd6478..d84d1ea 100644 --- a/sx-question-list.el +++ b/sx-question-list.el @@ -559,12 +559,11 @@ This does not update `sx-question-mode--window'." (defun sx-question-list-switch-site (site) "Switch the current site to SITE and display its questions. -Use `ido-completing-read' if variable `ido-mode' is active. Retrieve completions from `sx-site-get-api-tokens'. Sets `sx-question-list--site' and then call `sx-question-list-refresh' with `redisplay'." (interactive - (list (funcall (if ido-mode #'ido-completing-read #'completing-read) + (list (sx-completing-read "Switch to site: " (sx-site-get-api-tokens) (lambda (site) (not (equal site sx-question-list--site))) t))) diff --git a/sx-tab.el b/sx-tab.el index 6c5e21e..32a7784 100644 --- a/sx-tab.el +++ b/sx-tab.el @@ -34,10 +34,10 @@ (defun sx-tab-switch (tab) "Switch to another question-list tab." (interactive - (list (funcall (if ido-mode #'ido-completing-read #'completing-read) - "Switch to tab: " sx-tab--list - (lambda (tab) (not (equal tab sx-question-list--current-tab))) - t))) + (list (sx-completing-read + "Switch to tab: " sx-tab--list + (lambda (tab) (not (equal tab sx-question-list--current-tab))) + t))) (funcall (intern (format "sx-tab-%s" (downcase tab))))) diff --git a/sx.el b/sx.el index a63c155..c2d1164 100644 --- a/sx.el +++ b/sx.el @@ -183,6 +183,11 @@ See `sx-question-get-questions' and `sx-question-get-question'.") ;;; Utility Functions +(defun sx-completing-read (&rest args) + "Like `completing-read', but possibly use ido. +All ARGS are passed to `completing-read' or `ido-completing-read'." + (apply (if ido-mode #'ido-completing-read #'completing-read) + args)) (defmacro sx-sorted-insert-skip-first (newelt list &optional predicate) "Inserted NEWELT into LIST sorted by PREDICATE. -- cgit v1.2.3