feat: things generally seem to work

This commit is contained in:
Pavel Korytov 2022-08-24 15:31:32 +03:00
parent 8a775d63c8
commit c9481d7b3a

View file

@ -1,4 +1,4 @@
;;; reverso.el --- Client for the https://reverso.net translation service -*- lexical-binding: t -*- ;;; reverso.el --- Translation, grammar checking and bilingual concordances -*- lexical-binding: t -*-
;; Copyright (C) 2022 Korytov Pavel ;; Copyright (C) 2022 Korytov Pavel
@ -31,11 +31,12 @@
(require 'request) (require 'request)
(require 'transient) (require 'transient)
(require 'url-util) (require 'url-util)
(require 'dom)
(declare-function evil-define-key* "evil-core") (declare-function evil-define-key* "evil-core")
(defgroup reverso nil (defgroup reverso nil
"Client for the https://reverso.net translation service." "Translation, grammar checking and bilingual concordances."
:group 'applications) :group 'applications)
(defface reverso-highlight-face (defface reverso-highlight-face
@ -50,12 +51,17 @@
(defface reverso-heading-face (defface reverso-heading-face
'((t (:inherit transient-heading))) '((t (:inherit transient-heading)))
"Face for heading in reverso buffers." "Face for headings in reverso buffers."
:group 'reverso) :group 'reverso)
(defface reverso-language-face (defface reverso-keyword-face
'((t (:inherit transient-value))) '((t (:inherit transient-value)))
"Face for language names in reverso buffers." "Face for various keywords in reverso buffers."
:group 'reverso)
(defface reverso-definition-face
'((t (:inherit italic)))
"Face for word definitions in reverso buffer."
:group 'reverso) :group 'reverso)
(defcustom reverso-max-display-lines-in-input 5 (defcustom reverso-max-display-lines-in-input 5
@ -105,9 +111,9 @@ This one is used for the translation queries.")
(portuguese . pt) (portuguese . pt)
(romanian . ro) (romanian . ro)
(russian . ru)) (russian . ru))
"Mapping from long language names to short ones. "Another mapping from long language names to short ones.
This one is used for the synonyms queries.") This one is used for the synonym queries.")
(defconst reverso--right-to-left-languages (defconst reverso--right-to-left-languages
'(arabic hebrew) '(arabic hebrew)
@ -131,7 +137,6 @@ This one is used for the synonyms queries.")
russian))) russian)))
"Available languages for diferent operations.") "Available languages for diferent operations.")
(defconst reverso--languages-compatible (defconst reverso--languages-compatible
`((context `((context
. ((arabic . (english german spanish french hebrew italian . ((arabic . (english german spanish french hebrew italian
@ -205,10 +210,10 @@ This one is used for the synonyms queries.")
portuguese romanian ukrainian)) portuguese romanian ukrainian))
(ukrainian . (english)) (ukrainian . (english))
(chinese . (english french spanish ukrainian))))) (chinese . (english french spanish ukrainian)))))
"Which languages are compatible with which.") "Compatibility of languages for different operations.")
(defun reverso-verify-settings () (defun reverso-verify-settings ()
"Check if all the languages are set correctly." "Check if the settings are correct."
(interactive) (interactive)
(let ((languages (mapcar #'car reverso--language-mapping))) (let ((languages (mapcar #'car reverso--language-mapping)))
(dolist (cell reverso--languages) (dolist (cell reverso--languages)
@ -256,7 +261,7 @@ A random one is be picked at package initialization.")
(defvar reverso--user-agent (defvar reverso--user-agent
(nth (random (length reverso--user-agents)) (nth (random (length reverso--user-agents))
reverso--user-agents) reverso--user-agents)
"User-Agent to use for reverse.el requests.") "User-Agent to use for reverso.el requests.")
(defun reverso--translate (text source target cb) (defun reverso--translate (text source target cb)
"Translate TEXT from language SOURCE to TARGET. "Translate TEXT from language SOURCE to TARGET.
@ -265,11 +270,10 @@ SOURCE and TARGET are keys of `reverso--languages'. CB is called with
the result. the result.
The result is an alist with the following keys: The result is an alist with the following keys:
- `:corrected-text': set when the text has been corrected - `:corrected-text': corrected version of SOURCE (if available)
- `:language-from': the source language - `:language-from': the source language
- `:language-to': the target language - `:language-to': the target language
- `:detected-language': set when the detected target language is - `:detected-language': the detected source language
different from the source language
- `:translation': a string with translated text - `:translation': a string with translated text
- `:context-results': a list with found contexts. - `:context-results': a list with found contexts.
An item of the list is an alist with the keys: An item of the list is an alist with the keys:
@ -315,7 +319,7 @@ The result is an alist with the following keys:
(message "Error!: %S" error-thrown))))) (message "Error!: %S" error-thrown)))))
(defun reverso--convert-string (dom) (defun reverso--convert-string (dom)
"Convert html DOM from the reverso API to fontified string. "Convert DOM from the reverso API to fontified string.
reverso.net uses tags to highlight relevant works, e.g. <em> for the reverso.net uses tags to highlight relevant works, e.g. <em> for the
selected word in the context search. This function fontifies words selected word in the context search. This function fontifies words
@ -393,14 +397,14 @@ ALIST is an alist, LOOKUP-VALUE is a value to look in `cdr'."
(:context-results . ,context-results)))) (:context-results . ,context-results))))
(defun reverso--get-context (text source target cb) (defun reverso--get-context (text source target cb)
"Do a context translation for TEXT from SOURCE to TARGET. "Find bilingual concordances for TEXT.
SOURCE and TARGET are keys of `reverso--languages'. CB is called with SOURCE and TARGET are keys of `reverso--languages'. CB is called with
the result. the result.
The result is a list of alists with the keys: The result is a list of alists with the keys:
- `:source': string in the source language - `:source': a string in the source language
- `:target': string in the target language" - `:target': the same string in the target language"
(unless (and (alist-get source reverso--language-mapping) (unless (and (alist-get source reverso--language-mapping)
(member source (member source
(alist-get 'context reverso--languages))) (alist-get 'context reverso--languages)))
@ -432,7 +436,7 @@ The result is a list of alists with the keys:
(message "Error!: %S" error-thrown))))) (message "Error!: %S" error-thrown)))))
(defun reverso--get-context-parse (data) (defun reverso--get-context-parse (data)
"Parse response from reverso context API into an alist. "Parse response from reverso context API.
DATA is an html string." DATA is an html string."
(let ((html (with-temp-buffer (let ((html (with-temp-buffer
@ -456,7 +460,7 @@ The result is a list of alists with the following keys:
- `:kind': part of speech - `:kind': part of speech
- `:synonyms': list of alists: - `:synonyms': list of alists:
- `:synonym': word - `:synonym': word
- `:relevant': if t considered a \"good match\" by the service - `:relevant': if t, considered a \"good match\" by the service
- `:examples': list of strings with examples - `:examples': list of strings with examples
- `:antonyms': list of alists - `:antonyms': list of alists
- `:antonym': word" - `:antonym': word"
@ -521,6 +525,27 @@ HTML is a string."
`((:antonym . ,text)))))))) `((:antonym . ,text))))))))
(defun reverso--get-grammar (text language cb) (defun reverso--get-grammar (text language cb)
"Check TEXT in LANGUAGE for errors.
CB is called with the result.
The result is an alist with the keys:
`:corrected-text': corrected version of TEXT
`:source-text-hl': TEXT with highlighted errors
`:corrections': a list of alists with keys:
- `:type': error type
- `:short-description'
- `:long-description'
- `:mistake-text': part of TEXT with the error
- `:correction-text': corrected version of `:mistake-text'
- `:correction-defition': definiton of `:correction-text', if
available
- `:start-index': start index in TEXT
- `:end-index': end index TEXT
- `:suggestions': a list of alists with keys:
- `:text': the suggested text
- `:definition': definition of `:text', if available
- `:category': category of the correction, if available"
(unless (member language (alist-get 'grammar reverso--languages)) (unless (member language (alist-get 'grammar reverso--languages))
(error "Wrong language: %s" language)) (error "Wrong language: %s" language))
(request (concat (alist-get 'grammar reverso--urls) (request (concat (alist-get 'grammar reverso--urls)
@ -543,34 +568,39 @@ HTML is a string."
(message "Error!: %S" error-thrown))))) (message "Error!: %S" error-thrown)))))
(defun reverso--get-grammar-parse (source-text data) (defun reverso--get-grammar-parse (source-text data)
"Parse the reverso grammar API response.
SOURCE-TEXT is the text sent for checking. DATA is the JSON reply."
(let* ((corrected-text (alist-get 'text data)) (let* ((corrected-text (alist-get 'text data))
(source-text-hl (source-text-hl
(with-temp-buffer (with-temp-buffer
(insert source-text) (insert source-text)
(cl-loop for corr across (alist-get 'corrections data) (cl-loop for corr across (alist-get 'corrections data)
if (alist-get 'startIndex corr) if (alist-get 'startIndex corr)
do (put-text-property (alist-get 'startIndex corr) do (put-text-property (1+ (alist-get 'startIndex corr))
(alist-get 'endIndex corr) (+ 2 (alist-get 'endIndex corr))
'face 'reverso-error-face)) 'face 'reverso-error-face))
(buffer-string))) (buffer-string)))
(corrections (corrections
(cl-loop (cl-loop
for corr across (alist-get 'corrections data) for corr across (alist-get 'corrections data)
collect `((type . ,(alist-get 'type corr)) collect `((:type . ,(alist-get 'type corr))
(short-description . ,(alist-get 'shortDescription corr)) (:short-description . ,(alist-get 'shortDescription corr))
(long-description . ,(alist-get 'longDescription corr)) (:long-description . ,(alist-get 'longDescription corr))
(mistake-text . ,(alist-get 'mistakeText corr)) (:mistake-text . ,(alist-get 'mistakeText corr))
(correction-text . ,(alist-get 'correctionText corr)) (:correction-text . ,(alist-get 'correctionText corr))
(correction-defition . ,(alist-get 'correctionDefinition corr)) (:correction-defition . ,(alist-get 'correctionDefinition corr))
(suggestions (:start-index . ,(alist-get 'startIndex corr))
(:end-index . ,(alist-get 'endIndex corr))
(:suggestions
. ,(cl-loop for s across (alist-get 'suggestions corr) . ,(cl-loop for s across (alist-get 'suggestions corr)
collect collect
`((text . ,(alist-get 'text s)) `((:text . ,(alist-get 'text s))
(definition . ,(alist-get 'definition s)) (:definition . ,(alist-get 'definition s))
(category . ,(alist-get 'category s))))))))) (:category . ,(alist-get 'category s)))))))))
`((corrected-text . ,corrected-text) `((:corrected-text . ,corrected-text)
(source-text . ,source-text-hl) (:source-text-hl . ,source-text-hl)
(corrections . ,corrections)))) (:corrections . ,corrections))))
;;; Buffers ;;; Buffers
@ -608,16 +638,16 @@ source text."
(let ((multiline (string-match-p "\n" text))) (let ((multiline (string-match-p "\n" text)))
(insert (propertize (insert (propertize
(symbol-name (alist-get :language-from data)) (symbol-name (alist-get :language-from data))
'face 'reverso-language-face) 'face 'reverso-keyword-face)
" -> " " -> "
(propertize (propertize
(symbol-name (alist-get :language-to data)) (symbol-name (alist-get :language-to data))
'face 'reverso-language-face)) 'face 'reverso-keyword-face))
(when (alist-get :detected-language data) (when (alist-get :detected-language data)
(insert " [detected: " (insert " [detected: "
(propertize (propertize
(symbol-name (alist-get :detected-language data)) (symbol-name (alist-get :detected-language data))
'face 'reverso-language-face) 'face 'reverso-keyword-face)
"]")) "]"))
(insert "\n\n") (insert "\n\n")
@ -688,11 +718,11 @@ DATA is a list of alists with the following keys:
for target = (alist-get :target datum) for target = (alist-get :target datum)
do (insert (propertize do (insert (propertize
(format (format "%%-%ds: " lang-length) lang-to-name) (format (format "%%-%ds: " lang-length) lang-to-name)
'face 'reverso-language-face) 'face 'reverso-keyword-face)
source "\n" source "\n"
(propertize (propertize
(format (format "%%%ds: " lang-length) lang-from-name) (format (format "%%%ds: " lang-length) lang-from-name)
'face 'reverso-language-face) 'face 'reverso-keyword-face)
target "\n\n"))) target "\n\n")))
(defun reverso--translate-render-brief (text data) (defun reverso--translate-render-brief (text data)
@ -731,7 +761,7 @@ INPUT is the input string. DATA is a list as defined in
(when (alist-get :kind datum) (when (alist-get :kind datum)
(insert (propertize (insert (propertize
"Part of speech: " "Part of speech: "
'face 'reverso-language-face) 'face 'reverso-keyword-face)
(alist-get :kind datum) (alist-get :kind datum)
"\n")) "\n"))
(when (alist-get :synonyms datum) (when (alist-get :synonyms datum)
@ -760,6 +790,67 @@ INPUT is the input string. DATA is a list as defined in
(insert "- " (alist-get :antonym antonym) "\n")) (insert "- " (alist-get :antonym antonym) "\n"))
(insert "\n")))) (insert "\n"))))
(defun reverso--grammar-render (data)
"Render grammar checking results.
DATA is an alist as defined in `reverso--get-grammar'."
(insert
(propertize "Source text: " 'face 'reverso-heading-face)
"\n"
(alist-get :source-text-hl data)
"\n\n"
(propertize "Corrected text: " 'face 'reverso-heading-face)
"\n"
(alist-get :corrected-text data)
"\n\n")
(when (alist-get :corrections data)
(insert
(propertize "Corrections: " 'face 'reverso-heading-face)
"\n")
(dolist (corr (alist-get :corrections data))
(insert
(propertize (or (alist-get :type corr) "")
'face 'reverso-keyword-face))
(when (alist-get :short-description corr)
(insert ": " (alist-get :short-description corr)))
(insert "\n")
(when (alist-get :long-description corr)
(insert (alist-get :long-description corr))
(insert "\n"))
(insert "\n")
(insert
(propertize
(or (alist-get :mistake-text corr) "")
'face 'reverso-highlight-face)
" -> "
(propertize
(or (alist-get :correction-text corr) "")
'face 'reverso-highlight-face))
(when (alist-get :correction-defition corr)
(insert " [" (propertize
(alist-get :correction-defition corr)
'face 'reverso-definition-face)
"]"))
(insert "\n\n")
(when (alist-get :suggestions corr)
(insert "Suggestions:\n")
(dolist (sg (alist-get :suggestions corr))
(insert "- ")
(when (alist-get :category sg)
(insert (alist-get :category sg) ": "))
(insert (propertize
(alist-get :text sg)
'face 'reverso-highlight-face))
(when (alist-get :definition sg)
(insert
" ["
(propertize
(alist-get :definition sg)
'face 'reverso-definition-face)
"]"))
(insert "\n"))
(insert "\n")))))
(defmacro reverso--with-buffer (&rest body) (defmacro reverso--with-buffer (&rest body)
"Execute BODY in the clean `reverso' results buffer." "Execute BODY in the clean `reverso' results buffer."
(declare (indent 0)) (declare (indent 0))
@ -781,14 +872,25 @@ INPUT is the input string. DATA is a list as defined in
((format :initform " %k %d: %v")) ((format :initform " %k %d: %v"))
"Class used for retrieving the input string.") "Class used for retrieving the input string.")
(defvar reverso--use-buffer-as-input nil
"Whether to use the current buffer as input.
That parameter is normally set by the prefix argument, but as it
doesn't pesist between parent and child invocations, this variable is
used instead.")
(cl-defmethod transient-init-value ((obj reverso--transient-input)) (cl-defmethod transient-init-value ((obj reverso--transient-input))
"Initialize the value of `reverso--transient-input'.
OBJ is an instance of the class."
(oset obj value (oset obj value
(cond (cond
((and (slot-boundp obj 'value) (oref obj value)) ((and (slot-boundp obj 'value) (oref obj value))
(oref obj value)) (oref obj value))
((region-active-p) ((region-active-p)
(buffer-substring-no-properties (region-beginning) (region-end))) (buffer-substring-no-properties (region-beginning) (region-end)))
((equal current-prefix-arg '(4)) ((or (equal current-prefix-arg '(4))
reverso--use-buffer-as-input)
(if reverso--output (if reverso--output
reverso--output reverso--output
(buffer-substring-no-properties (point-min) (point-max)))) (buffer-substring-no-properties (point-min) (point-max))))
@ -796,9 +898,15 @@ INPUT is the input string. DATA is a list as defined in
(t "")))) (t ""))))
(cl-defmethod transient-infix-read ((obj reverso--transient-input)) (cl-defmethod transient-infix-read ((obj reverso--transient-input))
"Read input string from the minibuffer.
OBJ is an instance of the `reverso--transient-input'."
(read-from-minibuffer "Input: " (oref obj value))) (read-from-minibuffer "Input: " (oref obj value)))
(cl-defmethod transient-format-value ((obj reverso--transient-input)) (cl-defmethod transient-format-value ((obj reverso--transient-input))
"Format the input string for display in the transient buffer.
OBJ is an instance of `reverso--transient-input'."
(propertize (propertize
(with-temp-buffer (with-temp-buffer
(insert (oref obj value)) (insert (oref obj value))
@ -830,24 +938,47 @@ INPUT is the input string. DATA is a list as defined in
(is-target :initarg :is-target :initform nil)) (is-target :initarg :is-target :initform nil))
"Class used for switching the language.") "Class used for switching the language.")
(defvar reverso--source-value nil) (defvar reverso--source-value nil
"Selected source language in `reverso'.
(defvar reverso--target-value nil) Used for persistence between invocations of transient buffers.")
(defvar reverso--prefer-brief nil) (defvar reverso--target-value nil
"Selected target language in `reverso'.
(defun reverso--get-available-languages (obj &optional target-languages-list is-target) Used for persistence between invocations of transient buffers.")
(defvar reverso--prefer-brief nil
"If non-nil, select brief translation display by default.
Used for persistence between invocations of transient buffers.")
(defun reverso--get-available-languages (obj)
"Get available languages for the operation.
OBJ is an instance of transient infix. It needs to have the following
slots:
- `languages': list of available languages
- `is-target': if OBJ selects a target language
- `target-languages': alist, where the key is a source language, and
the value is a list of available target languages for that source
language.
If `is-target' is non-nil, then selection of languages has to limited.
In that case, `reverso--source-value' is used to get the source
language."
(let* ((all-languages (let* ((all-languages
(seq-sort (seq-sort
(lambda (a b) (string-lessp (symbol-name a) (lambda (a b) (string-lessp (symbol-name a)
(symbol-name b))) (symbol-name b)))
(or (oref obj languages) (or (oref obj languages)
(mapcar #'car reverso--language-mapping)))) (mapcar #'car reverso--language-mapping))))
(is-target (oref obj is-target))
(source-language (when is-target (source-language (when is-target
(or reverso--source-value (or reverso--source-value
(car all-languages)))) (car all-languages))))
(target-languages (when (and is-target target-languages-list) (target-languages (when (and is-target (oref obj target-languages))
(alist-get source-language target-languages-list))) (alist-get source-language (oref obj target-languages))))
(languages (cl-loop for lang in all-languages (languages (cl-loop for lang in all-languages
if (or (not source-language) if (or (not source-language)
(not (eq source-language lang))) (not (eq source-language lang)))
@ -861,11 +992,18 @@ INPUT is the input string. DATA is a list as defined in
(seq-intersection intersection-1 target-languages)))))) (seq-intersection intersection-1 target-languages))))))
(defun reverso--get-language-variable (obj) (defun reverso--get-language-variable (obj)
"Get the name of the variable that stores the selected language.
OBJ is an instance of a transient infix, that has to have a slot
called `is-target'."
(if (oref obj is-target) (if (oref obj is-target)
'reverso--target-value 'reverso--target-value
'reverso--source-value)) 'reverso--source-value))
(cl-defmethod transient-init-value ((obj reverso--transient-language)) (cl-defmethod transient-init-value ((obj reverso--transient-language))
"Initialize the value for the language picker.
OBJ is an instance of `reverso--transient-language'."
(let ((value (let ((value
(cond (cond
((and (slot-boundp obj 'value) (oref obj value)) ((and (slot-boundp obj 'value) (oref obj value))
@ -880,6 +1018,9 @@ INPUT is the input string. DATA is a list as defined in
(oset obj value value))) (oset obj value value)))
(cl-defmethod transient-format-value ((obj reverso--transient-language)) (cl-defmethod transient-format-value ((obj reverso--transient-language))
"Format the value of the language picker.
OBJ is an instance of `reverso--transient-language'."
(let ((value (transient-infix-value obj))) (let ((value (transient-infix-value obj)))
(concat (concat
(propertize "[" 'face 'transient-inactive-value) (propertize "[" 'face 'transient-inactive-value)
@ -889,18 +1030,15 @@ INPUT is the input string. DATA is a list as defined in
(if (eq choice value) (if (eq choice value)
'transient-value 'transient-value
'transient-inactive-value))) 'transient-inactive-value)))
(reverso--get-available-languages (reverso--get-available-languages obj)
obj
(oref obj target-languages)
(oref obj is-target))
(propertize "|" 'face 'transient-inactive-value)) (propertize "|" 'face 'transient-inactive-value))
(propertize "]" 'face 'transient-inactive-value)))) (propertize "]" 'face 'transient-inactive-value))))
(cl-defmethod transient-infix-read ((obj reverso--transient-language)) (cl-defmethod transient-infix-read ((obj reverso--transient-language))
(let* ((choices (reverso--get-available-languages "Pick a value in the language picker.
obj
(oref obj target-languages) OBJ is an instance of `reverso--transient-language'."
(oref obj is-target))) (let* ((choices (reverso--get-available-languages obj))
(current-idx (or (cl-position (oref obj value) choices) -1)) (current-idx (or (cl-position (oref obj value) choices) -1))
(next-idx (% (1+ current-idx) (length choices))) (next-idx (% (1+ current-idx) (length choices)))
(next-choice (next-choice
@ -917,10 +1055,10 @@ INPUT is the input string. DATA is a list as defined in
next-choice)) next-choice))
(cl-defmethod transient-infix-value ((obj reverso--transient-language)) (cl-defmethod transient-infix-value ((obj reverso--transient-language))
(let* ((choices (reverso--get-available-languages "Get the current value of the language picker.
obj
(oref obj target-languages) OBJ is an instance of `reverso--transient-language'."
(oref obj is-target))) (let* ((choices (reverso--get-available-languages obj))
(current-idx (or (cl-position (oref obj value) choices) -1))) (current-idx (or (cl-position (oref obj value) choices) -1)))
(nth current-idx choices))) (nth current-idx choices)))
@ -928,10 +1066,15 @@ INPUT is the input string. DATA is a list as defined in
"Toggle brief output.") "Toggle brief output.")
(cl-defmethod transient-init-value ((obj reverso--transient-brief)) (cl-defmethod transient-init-value ((obj reverso--transient-brief))
"Initialize the value of the brief output switcher.
OBJ is an instance of `reverso--transient-brief'."
(oset obj value reverso--prefer-brief)) (oset obj value reverso--prefer-brief))
(cl-defmethod transient-infix-read ((obj reverso--transient-brief)) (cl-defmethod transient-infix-read ((obj reverso--transient-brief))
"Toggle the switch on or off." "Toggle the switch on or off.
OBJ is an instance of `reverso--transient-brief'."
(setq reverso--prefer-brief (setq reverso--prefer-brief
(null (oref obj value)))) (null (oref obj value))))
@ -997,6 +1140,7 @@ INPUT is the input string. DATA is a list as defined in
(reverso--translate-render input data)))))) (reverso--translate-render input data))))))
(transient-define-prefix reverso-translate () (transient-define-prefix reverso-translate ()
"Translate text."
["Input" ["Input"
("i" "Input" reverso--transient-input-infix)] ("i" "Input" reverso--transient-input-infix)]
["Parameters" ["Parameters"
@ -1036,6 +1180,10 @@ INPUT is the input string. DATA is a list as defined in
(setq-local reverso--data data))))) (setq-local reverso--data data)))))
(transient-define-prefix reverso-context () (transient-define-prefix reverso-context ()
"Find bilingual concordances for text.
A bilingual concordance is a pair of strings of the same text in
different languages."
["Input" ["Input"
("i" "Input" reverso--transient-input-infix)] ("i" "Input" reverso--transient-input-infix)]
["Parameters" ["Parameters"
@ -1065,6 +1213,7 @@ INPUT is the input string. DATA is a list as defined in
(setq-local reverso--data data))))) (setq-local reverso--data data)))))
(transient-define-prefix reverso-synonyms () (transient-define-prefix reverso-synonyms ()
"Find synomyms."
["Input" ["Input"
("i" "Input" reverso--transient-input-infix)] ("i" "Input" reverso--transient-input-infix)]
["Parameters" ["Parameters"
@ -1073,5 +1222,53 @@ INPUT is the input string. DATA is a list as defined in
(reverso--synonyms-exec-suffix) (reverso--synonyms-exec-suffix)
("q" "Quit" transient-quit-one)]) ("q" "Quit" transient-quit-one)])
(transient-define-infix reverso--transient-grammar-language ()
:class 'reverso--transient-language
:description "Language"
:key "s"
:argument "-s"
:languages (alist-get 'grammar reverso--languages))
(transient-define-suffix reverso--grammar-exec-suffix (input source)
:key "e"
:description "Check grammar"
(interactive (transient-args transient-current-command))
(reverso--get-grammar
input source
(lambda (data)
(reverso--with-buffer
(reverso--grammar-render data)
(setq-local reverso--data data)))))
(transient-define-prefix reverso-grammar ()
"Check grammar."
["Input"
("i" "Input" reverso--transient-input-infix)]
["Parameters"
(reverso--transient-grammar-language)]
["Actions"
(reverso--grammar-exec-suffix)
("q" "Quit" transient-quit-one)])
(transient-define-prefix reverso ()
"Translation, grammar checking and bilingual concordances and more."
["Commands"
("t" "Translation" reverso-translate)
("c" "Context" reverso-context)
("s" "Synomyms" reverso-synonyms)
("g" "Grammar check" reverso-grammar)]
["Actions"
("q" "Quit" transient-quit-one)
("k" "Kek" (lambda () (interactive)
(message "%s"
(cl-mapcan (lambda (obj)
(when (and (slot-exists-p obj 'scope)
(oref obj scope))
(oref obj scope)))
(transient-suffixes 'reverso)))))]
(interactive)
(setq-local reverso--use-buffer-as-input (equal current-prefix-arg '(4)))
(transient-setup 'reverso))
(provide 'reverso) (provide 'reverso)
;;; reverso.el ends here ;;; reverso.el ends here