From 959f42aae3d8c29fc889af161653eedb1be4ed69 Mon Sep 17 00:00:00 2001 From: Valeriy Savchenko Date: Sun, 12 Mar 2023 19:29:35 +0000 Subject: [PATCH 1/4] Move from parsing the HTML to the use of the API --- powerthesaurus.el | 328 ++++++++++++++++++------------ test/powerthesaurus-smoke-test.el | 15 +- 2 files changed, 206 insertions(+), 137 deletions(-) diff --git a/powerthesaurus.el b/powerthesaurus.el index 94850c2..667a723 100644 --- a/powerthesaurus.el +++ b/powerthesaurus.el @@ -5,7 +5,7 @@ ;; Authors: Valeriy Savchenko ;; URL: http://github.com/SavchenkoValeriy/emacs-powerthesaurus ;; Version: 0.2.2 -;; Package-Requires: ((emacs "24") (request "0.3.0") (s "1.12.0")) +;; Package-Requires: ((emacs "24") (request "0.3.0") (s "1.12.0") (jeison "1.0.0")) ;; Keywords: convenience, writing ;; This file is NOT part of GNU Emacs. @@ -33,6 +33,7 @@ ;;; Code: (require 'dom) (require 'request) +(require 'jeison) ;; TODO: Remove unnecessary dependencies. ;; (require 'rx) (require 's) @@ -40,16 +41,14 @@ (defvar powerthesaurus-request-headers '(("User-Agent" . "Chrome/74.0.3729.169") - ("Accept" . "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8") - ("Accept-Language" . "en,en-US;q=0.5") - ("Upgrade-Insecure-Requests" . "1")) + ("Content-Type" . "application/json")) "List of headers included in the request sent to 'powerthesaurus.org'.") (defvar powerthesaurus-synchronous-requests nil "If non-nil, requests send to 'powerthesaurus.org' are synchronous.") (defconst powerthesaurus-supported-query-types - (list "synonyms" "antonyms" "related" "definitions" "sentences")) + (list :synonyms :antonyms :related :definitions :sentences)) (defun powerthesaurus-compose-url (query-term query-type) "Build and return powerthesaurus url to look up QUERY-TERM. @@ -63,6 +62,8 @@ QUERY-TYPE must be an element of `powerthesaurus-supported-query-types'." (url-encode-url query-term) query-type)) +(defconst powerthesaurus-api-url "https://api.powerthesaurus.org") + ;;;###autoload (defun powerthesaurus-lookup-dwim (&optional action-type query-type) "Wrapper function for general lookup commands. @@ -106,35 +107,35 @@ the user will be prompt for a valid value." "Wrapper function for synonym lookup. ACTION-TYPE accepts the same arguments as in `powerthesaurus-lookup-dwim'." (interactive "P") - (powerthesaurus-lookup-dwim action-type "synonyms")) + (powerthesaurus-lookup-dwim action-type :synonyms)) ;;;###autoload (defun powerthesaurus-lookup-antonyms-dwim (&optional action-type) "Wrapper function for antonym lookup. ACTION-TYPE accepts the same arguments as in `powerthesaurus-lookup-dwim'." (interactive "P") - (powerthesaurus-lookup-dwim action-type "antonyms")) + (powerthesaurus-lookup-dwim action-type :antonyms)) ;;;###autoload (defun powerthesaurus-lookup-related-dwim (&optional action-type) "Wrapper function for related lookup. ACTION-TYPE accepts the same arguments as in `powerthesaurus-lookup-dwim'." (interactive "P") - (powerthesaurus-lookup-dwim action-type "related")) + (powerthesaurus-lookup-dwim action-type :related)) ;;;###autoload (defun powerthesaurus-lookup-definitions-dwim (&optional action-type) "Wrapper function for definition lookup. ACTION-TYPE accepts the same arguments as in `powerthesaurus-lookup-dwim'." (interactive "P") - (powerthesaurus-lookup-dwim action-type "definitions")) + (powerthesaurus-lookup-dwim action-type :definitions)) ;;;###autoload (defun powerthesaurus-lookup-sentences-dwim (&optional action-type) "Wrapper function for sentence lookup. ACTION-TYPE accepts the same arguments as in `powerthesaurus-lookup-dwim'." (interactive "P") - (powerthesaurus-lookup-dwim action-type "sentences")) + (powerthesaurus-lookup-dwim action-type :sentences)) ;;;###autoload (defun powerthesaurus-lookup (query-term query-type &optional beg end) @@ -157,6 +158,10 @@ which will replace the text between these bounds." query-type (powerthesaurus--make-callback query-term query-type beg end))) +;; =============================================================== +;; UX functions implementation +;; =============================================================== + (defun powerthesaurus-prefix-to-action (uarg qtype) "Map given prefix argument UARG to corresponding action type. @@ -178,7 +183,7 @@ then the result defaults to `action-insert'. In any other case, it defaults to `action-display'." (cond ((null uarg) - (if (member qtype '("synonyms" "antonyms" "related")) + (if (member qtype '(:synonyms :antonyms :related)) 'action-insert 'action-display)) ((memq uarg '(action-insert action-display)) uarg) @@ -186,8 +191,6 @@ In any other case, it defaults to `action-display'." ((equal uarg '(16)) 'action-display) (t (error "Unexpected prefix argument")))) -(cl-defstruct (powerthesaurus-result) text rating) - (defun powerthesaurus--extract-original-word (&optional pnt) "Parse the word under point to look up. @@ -283,15 +286,10 @@ creating the corresponding request." (lambda (new original) (with-current-buffer buffer (powerthesaurus--replace-text new beg end original)))))) - (cl-function - (lambda (&key data &allow-other-keys) - ;; in order to allow users to quit powerthesaurus - ;; prompt with C-g, we need to wrap callback with this - (with-local-quit - (funcall backend - (powerthesaurus--select-candidate - (powerthesaurus--response-extract data query-type)) - query-term)))))) + (lambda (results) + (funcall backend + (powerthesaurus--select-candidate results) + query-term)))) (defun powerthesaurus--make-display-callback (query-term query-type) "Generate a callback that will display the query's results to another buffer. @@ -310,38 +308,11 @@ creating the corresponding request. Additionally, it affects aspects of the generated callback's behavior, such as the default string used for separating the results displayed in the buffer." - (cl-function - (lambda (&key data &allow-other-keys) - ;; in order to allow users to quit powerthesaurus - ;; prompt with C-g, we need to wrap callback with this - (with-local-quit - (powerthesaurus--display-results - (powerthesaurus--response-extract data query-type) - query-term - query-type))))) - -(defun powerthesaurus--query (term type &optional callback sync) - "Send query to 'powerthesaurus.org' and handle response. - -TERM corresponds to the phrase to look up and -TYPE must be an element of `powerthesaurus-supported-query-types' (e.g., -\"synonyms\"). - -Optional argument CALLBACK must be a function to be called upon -successfully completing the request. - -Finally, if SYNC is non-nil, the function will wait for the response from -'powerthesaurus.org' before returning. -If not specified, the value of `powerthesaurus-synchronous-requests' -will determine this behavior." - (request - (powerthesaurus-compose-url term type) - :parser (lambda () (libxml-parse-html-region (point) (point-max))) - :headers powerthesaurus-request-headers - :success callback - :sync (or (null callback) - sync - powerthesaurus-synchronous-requests))) + (lambda (results) + (powerthesaurus--display-results + results + query-term + query-type))) (defun powerthesaurus--replace-text (replacement beg end original) "Pick an alternative from response and replace the selected text. @@ -352,7 +323,7 @@ BEG and END correspond to the bounds of the selected text to be replaced." (powerthesaurus--insert-text replacement original (min beg end))) (defun powerthesaurus--preprocess-text (text reference) - "Adjust cases of TEXT according on REFERENCE. + "Adjust cases of TEXT according to REFERENCE. For now, it supports upcasing and capitalization." (cond ((s-uppercase-p reference) (upcase text)) @@ -382,7 +353,7 @@ the displayed results in the buffer. If not specified, its default value varies depending on value of QUERY-TYPE." (unless sep (cond - ((member query-type '("definitions" "sentences")) + ((member query-type '(:definitions :sentences)) (setq sep "\n----------------\n")) (t (setq sep "\n")))) (let* ((buf-name (format "*Powerthesaurus - \"%s\" - %s*" @@ -395,7 +366,7 @@ its default value varies depending on value of QUERY-TYPE." (read-only-mode -1) (erase-buffer)) (dolist (elt results) - (insert (powerthesaurus-result-text elt) sep)) + (insert (oref elt text) sep)) (help-mode) (goto-char (point-min))) (pop-to-buffer buf))) @@ -420,77 +391,124 @@ its default value varies depending on value of QUERY-TYPE." (defun powerthesaurus--sort-candidates (synonyms) "Compose choices from the `powerthesaurus-result' list of SYNONYMS." - (mapcar (lambda (word) (powerthesaurus-result-text word)) - (sort synonyms (lambda (x y) (< (powerthesaurus-result-rating x) - (powerthesaurus-result-rating y)))))) + (mapcar (lambda (word) (oref word text)) + (sort synonyms (lambda (x y) (< (oref x rating) + (oref y rating)))))) + +;; =============================================================== +;; Requests and JSON parsing +;; =============================================================== + +(jeison-defclass powerthesaurus-result nil + ((text :initarg :text :type string :path (node targetTerm name) + :documentation "Actual text of the word from Powerthesaurus") + (rating :initarg :rating :type number :path (node rating) + :documentation "User rating of the word"))) + +(jeison-defclass powerthesaurus-definition nil + ((text :initarg :text :type string :path (node definition) + :documentation "Definition from Powerthesaurus") + (rating :initarg :rating :type number :path (node rating) + :documentation "User rating of the definition"))) + +(jeison-defclass powerthesaurus-sentence nil + ((text :initarg :text :type string :path (node sentence) + :documentation "Sentence example from Powerthesaurus") + (rating :initarg :rating :type number :path (node rating) + :documentation "User rating of the sentence"))) -(defun powerthesaurus--response-extract (data type) - "Extract specified TYPE from response's DATA." - (cond - ((member type '("synonyms" "antonyms" "related")) - (powerthesaurus--response-extract-sar data)) - ((member type '("definitions")) - (powerthesaurus--response-extract-definitions data)) - ((member type '("sentences")) - (powerthesaurus--response-extract-sentences data)) - (t (error "Unknown query type '%s'" type)))) - -(defun powerthesaurus--response-extract-sar (data) - "Extract synonyms, antonyms or related from response's DATA." - (let* ((results - (cl-map 'list (lambda (it) (dom-text (dom-by-tag it 'a))) - (dom-by-id data "primary-area"))) - (results-ranked - (cl-loop for elt in results and n from 0 by 1 - collect (make-powerthesaurus-result :text elt - :rating n)))) - results-ranked)) - -(defun powerthesaurus--response-extract-definitions (data) - "Extract definitions from response's DATA." - (let* ((results - (dom-children - (dom-children - (dom-children - (dom-children - (dom-by-tag data 'main)))))) - (results (cl-map 'list - (lambda (it) - (dom-text - (nth 1 (dom-children - (nth 1 (dom-children - (dom-children it))))))) - results)) - (results-ranked - (cl-loop for elt in results and n from 0 by 1 - collect (make-powerthesaurus-result :text elt - :rating n)))) - results-ranked)) - -(defun powerthesaurus--response-extract-sentences (data) - "Extract sentences from response's DATA." - (let* ((results - (dom-children - (dom-children - (dom-children - (dom-by-tag data 'main))))) - (results (cl-map 'list - (lambda (it) - (dom-texts - (dom-children - (nth 1 (dom-children - (dom-children it)))) "")) - (dom-children results))) - (results (cl-map 'list - (lambda (it) - (s-chop-prefix "\"" - (s-chop-suffix "\"" it))) - results)) - (results-ranked - (cl-loop for elt in results and n from 0 by 1 - collect (make-powerthesaurus-result :text elt - :rating n)))) - results-ranked)) +(defun powerthesaurus--query (term type &optional callback sync) + "TBD" + (let ((query (pcase type + ((pred powerthesaurus--is-thesaurus-query-type) + #'powerthesaurus--query-thesaurus) + (:definitions #'powerthesaurus--query-definition) + (:sentences #'powerthesaurus--query-sentence) + (_ (error "Unknown query type '%s'" type))))) + (funcall query term type callback sync))) + +(defun powerthesaurus--request-term-id (term callback &optional sync) + (powerthesaurus--api-query + `(("query" . ,term)) + powerthesaurus--search-query + callback + (lambda (data) (jeison-read t data '(data search terms 0 id))) + sync)) + +(defmacro powerthesaurus--with-term-id (term name sync &rest body) + "TBD" + (declare (indent 3) (debug t)) + `(let ((on-success + (lambda (,name) + ,@body))) + (powerthesaurus--request-term-id ,term on-success sync))) + +(defun powerthesaurus--query-thesaurus (term type &optional callback sync) + "TBD" + (powerthesaurus--with-term-id term term-id sync + (powerthesaurus--api-query + `(("type" . ,(powerthesaurus--type-of-thesaurus-query type)) + ("termID" . ,term-id) + ("sort" . + (("field" . "RATING") + ("direction" . "DESC")))) + powerthesaurus--thesaurus-query + callback + (lambda (data) (jeison-read '(list-of powerthesaurus-result) data '(data thesauruses edges))) + sync))) + +(defun powerthesaurus--is-thesaurus-query-type (query-type) + "TBD" + (member query-type '(:synonyms :antonyms :related))) + +(defun powerthesaurus--type-of-thesaurus-query (type) + (pcase type + (:synonyms "SYNONYM") + (:antonyms "ANTONYM") + (:related "RELATED") + (_ (error "Unknown thesaurus query type '%s'" type)))) + +(defun powerthesaurus--query-definition (term type &optional callback sync) + "TBD" + (powerthesaurus--with-term-id term term-id sync + (powerthesaurus--api-query + `(("termID" . ,term-id)) + powerthesaurus--definition-query + callback + (lambda (data) (jeison-read '(list-of powerthesaurus-definition) data '(data definitions edges))) + sync))) + +(defun powerthesaurus--query-sentence (term type &optional callback sync) + "TBD" + (powerthesaurus--with-term-id term term-id sync + (powerthesaurus--api-query + `(("termID" . ,term-id)) + powerthesaurus--sentence-query + callback + (lambda (data) (jeison-read '(list-of powerthesaurus-sentence) data '(data sentences edges))) + sync))) + +(defun powerthesaurus--api-query (variables query &optional callback postprocess sync) + "TBD" + (let ((post (or postprocess 'identity))) + (request + powerthesaurus-api-url + :type "POST" + :data (json-encode `(("variables" . ,variables) + ("query" . ,query))) + :parser #'(lambda () (funcall post (json-parse-buffer :object-type 'alist))) + :headers powerthesaurus-request-headers + :success (powerthesaurus--wrap-as-callback callback) + :sync (or (null callback) + sync + powerthesaurus-synchronous-requests)))) + +(defun powerthesaurus--wrap-as-callback (fun) + (cl-function + (lambda (&key data &allow-other-keys) + ;; in order to allow users to quit powerthesaurus + ;; prompt with C-g, we need to wrap callback with this + (with-local-quit (funcall fun data))))) (defun powerthesaurus-debug-connection () "Debug requests to powerthesaurus.org." @@ -531,7 +549,7 @@ otherwise as for word using powerthesaurus-lookup-word" (interactive (list (point))) (pcase-let ((`(,word ,beg ,end) (powerthesaurus--extract-original-word word-point))) - (powerthesaurus-lookup word "synonyms" beg end))) + (powerthesaurus-lookup word :synonyms beg end))) ;;;###autoload (defun powerthesaurus-lookup-word (&optional beginning end) @@ -549,7 +567,7 @@ In this case, a selected synonym will be inserted at the point." (if beginning (powerthesaurus--extract-query-region beginning end) (powerthesaurus--read-query-term "Word to fetch: ")))) - (powerthesaurus-lookup word "synonyms" (or beginning (point)) end))) + (powerthesaurus-lookup word :synonyms (or beginning (point)) end))) (make-obsolete 'powerthesaurus-lookup-word 'powerthesaurus-lookup "0.2.0") @@ -558,5 +576,57 @@ In this case, a selected synonym will be inserted at the point." (make-obsolete 'powerthesaurus-lookup-word-dwim 'powerthesaurus-lookup "0.2.0") +;; GraphQL queries +(defconst powerthesaurus--search-query + "query SEARCH($query: String!) { + search(query: $query) { + terms { + id + name + } + } +}") + +(defconst powerthesaurus--thesaurus-query + "query THESAURUS($termID: ID!, $type: List!, $sort: ThesaurusSorting!) { + thesauruses(termId: $termID, sort: $sort, list: $type) { + edges { + node { + targetTerm { + name + } + rating + votes + } + } + } +}") + +(defconst powerthesaurus--definition-query + "query DEFINITION($termID: ID!) { + definitions(termId: $termID) { + edges { + node { + definition + rating + votes + } + } + } +}") + +(defconst powerthesaurus--sentence-query + "query SENTENCE($termID: ID!) { + sentences(termId: $termID) { + edges { + node { + sentence + rating + votes + } + } + } +}") + (provide 'powerthesaurus) ;;; powerthesaurus.el ends here diff --git a/test/powerthesaurus-smoke-test.el b/test/powerthesaurus-smoke-test.el index 3a430e2..85b7503 100644 --- a/test/powerthesaurus-smoke-test.el +++ b/test/powerthesaurus-smoke-test.el @@ -29,28 +29,27 @@ (powerthesaurus--query term type - (cl-function - (lambda (&key data &allow-other-keys) - (setq results (powerthesaurus--response-extract data type)))) + (lambda (data) + (setq results data)) t) results)) (ert-deftest powerthesaurus:check-synonyms () - (let ((results (powerthesaurus:test-get "good" "synonyms"))) + (let ((results (powerthesaurus:test-get "good" :synonyms))) (should (> (length results) 0)))) (ert-deftest powerthesaurus:check-antonyms () - (let ((results (powerthesaurus:test-get "good" "antonyms"))) + (let ((results (powerthesaurus:test-get "good" :antonyms))) (should (> (length results) 0)))) (ert-deftest powerthesaurus:check-related () - (let ((results (powerthesaurus:test-get "good" "related"))) + (let ((results (powerthesaurus:test-get "good" :related))) (should (> (length results) 0)))) (ert-deftest powerthesaurus:check-definitions () - (let ((results (powerthesaurus:test-get "good" "definitions"))) + (let ((results (powerthesaurus:test-get "good" :definitions))) (should (> (length results) 0)))) (ert-deftest powerthesaurus:check-sentences () - (let ((results (powerthesaurus:test-get "good" "sentences"))) + (let ((results (powerthesaurus:test-get "good" :sentences))) (should (> (length results) 0)))) From c7dc8948de6962555ceef6e473ae954f4885270e Mon Sep 17 00:00:00 2001 From: Valeriy Savchenko Date: Sun, 12 Mar 2023 19:45:32 +0000 Subject: [PATCH 2/4] Conditionally use native JSON parsing --- powerthesaurus.el | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/powerthesaurus.el b/powerthesaurus.el index 667a723..c40d6bd 100644 --- a/powerthesaurus.el +++ b/powerthesaurus.el @@ -5,7 +5,7 @@ ;; Authors: Valeriy Savchenko ;; URL: http://github.com/SavchenkoValeriy/emacs-powerthesaurus ;; Version: 0.2.2 -;; Package-Requires: ((emacs "24") (request "0.3.0") (s "1.12.0") (jeison "1.0.0")) +;; Package-Requires: ((emacs "25.1") (request "0.3.0") (jeison "1.0.0")) ;; Keywords: convenience, writing ;; This file is NOT part of GNU Emacs. @@ -31,13 +31,8 @@ ;;; insert selected option in the buffer (depending on the current selection). ;;; Code: -(require 'dom) (require 'request) (require 'jeison) -;; TODO: Remove unnecessary dependencies. -;; (require 'rx) -(require 's) -(require 'url-util) (defvar powerthesaurus-request-headers '(("User-Agent" . "Chrome/74.0.3729.169") @@ -50,18 +45,6 @@ (defconst powerthesaurus-supported-query-types (list :synonyms :antonyms :related :definitions :sentences)) -(defun powerthesaurus-compose-url (query-term query-type) - "Build and return powerthesaurus url to look up QUERY-TERM. - -QUERY-TYPE must be an element of `powerthesaurus-supported-query-types'." - (unless (member query-type powerthesaurus-supported-query-types) - (error "Unknown query type '%s'" query-type)) - (format "https://www.powerthesaurus.org/%s/%s" - ;; Escape text of query-term, - ;; in order to properly handle spaces, etc. - (url-encode-url query-term) - query-type)) - (defconst powerthesaurus-api-url "https://api.powerthesaurus.org") ;;;###autoload @@ -428,6 +411,7 @@ its default value varies depending on value of QUERY-TYPE." (funcall query term type callback sync))) (defun powerthesaurus--request-term-id (term callback &optional sync) + "TBD" (powerthesaurus--api-query `(("query" . ,term)) powerthesaurus--search-query @@ -462,6 +446,7 @@ its default value varies depending on value of QUERY-TYPE." (member query-type '(:synonyms :antonyms :related))) (defun powerthesaurus--type-of-thesaurus-query (type) + "TBD" (pcase type (:synonyms "SYNONYM") (:antonyms "ANTONYM") @@ -488,6 +473,12 @@ its default value varies depending on value of QUERY-TYPE." (lambda (data) (jeison-read '(list-of powerthesaurus-sentence) data '(data sentences edges))) sync))) +(defvar powerthesaurus--json-parser #'(lambda () (json-read))) + +(when (and (functionp 'json-available-p) + (json-available-p)) + (setq powerthesaurus--json-parser #'(lambda () (json-parse-buffer :object-type 'alist)))) + (defun powerthesaurus--api-query (variables query &optional callback postprocess sync) "TBD" (let ((post (or postprocess 'identity))) @@ -496,7 +487,7 @@ its default value varies depending on value of QUERY-TYPE." :type "POST" :data (json-encode `(("variables" . ,variables) ("query" . ,query))) - :parser #'(lambda () (funcall post (json-parse-buffer :object-type 'alist))) + :parser #'(lambda () (funcall post (funcall powerthesaurus--json-parser))) :headers powerthesaurus-request-headers :success (powerthesaurus--wrap-as-callback callback) :sync (or (null callback) @@ -504,6 +495,7 @@ its default value varies depending on value of QUERY-TYPE." powerthesaurus-synchronous-requests)))) (defun powerthesaurus--wrap-as-callback (fun) + "TBD" (cl-function (lambda (&key data &allow-other-keys) ;; in order to allow users to quit powerthesaurus @@ -520,7 +512,9 @@ its default value varies depending on value of QUERY-TYPE." (setq request-log-level -1) (setq request-message-level -1)) +;; =============================================================== ;; Define old API's now deprecated functions. +;; =============================================================== ;;;###autoload (defun powerthesaurus-lookup-word-dwim () From 9546c3a4e803a0fca63051f8a14cc3ace1e9f9ae Mon Sep 17 00:00:00 2001 From: Valeriy Savchenko Date: Sun, 12 Mar 2023 19:59:53 +0000 Subject: [PATCH 3/4] Add documentation for new functions --- README.md | 10 ++++++++ powerthesaurus.el | 63 ++++++++++++++++++++++++++++++++++++----------- 2 files changed, 59 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index ab98dc1..2409107 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,9 @@ If you have any active selection, `powerthesaurus-lookup-word` fetches selected ## Changelog +### Version 0.3.0 +* Migrate from parsing HTML of the page to the use of the API. + ### Version 0.2.2 * Remove redundant headers in request messages to server that potentially cause failure to parse received candidates (Github issue #16). @@ -93,3 +96,10 @@ If you have any active selection, `powerthesaurus-lookup-word` fetches selected * Support queries involving terms that consist of multiple words (e.g., "give up"). * Fix Github issues #13, #14, #15 and #17. + +## Acknowledgements + +I want to give a huge shoutout to the creators of powerthesaurus.org for creating +such an amazing tool. + +Also, kudos to the authors of [alfred-powerthesaurus](https://github.com/clarencecastillo/alfred-powerthesaurus) who figured out internal APIs and whose work I shamelessly copied. diff --git a/powerthesaurus.el b/powerthesaurus.el index c40d6bd..985fcf7 100644 --- a/powerthesaurus.el +++ b/powerthesaurus.el @@ -401,7 +401,12 @@ its default value varies depending on value of QUERY-TYPE." :documentation "User rating of the sentence"))) (defun powerthesaurus--query (term type &optional callback sync) - "TBD" + "Make a query to Powerthesaurus. + +TERM is the main text of the query. +TYPE should be a query type for thesaurus (e.g. ':synonyms' or ':related'). +CALLBACK gets called whenever the response is received and processed. +SYNC is t for synchronous version of the request." (let ((query (pcase type ((pred powerthesaurus--is-thesaurus-query-type) #'powerthesaurus--query-thesaurus) @@ -411,8 +416,14 @@ its default value varies depending on value of QUERY-TYPE." (funcall query term type callback sync))) (defun powerthesaurus--request-term-id (term callback &optional sync) - "TBD" - (powerthesaurus--api-query + "Request id for the given TERM. + +CALLBACK gets called whenever the response is received and processed. +SYNC is t for synchronous version of the request. + +Powerthesaurus APIs require explicit IDs assigned to every term. +This request fetches it for the further use." + (powerthesaurus--query-impl `(("query" . ,term)) powerthesaurus--search-query callback @@ -420,7 +431,10 @@ its default value varies depending on value of QUERY-TYPE." sync)) (defmacro powerthesaurus--with-term-id (term name sync &rest body) - "TBD" + "Request id for the given TERM, bind it to NAME, and execute BODY. + +TERM is the term to get ID for. +SYNC is t for synchronous version of the request." (declare (indent 3) (debug t)) `(let ((on-success (lambda (,name) @@ -428,9 +442,14 @@ its default value varies depending on value of QUERY-TYPE." (powerthesaurus--request-term-id ,term on-success sync))) (defun powerthesaurus--query-thesaurus (term type &optional callback sync) - "TBD" + "Request thesaurus information from Powerthesaurus. + +TERM is the text to get definition for. +TYPE should be a query type for thesaurus (e.g. ':synonyms' or ':related'). +CALLBACK gets called whenever the response is received and processed. +SYNC is t for synchronous version of the request." (powerthesaurus--with-term-id term term-id sync - (powerthesaurus--api-query + (powerthesaurus--query-impl `(("type" . ,(powerthesaurus--type-of-thesaurus-query type)) ("termID" . ,term-id) ("sort" . @@ -442,11 +461,11 @@ its default value varies depending on value of QUERY-TYPE." sync))) (defun powerthesaurus--is-thesaurus-query-type (query-type) - "TBD" + "Return 't' if the given QUERY-TYPE is for thesaurus queries." (member query-type '(:synonyms :antonyms :related))) (defun powerthesaurus--type-of-thesaurus-query (type) - "TBD" + "Return an API type corresponding to the given query TYPE." (pcase type (:synonyms "SYNONYM") (:antonyms "ANTONYM") @@ -454,9 +473,14 @@ its default value varies depending on value of QUERY-TYPE." (_ (error "Unknown thesaurus query type '%s'" type)))) (defun powerthesaurus--query-definition (term type &optional callback sync) - "TBD" + "Request definitions from Powerthesaurus. + +TERM is the text to get definition for. +TYPE should be nothing but ':definitions'. +CALLBACK gets called whenever the response is received and processed. +SYNC is t for synchronous version of the request." (powerthesaurus--with-term-id term term-id sync - (powerthesaurus--api-query + (powerthesaurus--query-impl `(("termID" . ,term-id)) powerthesaurus--definition-query callback @@ -464,9 +488,14 @@ its default value varies depending on value of QUERY-TYPE." sync))) (defun powerthesaurus--query-sentence (term type &optional callback sync) - "TBD" + "Request sentences from Powerthesaurus. + +TERM is the text for sentence examples. +TYPE should be nothing but ':sentences'. +CALLBACK gets called whenever the response is received and processed. +SYNC is t for synchronous version of the request." (powerthesaurus--with-term-id term term-id sync - (powerthesaurus--api-query + (powerthesaurus--query-impl `(("termID" . ,term-id)) powerthesaurus--sentence-query callback @@ -479,8 +508,14 @@ its default value varies depending on value of QUERY-TYPE." (json-available-p)) (setq powerthesaurus--json-parser #'(lambda () (json-parse-buffer :object-type 'alist)))) -(defun powerthesaurus--api-query (variables query &optional callback postprocess sync) - "TBD" +(defun powerthesaurus--query-impl (variables query &optional callback postprocess sync) + "Request data from Powerthesaurus GraphQL API. + +VARIABLES is an alist of query-specific parameters. +QUERY is the actual GraphQL query. +CALLBACK gets called whenever the response is received and processed. +POSTPROCESS is the additional processing of the JSON response alist. +SYNC is t for synchronous version of the request." (let ((post (or postprocess 'identity))) (request powerthesaurus-api-url From c9c006969d2cbaf49ddd12222866852e0a3385c1 Mon Sep 17 00:00:00 2001 From: Valeriy Savchenko Date: Sun, 12 Mar 2023 20:34:35 +0000 Subject: [PATCH 4/4] Bump version --- powerthesaurus.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/powerthesaurus.el b/powerthesaurus.el index 985fcf7..1b792e8 100644 --- a/powerthesaurus.el +++ b/powerthesaurus.el @@ -4,7 +4,7 @@ ;; Authors: Valeriy Savchenko ;; URL: http://github.com/SavchenkoValeriy/emacs-powerthesaurus -;; Version: 0.2.2 +;; Version: 0.3.0 ;; Package-Requires: ((emacs "25.1") (request "0.3.0") (jeison "1.0.0")) ;; Keywords: convenience, writing