diff --git a/.github/workflows/byte-compile.yml b/.github/workflows/byte-compile.yml index e76104c..1f1084b 100644 --- a/.github/workflows/byte-compile.yml +++ b/.github/workflows/byte-compile.yml @@ -16,10 +16,11 @@ jobs: emacs_version: - 27.1 - 27.2 - - snapshot + - 28.1 + - 28.2 steps: - name: Checkout Repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Install emacs uses: purcell/setup-emacs@master with: diff --git a/ChangeLog.org b/ChangeLog.org index fcaa30a..7bedc9a 100644 --- a/ChangeLog.org +++ b/ChangeLog.org @@ -8,6 +8,13 @@ Versioning]]. ** [Unreleased] +** [1.2.0] +*** Added +- Support for ~ispell~ ~LocalWords~ ignored words. + +*** Removed +- Package ~request 0.3.*~ dependency. + ** [1.1.0] *** Added - Support for API premium features. diff --git a/Contributing.org b/Contributing.org new file mode 100644 index 0000000..c8db0d7 --- /dev/null +++ b/Contributing.org @@ -0,0 +1,64 @@ +* Contributing + +In this guide you will get an overview of the contribution workflow from opening +an issue, creating a PR, reviewing, and merging the PR. + +** Issues + +*** Create a new issues + +If you spot a problem with the package, [[https://github.com/PillFall/languagetool.el/issues][search if an issue already exists]]. If a +related issue doesn't exist, you can open a new issue using a relevant [[https://github.com/PillFall/languagetool.el/issues/new/choose][issue +form]]. + +*** Solve an issue + +Scan through our [[https://github.com/PillFall/languagetool.el/issues][existing issues]] to find one that interests you. You can narrow +down the search using ~labels~ as filters. See Labels for more information. If +you find an issue to work on, you are welcome to open a PR with a fix. + + + +** Pull Request + +When you're finished with the changes, create a pull request, also known as a +PR. + +- Brach out from ~develop~, name the branch the way you want, but keep in mind + that is better to name the branch after the feature or fix. +- All PR that doesn't come from-to ~develop~ will be rejected. +- Don't forget to link PR to issue if you are solving one. +- Enable the checkbox to allow maintainer edits so the branch can be update for + a merge. Once you submit your PR, your code will be reviewed. We may ask + questions or request additional information. +- We may ask for changes to be made before a PR can be merged, either using + suggested changes or pull request comments. You can apply suggested changes + directly through the UI. You can make any other changes in your fork, then + commit them to your branch. +- As you update your PR and apply changes, mark each conversation as resolved. +- If you run into any merge issues, checkout this [[https://github.com/skills/resolve-merge-conflicts][git tutorial]] to help you + resolve merge conflicts and other issues. + + +** Commit your update + +Commit the changes once you are happy with them. Remember to always test: + +- The Emacs Lisp files should follow the [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Tips.html][Emacs Lisp conventions]] and the + [[https://github.com/bbatsov/emacs-lisp-style-guide][Emacs Lisp Style Guide]]. +- Your code byte-compiles cleanly. +- Use the last version of ~package-lint~ to check for packaging issues, and + address its feedback. +- ~M-x checkdoc~ is happy with your docstrings. + + + +** Your PR is merged! + +Congratulations! + +Once your PR is merged, your contributions will be publicly visible on the +package. + +Now that you are part of the ~languagetool.el~ developers, see how else you can +contribute. diff --git a/ReadMe.org b/ReadMe.org index 7a492ff..1779d15 100644 --- a/ReadMe.org +++ b/ReadMe.org @@ -138,7 +138,8 @@ will call LanguageTool from its class, so set ~languagetool-java-arguments~, languagetool-server-command "org.languagetool.server.HTTPServer") #+END_SRC -If you pay for LanguageTool Premium features, you can add the keys for the LanguageTool api as follows: +If you pay for [[https://languagetool.org/proofreading-api][LanguageTool Proofreading API]] features, you can add the keys for +the LanguageTool API as follows: #+BEGIN_SRC elisp (setq languagetool-api-key "xxxxxxxxxxxx" @@ -154,6 +155,14 @@ or call ~languagetool-set-language~. If you want to know more customization options you can find those at the /customize/ interface. +When you decide to ignore a word, this package will add a /comment like/ +following ~ispell~ conventions. So, after the ignore you'll get a comment like +this at the end of your file. + +#+BEGIN_SRC org +# LocalWords: seplling +#+END_SRC + ** Quick Usage @@ -197,7 +206,7 @@ to Emacs (If you close Emacs, it's over). This server starts to listen in port another value. If you are going to use a server with another configuration, like servers not -located in your localhost, you must set ~languagetool-server-host~ and +located in your localhost, you must set ~languagetool-server-url~ and ~languagetool-server-port~ to whatever adjust your needs. These variables play in the communication to the LanguageTool HTTP API. diff --git a/languagetool-console.el b/languagetool-console.el index 2893e11..ae1e933 100644 --- a/languagetool-console.el +++ b/languagetool-console.el @@ -5,8 +5,8 @@ ;; Author: Joar Buitrago ;; Keywords: grammar text docs tools convenience checker ;; URL: https://github.com/PillFall/Emacs-LanguageTool.el -;; Version: 1.1.0 -;; Package-Requires: ((emacs "27.0") (request "0.3.2")) +;; Version: 1.2.0 +;; Package-Requires: ((emacs "27.1")) ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by @@ -32,11 +32,13 @@ (require 'languagetool-core) (require 'languagetool-issue) (require 'languagetool-java) +(eval-when-compile + (require 'subr-x)) ;; Group definition: (defgroup languagetool-console nil - "LanguageTool command line parser and checking" + "LanguageTool command line parser and checking." :tag "Console" :prefix "languagetool-console-" :group 'languagetool) @@ -74,7 +76,7 @@ Command Line.") ;;; Function definitions: (defun languagetool-console-class-p () - "Return nil if `languagetool-console-command' is not a Java class." + "Return non-nil if `languagetool-console-command' is a Java class." (let ((regex (rx line-start (zero-or-more @@ -90,7 +92,7 @@ Command Line.") (string-match-p regex languagetool-console-command))) (defun languagetool-console-command-exists-p () - "Return t is `languagetool-console-command' can be used or exists. + "Return non-nil if `languagetool-console-command' can be used or exists. Also sets `languagetool-console-command' to a full path if needed for this package to work." @@ -104,63 +106,55 @@ for this package to work." (unless (listp languagetool-console-arguments) (error "LanguageTool Console Arguments must be a list of strings")) - (let ((arguments nil)) + (let (arguments) ;; Appends LanguageTool Console Command (unless (languagetool-console-class-p) - (setq arguments (append arguments (list "-jar")))) - (setq arguments (append arguments (list languagetool-console-command))) + (push "-jar" arguments)) + (push languagetool-console-command arguments) ;; Appends the LanguageTool arguments - (setq arguments (append arguments languagetool-console-arguments)) + (push languagetool-console-arguments arguments) ;; Appends the common arguments - (setq arguments (append arguments - (list "--encoding" "utf8") - (list "--json"))) + (push (list "--encoding" "utf8" "--json") arguments) ;; Appends the correction language information (if (string= languagetool-correction-language "auto") - (setq arguments (append arguments (list "--autoDetect"))) - (setq arguments (append arguments (list "--language" languagetool-correction-language)))) + (push "--autoDetect" arguments) + (push (list "--language" languagetool-correction-language) arguments)) ;; Appends the mother tongue information (when (stringp languagetool-mother-tongue) - (setq arguments (append arguments (list "--mothertongue" languagetool-mother-tongue)))) + (push (list "--mothertongue" languagetool-mother-tongue) arguments)) ;; Appends the disabled rules - (let ((rules "")) - ;; Global disabled rules - (dolist (rule languagetool-disabled-rules) - (if (string= rules "") - (setq rules (concat rules rule)) - (setq rules (concat rules "," rule)))) - ;; Local disabled rules - (dolist (rule languagetool-local-disabled-rules) - (if (string= rules "") - (setq rules (concat rules rule)) - (setq rules (concat rules "," rule)))) + (let ((rules (string-join (append languagetool-disabled-rules languagetool-local-disabled-rules) ","))) (unless (string= rules "") - (setq arguments (append arguments (list "--disable" rules))))) - arguments)) + (push (list "--disable" rules) arguments ))) + (flatten-tree (reverse arguments)))) (defun languagetool-console-write-debug-info (text) "Write debug info in `languagetool-console-output-buffer-name'. The argument TEXT is the region passed to LanguageTool for checking." - (insert (propertize " ----- LanguageTool Command:" 'face 'font-lock-warning-face) - "\n\n") - (insert languagetool-java-bin " " - (mapconcat (lambda (x) (format "%s" x)) (append - (languagetool-console-parse-arguments) - (languagetool-java-parse-arguments)) " ") - "\n\n\n\n") - (insert (propertize " ----- LanguageTool Text:" 'face 'font-lock-warning-face) - "\n\n") - (insert text "\n\n\n\n") - (insert (propertize " ----- LanguageTool Output:" 'face 'font-lock-warning-face) - "\n\n")) + (insert + (propertize " ----- LanguageTool Command:" 'face 'font-lock-warning-face) + "\n\n" + (string-join + (append + (list languagetool-java-bin) + (languagetool-java-parse-arguments) + (languagetool-console-parse-arguments)) + " ") + "\n\n\n\n" + (propertize " ----- LanguageTool Text:" 'face 'font-lock-warning-face) + "\n\n" + text + "\n\n\n\n" + (propertize " ----- LanguageTool Output:" 'face 'font-lock-warning-face) + "\n\n")) (defun languagetool-console-invoke-command-region (begin end) "Invoke LanguageTool passing the current region to STDIN. @@ -219,24 +213,25 @@ Found no errors.") (defun languagetool-console-matches-exists-p () "Return t if issues where found by LanguageTool or nil otherwise." - (/= 0 (length (cdr (assoc 'matches languagetool-console-output-parsed))))) + (/= 0 (length (alist-get 'matches languagetool-console-output-parsed)))) (defun languagetool-console-highlight-matches (begin) "Highlight issues in the buffer. BEGIN defines the start of the current region." - (let ((corrections (cdr (assoc 'matches languagetool-console-output-parsed))) - (correction nil)) + (let ((corrections (alist-get 'matches languagetool-console-output-parsed))) (dotimes (index (length corrections)) - (setq correction (aref corrections index)) - (let ((offset (cdr (assoc 'offset correction))) - (size (cdr (assoc 'length correction)))) - (languagetool-issue-create-overlay - (+ begin offset) (+ begin offset size) - correction)))) - (setq languagetool-core-hint-timer - (run-with-idle-timer languagetool-hint-idle-delay t - languagetool-hint-function))) + (let* ((correction (aref corrections index)) + (offset (alist-get 'offset correction)) + (size (alist-get 'length correction)) + (start (+ begin offset)) + (end (+ begin offset size)) + (word (buffer-substring-no-properties start end))) + (unless (languagetool-core-correct-p word) + (languagetool-issue-create-overlay start end correction)))) + (setq languagetool-core-hint-timer + (run-with-idle-timer languagetool-hint-idle-delay t + languagetool-hint-function)))) (provide 'languagetool-console) diff --git a/languagetool-core.el b/languagetool-core.el index f260cd1..77dce06 100644 --- a/languagetool-core.el +++ b/languagetool-core.el @@ -5,8 +5,8 @@ ;; Author: Joar Buitrago ;; Keywords: grammar text docs tools convenience checker ;; URL: https://github.com/PillFall/Emacs-LanguageTool.el -;; Version: 1.1.0 -;; Package-Requires: ((emacs "27.0") (request "0.3.2")) +;; Version: 1.2.0 +;; Package-Requires: ((emacs "27.1")) ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by @@ -29,6 +29,10 @@ ;; Variable definitions: +(require 'ispell) +(eval-when-compile + (require 'subr-x)) + (defcustom languagetool-api-key nil "LanguageTool API Key for Premium features." :group 'languagetool @@ -163,13 +167,12 @@ A example hint function: (when (overlay-get ov 'languagetool-message) (unless (current-message) (message - \"%s%s\" (overlay-get ov 'languagetool-short-message) - (if (/= 0 - (length (overlay-get ov 'languagetool-replacements))) + \"%s%s\" + (overlay-get ov 'languagetool-short-message) + (if (/= 0 (length (overlay-get ov 'languagetool-replacements))) (concat \" -> (\" - (mapconcat - #'identity (languagetool-core-get-replacements ov) \", \") + (string-join (languagetool-core-get-replacements ov) \", \") \")\") \"\"))))))" :group 'languagetool @@ -206,24 +209,36 @@ A example hint function: (when (overlay-get ov 'languagetool-message) (unless (current-message) (message - "%s%s" (overlay-get ov 'languagetool-short-message) - (if (/= 0 - (length (overlay-get ov 'languagetool-replacements))) + "%s%s" + (overlay-get ov 'languagetool-short-message) + (if (/= 0 (length (overlay-get ov 'languagetool-replacements))) (concat " -> (" - (mapconcat - #'identity (languagetool-core-get-replacements ov) ", ") + (string-join (languagetool-core-get-replacements ov) ", ") ")") "")))))) (defun languagetool-core-get-replacements (overlay) "Return the replacements of OVERLAY in a list." (let ((replacements (overlay-get overlay 'languagetool-replacements)) - (replace nil)) + replace) (dotimes (index (length replacements)) - (setq replace (append replace - (list (cdr (assoc 'value (aref replacements index))))))) - replace)) + (push (alist-get 'value (aref replacements index)) replace)) + (reverse replace))) + +(defun languagetool-core-correct-p (word) + "Return non-nil if WORD is on the LocalWords comment in the current buffer." + (save-excursion + (goto-char (point-min)) + (let (found) + (while (and (search-forward ispell-words-keyword nil t) + (not found)) + (when (re-search-forward (rx + (zero-or-more space) + (group (literal word)) + (zero-or-more space)) (line-end-position) t) + (setq found t))) + found))) (provide 'languagetool-core) diff --git a/languagetool-correction.el b/languagetool-correction.el index 203dc94..b4fcec6 100644 --- a/languagetool-correction.el +++ b/languagetool-correction.el @@ -5,8 +5,8 @@ ;; Author: Joar Buitrago ;; Keywords: grammar text docs tools convenience checker ;; URL: https://github.com/PillFall/Emacs-LanguageTool.el -;; Version: 1.1.0 -;; Package-Requires: ((emacs "27.0") (request "0.3.2")) +;; Version: 1.2.0 +;; Package-Requires: ((emacs "27.1")) ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by @@ -29,6 +29,7 @@ (require 'cl-lib) (require 'languagetool-core) +(require 'ispell) ;; Variable definitions: @@ -47,9 +48,11 @@ "Parse and style minibuffer correction. Get the information about corrections from OVERLAY." - (let ((msg nil) - (rule (cdr (assoc 'id (overlay-get overlay 'languagetool-rule)))) - (message (overlay-get overlay 'languagetool-message))) + (let* ((msg nil) + (rule (alist-get 'id (overlay-get overlay 'languagetool-rule))) + (message (overlay-get overlay 'languagetool-message)) + (replacements (languagetool-core-get-replacements overlay)) + (num-choices (length replacements))) ;; Add LanguageTool rule to the message (setq msg (concat msg "[" rule "] ")) @@ -57,34 +60,34 @@ Get the information about corrections from OVERLAY." (setq msg (concat msg (propertize (format "%s" message) 'face 'font-lock-warning-face) "\n")) ;; Format all the possible replacements for the correction suggestion - (let ((replacements (languagetool-core-get-replacements overlay))) - (when (< 0 (length replacements)) - (let ((num-choices (length replacements))) - ;; If can't assoc each replacement with each hotkey - (when (> (length replacements) (length languagetool-correction-keys)) - (setq num-choices (length languagetool-correction-keys)) - (setq msg (concat msg "Not all choices shown.\n"))) - (setq msg (concat msg "\n")) - ;; Format all choices - (dotimes (index num-choices) - (setq msg (concat msg - "[" - (propertize - (format "%c" (aref languagetool-correction-keys index)) - 'face 'font-lock-keyword-face) - "]: ")) - (setq msg (concat msg (nth index replacements) " ")))))) + ;; If can't assoc each replacement with each hotkey truncate the replacements + (when (> (length replacements) (length languagetool-correction-keys)) + (setq num-choices (length languagetool-correction-keys)) + (setq msg (concat msg "Not all choices shown.\n"))) + (setq msg (concat msg "\n")) + ;; Format all choices + (dotimes (index num-choices) + (setq msg (concat msg + "[" + (propertize + (format "%c" (aref languagetool-correction-keys index)) + 'face 'font-lock-keyword-face) + "]: ")) + (setq msg (concat msg (nth index replacements) " "))) ;; Add default Ignore and Skip options (setq msg (concat msg "\n[" (propertize "C-i" 'face 'font-lock-keyword-face) "]: Ignore ")) (setq msg (concat msg "[" (propertize "C-s" 'face 'font-lock-keyword-face) - "]: Skip\n")) - msg)) + "]: Skip ")) + ;; Some people do not know C-g is the global exit key + (setq msg (concat msg "[" + (propertize "C-g" 'face 'font-lock-keyword-face) + "]: Quit\n")))) (defun languagetool-correction-apply (pressed-key overlay) - "Correct text marked by LanguageTool with user choice. + "Apply LanguageTool replacement suggestion in OVERLAY. PRESSED-KEY is the index of the suggestion in the array contained on OVERLAY." @@ -92,6 +95,7 @@ on OVERLAY." ((char-equal ?\C-i pressed-key) (progn (goto-char (overlay-end overlay)) + (ispell-add-per-file-word-list (buffer-substring-no-properties (overlay-start overlay) (overlay-end overlay))) (delete-overlay overlay))) ((char-equal ?\C-s pressed-key) (goto-char (overlay-end overlay))) @@ -108,14 +112,16 @@ on OVERLAY." (defun languagetool-correction-at-point () "Show issue at point and try to apply suggestion." - (let (pressed-key) - (dolist (ov (overlays-at (point))) - (when (overlay-get ov 'languagetool-message) - (message nil) - (setq pressed-key - (read-char (languagetool-correction-parse-message ov))) - (languagetool-correction-apply pressed-key ov))))) + (dolist (ov (overlays-at (point))) + (when (overlay-get ov 'languagetool-message) + ;; Cancel any previous message + (message nil) + (languagetool-correction-apply + (read-char (languagetool-correction-parse-message ov)) + ov)))) (provide 'languagetool-correction) ;;; languagetool-correction.el ends here + +; LocalWords: languagetool diff --git a/languagetool-issue.el b/languagetool-issue.el index a214842..6600865 100644 --- a/languagetool-issue.el +++ b/languagetool-issue.el @@ -5,8 +5,8 @@ ;; Author: Joar Buitrago ;; Keywords: grammar text docs tools convenience checker ;; URL: https://github.com/PillFall/Emacs-LanguageTool.el -;; Version: 1.1.0 -;; Package-Requires: ((emacs "27.0") (request "0.3.2")) +;; Version: 1.2.0 +;; Package-Requires: ((emacs "27.1")) ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by @@ -37,7 +37,7 @@ ;; Group definition: (defgroup languagetool-issue nil - "LanguageTool faces for marking issues" + "LanguageTool faces for marking issues." :tag "Issue Faces" :prefix "languagetool-issue-" :group 'languagetool) @@ -92,7 +92,7 @@ Each element is a cons cell with the form (ISSUE_TYPE . FACE_NAME)." (defun languagetool-issue-get-face (issue-type) "Return the face for ISSUE-TYPE." - (or (cdr (assoc issue-type languagetool-issue-face-alist)) + (or (alist-get issue-type languagetool-issue-face-alist) 'languagetool-issue-default)) (defun languagetool-issue-create-overlay (begin end correction) @@ -102,11 +102,11 @@ Create an overlay for correction in the region delimited by BEGIN and END, parsing CORRECTION as overlay properties." (save-excursion (let* ((ov (make-overlay begin end)) - (short-message (cdr (assoc 'shortMessage correction))) - (message (cdr (assoc 'message correction))) - (replacements (cdr (assoc 'replacements correction))) - (rule (cdr (assoc 'rule correction))) - (issue-type (cdr (assoc 'issueType rule)))) + (short-message (alist-get 'shortMessage correction)) + (message (alist-get 'message correction)) + (replacements (alist-get 'replacements correction)) + (rule (alist-get 'rule correction)) + (issue-type (alist-get 'issueType rule))) (when (string= short-message "") (setq short-message message)) (overlay-put ov 'languagetool-short-message short-message) diff --git a/languagetool-java.el b/languagetool-java.el index 2bbb9a3..75742d3 100644 --- a/languagetool-java.el +++ b/languagetool-java.el @@ -5,8 +5,8 @@ ;; Author: Joar Buitrago ;; Keywords: grammar text docs tools convenience checker ;; URL: https://github.com/PillFall/Emacs-LanguageTool.el -;; Version: 1.1.0 -;; Package-Requires: ((emacs "27.0") (request "0.3.2")) +;; Version: 1.2.0 +;; Package-Requires: ((emacs "27.1")) ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by @@ -30,7 +30,7 @@ ;; Group definition: (defgroup languagetool-java nil - "LanguageTool Java related configuration" + "LanguageTool Java related configuration." :tag "Java" :prefix "languagetool-java-" :group 'languagetool) @@ -76,11 +76,11 @@ For example to use in Arch Linux (with pacman dependency): (unless (listp languagetool-java-arguments) (error "LanguageTool Java Arguments must be a list of strings")) - (let ((arguments nil)) + (let (arguments) - (setq arguments (append arguments languagetool-java-arguments)) + (push languagetool-java-arguments arguments) - arguments)) + (flatten-tree (reverse arguments)))) (provide 'languagetool-java) diff --git a/languagetool-server.el b/languagetool-server.el index 45e10a4..1e86383 100644 --- a/languagetool-server.el +++ b/languagetool-server.el @@ -5,8 +5,8 @@ ;; Author: Joar Buitrago ;; Keywords: grammar text docs tools convenience checker ;; URL: https://github.com/PillFall/Emacs-LanguageTool.el -;; Version: 1.1.0 -;; Package-Requires: ((emacs "27.0") (request "0.3.2")) +;; Version: 1.2.0 +;; Package-Requires: ((emacs "27.1")) ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by @@ -29,8 +29,7 @@ ;;; Code: (require 'json) -(require 'cl-lib) -(require 'request) +(require 'url) (require 'languagetool-java) (require 'languagetool-core) (require 'languagetool-issue) @@ -38,7 +37,7 @@ ;; Group definition: (defgroup languagetool-server nil - "Real time LanguageTool Server" + "Real time LanguageTool Server." :tag "Server" :prefix "languagetool-server-" :group 'languagetool) @@ -74,10 +73,10 @@ More info at http://wiki.languagetool.org/command-line-options." :group 'languagetool-server :type 'integer) -(defcustom languagetool-server-max-tries 20 - "LanguageTool Server max number of tries before disconnect from server." +(defcustom languagetool-server-max-timeout 5.0 + "LanguageTool Server maximum number of seconds to wait before giving up." :group 'languagetool-server - :type 'integer) + :type 'number) (defcustom languagetool-server-check-delay 3.0 "LanguageTool Server delay time before checking again for issues." @@ -144,7 +143,7 @@ Don't use this function, use `languagetool-server-mode' instead." (defun languagetool-server-class-p () - "Return nil if `languagetool-server-command' is not a Java class." + "Return non-nil if `languagetool-server-command' is a Java class." (let ((regex (rx line-start (zero-or-more @@ -160,7 +159,7 @@ Don't use this function, use `languagetool-server-mode' instead." (string-match-p regex languagetool-server-command))) (defun languagetool-server-command-exists-p () - "Return t is `languagetool-console-command' can be used or exists. + "Return non-nil is `languagetool-console-command' can be used or exists. Also sets `languagetool-console-command' to a full path if needed for this package to work." @@ -211,23 +210,21 @@ It's not recommended to run this function more than once." (unless (listp languagetool-server-arguments) (error "LanguageTool Server Arguments must be a list of strings")) - (let ((arguments nil)) + (let (arguments) ;; Appends the LanguageTool Server Command (unless (languagetool-server-class-p) - (setq arguments (append arguments (list "-cp")))) - (setq arguments (append arguments (list languagetool-server-command))) + (push "-cp" arguments)) + (push languagetool-server-command arguments) (unless (languagetool-server-class-p) - (setq arguments (append arguments (list "org.languagetool.server.HTTPServer")))) + (push "org.languagetool.server.HTTPServer" arguments)) - (setq arguments (append arguments languagetool-server-arguments)) + (push languagetool-server-arguments arguments) ;; Appends the port information - (setq arguments (append arguments - (list "--port" - (format "%d" languagetool-server-port)))) + (push (list "--port" (format "%d" languagetool-server-port)) arguments) - arguments)) + (flatten-tree (reverse arguments)))) ;;;###autoload (defun languagetool-server-stop () @@ -235,82 +232,58 @@ It's not recommended to run this function more than once." (interactive) (delete-process languagetool-server-process)) -(defun languagetool-server-check-for-communication (&optional try) +(defun languagetool-server-check-for-communication () "Check if the LanguageTool Server is able to handle requests. -Optional parameter TRY is the try number before Emacs show an error." - (unless try (setq try 1)) - (when (>= try languagetool-server-max-tries) - (languagetool-server-mode -1) - (error "LanguageTool Server cannot communicate with server")) +This methods will only check if the server is up for the number +of seconds specified in `languagetool-server-max-timeout'." (unless languagetool-server-open-communication-p - (request - (format "%s:%d/v2/languages" languagetool-server-url languagetool-server-port) - :type "GET" - :parser 'json-read - :success (cl-function - (lambda (&key _response &allow-other-keys) - (message "LanguageTool Server communication is up...") - (setq languagetool-server-open-communication-p t) - (languagetool-server-check))) - :error (cl-function - (lambda (&key _error-thrown &allow-other-keys) - (when (or - languagetool-server-mode - (not languagetool-server-open-communication-p)) - (languagetool-server-check-for-communication (+ try 1)))))))) + (condition-case nil + (let ((url-request-method "GET")) + (with-current-buffer (url-retrieve-synchronously + (url-encode-url (format "%s:%d/v2/languages" languagetool-server-url languagetool-server-port)) + nil + nil + languagetool-server-max-timeout) + (when (/= (symbol-value 'url-http-response-status) 200) + (error "Not successful response")) + (setq languagetool-server-open-communication-p t) + (message "LanguageTool Server communication is up...") + (languagetool-server-check))) + (error + (languagetool-server-mode -1) + (error "LanguageTool Server cannot communicate with server"))))) (defun languagetool-server-parse-request () - "Return a json-like object with LanguageTool Server request arguments parsed. + "Return a assoc-list with LanguageTool Server request arguments parsed. Return the arguments as an assoc list of string which will be used in the POST request made to the LanguageTool server." - (let ((arguments (json-new-object))) + (let (arguments) ;; Appends the correction language information - (setq arguments (json-add-to-object arguments - "language" - languagetool-correction-language)) + (push (list "language" languagetool-correction-language) arguments) ;; Appends the mother tongue information (when (stringp languagetool-mother-tongue) - (setq arguments (json-add-to-object arguments - "motherTongue" - languagetool-mother-tongue))) + (push (list "motherTongue" languagetool-mother-tongue) arguments)) ;; Add LanguageTool Preamium features (when (stringp languagetool-api-key) - (setq arguments (json-add-to-object arguments - "apiKey" - languagetool-api-key))) + (push (list "apiKey" languagetool-api-key) arguments)) (when (stringp languagetool-username) - (setq arguments (json-add-to-object arguments - "username" - languagetool-username))) + (push (list "username" languagetool-username) arguments)) ;; Appends the disabled rules - (let ((rules "")) + (let ((rules)) ;; Global disabled rules - (dolist (rule languagetool-disabled-rules) - (if (string= rules "") - (setq rules (concat rules rule)) - (setq rules (concat rules "," rule)))) - ;; Local disabled rules - (dolist (rule languagetool-local-disabled-rules) - (if (string= rules "") - (setq rules (concat rules rule)) - (setq rules (concat rules "," rule)))) + (setq rules (string-join (append languagetool-disabled-rules languagetool-local-disabled-rules) ",")) (unless (string= rules "") - (setq arguments (json-add-to-object arguments "disabledRules" rules)))) + (push (list "disabledRules" rules) arguments))) ;; Add the buffer contents - (setq arguments (json-add-to-object arguments - "text" - (buffer-substring-no-properties - (point-min) - (point-max)))) - arguments)) + (push (list "text" (buffer-substring-no-properties (point-min) (point-max))) arguments))) (defun languagetool-server-check () "Show LanguageTool Server suggestions in the buffer. @@ -319,38 +292,38 @@ This function checks for the actual showed region of the buffer for suggestions." (when (and languagetool-server-mode (not languagetool-server-correction-p)) - (request - (format "%s:%d/v2/check" languagetool-server-url languagetool-server-port) - :type "POST" - :data (languagetool-server-parse-request) - :parser 'json-read - :success (cl-function - (lambda (&key response &allow-other-keys) - (languagetool-server-highlight-matches - (request-response-data response)))) - :error (cl-function - (lambda (&key error-thrown &allow-other-keys) - (languagetool-server-mode -1) - (error - "[Fatal Error] LanguageTool closed and got error: %S" - error-thrown)))))) - -(defun languagetool-server-highlight-matches (json-parsed) - "Highlight LanguageTool Server issues in the buffer. - -JSON-PARSED is a json object with the suggestions thrown by the -LanguageTool Server." - (languagetool-core-clear-buffer) - (when languagetool-server-mode - (let ((corrections (cdr (assoc 'matches json-parsed))) - (correction nil)) - (dotimes (index (length corrections)) - (setq correction (aref corrections index)) - (let ((offset (cdr (assoc 'offset correction))) - (size (cdr (assoc 'length correction)))) - (languagetool-issue-create-overlay - (+ (point-min) offset) (+ (point-min) offset size) - correction)))))) + (let ((url-request-method "POST") + (url-request-data (url-build-query-string (languagetool-server-parse-request)))) + (url-retrieve + (url-encode-url(format "%s:%d/v2/check" languagetool-server-url languagetool-server-port)) + #'languagetool-server-highlight-matches + (list (current-buffer)) + t)))) + +(defun languagetool-server-highlight-matches (_status checking-buffer) + "Highlight LanguageTool Server issues in CHECKING-BUFFER. + +STATUS is a plist thrown by Emacs url. Throws an error if the response is null." + (when (/= (symbol-value 'url-http-response-status) 200) + (error "LanguageTool Server closed")) + (set-buffer-multibyte t) + (goto-char (point-max)) + (backward-sexp) + (let ((json-parsed (json-read))) + (with-current-buffer checking-buffer + (save-excursion + (languagetool-core-clear-buffer) + (when languagetool-server-mode + (let ((corrections (alist-get 'matches json-parsed))) + (dotimes (index (length corrections)) + (let* ((correction (aref corrections index)) + (offset (alist-get 'offset correction)) + (size (alist-get 'length correction)) + (start (+ (point-min) offset)) + (end (+ (point-min) offset size)) + (word (buffer-substring-no-properties start end))) + (unless (languagetool-core-correct-p word) + (languagetool-issue-create-overlay start end correction)))))))))) (provide 'languagetool-server) diff --git a/languagetool.el b/languagetool.el index 0465f30..a9e6b6c 100644 --- a/languagetool.el +++ b/languagetool.el @@ -5,8 +5,8 @@ ;; Author: Joar Buitrago ;; Keywords: grammar text docs tools convenience checker ;; URL: https://github.com/PillFall/Emacs-LanguageTool.el -;; Version: 1.1.0 -;; Package-Requires: ((emacs "27.0") (request "0.3.2")) +;; Version: 1.2.0 +;; Package-Requires: ((emacs "27.0")) ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by diff --git a/makefile b/makefile index 4de25a3..08799c7 100644 --- a/makefile +++ b/makefile @@ -7,7 +7,7 @@ EMACSBIN ?= emacs BATCH = $(EMACSBIN) -Q --batch $(LOAD_PATH) PKG = languagetool -RQD_PKG = request +RQD_PKG = all: lisp @@ -49,18 +49,6 @@ clean: ## CI integration #################################################### -ci: require lisp +ci: lisp require: $(RQD_PKG) - -request: - @printf "Installing $@\n" - @$(BATCH) \ - --eval "(progn \ - (require 'package) \ - (add-to-list \ - 'package-archives \ - '(\"melpa\" . \"http://melpa.org/packages/\") t) \ - (package-initialize) \ - (package-refresh-contents) \ - (package-install 'request))"