[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[nongnu] elpa/geiser-kawa 86ef157 020/119: Join projects: kawa-geiser is
From: |
Philip Kaludercic |
Subject: |
[nongnu] elpa/geiser-kawa 86ef157 020/119: Join projects: kawa-geiser is now part of geiser-kawa |
Date: |
Sun, 1 Aug 2021 18:30:31 -0400 (EDT) |
branch: elpa/geiser-kawa
commit 86ef157ea976bce407e758850a7291aa0b574841
Author: spellcard199 <spellcard199@protonmail.com>
Commit: spellcard199 <spellcard199@protonmail.com>
Join projects: kawa-geiser is now part of geiser-kawa
---
elisp/geiser-kawa.el | 2 +-
example-mvn-run-geiser.sh | 14 +
pom.xml | 21 +-
src/main/java/kawageiser/Geiser.java | 32 +++
src/main/java/kawageiser/GeiserAutodoc.java | 307 +++++++++++++++++++++
src/main/java/kawageiser/GeiserCompleteModule.java | 86 ++++++
src/main/java/kawageiser/GeiserCompleteSymbol.java | 70 +++++
src/main/java/kawageiser/GeiserEval.java | 109 ++++++++
src/main/java/kawageiser/GeiserLoadFile.java | 39 +++
src/main/java/kawageiser/GeiserNoValues.java | 24 ++
.../kawageiser/StartKawaWithGeiserSupport.java | 53 ++++
.../geiserDoc/ManualEpubUnzipToTmpDir.java | 42 +++
src/main/java/kawageiser/java/Complete.java | 99 +++++++
src/test/java/kawageiser/GeiserAutodocTest.java | 88 ++++++
14 files changed, 982 insertions(+), 4 deletions(-)
diff --git a/elisp/geiser-kawa.el b/elisp/geiser-kawa.el
index 5bf5435..be5492f 100644
--- a/elisp/geiser-kawa.el
+++ b/elisp/geiser-kawa.el
@@ -86,7 +86,7 @@
;; jar containing all the java dependencies.
(defcustom geiser-kawa-kawa-geiser-jar-path
(expand-file-name
- "./target/kawa-geiser-wrapper-0.1-SNAPSHOT-jar-with-dependencies.jar"
+ "./target/kawa-geiser-0.1-SNAPSHOT-jar-with-dependencies.jar"
geiser-kawa-dir)
"Path to the kawa-geiser fat jar."
:type 'string
diff --git a/example-mvn-run-geiser.sh b/example-mvn-run-geiser.sh
new file mode 100644
index 0000000..f0cabc6
--- /dev/null
+++ b/example-mvn-run-geiser.sh
@@ -0,0 +1,14 @@
+#!/bin/env sh
+
+# This file is not used by geiser-kawa. It's just to show that you can
+# start a Kawa repl with geiser support using the Kawa version that is
+# included in the maven dependencies of kawa-geiser.
+
+# valid exec.args are either:
+# - a port number: starts a Kawa telnet server listening on that port
+# - --no-server: starts a Kawa repl in current terminal
+
+mvn compile &&
+ mvn exec:java \
+ -D"exec.mainClass"="kawageiser.StartKawaWithGeiserSupport" \
+ -D"exec.args"=$@
diff --git a/pom.xml b/pom.xml
index 32e215e..71bbc1a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,11 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Copyright (C) 2020 spellcard199 <spellcard199@protonmail.com>
+ ~ This is free software; for terms and warranty disclaimer see ./COPYING.
+ -->
+
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.gitlab.spellcard199</groupId>
- <artifactId>kawa-geiser-wrapper</artifactId>
+ <artifactId>kawa-geiser</artifactId>
<version>0.1-SNAPSHOT</version>
<build>
@@ -52,11 +57,21 @@
</repositories>
<dependencies>
+
<dependency>
<groupId>com.gitlab.spellcard199</groupId>
- <artifactId>kawa-geiser</artifactId>
- <version>3e7d104a58457e9710f57b1a9b79ea8b48467b5c</version>
+ <artifactId>kawa-devutil</artifactId>
+ <version>0c12c104505e4965308b9214486f2051af152360</version>
+ </dependency>
+
+ <!-- https://mvnrepository.com/artifact/org.testng/testng -->
+ <dependency>
+ <groupId>org.testng</groupId>
+ <artifactId>testng</artifactId>
+ <version>7.0.0</version>
+ <scope>test</scope>
</dependency>
+
</dependencies>
</project>
diff --git a/src/main/java/kawageiser/Geiser.java
b/src/main/java/kawageiser/Geiser.java
new file mode 100644
index 0000000..40b7e18
--- /dev/null
+++ b/src/main/java/kawageiser/Geiser.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2020 spellcard199 <spellcard199@protonmail.com>
+ * This is free software; for terms and warranty disclaimer see ./COPYING.
+ */
+
+package kawageiser;
+
+import gnu.expr.Language;
+import kawageiser.geiserDoc.ManualEpubUnzipToTmpDir;
+
+public class Geiser implements Runnable {
+ private static boolean prettyPrintResult = true;
+ public static boolean isPrettyPrintResult() { return prettyPrintResult; }
+ public static boolean isPrettyPrintOutput() { return
evaluator.isPrettyPrintOutput(); }
+ public static void setPrettyPrintResult(boolean v) { prettyPrintResult =
v; }
+ public static void setPrettyPrintOutput(boolean v) {
evaluator.setPrettyPrintOutput(v); }
+
+ public static kawadevutil.eval.Eval evaluator = new
kawadevutil.eval.Eval();
+
+ @Override
+ public void run() {
+ Language lang = Language.getDefaultLanguage();
+ lang.defineFunction(new GeiserEval("geiser:eval"));
+ lang.defineFunction(new GeiserNoValues("geiser:no-values"));
+ lang.defineFunction(new GeiserLoadFile("geiser:load-file"));
+ lang.defineFunction(new GeiserCompleteSymbol("geiser:completions"));
+ lang.defineFunction(new
GeiserCompleteModule("geiser:module-completions"));
+ lang.defineFunction(new GeiserAutodoc("geiser:autodoc", lang));
+ lang.defineFunction(new
kawageiser.java.Complete("geiser:complete-java"));
+ lang.defineFunction(new
ManualEpubUnzipToTmpDir("geiser:manual-epub-unzip-to-tmp-dir"));
+ }
+}
diff --git a/src/main/java/kawageiser/GeiserAutodoc.java
b/src/main/java/kawageiser/GeiserAutodoc.java
new file mode 100644
index 0000000..747bbd2
--- /dev/null
+++ b/src/main/java/kawageiser/GeiserAutodoc.java
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2020 spellcard199 <spellcard199@protonmail.com>
+ * This is free software; for terms and warranty disclaimer see ./COPYING.
+ */
+
+package kawageiser;
+
+import gnu.expr.CompiledProc;
+import gnu.expr.Language;
+import gnu.kawa.functions.Format;
+import gnu.lists.LList;
+import gnu.mapping.*;
+import kawadevutil.data.ParamData;
+import kawadevutil.data.ProcDataGeneric;
+import kawadevutil.data.ProcDataNonGeneric;
+import kawadevutil.kawa.GnuMappingLocation;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+public class GeiserAutodoc extends Procedure1or2 {
+
+ public static boolean showTypes = true;
+ Language lang;
+
+ GeiserAutodoc(String name, Language lang) {
+ super(name);
+ this.lang = lang;
+ }
+
+ // TODO: find the "right" way to get modules for symbols.
+ // TODO: support for procedures defined in java, like `append'
+ // TODO: support for macros (possible?)
+ // TODO: support for getting parameter names for java instance
+ // methods getMethods bytecode with ClassType (not so simple)
+ // TODO: support names with special characters, like |a[)|
+ // Maybe we can:
+ // 1. keep a list of special chars
+ // 2. when `id' contains one: surround with || (e.g. |id|)
+ // TODO: consider multiple ids:
+ // - Examples: to get more add (message (format "(geiser:%s %s)" proc
form))
+ // in the t clause of the geiser-kawa--geiser-procedure:
+ // - (display [cursor] -> (geiser:autodoc ’(display))
+ // - (display (symbol? (string->symbol [cursor] -> (geiser:autodoc
’(string->symbol symbol? display))
+
+
+ // At the moment arguments are enclosed in double quotes. The
+ // reason is that geiser's output is `read' by elisp, but java types
+ // may contain characters that are not valid in elisp symbols
+ // (e.g. java arrays contain square brackets). So instead of symbols
+ // we use strings. When type annotations are disabled using
+ // (geiser:set-autodoc-show-types #f) parameter names displayed as
+ // symbols (without double quotes around them).
+
+ // List<Object> idsArr = List.getLocalVarsAttr(ids.toArray());
+ // idsArr.stream().map( (Object symId, Object env) -> {
+ // return (new SymToAutodoc()).apply2(symId, env);
+ // })
+
+ // @Override
+ public Object apply1(Object ids) {
+ return apply2(ids, Language.getDefaultLanguage().getEnvironment());
+ }
+
+ // @Override
+ public Object apply2(Object ids, Object env) {
+
+ if (!LList.class.isAssignableFrom(ids.getClass())) {
+ throw new IllegalArgumentException(String.format(
+ "GeiserAutodoc's 1st arg should be a gnu.lists.LList"));
+ }
+ if (!Environment.class.isAssignableFrom(env.getClass())) {
+ throw new IllegalArgumentException(String.format(
+ "GeiserAutodoc's 2nd arg should be a
gnu.mapping.Environment"));
+ }
+ try {
+ ArrayList<Object> autodocList = new ArrayList<>();
+ for (Object symId : (LList) ids) {
+ AutodocDataForSymId autodocDataForSymId =
+ new AutodocDataForSymId((Symbol) symId, (Environment)
env, this.lang);
+ autodocList.add(autodocDataForSymId.toLList());
+ }
+ String formattedAutodoc =
+ Format
+ .format("~S", LList.makeList(autodocList))
+ .toString();
+ return formattedAutodoc;
+ } catch (Throwable throwable) {
+ throwable.printStackTrace();
+ return throwable;
+ }
+ }
+
+ public static class OperatorArgListData {
+ ProcDataGeneric procDataGeneric;
+
+ public OperatorArgListData(ProcDataGeneric procDataGeneric) {
+ this.procDataGeneric = procDataGeneric;
+ }
+
+ private static String
+ formatParam(ParamData param, String formatting) {
+ // This method is just to reduce boilerplate in the other
`formatParam'
+ String paramName = param.getName();
+ String formattedParamType =
+ Format
+ .format("::~a",
+
param.getType().getReflectClass().getName())
+ .toString();
+ return Format.format(
+ formatting,
+ paramName,
+ formattedParamType).toString();
+ }
+
+ public static String
+ formatParam(ParamData param,
+ boolean isOptionalParam) {
+ if (isOptionalParam && showTypes) {
+ return formatParam(param, "(~a~a)");
+ } else if (isOptionalParam && !showTypes) {
+ return formatParam(param, "(~a)");
+ } else if (!isOptionalParam && showTypes) {
+ return formatParam(param, "~a~a");
+ } else if (!isOptionalParam && !showTypes) {
+ return formatParam(param, "~a");
+ } else {
+ throw new Error("No worries, can't happen (2 booleans == 4
possibilities)." +
+ "Just silencing the \"Missing return statement\"
error.");
+ }
+ }
+
+ public LList paramListToFormattedParamLList(List<ParamData> params,
boolean areOptionalParams) {
+ List<String> formattedParamList = new ArrayList<>();
+ for (ParamData req : params) {
+ String s = formatParam(req, areOptionalParams);
+ formattedParamList.add(s);
+ }
+ return LList.makeList(formattedParamList);
+ }
+
+ public LList toLList() {
+ ArrayList<Object> genericProcArgList = new ArrayList<>();
+
+ for (ProcDataNonGeneric pd :
this.procDataGeneric.getProcDataNonGenericList()) {
+ ArrayList<Object> nonGenericProcArgList = new ArrayList<>();
+ ArrayList<Object> requiredParamList = new ArrayList<>();
+ ArrayList<Object> optionalParamList = new ArrayList<>();
+
+ List<ParamData> requiredParams = pd.getRequiredParams();
+
+ if (!requiredParams.isEmpty()) {
+ LList requiredParamLList =
paramListToFormattedParamLList(requiredParams, false);
+ // argList.add(LList.list2("required",
requiredParamLList));
+ requiredParamList.add("required");
+ requiredParamList.addAll(requiredParamLList);
+ }
+
+ List<ParamData> optionalParams = pd.getOptionalParams();
+ Optional<ParamData> restParamMaybe = pd.getRestParam();
+ if (optionalParams.size() > 0 || restParamMaybe.isPresent()) {
+ LList optionalOrRestParamLList =
+ optionalParams.size() > 0
+ ?
paramListToFormattedParamLList(optionalParams, true)
+ :
LList.makeList(java.util.Collections.emptyList());
+ if (restParamMaybe.isPresent()) {
+ optionalOrRestParamLList.add(
+ Format.format(
+ "(... ~a...)",
+ formatParam(restParamMaybe.get(),
false)
+ )
+ );
+ }
+ optionalParamList.add("optional");
+ optionalParamList.addAll(optionalOrRestParamLList);
+ }
+
+ if (!requiredParamList.isEmpty()) {
+
nonGenericProcArgList.add(LList.makeList(requiredParamList));
+ }
+ if (!optionalParamList.isEmpty()) {
+
nonGenericProcArgList.add(LList.makeList(optionalParamList));
+ }
+ genericProcArgList.add(LList.makeList(nonGenericProcArgList));
+ }
+
+ return LList.makeList(genericProcArgList);
+ }
+ }
+
+ public static class AutodocDataForSymId {
+ private boolean symExists;
+ private Symbol symId;
+ private Object operator;
+ private Environment environment;
+ private Optional<OperatorArgListData> operatorArgListMaybe;
+ // TODO: fix type, write way to get it
+ private Object module;
+
+
+ public AutodocDataForSymId(Symbol symId, Environment env, Language
lang) {
+ this.symId = symId;
+ this.environment = env;
+
+ Optional<OperatorArgListData> operatorArgListMaybe =
Optional.empty();
+ Object operator = null;
+ boolean symExists = false;
+ try {
+ operator = lang.eval(symId.toString());
+ symExists = true; // If it didn't exist env.get(symId) would
have raised UnboundLocationException
+ if (!Procedure.class.isAssignableFrom(operator.getClass())) {
+ // Not a procedure
+ // TODO : is it possible to implement autodoc for macros?
+ // If not: write a comment why.
+ operatorArgListMaybe = Optional.empty();
+ } else {
+ ProcDataGeneric procDataGeneric =
ProcDataGeneric.makeForProcedure((Procedure) operator);
+ operatorArgListMaybe = Optional.of(new
OperatorArgListData(procDataGeneric));
+ }
+ } catch (Throwable throwable) {
+ throwable.printStackTrace();
+ }
+
+ this.operatorArgListMaybe = operatorArgListMaybe;
+ this.operator = operator;
+ this.symExists = symExists;
+ }
+
+ public LList toLList() {
+
+ ArrayList<Object> operatorArgListAsList = new ArrayList<>();
+ operatorArgListAsList.add("args");
+ if (operatorArgListMaybe.isPresent()) {
+
operatorArgListAsList.addAll(operatorArgListMaybe.get().toLList());
+ } else {
+ operatorArgListAsList.add(false);
+ }
+ LList operatorArgListAsLList =
LList.makeList(operatorArgListAsList);
+
+ // TODO: write a procedure that gets the module getMethods
+ // which a symbol comes getMethods using "the right way" (is
there one?)
+ // TODO: When we find the correct way to do it, refactor
moduleValue inside
+ // ProcDataNonGeneric or a generic wrapper for Procedure data
+ LList moduleValue = null;
+ if (operator.getClass() == CompiledProc.class) {
+ CompiledProc compProc = (CompiledProc) operator;
+ moduleValue = LList.makeList(
+ java.util.Arrays
+ .asList(compProc
+ .getModuleClass()
+ .getName()
+ .split("\\.")));
+ } else {
+ try {
+ // If it's not a CompiledProc it does not have a
+ // `getModule' method: fallback to trying to figure
+ // out getMethods GnuMappingLocation in Environment.
+ // TODO: generalize to arbitrary environment
+ moduleValue = (LList) kawa.lib.ports.read(
+ new gnu.kawa.io.CharArrayInPort(
+
GnuMappingLocation.baseLocationToModuleName(
+ environment.lookup(symId).getBase()
+ )
+ )
+ );
+ } catch (NullPointerException e) {
+ // If it is not even a sym in the environment, give up.
+ // TODO: should we consider all java classes as modules?
+ moduleValue = LList.makeList(new ArrayList());
+ }
+ }
+
+ // If you don't convert your symbol to String it may not match with
+ // the string seen from the emacs side and when that happens geiser
+ // does not considers that a valid autodoc response.
+ // Example: as a Symbol, java.lang.String:format is displayed by
+ // kawa as:
+ // java.lang.String{$unknown$}:format
+ // which does not match:
+ // java.lang.String:format
+ // so geiser ignores it.
+ String symIdAsStr = symId.toString();
+ LList returnMe;
+ if (moduleValue.size() > 0) {
+ ArrayList<Object> moduleList = new ArrayList<>();
+ moduleList.add("module");
+ for (Object m : moduleValue) {
+ moduleList.add(Symbol.valueOf(m.toString()));
+ }
+ returnMe = LList.list3(
+ symIdAsStr,
+ operatorArgListAsLList,
+ LList.makeList(moduleList)
+ );
+ } else {
+ returnMe = LList.list2(
+ symIdAsStr,
+ operatorArgListAsLList
+ );
+ }
+
+ return returnMe;
+ }
+ }
+}
+
diff --git a/src/main/java/kawageiser/GeiserCompleteModule.java
b/src/main/java/kawageiser/GeiserCompleteModule.java
new file mode 100644
index 0000000..fe00508
--- /dev/null
+++ b/src/main/java/kawageiser/GeiserCompleteModule.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2020 spellcard199 <spellcard199@protonmail.com>
+ * This is free software; for terms and warranty disclaimer see ./COPYING.
+ */
+
+package kawageiser;
+
+import gnu.expr.Language;
+import gnu.lists.IString;
+import gnu.lists.LList;
+import gnu.mapping.Environment;
+import gnu.mapping.Procedure1or2;
+import kawadevutil.kawa.GnuMappingLocation;
+
+import java.util.ArrayList;
+
+
+public class GeiserCompleteModule extends Procedure1or2 {
+
+ GeiserCompleteModule(String name) {
+ super(name);
+ }
+
+ @Override
+ public Object apply1(Object prefix) throws Throwable {
+ return apply2(
+ prefix,
+ Language.getDefaultLanguage().getEnvironment());
+ }
+
+ @Override
+ public Object apply2(Object prefix, Object env) throws Throwable {
+
+ String prefixStr = null;
+ if (prefix instanceof String) {
+ prefixStr = (String) prefix;
+ } else if (prefix instanceof IString) {
+ prefixStr = prefix.toString();
+ } else {
+ throw new IllegalArgumentException(
+ "`prefix' arg should be either a String or an IString");
+ }
+
+ Environment castedEnv;
+ if (Environment.class.isAssignableFrom(env.getClass())) {
+ castedEnv = (Environment) env;
+ } else {
+ throw new IllegalArgumentException(
+ "`env' arg should be an gnu.mapping.Environment");
+ }
+
+ ArrayList<String> moduleCompletions = getCompletions(prefixStr,
castedEnv);
+ // Geiser protocol wants modules in the result to be printed
+ // between double quotes
+ // ("(... ... ...)" "(... ...)")
+ // Kawa repl doesn't show returned strings with surrounding
+ // quotes, so we have to manually surround completions.
+ return gnu.kawa.functions.Format.format("~S",
LList.makeList(moduleCompletions));
+ }
+
+ private ArrayList<String> getCompletions(String prefix, Environment env) {
+
+ ArrayList<String> moduleCompletions = new ArrayList<>();
+
+ // Since this procedure works iterating over locations in the
+ // (interaction-environment), if a module does not export any
+ // symbol it won't appear in the result.
+ // TODO: this is an hack. If it exists, find a way to list
+ // modules directly.
+ env.enumerateAllLocations().forEachRemaining(
+ loc ->
+ {
+ String moduleStrRepr = GnuMappingLocation
+ .baseLocationToModuleName(loc.getBase());
+ if ((!moduleCompletions.contains(moduleStrRepr))
+ && (!(moduleStrRepr.equals("")))
+ && (moduleStrRepr.startsWith(prefix))
+ ) {
+ moduleCompletions.add(moduleStrRepr);
+ }
+ }
+ );
+
+ return moduleCompletions;
+ }
+}
diff --git a/src/main/java/kawageiser/GeiserCompleteSymbol.java
b/src/main/java/kawageiser/GeiserCompleteSymbol.java
new file mode 100644
index 0000000..5dda5c7
--- /dev/null
+++ b/src/main/java/kawageiser/GeiserCompleteSymbol.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2020 spellcard199 <spellcard199@protonmail.com>
+ * This is free software; for terms and warranty disclaimer see ./COPYING.
+ */
+
+package kawageiser;
+
+import gnu.expr.Language;
+import gnu.lists.IString;
+import gnu.lists.LList;
+import gnu.mapping.Environment;
+import gnu.mapping.Procedure1or2;
+import gnu.mapping.Symbol;
+
+import java.util.ArrayList;
+
+public class GeiserCompleteSymbol extends Procedure1or2 {
+
+ GeiserCompleteSymbol(String name) {
+ super(name);
+ }
+
+ @Override
+ public Object apply1(Object prefix) {
+ return apply2(
+ prefix,
+ Language.getDefaultLanguage().getEnvironment());
+ }
+
+ @Override
+ public Object apply2(Object prefix, Object module) {
+
+ String prefixStr = null;
+ if (prefix instanceof String) {
+ prefixStr = (String) prefix;
+ } else if (prefix instanceof IString) {
+ prefixStr = prefix.toString();
+ } else {
+ throw new IllegalArgumentException(
+ "prefix arg should be either String or IString");
+ }
+
+ Environment env = null;
+ if (Environment.class.isAssignableFrom(module.getClass())) {
+ // already an Environment
+ env = (Environment) module;
+ } else if (kawa.lib.lists.isList(module)) {
+ env = kawa.lib.scheme.eval.environment$V(((LList) module));
+ } else {
+ throw new IllegalArgumentException(
+ "module argument should be either a proper list or an
Environment.");
+ }
+
+ return getCompletions(prefixStr, env);
+ }
+
+ private LList getCompletions(String prefix, Environment env) {
+ ArrayList<Symbol> resultArrList = new ArrayList<>();
+ env.enumerateAllLocations().forEachRemaining(
+ loc -> {
+ Symbol sym = loc.getKeySymbol();
+ String symName = sym.getName();
+ if (symName.contains(prefix)) {
+ resultArrList.add(sym);
+ }
+ }
+ );
+ return LList.makeList(resultArrList);
+ }
+}
diff --git a/src/main/java/kawageiser/GeiserEval.java
b/src/main/java/kawageiser/GeiserEval.java
new file mode 100644
index 0000000..906b41a
--- /dev/null
+++ b/src/main/java/kawageiser/GeiserEval.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2020 spellcard199 <spellcard199@protonmail.com>
+ * This is free software; for terms and warranty disclaimer see ./COPYING.
+ */
+
+package kawageiser;
+
+import gnu.kawa.functions.Format;
+import gnu.lists.IString;
+import gnu.lists.LList;
+import gnu.lists.Pair;
+import gnu.mapping.Environment;
+import gnu.mapping.Procedure2;
+import gnu.mapping.Symbol;
+import kawadevutil.eval.EvalResult;
+import kawadevutil.eval.EvalResultAndOutput;
+import kawadevutil.redirect.RedirectedOutErr;
+
+public class GeiserEval extends Procedure2 {
+ /*
+ * Actual evaluation happens in kawadevtools.eval.Eval.
+ * Here we are just sending arguments and converting our own
+ * types into the geiser protocol.
+ */
+
+ GeiserEval(String procName) {
+ super(procName);
+ }
+
+ @Override
+ public String
+ apply2(Object module, Object codeStr) {
+ // Today (2019-12-9) Kawa has still that issue when
+ // quoting (this) followed by a double colon. So, to avoid
+ // it altogether, geiser:eval default is to accept Strings
+ // instead of sexprs.
+ // You can still evaluate expressions instead of strings using
+ // the other GeiserEval:eval method explicitly.
+ String code;
+ if (codeStr instanceof IString) {
+ code = ((IString) codeStr).toString();
+ } else if (codeStr instanceof String) {
+ code = (String) codeStr;
+ } else {
+ throw new IllegalArgumentException(
+ "`codeStr' arg should be either a String or an IString");
+ }
+ return eval((Environment) module, code);
+ }
+
+ public static String
+ eval(Environment module, String codeStr) {
+ EvalResultAndOutput resOutErr =
Geiser.evaluator.evalCatchingOutErr(module, codeStr);
+ return formatGeiserProtocol(evaluationDataToGeiserProtocol(resOutErr));
+ }
+
+ public static String
+ eval(Environment module, Object sexpr) {
+ EvalResultAndOutput resOutErr =
Geiser.evaluator.evalCatchingOutErr(module, sexpr);
+ return formatGeiserProtocol(evaluationDataToGeiserProtocol(resOutErr));
+ }
+
+ public static LList
+ evaluationDataToGeiserProtocol(EvalResultAndOutput resOutErr) {
+ EvalResult evalRes = resOutErr.getResultOfSupplier();
+ RedirectedOutErr outErr = resOutErr.getOutErr();
+
+ // result
+ String geiserResult = evalRes.isSuccess()
+ ? evalRes.getResultAsString(Geiser.isPrettyPrintResult())
+ : "";
+
+ // output
+ String messages = (evalRes.getMessages() != null)
+ ? evalRes.getMessages().toString(100000)
+ : "";
+ messages = (messages != null) ? messages : "";
+ String stackTrace = (evalRes.getThrowed() != null)
+ ? Geiser.evaluator.formatStackTrace(evalRes.getThrowed())
+ : "";
+ String output = outErr.getOutAndErrInPrintOrder();
+ // If we wanted, we could include stack traces directly in
+ // the output using Eval.setPrintStackTrace(): that would
+ // display stack traces of exceptions after the output
+ // produced by the code instead of before.
+ // Since the Kawa repl prints in order: messages, stacktrace,
+ // output, we are doing the same.
+ String geiserOutput = messages + stackTrace + output;
+
+ return evaluationDataToGeiserProtocol(
+ evalRes.isSuccess(), geiserResult, geiserOutput);
+ }
+
+ private static LList
+ evaluationDataToGeiserProtocol
+ (boolean isSuccess, String geiserResult, String geiserOutput) {
+ LList geiserResOrErr =
+ isSuccess
+ ? LList.list2(Symbol.valueOf("result"), geiserResult)
+ : LList.list2(Symbol.valueOf("error"), "");
+ Pair geiserOut = Pair.make(Symbol.valueOf("output"), geiserOutput);
+ return LList.list2(geiserResOrErr, geiserOut);
+ }
+
+ public static String formatGeiserProtocol(LList geiserAnswer) {
+ return (String) Format.format("~S", geiserAnswer);
+ }
+
+}
diff --git a/src/main/java/kawageiser/GeiserLoadFile.java
b/src/main/java/kawageiser/GeiserLoadFile.java
new file mode 100644
index 0000000..6fa7763
--- /dev/null
+++ b/src/main/java/kawageiser/GeiserLoadFile.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 spellcard199 <spellcard199@protonmail.com>
+ * This is free software; for terms and warranty disclaimer see ./COPYING.
+ */
+
+package kawageiser;
+
+import gnu.expr.Language;
+import gnu.lists.IString;
+import gnu.lists.LList;
+import gnu.mapping.Procedure1;
+import kawa.standard.load;
+
+public class GeiserLoadFile extends Procedure1 {
+
+ GeiserLoadFile(String name) {
+ super(name);
+ }
+
+ @Override
+ public Object apply1(Object o) throws Throwable {
+ String filepath;
+ if (o instanceof String) {
+ filepath = (String) o;
+ } else if (o instanceof IString) {
+ filepath = ((IString) o).toString();
+ } else {
+ throw new IllegalArgumentException(
+ "geiser:load should take a String or an IString as
argument");
+ }
+ return load(filepath);
+ }
+
+ public Object load(String filepath) {
+ return GeiserEval.eval(
+ Language.getDefaultLanguage().getEnvironment(),
+ LList.list2(load.load, filepath));
+ }
+}
diff --git a/src/main/java/kawageiser/GeiserNoValues.java
b/src/main/java/kawageiser/GeiserNoValues.java
new file mode 100644
index 0000000..b15b29c
--- /dev/null
+++ b/src/main/java/kawageiser/GeiserNoValues.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2020 spellcard199 <spellcard199@protonmail.com>
+ * This is free software; for terms and warranty disclaimer see ./COPYING.
+ */
+
+package kawageiser;
+
+import gnu.mapping.Procedure0;
+import gnu.mapping.Values;
+
+public class GeiserNoValues extends Procedure0 {
+
+ GeiserNoValues(String name) {
+ super(name);
+ }
+
+ @Override
+ public Object apply0() throws Throwable {
+ gnu.kawa.io.InPort.inDefault().setLineNumber(
+ gnu.kawa.io.InPort.inDefault().getLineNumber() - 1);
+ // apply0 signature doesn't allow us to return void
+ return Values.FromArray.make();
+ }
+}
diff --git a/src/main/java/kawageiser/StartKawaWithGeiserSupport.java
b/src/main/java/kawageiser/StartKawaWithGeiserSupport.java
new file mode 100644
index 0000000..cc558e8
--- /dev/null
+++ b/src/main/java/kawageiser/StartKawaWithGeiserSupport.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2020 spellcard199 <spellcard199@protonmail.com>
+ * This is free software; for terms and warranty disclaimer see ./COPYING.
+ */
+
+package kawageiser;
+
+public class StartKawaWithGeiserSupport {
+
+ public static void main(String[] args) {
+ if (args.length == 0) {
+ int defaultPort = 37146;
+ System.out.println(
+ String.format(
+ "No port specified. Starting kawa server on
default port (%d)...",
+ defaultPort));
+ startKawaServerWithGeiserSupport(defaultPort);
+ } else if (args.length == 1 && args[0].matches("[0-9]+")) {
+ int port = Integer.parseInt(args[0]);
+ startKawaServerWithGeiserSupport(port);
+ } else if (args.length == 1 && args[0].equals("--no-server")) {
+ System.out.println("Starting kawa repl in current terminal...");
+ startKawaReplWithGeiserSupport();
+ } else {
+ System.out.println(
+ "You must pass at most 1 argument and it can be only one
of:\n"
+ + "- a port number"
+ + "- --no-server"
+ );
+ }
+ }
+
+ public static void startKawaReplWithGeiserSupport() {
+ String[] interpArgs = new String[]{
+ "-e", "(require <kawageiser.Geiser>)",
+ "--",
+ };
+ runSchemeAsApplication(interpArgs);
+ }
+
+ public static void startKawaServerWithGeiserSupport(int port) {
+ String[] interpArgs = new String[]{
+ "-e", "(require <kawageiser.Geiser>)",
+ "--server", String.valueOf(port)};
+ runSchemeAsApplication(interpArgs);
+ }
+
+ public static void runSchemeAsApplication(String[] args) {
+ kawa.standard.Scheme scheme = kawa.standard.Scheme.getInstance();
+ scheme.runAsApplication(args);
+ }
+
+}
diff --git a/src/main/java/kawageiser/geiserDoc/ManualEpubUnzipToTmpDir.java
b/src/main/java/kawageiser/geiserDoc/ManualEpubUnzipToTmpDir.java
new file mode 100644
index 0000000..f24b035
--- /dev/null
+++ b/src/main/java/kawageiser/geiserDoc/ManualEpubUnzipToTmpDir.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2020 spellcard199 <spellcard199@protonmail.com>
+ * This is free software; for terms and warranty disclaimer see ./COPYING.
+ */
+
+package kawageiser.geiserDoc;
+
+import gnu.lists.IString;
+import gnu.mapping.Procedure1;
+
+import java.io.File;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.List;
+
+public class ManualEpubUnzipToTmpDir extends Procedure1 {
+
+ public ManualEpubUnzipToTmpDir(String name) {
+ super(name);
+ }
+
+ @Override
+ public Object apply1(Object kawaEpubManualPath) throws Throwable {
+ if (! (kawaEpubManualPath.getClass() == String.class ||
+ kawaEpubManualPath.getClass() == IString.class)) {
+ throw new IllegalArgumentException(
+ "`kawaEpubManualPath' arg must be either String or
IString");
+ }
+ String systemTmpDir = System.getProperty("java.io.tmpdir");
+ String manualUnzippedTmpDir = String.join(
+ File.separator,
+ systemTmpDir,
+ "geiser-kawa",
+ "manual-epub-unzipped");
+
+ File zipArchiveFile = new File(kawaEpubManualPath.toString());
+ Path destDirPath = new File(manualUnzippedTmpDir).toPath();
+
+ kawadevutil.util.ZipExtractor.unzip(zipArchiveFile, destDirPath);
+ return gnu.kawa.functions.Format.format("~S", manualUnzippedTmpDir);
+ }
+}
diff --git a/src/main/java/kawageiser/java/Complete.java
b/src/main/java/kawageiser/java/Complete.java
new file mode 100644
index 0000000..6be9291
--- /dev/null
+++ b/src/main/java/kawageiser/java/Complete.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2020 spellcard199 <spellcard199@protonmail.com>
+ * This is free software; for terms and warranty disclaimer see ./COPYING.
+ */
+
+package kawageiser.java;
+
+import gnu.expr.Language;
+import gnu.lists.IString;
+import gnu.lists.LList;
+import gnu.lists.Pair;
+import gnu.mapping.Environment;
+import gnu.mapping.Procedure1or2;
+import gnu.mapping.Procedure3;
+import gnu.mapping.Procedure4;
+import gnu.math.IntNum;
+import kawadevutil.complete.*;
+
+import java.io.File;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+public class Complete extends Procedure4 {
+
+ public static boolean showTypes = true;
+
+ public Complete(String name) {
+ super(name);
+ }
+
+ @Override
+ public Object
+ apply4(Object codeStr, Object cursorIndex, Object lang, Object env) throws
Throwable {
+
+ String codeStrChecked = null;
+ if (codeStr.getClass().equals(IString.class) ||
codeStr.getClass().equals(String.class)) {
+ codeStrChecked = codeStr.toString();
+ } else {
+ throw new IllegalArgumentException(
+ "`codeStr` must be either String or IString: " +
codeStr.getClass().toString());
+ }
+
+ Integer cursorIndexChecked = null;
+ if (cursorIndex.getClass().equals(Integer.class)) {
+ cursorIndexChecked = (Integer) cursorIndex;
+ } else if (cursorIndex.getClass().equals(IntNum.class)) {
+ cursorIndexChecked = ((IntNum) cursorIndex).intValue();
+ } else {
+ throw new IllegalArgumentException(
+ "`cursorIndex` must be either Integer or IntNum: " +
cursorIndex.getClass().toString());
+ }
+
+ // Get Data
+ Optional<CompletionDataForJava> complDataMaybe =
kawadevutil.complete.Complete.complete(
+ codeStrChecked, cursorIndexChecked, (Language) lang,
(Environment) env, (String name) -> true);
+
+ // Wrap data of interest in Scheme's LList
+ if (!complDataMaybe.isPresent()) {
+ return LList.Empty;
+ } else {
+ CompletionDataForJava complData = complDataMaybe.get();
+ if (complData.getClass().equals(CompletionDataForJavaField.class))
{
+ CompletionDataForJavaField complDataForField =
(CompletionDataForJavaField) complData;
+ } else if
(complData.getClass().equals(CompletionDataForJavaMethod.class)) {
+ CompletionDataForJavaMethod complDataForMethod =
(CompletionDataForJavaMethod) complData;
+ } else {
+ throw new Error("Bug spotted.");
+ }
+
+ String completionsForClass = complData.getForClass().getName();
+ CompletionDataForJava.FieldOrMethod fieldOrMethod =
complData.getFieldOrMethod();
+ List<String> names = (List<String>)
complData.getNames().stream().distinct().collect(Collectors.toList());
+ String beforeCursor =
complData.getCursorMatcher().getCursorMatch().getBeforeCursor();
+ String afterCursor =
complData.getCursorMatcher().getCursorMatch().getAfterCursor();
+ // I don't know why it says "unchecked call" when using
complData.getRequiredModifiers().stream()
+ ArrayList<String> modifiers = new ArrayList<>();
+ for (Object modifier : complData.getRequiredModifiers()) {
+ modifiers.add(modifier.toString());
+ }
+
+ java.util.List<LList> res = Arrays.asList(
+ LList.list2("compl-for-class", completionsForClass),
+ LList.list2("modifiers", LList.makeList(modifiers)),
+ LList.list2("field-or-method", fieldOrMethod.toString()),
+ LList.list2("completions", LList.makeList(names)),
+ LList.list2("before-cursor", beforeCursor),
+ LList.list2("after-cursor", afterCursor)
+ );
+ LList resLList = LList.makeList(res);
+ return gnu.kawa.functions.Format.format("~S", resLList);
+ }
+ }
+
+}
diff --git a/src/test/java/kawageiser/GeiserAutodocTest.java
b/src/test/java/kawageiser/GeiserAutodocTest.java
new file mode 100644
index 0000000..a2c0253
--- /dev/null
+++ b/src/test/java/kawageiser/GeiserAutodocTest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2020 spellcard199 <spellcard199@protonmail.com>
+ * This is free software; for terms and warranty disclaimer see ./COPYING.
+ */
+
+package kawageiser;
+
+import gnu.lists.LList;
+import gnu.mapping.Environment;
+import gnu.mapping.Symbol;
+import kawa.lib.ports;
+import kawa.standard.Scheme;
+import kawadevutil.data.ProcDataGeneric;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.*;
+
+public class GeiserAutodocTest {
+
+ @Test
+ public void testApply2() {
+ Scheme scheme = new Scheme();
+ Environment env = scheme.getEnvironment();
+ Symbol displaySym = env.getSymbol("display");
+ Symbol cdddrSym = env.getSymbol("cdddr");
+ GeiserAutodoc geiserAutodoc = new
GeiserAutodoc("geiser-testing-autodoc", scheme);
+ String autodocDisplay = (String)
geiserAutodoc.apply2(LList.list1(displaySym), env);
+ String autodocCdddr = (String)
geiserAutodoc.apply2(LList.list1(cdddrSym), env);
+
+ // System.out.println(autodocDisplay);
+
+ assertTrue(autodocDisplay.startsWith("((\"display\""));
+ assertTrue(autodocDisplay.contains(" (\"args\" "));
+ assertTrue(autodocDisplay.contains("((\"required\" "));
+ assertTrue(autodocDisplay.contains("(\"optional\" "));
+ assertTrue(autodocDisplay.contains("(\"module\" "));
+
+ assertTrue(autodocCdddr.startsWith("((\"cdddr\""));
+ assertTrue(autodocCdddr.contains(" (\"args\" "));
+ assertTrue(autodocCdddr.contains("((\"required\" "));
+ assertTrue(!autodocCdddr.contains("(\"optional\" "));
+ assertTrue(autodocCdddr.contains("(\"module\" "));
+ }
+
+ public static class OperatorArgListDataTest {
+
+ @Test
+ public void testToLList() {
+ ProcDataGeneric procDataNonGenericList =
ProcDataGeneric.makeForProcedure(ports.display);
+ GeiserAutodoc.OperatorArgListData operatorArgListData = new
GeiserAutodoc.OperatorArgListData(procDataNonGenericList);
+ LList llist = operatorArgListData.toLList();
+ // System.out.println(llist);
+ String required = (String) ((LList) ((LList)
llist.get(0)).get(0)).get(0);
+ String optional = (String) ((LList) ((LList)
llist.get(0)).get(1)).get(0);
+
+ assertEquals(required, "required");
+ assertEquals(optional, "optional");
+
+ }
+ }
+
+ public static class AutodocDataForSymIdTest {
+
+ @Test
+ public void testToLListForProc1() {
+ Scheme scheme = new Scheme();
+ Environment env = scheme.getEnvironment();
+ Symbol display = env.getSymbol("display");
+ GeiserAutodoc.AutodocDataForSymId autodocDataForDisplay = new
GeiserAutodoc.AutodocDataForSymId(display, env, scheme);;
+ assertEquals(display.toString(),
autodocDataForDisplay.toLList().get(0));
+ }
+
+ @Test
+ public void testToLListForProcN() {
+ Scheme scheme = new Scheme();
+ Environment env = scheme.getEnvironment();
+ Symbol strFormatSym = null;
+ try {
+ strFormatSym = (Symbol)
scheme.eval("'java.lang.String:format");
+ } catch (Throwable throwable) {
+ throwable.printStackTrace();
+ }
+ GeiserAutodoc.AutodocDataForSymId autodocDataForDisplay = new
GeiserAutodoc.AutodocDataForSymId(strFormatSym, env, scheme);;
+ LList llist = autodocDataForDisplay.toLList();
+ assertEquals("java.lang.String:format", llist.get(0));
+ }
+ }
+}
\ No newline at end of file
- [nongnu] elpa/geiser-kawa ed8d954 055/119: Rename funcs, (continued)
- [nongnu] elpa/geiser-kawa ed8d954 055/119: Rename funcs, Philip Kaludercic, 2021/08/01
- [nongnu] elpa/geiser-kawa e4679f7 066/119: pom.xml update kawa-devutil dep + fix code accordingly, Philip Kaludercic, 2021/08/01
- [nongnu] elpa/geiser-kawa 80ed3e7 068/119: Update geiser version + remove geiser workaround for Cask, Philip Kaludercic, 2021/08/01
- [nongnu] elpa/geiser-kawa f258b9a 073/119: TODO.org: add notes to self on how to make the melpa recipe, Philip Kaludercic, 2021/08/01
- [nongnu] elpa/geiser-kawa da47cd7 082/119: Fix broken name, Philip Kaludercic, 2021/08/01
- [nongnu] elpa/geiser-kawa e0fd1de 084/119: Refactor geiser-kawa-devutil-exprtree.el, Philip Kaludercic, 2021/08/01
- [nongnu] elpa/geiser-kawa 4750e5c 021/119: Update README, Philip Kaludercic, 2021/08/01
- [nongnu] elpa/geiser-kawa c9c493e 006/119: Add pom.xml for kawa-geiser dependency, Philip Kaludercic, 2021/08/01
- [nongnu] elpa/geiser-kawa 8d04e27 032/119: Update kawa-devutil dep, Philip Kaludercic, 2021/08/01
- [nongnu] elpa/geiser-kawa 84eea5c 008/119: Add quickstart.el, Philip Kaludercic, 2021/08/01
- [nongnu] elpa/geiser-kawa 86ef157 020/119: Join projects: kawa-geiser is now part of geiser-kawa,
Philip Kaludercic <=
- [nongnu] elpa/geiser-kawa 29d4f87 015/119: pom.xml - Update kawa-geiser SHA, Philip Kaludercic, 2021/08/01
- [nongnu] elpa/geiser-kawa 0eab288 018/119: README.org - Small reword, Philip Kaludercic, 2021/08/01
- [nongnu] elpa/geiser-kawa 11c8415 037/119: Fix (workaround) autodoc for certain symbol names, Philip Kaludercic, 2021/08/01
- [nongnu] elpa/geiser-kawa aad27bb 039/119: Small reword in comment, Philip Kaludercic, 2021/08/01
- [nongnu] elpa/geiser-kawa 95e3f4a 010/119: Fix error when requiring geiser-kawa and kawa binary is not in PATH, Philip Kaludercic, 2021/08/01
- [nongnu] elpa/geiser-kawa cf06550 030/119: Small changes to README, Philip Kaludercic, 2021/08/01
- [nongnu] elpa/geiser-kawa 0c311ae 051/119: Rename var to geiser-kawa-use-included-kawa, Philip Kaludercic, 2021/08/01
- [nongnu] elpa/geiser-kawa 5762c19 053/119: Cask file: add buttercup dep + copyright, Philip Kaludercic, 2021/08/01
- [nongnu] elpa/geiser-kawa bd3e31f 054/119: Update README.org after renamings, Philip Kaludercic, 2021/08/01
- [nongnu] elpa/geiser-kawa e440789 058/119: Add optional arg to function checking for jar file, Philip Kaludercic, 2021/08/01