branch: elpa/geiser-kawa commit eb834833972494af2ce50590273c891275495008 Author: spellcard199 <spellcard...@protonmail.com> Commit: spellcard199 <spellcard...@protonmail.com>
Add+Refactor: add support for generic kawa-devutil completion + refactor --- elisp/geiser-kawa-complete-java.el | 209 --------------- elisp/geiser-kawa-devutil-complete.el | 215 ++++++++++++++++ ...exprtree.el => geiser-kawa-devutil-exprtree.el} | 24 +- elisp/geiser-kawa-eval-util.el | 28 --- elisp/geiser-kawa-util.el | 54 ++++ elisp/geiser-kawa.el | 4 +- pom.xml | 10 +- src/main/java/kawageiser/Geiser.java | 17 +- .../java/kawageiser/java/GeiserCompleteJava.java | 153 ----------- src/main/java/kawageiser/kawadevutil/Complete.java | 280 +++++++++++++++++++++ .../{exprtree => kawadevutil}/ExprTree.java | 10 +- 11 files changed, 587 insertions(+), 417 deletions(-) diff --git a/elisp/geiser-kawa-complete-java.el b/elisp/geiser-kawa-complete-java.el deleted file mode 100644 index aeccf53..0000000 --- a/elisp/geiser-kawa-complete-java.el +++ /dev/null @@ -1,209 +0,0 @@ -;; Copyright (C) 2020 spellcard199 <spellcard...@protonmail.com> - -;; This program is free software; you can redistribute it and/or -;; modify it under the terms of the Modified BSD License. You should -;; have received a copy of the license along with this program. If -;; not, see <http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5>. - -(require 'subr-x) -(require 'geiser-kawa-exprtree) - -;; fmp stands for: -;; 1. Field -;; 2. Method -;; 3. Package - -(defun geiser-kawa--repl--point-after-prompt () - (save-excursion - (and (string-prefix-p - (geiser-repl-buffer-name 'kawa) - (buffer-name)) - (re-search-backward geiser-kawa--prompt-regexp nil t) - (re-search-forward geiser-kawa--prompt-regexp nil t)))) - -(defun geiser-kawa--point-at-toplevel-p () - (equal (point) - (save-excursion - (geiser-syntax--pop-to-top) - (point)))) - -(defun geiser-kawa-complete-fmp--get-data (code-str cursor-index) - "`code' is a string containing the code. It must be syntatically - scheme, including balanced parentheses. -`cursor' is an integer representing where the cursor is in that code." - (let* ((geiser-question - ;; this formatting hell is caused by the fact geiser:eval - ;; takes a string instead of a form. - (format "(geiser:eval (interaction-environment) %S)" - (format "%S" - `(geiser:complete-java - ,code-str - ,cursor-index - (gnu.expr.Language:getDefaultLanguage) - (interaction-environment))))) - (geiser-answer (geiser-eval--send/wait - geiser-question))) - - (if (assoc 'error geiser-answer) - (signal 'peculiar-error - (list (string-trim - (car (split-string (geiser-eval--retort-output - geiser-answer) - "\t"))))) - (geiser-eval--retort-result geiser-answer)))) - -(defun geiser-kawa-complete-fmp--user-choice--field-or-method - (fm-compl-data) - ;; fm stands for field or method. - (let ((compl-for-class - (cadr (assoc "compl-for-class" fm-compl-data))) - (modifiers - (cadr (assoc "modifiers" fm-compl-data))) - (field-or-method - (cadr (assoc "field-or-method-or-package" fm-compl-data))) - (names - (cadr (assoc "names" fm-compl-data))) - (before-cursor - (cadr (assoc "before-cursor" fm-compl-data))) - ;; unused - (after-cursor - (cadr (assoc "after-cursor" fm-compl-data)))) - - (completing-read - (concat "(" (string-join modifiers " ") " " field-or-method ") " - compl-for-class "." - ;; "- Exp : " compl-for-expr "\n" - ;; ": " - ) - names - nil - nil - before-cursor))) - -(defun geiser-kawa-complete-fmp--user-choice--package - (package-compl-data) - (let ((field-or-method-or-package - (cadr (assoc "field-or-method-or-package" package-compl-data))) - (package-name - (cadr (assoc "package-name" package-compl-data))) - (names - (cadr (assoc "names" package-compl-data))) - (before-cursor - (cadr (assoc "before-cursor" package-compl-data))) - ;; unused - (after-cursor - (cadr (assoc "after-cursor" package-compl-data)))) - (completing-read - (concat "(" field-or-method-or-package ") " - (if (string-equal "" package-name) - "(root.)" - (concat package-name "."))) - (mapcar (lambda (name) - (string-remove-prefix - "." (string-remove-prefix package-name name))) - names) - nil - nil - (string-remove-prefix - "." (string-remove-prefix package-name before-cursor)) - ))) - -(defun geiser-kawa-complete-fmp--user-choice-dispatch - (compl-data) - (let ((compl-for (cadr (assoc "field-or-method-or-package" - compl-data)))) - (cond ((equal compl-for "FIELD") - (geiser-kawa-complete-fmp--user-choice--field-or-method - compl-data)) - ((equal compl-for "METHOD") - (geiser-kawa-complete-fmp--user-choice--field-or-method - compl-data)) - ((equal compl-for "PACKAGE") - (geiser-kawa-complete-fmp--user-choice--package - compl-data)) - ((equal compl-for nil) - (message "No completions found.") - "") - (t (error (format "[Unexpected condition] compl-for: %s" - (prin1-to-string compl-for))))))) - -(defun geiser-kawa-complete-fmp--code-point-from-toplevel () - (let* (reg-beg - reg-end - code-str - cursor-index) - (if (geiser-kawa--point-at-toplevel-p) - (progn - (setq reg-beg (line-beginning-position)) - (setq reg-end (line-end-position)) - (setq cursor-index (current-column))) - (progn - (save-excursion - (setq reg-beg (progn (geiser-syntax--pop-to-top) - (point))) - (setq reg-end (condition-case data - (progn (forward-sexp) - (point)) - (scan-error data)))) - (when (and (listp reg-end) - (equal (car reg-end) 'scan-error)) - ;; For now, it's easier not to fix unbalanced parenses - (signal (car reg-end) (cdr reg-end))) - (setq cursor-index (- (point) reg-beg)))) - (setq code-str (buffer-substring-no-properties - reg-beg reg-end)) - (list - `("reg-beg" . ,reg-beg) - `("reg-end" . ,reg-end) - `("code-str" . ,code-str) - `("cursor-index" . ,cursor-index)))) - -(defun geiser-kawa-complete-fmp-at-point () - (interactive) - "Complete java field or method or package (fmp) at point" - - (let* ((code-and-point-data - (geiser-kawa-complete-fmp--code-point-from-toplevel)) - (code-str (cdr (assoc "code-str" - code-and-point-data))) - (cursor-index (cdr (assoc "cursor-index" - code-and-point-data))) - (compl-data (geiser-kawa-complete-fmp--get-data - code-str cursor-index)) - (user-choice (geiser-kawa-complete-fmp--user-choice-dispatch - compl-data))) - (when (thing-at-point 'word) - (if (looking-back ":" (- (point) 2)) - (kill-word 1) - (kill-word -1))) - (insert user-choice) - ;; (when (not (equal (word-at-point) user-choice)) - ;; (kill-word 1) - )) - - -;;;; Functions to get the Expression tree that is made to try and get -;;;; java completions. Useful when debugging why java completion fails. - -(defun geiser-kawa-complete-fmp--exprtree (code-str cursor-index) - (geiser-kawa-eval--to-res - `(geiser:complete-java-show-expr-tree - ,code-str - ,cursor-index))) - -(defun geiser-kawa-complete-fmp-at-point-exprtree () - (interactive) - (let* ((code-and-point-data - (geiser-kawa-complete-fmp--code-point-from-toplevel)) - (code-str (cdr (assoc "code-str" - code-and-point-data))) - (cursor-index (cdr (assoc "cursor-index" - code-and-point-data))) - (expr-tree (geiser-kawa-complete-fmp--exprtree - code-str cursor-index))) - (geiser-kawa-exprtree--view expr-tree))) - - -(provide 'geiser-kawa-complete-java) - -;;; geiser-kawa-complete-fmp.el ends here diff --git a/elisp/geiser-kawa-devutil-complete.el b/elisp/geiser-kawa-devutil-complete.el new file mode 100644 index 0000000..5844419 --- /dev/null +++ b/elisp/geiser-kawa-devutil-complete.el @@ -0,0 +1,215 @@ +;; Copyright (C) 2020 spellcard199 <spellcard...@protonmail.com> + +;; This program is free software; you can redistribute it and/or +;; modify it under the terms of the Modified BSD License. You should +;; have received a copy of the license along with this program. If +;; not, see <http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5>. + +(require 'subr-x) +(require 'geiser-kawa-devutil-exprtree) +(require 'geiser-kawa-util) + +(defvar geiser-kawa-devutil-complete-add-missing-parentheses + nil + "If true, when completing with kawa-devutil we don't check +for missing parentheses and just let kawa-devutil append them +at the end.") + +(defun geiser-kawa-devutil-complete--get-data (code-str cursor-index) + "`code' is a string containing the code. It must be syntatically + scheme, including balanced parentheses. +`cursor' is an integer representing where the cursor is in that code." + (let* ((geiser-question + ;; this formatting hell is caused by the fact geiser:eval + ;; takes a string instead of a form. + (format "(geiser:eval (interaction-environment) %S)" + (format "%S" + `(geiser:complete-java + ,code-str + ,cursor-index)))) + (geiser-answer (geiser-eval--send/wait + geiser-question))) + + (if (assoc 'error geiser-answer) + (signal 'peculiar-error + (list (string-trim + (car (split-string (geiser-eval--retort-output + geiser-answer) + "\t"))))) + + (geiser-kawa-util--retort-result geiser-answer)))) + +(defun geiser-kawa-devutil-complete--user-choice-classmembers + (classmember-data) + + (let* ((completion-type + (cadr (assoc "completion-type" classmember-data))) + (before-cursor + (cadr (assoc "before-cursor" classmember-data))) + (after-cursor ;; unused + (cadr (assoc "after-cursor" classmember-data))) + (owner-class + (cadr (assoc "owner-class" classmember-data))) + (modifiers + (cadr (assoc "modifiers" classmember-data))) + (names + (cadr (assoc "names" classmember-data))) + + (prompt + (concat "(" + (string-join modifiers " ") " " completion-type + ") " + owner-class "."))) + + (completing-read prompt names + nil nil + before-cursor))) + +(defun geiser-kawa-devutil-complete--user-choice-symbols-plus-packagemembers + (syms-plus-pkgmembers-data) + (let* ((completion-type + (cadr (assoc "completion-type" syms-plus-pkgmembers-data))) + (before-cursor + (cadr (assoc "before-cursor" syms-plus-pkgmembers-data))) + (symbol-names + (cadr (assoc "symbol-names" syms-plus-pkgmembers-data))) + (pkgmembers-data + (cadr (assoc "package-members" syms-plus-pkgmembers-data))) + (owner-package + (cadr (assoc "owner-package" pkgmembers-data))) + (child-package-names + (cadr (assoc "child-package-names" pkgmembers-data))) + (child-class-names + (cadr (assoc "child-class-names" pkgmembers-data))) + + (prompt (concat "(" completion-type + " (" owner-package ".) " + "(" before-cursor ")" + ") ")) + (candidates + (append symbol-names + (mapcar (lambda (n) (concat n ".")) + child-package-names) + child-class-names)) + (initial-input + (string-remove-prefix + (if (and owner-package + (not (string-equal owner-package ""))) + (concat owner-package ".") + "") + before-cursor)) + (choice + (completing-read prompt candidates + nil nil initial-input))) + choice)) + +(defun geiser-kawa-devutil-complete--user-choice-dispatch + (compl-data) + (let ((completion-type + (cadr (assoc "completion-type" compl-data)))) + (cond ((or (equal completion-type "METHODS") + (equal completion-type "FIELDS")) + (geiser-kawa-devutil-complete--user-choice-classmembers compl-data)) + ((equal completion-type "SYMBOLS_PLUS_PACKAGEMEMBERS") + (geiser-kawa-devutil-complete--user-choice-symbols-plus-packagemembers + compl-data)) + ((equal completion-type nil) + (message "No completions found.") + "") + (t (error (format "[Unexpected `completion-type' value] completion-type: %s" + (prin1-to-string completion-type)))) + ))) + +(defun geiser-kawa-devutil-complete--code-point-from-toplevel () + (let* (reg-beg + reg-end + code-str + cursor-index) + (if (geiser-kawa-util--point-is-at-toplevel-p) + (let ;; At toplevel + ((repl-point-after-prompt + (geiser-kawa-util--repl-point-after-prompt))) + (if repl-point-after-prompt + (progn ;; Inside the REPL + (setq reg-beg repl-point-after-prompt) + (setq reg-end (point-max)) + (setq cursor-index (- (point) + repl-point-after-prompt))) + (progn ;; Not inside the REPL + (setq reg-beg (line-beginning-position)) + (setq reg-end (line-end-position)) + (setq cursor-index (current-column))))) + (progn ;; Not at toplevel + (save-excursion + (setq reg-beg (progn (geiser-syntax--pop-to-top) + (point))) + (setq reg-end (condition-case data + (progn (forward-sexp) + (point)) + (scan-error data)))) + (when (and (listp reg-end) + (equal (car reg-end) 'scan-error)) + (if geiser-kawa-devutil-complete-add-missing-parentheses + ;; kawa-devutil appends missing parentheses at the end, + ;; so in many cases this would work, but I'm not sure + ;; it's a good thing not to let the developer know + ;; about it. + (setq reg-end (point)) + (signal (car reg-end) (cdr reg-end)))) + (setq cursor-index (- (point) reg-beg)))) + (setq code-str (buffer-substring-no-properties + reg-beg reg-end)) + (setq moo code-str) + (list + `("reg-beg" . ,reg-beg) + `("reg-end" . ,reg-end) + `("code-str" . ,code-str) + `("cursor-index" . ,cursor-index)))) + +(defun geiser-kawa-devutil-complete-at-point () + (interactive) + "Complete at point using kawa-devutil's completion." + + (let* ((code-and-point-data + (geiser-kawa-devutil-complete--code-point-from-toplevel)) + (code-str (cdr (assoc "code-str" + code-and-point-data))) + (cursor-index (cdr (assoc "cursor-index" + code-and-point-data))) + (compl-data (geiser-kawa-devutil-complete--get-data + code-str cursor-index)) + (user-choice (geiser-kawa-devutil-complete--user-choice-dispatch + compl-data))) + (when (thing-at-point 'word) + (if (looking-back ":" (- (point) 2)) + (kill-word 1) + (kill-word -1))) + (insert user-choice) + ;; (when (not (equal (word-at-point) user-choice)) + ;; (kill-word 1) + )) + +;;;; Functions to get the Expression tree that is made to try and get +;;;; java completions. Useful when debugging why java completion fails. + +(defun geiser-kawa-devutil-complete--exprtree (code-str cursor-index) + (geiser-kawa-util--eval-to-res + `(geiser:complete-java-show-expr-tree + ,code-str + ,cursor-index))) + +(defun geiser-kawa-devutil-complete-expree-at-point () + (interactive) + (let* ((code-and-point-data + (geiser-kawa-devutil-complete--code-point-from-toplevel)) + (code-str (cdr (assoc "code-str" + code-and-point-data))) + (cursor-index (cdr (assoc "cursor-index" + code-and-point-data))) + (expr-tree (geiser-kawa-devutil-complete--exprtree + code-str cursor-index))) + (geiser-kawa-devutil-exprtree--view expr-tree))) + +(provide 'geiser-kawa-devutil-complete) + +;;; geiser-kawa-devutil-complete.el ends here diff --git a/elisp/geiser-kawa-exprtree.el b/elisp/geiser-kawa-devutil-exprtree.el similarity index 64% rename from elisp/geiser-kawa-exprtree.el rename to elisp/geiser-kawa-devutil-exprtree.el index 24a735a..fed5671 100644 --- a/elisp/geiser-kawa-exprtree.el +++ b/elisp/geiser-kawa-devutil-exprtree.el @@ -5,27 +5,27 @@ ;; have received a copy of the license along with this program. If ;; not, see <http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5>. -(require 'geiser-kawa-eval-util) +(require 'geiser-kawa-util) -(defvar geiser-kawa-exprtree-buffer "*kawa exprtree*" +(defvar geiser-kawa-devutil-exprtree-buffer "*kawa exprtree*" "Buffer where Expression tree is showed") -(defun geiser-kawa-exprtree--view (expr-tree) +(defun geiser-kawa-devutil-exprtree--view (expr-tree) (with-current-buffer (get-buffer-create - geiser-kawa-exprtree-buffer) + geiser-kawa-devutil-exprtree-buffer) (View-quit) (delete-region (point-min) (point-max)) (insert expr-tree) (goto-char (point-min))) (view-buffer-other-window - geiser-kawa-exprtree-buffer)) + geiser-kawa-devutil-exprtree-buffer)) -(defun geiser-kawa-exprtree--for-expression (code-str) - (geiser-kawa-eval--to-res +(defun geiser-kawa-devutil-exprtree--for-expression (code-str) + (geiser-kawa-util--eval-to-res `(geiser:expr-tree-formatted ,code-str))) -(defun geiser-kawa-exprtree-sexp () +(defun geiser-kawa-devutil-exprtree-sexp () (interactive) "If region is active send region, otherwise send last expression." (let* ((code-str @@ -35,10 +35,10 @@ (let ((sexp-beg (progn (backward-sexp) (point))) (sexp-end (progn (forward-sexp) (point)))) (buffer-substring-no-properties sexp-beg sexp-end))))) - (expr-tree (geiser-kawa-exprtree--for-expression + (expr-tree (geiser-kawa-devutil-exprtree--for-expression code-str))) - (geiser-kawa-exprtree--view expr-tree))) + (geiser-kawa-devutil-exprtree--view expr-tree))) -(provide 'geiser-kawa-exprtree) +(provide 'geiser-kawa-devutil-exprtree) -;;; geiser-kawa-exprtree.el ends here +;;; geiser-kawa-devutil-exprtree.el ends here diff --git a/elisp/geiser-kawa-eval-util.el b/elisp/geiser-kawa-eval-util.el deleted file mode 100644 index 6f235f4..0000000 --- a/elisp/geiser-kawa-eval-util.el +++ /dev/null @@ -1,28 +0,0 @@ -;; Copyright (C) 2020 spellcard199 <spellcard...@protonmail.com> - -;; This program is free software; you can redistribute it and/or -;; modify it under the terms of the Modified BSD License. You should -;; have received a copy of the license along with this program. If -;; not, see <http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5>. - -(require 'geiser-eval) - -;; Simple wrappers for geiser functions. - -(defun geiser-kawa-eval--to-res (sexp) - (let* ((question - (format "(geiser:eval (interaction-environment) %S)" - (format "%S" sexp))) - (answer (geiser-eval--send/wait question))) - - (if (assoc 'error answer) - (signal 'peculiar-error - (list (string-trim - (car (split-string (geiser-eval--retort-output - answer) - "\t"))))) - ;; from: ((result "expr-tree") (output . ...)) - ;; to: "expr-tree" - (cadr (car answer))))) - -(provide 'geiser-kawa-eval-util) diff --git a/elisp/geiser-kawa-util.el b/elisp/geiser-kawa-util.el new file mode 100644 index 0000000..50b9d8b --- /dev/null +++ b/elisp/geiser-kawa-util.el @@ -0,0 +1,54 @@ +;; Copyright (C) 2020 spellcard199 <spellcard...@protonmail.com> + +;; This program is free software; you can redistribute it and/or +;; modify it under the terms of the Modified BSD License. You should +;; have received a copy of the license along with this program. If +;; not, see <http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5>. + +(require 'geiser-syntax) +(require 'geiser-eval) + +;; Utility functions used by other parts of `geiser-kawa'. + +(defun geiser-kawa-util--eval-to-res (sexp) + (let* ((question + (format "(geiser:eval (interaction-environment) %S)" + (format "%S" sexp))) + (answer (geiser-eval--send/wait question))) + + (if (assoc 'error answer) + (signal 'peculiar-error + (list (string-trim + (car (split-string (geiser-eval--retort-output + answer) + "\t"))))) + ;; from: ((result "expr-tree") (output . ...)) + ;; to: "expr-tree" + (cadr (car answer))))) + +(defun geiser-kawa-util--retort-result (ret) + ;; This skips the reading `geiser-eval--retort-result' + ;; does, but doesn't have the variable binding depth + ;; limit that `geiser-eval--retort-result' has. + ;; We use this when we need to read strings longer + ;; than what `geiser-eval--retort-result' allows. + ;; Drawback is that `ret' must be valid elisp. + (car (read-from-string (cadr (assoc 'result ret))))) + +(defun geiser-kawa-util--repl-point-after-prompt () + (save-excursion + (and (string-prefix-p + (geiser-repl-buffer-name 'kawa) + (buffer-name)) + (re-search-backward geiser-kawa--prompt-regexp nil t) + (re-search-forward geiser-kawa--prompt-regexp nil t)))) + +(defun geiser-kawa-util--point-is-at-toplevel-p () + (equal (point) + (save-excursion + (geiser-syntax--pop-to-top) + (point)))) + +(provide 'geiser-kawa-util) + +;;; geiser-kawa-util.el ends here diff --git a/elisp/geiser-kawa.el b/elisp/geiser-kawa.el index 2f0d9ef..19a15ef 100644 --- a/elisp/geiser-kawa.el +++ b/elisp/geiser-kawa.el @@ -36,8 +36,8 @@ (require 'info-look) (require 'cl) -(require 'geiser-kawa-complete-java) -(require 'geiser-kawa-exprtree) +(require 'geiser-kawa-devutil-complete) +(require 'geiser-kawa-devutil-exprtree) ;;; Code: diff --git a/pom.xml b/pom.xml index e524782..021d350 100644 --- a/pom.xml +++ b/pom.xml @@ -55,6 +55,14 @@ <repository> <id>jitpack.io</id> <url>https://jitpack.io</url> + <releases> + <enabled>true</enabled> + <updatePolicy>always</updatePolicy> + </releases> + <snapshots> + <enabled>true</enabled> + <updatePolicy>always</updatePolicy> + </snapshots> </repository> </repositories> @@ -63,7 +71,7 @@ <dependency> <groupId>com.gitlab.spellcard199</groupId> <artifactId>kawa-devutil</artifactId> - <version>8e0eefcee1e7cd12d6929cbecd2584f8fc5bca2e</version> + <version>4d17babf5483a7e292caf1edd3a36d5a952366df</version> </dependency> <!-- https://mvnrepository.com/artifact/org.testng/testng --> diff --git a/src/main/java/kawageiser/Geiser.java b/src/main/java/kawageiser/Geiser.java index 1909257..4e67548 100644 --- a/src/main/java/kawageiser/Geiser.java +++ b/src/main/java/kawageiser/Geiser.java @@ -6,7 +6,7 @@ package kawageiser; import gnu.expr.Language; -import kawadevutil.complete.java.data.CompletionDataForJavaPackage; +import kawadevutil.complete.find.packagemembers.CompletionFindPackageMemberUtil; import java.util.HashMap; import java.util.Map; @@ -38,18 +38,19 @@ public class Geiser implements Runnable { procMap.put("geiser:load-file", "kawageiser.GeiserLoadFile:loadFile"); procMap.put("geiser:completions", "kawageiser.GeiserCompleteSymbol:getCompletions"); procMap.put("geiser:no-values", "kawageiser.GeiserNoValues:noValues"); - procMap.put("geiser:complete-java", "kawageiser.java.GeiserCompleteJava:completeJava"); - procMap.put("geiser:complete-java-show-expr-tree", "kawageiser.java.GeiserCompleteJava:getExprTreeFormatted"); + procMap.put("geiser:complete-java", "kawageiser.kawadevutilcompletion.Complete:completeJava"); + procMap.put("geiser:complete-java-show-expr-tree", "kawageiser.kawadevutilcompletion.Complete:getExprTreeFormatted"); procMap.put("geiser:manual-epub-unzip-to-tmp-dir", "kawageiser.docutil.ManualEpubUnzipToTmpDir:unzipToTmpDir"); procMap.put("geiser:macroexpand", "kawageiser.GeiserMacroexpand:expand"); - procMap.put("geiser:expr-tree-formatted", "kawageiser.exprtree.ExprTree:getExprTreeFormatted"); + procMap.put("geiser:expr-tree-formatted", "kawageiser.kawadevutil.ExprTree:getExprTreeFormatted"); try { if (lang.lookup("geiser:eval") == null) { // Tell kawadevutil to build package cache, which takes a couple of seconds, // in a separate thread, so user doesn't have to wait later. - new Thread( - () -> CompletionDataForJavaPackage.getChildrenNamesOfRoot(true) + new Thread(() -> + CompletionFindPackageMemberUtil + .getChildrenNamesOfRoot(true) ).start(); // The reason for this if block is that if someone re-imported this module @@ -69,7 +70,9 @@ public class Geiser implements Runnable { } } - public void kawaDefineFunction(Language lang, String procName, String methodPathAsKawaCode) throws Throwable { + public void + kawaDefineFunction(Language lang, String procName, String methodPathAsKawaCode) + throws Throwable { // Using lang.eval is a workaround to the fact I don't know // how to create a working PrimProcedure using Kawa's java api. Object proc = lang.eval(methodPathAsKawaCode); diff --git a/src/main/java/kawageiser/java/GeiserCompleteJava.java b/src/main/java/kawageiser/java/GeiserCompleteJava.java deleted file mode 100644 index d2664ce..0000000 --- a/src/main/java/kawageiser/java/GeiserCompleteJava.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright (C) 2020 spellcard199 <spellcard...@protonmail.com> - * This is free software; for terms and warranty disclaimer see ./COPYING. - */ - -package kawageiser.java; - -import gnu.expr.Language; -import gnu.kawa.functions.Format; -import gnu.lists.IString; -import gnu.lists.LList; -import gnu.mapping.Environment; -import gnu.math.IntNum; -import kawadevutil.ast.AstElemWrapper; -import kawadevutil.complete.java.data.*; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; - -public class GeiserCompleteJava { - - public static String - completeJava(IString codeStr, IntNum cursorIndex) - throws Throwable { - return completeJava( - codeStr, - cursorIndex, - Language.getDefaultLanguage(), - Environment.user()); - } - - public static String - completeJava(IString codeStr, IntNum cursorIndex, Language lang, - Environment env) - throws Throwable { - - // Get Data - Optional<CompletionDataForJava> complDataMaybe = - kawadevutil.complete.java.CompleteJavaFMP.complete( - codeStr.toString(), - Integer.valueOf(cursorIndex.toString()), - lang, - env); - - return complDataMaybe - .map(GeiserCompleteJava::complDataForJavaToLList) - .map(x -> Format.format("~S", x).toString()) - .orElse(Format.format("~A", LList.Empty).toString()); - } - - public static LList - complDataForJavaToLList(CompletionDataForJava complData) { - // Wrap data of interest in Scheme's LList - LList complDataAsLList = null; - if (complData.getClass().equals(CompletionDataForJavaField.class) - || complData.getClass().equals(CompletionDataForJavaMethod.class)) { - complDataAsLList = toLList((CompletionDataForJavaFOM) complData); - } else if (complData.getClass().equals(CompletionDataForJavaPackage.class)) { - complDataAsLList = toLList((CompletionDataForJavaPackage) complData); - } else { - throw new Error("[BUG SPOTTED] `complData's class is one not expected: " - + complData.getClass().toString()); - } - return complDataAsLList; - } - - private static LList - toLList(CompletionDataForJavaFOM complData) { - String completionsForClass = complData.getForClass().getName(); - // I don't know why it says "unchecked call" when using complData.getRequiredModifiers().stream() - ArrayList<String> modifiers = new ArrayList<>(); - for (Object modifier : complData.getModifierMask().getRequired()) { - modifiers.add(modifier.toString()); - } - - ArrayList<LList> res = new ArrayList<>(getCommonData(complData)); - res.addAll(Arrays.asList( - LList.list2("compl-for-class", completionsForClass), - LList.list2("modifiers", LList.makeList(modifiers)) - )); - return LList.makeList(res); - - } - - private static LList - toLList(CompletionDataForJavaPackage complData) { - ArrayList<LList> res = new ArrayList<>(getCommonData(complData)); - res.addAll(Arrays.asList( - LList.list2("package-name", complData.getPinfo().getName()) - )); - return LList.makeList(res); - } - - private static List<LList> - getCommonData(CompletionDataForJava complData) { - CompletionDataForJava.FieldOrMethodOrPackage fieldOrMethod = complData.getFieldOrMethodOrPackage(); - List<String> names = (List<String>) complData.getNames().stream().distinct().collect(Collectors.toList()); - String beforeCursor = complData.getCursorMatcher().getCursorMatch().getBeforeCursor(); - String afterCursor = complData.getCursorMatcher().getCursorMatch().getAfterCursor(); - - java.util.List<LList> res = Arrays.asList( - LList.list2("field-or-method-or-package", fieldOrMethod.toString()), - LList.list2("names", LList.makeList(names)), - LList.list2("before-cursor", beforeCursor), - LList.list2("after-cursor", afterCursor) - ); - return res; - } - - public static Optional<AstElemWrapper> - getExprTreeMaybe(IString codeStr, IntNum cursorIndex, Language lang, - Environment env) - throws IOException { - Optional<CompletionDataForJava> complDataMaybe = - kawadevutil.complete.java.CompleteJavaFMP.complete( - codeStr.toString(), - Integer.valueOf(cursorIndex.toString()), - lang, - env - ); - return complDataMaybe.map(complData -> - complData.getCursorMatcher().getRootWrapper()); - } - - public static Optional<AstElemWrapper> - getExprTreeMaybe(IString codeStr, IntNum cursorIndex) - throws IOException { - return getExprTreeMaybe( - codeStr, cursorIndex, - Language.getDefaultLanguage(), Environment.user()); - } - - public static String getExprTreeFormatted(IString codeStr, IntNum cursorIndex, - Language lang, Environment env) - throws IOException { - return getExprTreeMaybe(codeStr, cursorIndex, lang, env) - .map(complData -> complData.formatElem(true)).get(); - } - - public static String getExprTreeFormatted(IString codeStr, IntNum cursorIndex) - throws IOException { - return getExprTreeFormatted( - codeStr, - cursorIndex, - Language.getDefaultLanguage(), - Environment.user() - ); - } -} diff --git a/src/main/java/kawageiser/kawadevutil/Complete.java b/src/main/java/kawageiser/kawadevutil/Complete.java new file mode 100644 index 0000000..f1ca57e --- /dev/null +++ b/src/main/java/kawageiser/kawadevutil/Complete.java @@ -0,0 +1,280 @@ +/* + * Copyright (C) 2020 spellcard199 <spellcard...@protonmail.com> + * This is free software; for terms and warranty disclaimer see ./COPYING. + */ + +package kawageiser.kawadevutil; + +import gnu.expr.CommandCompleter; +import gnu.expr.Language; +import gnu.kawa.functions.Format; +import gnu.lists.IString; +import gnu.lists.LList; +import gnu.mapping.Environment; +import gnu.mapping.Symbol; +import gnu.math.IntNum; +import kawadevutil.complete.find.CompletionFindGeneric; +import kawadevutil.complete.find.MakeCursorFinder; +import kawadevutil.complete.find.packagemembers.CompletionFindPackageMemberUtil; +import kawadevutil.complete.result.abstractdata.CompletionData; +import kawadevutil.complete.result.abstractdata.CompletionForClassMember; +import kawadevutil.complete.result.concretedata.CompletionForPackageMember; +import kawadevutil.complete.result.concretedata.CompletionForSymbol; +import kawadevutil.complete.result.concretedata.CompletionForSymbolAndPackageMember; +import kawadevutil.exprtree.CursorFinder; +import kawadevutil.exprtree.ExprWrap; +import kawadevutil.shaded.io.github.classgraph.PackageInfo; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +public class Complete { + + public static String + completeJava(IString codeStr, IntNum cursorIndex) + throws Throwable { + return completeJava( + codeStr, + cursorIndex, + Language.getDefaultLanguage(), + Environment.user()); + } + + public static String + completeJava(IString codeStr, IntNum cursorIndex, Language lang, + Environment env) + throws Throwable { + + // Get Data + Optional<CompletionData> complDataMaybe = CompletionFindGeneric.find( + codeStr.toString(), cursorIndex.intValue()); + + return complDataMaybe + .map(Complete::complDataToLList) + .map(x -> Format.format("~S", x).toString()) + .orElse(Format.format("~A", LList.Empty).toString()); + } + + public static LList + complDataToLList(CompletionData complData) { + // Wrap data of interest in Scheme's LList + LList complDataAsLList = null; + if (complData instanceof CompletionForClassMember) { + complDataAsLList = toLList((CompletionForClassMember) complData); + } else if (complData instanceof CompletionForSymbolAndPackageMember) { + complDataAsLList = toLList((CompletionForSymbolAndPackageMember) complData); + } else { + throw new Error("[BUG SPOTTED] `complData's class is one not expected: " + + complData.getClass().toString()); + } + return complDataAsLList; + } + + private static LList + toLList(CompletionForClassMember completionForClassMember) { + + String ownerClassName = completionForClassMember.getForClass().getName(); + + ArrayList<String> modifiers = new ArrayList<>(); + for (Object modifier : completionForClassMember.getModifierMask().getRequired()) { + modifiers.add(modifier.toString()); + } + + CompletionData.CompletionType completionType + = completionForClassMember.getCompletionType(); + + List<String> names + = completionForClassMember + .getNames() + .stream() + .distinct() + .collect(Collectors.toList()); + + String beforeCursor + = completionForClassMember + .getCursorFinder() + .getCursorMatch() + .getBeforeCursor(); + + String afterCursor + = completionForClassMember + .getCursorFinder() + .getCursorMatch() + .getAfterCursor(); + + LList res = LList.makeList( + Arrays.asList( + LList.list2("completion-type", completionType.toString()), + LList.list2("before-cursor", beforeCursor), + LList.list2("after-cursor", afterCursor), + LList.list2("owner-class", ownerClassName), + LList.list2("modifiers", LList.makeList(modifiers)), + LList.list2("names", LList.makeList(names)) + )); + + return res; + } + + private static LList + toLList(CompletionForSymbolAndPackageMember completionForSymbolAndPackageMember) { + + Optional<CompletionForPackageMember> completionForPackageMember + = completionForSymbolAndPackageMember.getCompletionForPackageMember(); + + LList completionForPackageMemberLList; + + if (completionForPackageMember.isPresent()) { + completionForPackageMemberLList + = completionForSymbolAndPackageMember + .getCompletionForPackageMember() + .map(Complete::toLList) + .orElse(LList.Empty); + } else { + completionForPackageMemberLList = toLList( + CompletionFindPackageMemberUtil.getRootCache(true) + ); + } + + CompletionData.CompletionType + completionType = completionForSymbolAndPackageMember.getCompletionType(); + + CommandCompleter commandCompleter + = completionForSymbolAndPackageMember.getCommandCompleter(); + ArrayList<String> symbolNames = new ArrayList<>(); + if (completionForPackageMember.isPresent() + && + !completionForPackageMember + .get().getPackageInfo().getName().equals("")) { + symbolNames.addAll(commandCompleter.candidates); + } else { + Environment.user().enumerateAllLocations().forEachRemaining( + loc -> { + Symbol sym = loc.getKeySymbol(); + // String symName = sym.getName(); + // TODO: with toString(), things like + // $construct$:PD and $construct$:sh + // are stringified correctly. + // Check if with using toString() instead of getNames(): + // 1. other things break + // 2. if yes, why + String symName = sym.toString(); + symbolNames.add(symName); + } + ); + } + + LList res = LList.makeList( + Arrays.asList( + LList.list2("completion-type", completionType.toString()), + // CommandCompleter doesn't know what's after the cursor + LList.list2("before-cursor", commandCompleter.word), + LList.list2("word-cursor", commandCompleter.wordCursor), + LList.list2( "symbol-names", LList.makeList(symbolNames)), + LList.list2("package-members", completionForPackageMemberLList) + ) + ); + + return res; + } + + public static LList + toLList(CompletionForSymbol completionForSymbol) { + CommandCompleter commandCompleter + = completionForSymbol.getCommandCompleter(); + return LList.list1( + LList.list2("names", LList.makeList(commandCompleter.candidates)) + ); + } + + public static LList + toLList(CompletionForPackageMember completionForPackageMember) { + PackageInfo pinfo = completionForPackageMember.getPackageInfo(); + return toLList(pinfo); + } + + public static LList + toLList(PackageInfo pinfo) { + + String ownerPackageName = pinfo.getName(); + + // strip ownerPackageName plus the the dot + int prefixLengthToStrip = ownerPackageName.length() > 0 + ? ownerPackageName.length() + 1 + : 0; + List<String> childPackageNames + = pinfo + .getChildren() + .getNames() + .stream() + .map(n -> n.substring(prefixLengthToStrip)) + .collect(Collectors.toList()); + + List<String> childClassNames + = pinfo + .getClassInfo() + .getNames() + .stream() + .map(n -> n.substring(prefixLengthToStrip)) + .collect(Collectors.toList()); + + LList res = LList.makeList( + Arrays.asList( + LList.list2("owner-package", pinfo.getName()), + LList.list2( + "child-package-names", + LList.makeList(childPackageNames)), + LList.list2( + "child-class-names", + LList.makeList(childClassNames)) + ) + ); + return res; + + } + + public static Optional<ExprWrap> + getExprTreeMaybe(IString codeStr, IntNum cursorIndex, Language lang, + Environment env) + throws IOException { + try { + CursorFinder cursorFinder = MakeCursorFinder.makeCursorFinder( + codeStr.toString(), cursorIndex.intValue(), + lang, env, + true); + return Optional.of(cursorFinder.getRootExprWrap()); + } catch (IOException e) { + return Optional.empty(); + } + } + + public static Optional<ExprWrap> + getExprTreeMaybe(IString codeStr, IntNum cursorIndex) + throws IOException { + return getExprTreeMaybe( + codeStr, cursorIndex, + Language.getDefaultLanguage(), Environment.user()); + } + + public static String + getExprTreeFormatted(IString codeStr, IntNum cursorIndex, + Language lang, Environment env) + throws IOException { + return getExprTreeMaybe(codeStr, cursorIndex, lang, env) + .map(complData -> complData.formatElem(true)).get(); + } + + public static String + getExprTreeFormatted(IString codeStr, IntNum cursorIndex) + throws IOException { + return getExprTreeFormatted( + codeStr, + cursorIndex, + Language.getDefaultLanguage(), + Environment.user() + ); + } +} diff --git a/src/main/java/kawageiser/exprtree/ExprTree.java b/src/main/java/kawageiser/kawadevutil/ExprTree.java similarity index 80% rename from src/main/java/kawageiser/exprtree/ExprTree.java rename to src/main/java/kawageiser/kawadevutil/ExprTree.java index dd3b42b..3c667af 100644 --- a/src/main/java/kawageiser/exprtree/ExprTree.java +++ b/src/main/java/kawageiser/kawadevutil/ExprTree.java @@ -3,23 +3,23 @@ * This is free software; for terms and warranty disclaimer see ./COPYING. */ -package kawageiser.exprtree; +package kawageiser.kawadevutil; import gnu.expr.Language; import gnu.mapping.Environment; -import kawadevutil.ast.AstElemWrapper; +import kawadevutil.exprtree.ExprWrap; import java.io.IOException; public class ExprTree { - public static AstElemWrapper + public static ExprWrap getExprTree(String codeStr, Language lang, Environment env) throws IOException { - return new kawadevutil.ast.AstElemWrapper(codeStr, lang, env); + return new ExprWrap(codeStr, lang, env); } - public static AstElemWrapper + public static ExprWrap getExprTree(String codeStr) throws IOException { return getExprTree(codeStr, Language.getDefaultLanguage(), Environment.user()); }