diff --git a/src/main/java/com/github/jlangch/venice/impl/docgen/cheatsheet/DocGenerator.java b/src/main/java/com/github/jlangch/venice/impl/docgen/cheatsheet/DocGenerator.java index 2d1db0783..ee6dc7440 100644 --- a/src/main/java/com/github/jlangch/venice/impl/docgen/cheatsheet/DocGenerator.java +++ b/src/main/java/com/github/jlangch/venice/impl/docgen/cheatsheet/DocGenerator.java @@ -144,7 +144,7 @@ public DocGenerator(final boolean runExamples) { null); // make REPL specific functions available (e.g: 'repl/info') - final Env env = ReplFunctions.register(docEnv, null, null, false, ReplDirs.notavail()); + final Env env = ReplFunctions.register(docEnv, null, null, null, false, ReplDirs.notavail()); this.diBuilder = new DocItemBuilder( env, diff --git a/src/main/java/com/github/jlangch/venice/impl/docgen/cheatsheet/section/ReplSection.java b/src/main/java/com/github/jlangch/venice/impl/docgen/cheatsheet/section/ReplSection.java index e5d6b1945..11cbb8a68 100644 --- a/src/main/java/com/github/jlangch/venice/impl/docgen/cheatsheet/section/ReplSection.java +++ b/src/main/java/com/github/jlangch/venice/impl/docgen/cheatsheet/section/ReplSection.java @@ -54,6 +54,11 @@ public DocSection section() { dirs.addItem(diBuilder.getDocItem("repl/home-dir", false)); dirs.addItem(diBuilder.getDocItem("repl/libs-dir", false)); + final DocSection config = new DocSection("Config", "repl.config"); + all.addSection(config); + config.addItem(diBuilder.getDocItem("repl/prompt", false)); + config.addItem(diBuilder.getDocItem("repl/handler", false)); + return section; } diff --git a/src/main/java/com/github/jlangch/venice/impl/repl/CustomREPL.java b/src/main/java/com/github/jlangch/venice/impl/repl/CustomREPL.java index f87042443..7aa79c322 100644 --- a/src/main/java/com/github/jlangch/venice/impl/repl/CustomREPL.java +++ b/src/main/java/com/github/jlangch/venice/impl/repl/CustomREPL.java @@ -277,7 +277,9 @@ private Env loadEnv( .setStdinReader(in); return ReplFunctions.register( - env, terminal, config, macroexpand, ReplDirs.create()); + env, + this, terminal, config, + macroexpand, ReplDirs.create()); } private PrintStream createPrintStream(final String context, final Terminal terminal) { diff --git a/src/main/java/com/github/jlangch/venice/impl/repl/REPL.java b/src/main/java/com/github/jlangch/venice/impl/repl/REPL.java index 54a61e971..7eeb4c307 100644 --- a/src/main/java/com/github/jlangch/venice/impl/repl/REPL.java +++ b/src/main/java/com/github/jlangch/venice/impl/repl/REPL.java @@ -1231,7 +1231,9 @@ private Env loadEnv( .setStdinReader(in); return ReplFunctions.register( - env, terminal, config, venice.isMacroExpandOnLoad(), replDirs); + env, + this, terminal, config, + venice.isMacroExpandOnLoad(), replDirs); } private void reconfigureVenice( diff --git a/src/main/java/com/github/jlangch/venice/impl/repl/ReplFunctions.java b/src/main/java/com/github/jlangch/venice/impl/repl/ReplFunctions.java index e2a6d76b5..5e8a0b5d0 100644 --- a/src/main/java/com/github/jlangch/venice/impl/repl/ReplFunctions.java +++ b/src/main/java/com/github/jlangch/venice/impl/repl/ReplFunctions.java @@ -23,13 +23,16 @@ import java.util.ArrayList; import java.util.List; +import java.util.function.Consumer; import org.jline.terminal.Terminal; import org.jline.utils.InfoCmp.Capability; +import com.github.jlangch.venice.IRepl; import com.github.jlangch.venice.VncException; import com.github.jlangch.venice.impl.env.Env; import com.github.jlangch.venice.impl.env.Var; +import com.github.jlangch.venice.impl.javainterop.DynamicInvocationHandler; import com.github.jlangch.venice.impl.types.Constants; import com.github.jlangch.venice.impl.types.VncFunction; import com.github.jlangch.venice.impl.types.VncJavaObject; @@ -38,22 +41,26 @@ import com.github.jlangch.venice.impl.types.VncString; import com.github.jlangch.venice.impl.types.VncSymbol; import com.github.jlangch.venice.impl.types.VncVal; +import com.github.jlangch.venice.impl.types.collections.VncHashMap; import com.github.jlangch.venice.impl.types.collections.VncList; import com.github.jlangch.venice.impl.types.collections.VncOrderedMap; +import com.github.jlangch.venice.impl.types.util.Coerce; import com.github.jlangch.venice.impl.util.ArityExceptions; +import com.github.jlangch.venice.impl.util.callstack.CallFrame; public class ReplFunctions { public static Env register( final Env env, - final Terminal terminal, + final IRepl repl, + final Terminal terminal, final ReplConfig config, final boolean macroExpandOnLoad, final ReplDirs replDirs ) { Env e = env; - for(VncFunction fn : createFunctions(terminal, config, macroExpandOnLoad, replDirs)) { + for(VncFunction fn : createFunctions(repl, terminal, config, macroExpandOnLoad, replDirs)) { e = registerFn(e,fn); } return e; @@ -65,6 +72,7 @@ private static Env registerFn(final Env env, final VncFunction fn) { } private static List createFunctions( + final IRepl repl, final Terminal terminal, final ReplConfig config, final boolean macroExpandOnLoad, @@ -73,11 +81,13 @@ private static List createFunctions( final List fns = new ArrayList<>(); fns.add(createReplInfoFn(terminal, config)); - fns.add(createReplRestartFn(terminal, config, macroExpandOnLoad)); + fns.add(createReplRestartFn(config, macroExpandOnLoad)); fns.add(createTermRowsFn(terminal)); fns.add(createTermColsFn(terminal)); fns.add(createReplHomeDirFn(replDirs)); fns.add(createReplLibsDirFn(replDirs)); + fns.add(createPromptFn(repl)); + fns.add(setHandlerFn(repl)); return fns; } @@ -113,18 +123,30 @@ private static VncFunction createReplInfoFn( public VncVal apply(final VncList args) { ArityExceptions.assertArity(this, args, 0); - try { - return VncOrderedMap.of( - new VncKeyword("term-name"), new VncString(terminal.getName()), - new VncKeyword("term-type"), new VncString(terminal.getType()), - new VncKeyword("term-cols"), new VncLong(terminal.getSize().getColumns()), - new VncKeyword("term-rows"), new VncLong(terminal.getSize().getRows()), - new VncKeyword("term-colors"), new VncLong(terminal.getNumericCapability(Capability.max_colors)), - new VncKeyword("term-class"), new VncKeyword(terminal.getClass().getName()), - new VncKeyword("color-mode"), new VncKeyword(config.getColorMode().toString().toLowerCase())); + if (terminal != null) { + try { + return VncOrderedMap.of( + new VncKeyword("term-name"), new VncString(terminal.getName()), + new VncKeyword("term-type"), new VncString(terminal.getType()), + new VncKeyword("term-cols"), new VncLong(terminal.getSize().getColumns()), + new VncKeyword("term-rows"), new VncLong(terminal.getSize().getRows()), + new VncKeyword("term-colors"), new VncLong(terminal.getNumericCapability(Capability.max_colors)), + new VncKeyword("term-class"), new VncKeyword(terminal.getClass().getName()), + new VncKeyword("color-mode"), new VncKeyword(config.getColorMode().toString().toLowerCase())); + } + catch(Exception ex) { + throw new VncException("Failed to get the REPL terminal info", ex); + } } - catch(Exception ex) { - throw new VncException("Failed to get the REPL terminal info", ex); + else { + return VncOrderedMap.of( + new VncKeyword("term-name"), new VncString("unknown"), + new VncKeyword("term-type"), new VncString("unknown"), + new VncKeyword("term-cols"), new VncLong(0), + new VncKeyword("term-rows"), new VncLong(0), + new VncKeyword("term-colors"), new VncLong(0), + new VncKeyword("term-class"), new VncKeyword("unknown"), + new VncKeyword("color-mode"), new VncKeyword("unknown")); } } @@ -133,7 +155,6 @@ public VncVal apply(final VncList args) { } private static VncFunction createReplRestartFn( - final Terminal terminal, final ReplConfig config, final boolean macroExpandOnLoad ) { @@ -183,7 +204,7 @@ private static VncFunction createTermRowsFn(final Terminal terminal) { public VncVal apply(final VncList args) { ArityExceptions.assertArity(this, args, 0); - return new VncLong(terminal.getSize().getRows()); + return new VncLong(terminal == null ? 0 : terminal.getSize().getRows()); } private static final long serialVersionUID = -1L; @@ -209,7 +230,7 @@ private static VncFunction createTermColsFn(final Terminal terminal) { public VncVal apply(final VncList args) { ArityExceptions.assertArity(this, args, 0); - return new VncLong(terminal.getSize().getColumns()); + return new VncLong(terminal == null ? 0 : terminal.getSize().getColumns()); } private static final long serialVersionUID = -1L; @@ -267,4 +288,80 @@ public VncVal apply(final VncList args) { private static final long serialVersionUID = -1L; }; } + + private static VncFunction createPromptFn(final IRepl repl) { + return + new VncFunction( + "repl/prompt", + VncFunction + .meta() + .arglists("(repl/prompt s)") + .doc( + "Sets the REPL prompt string!") + .examples( + "(repl/prompt \"venice> \")") + .seeAlso( + "repl?", "repl/handler", "repl/info") + .build() + ) { + @Override + public VncVal apply(final VncList args) { + ArityExceptions.assertArity(this, args, 1); + + final String prompt = Coerce.toVncString(args.first()).getValue(); + + if (repl != null) { + repl.setPrompt(prompt); + } + + return Constants.Nil; + } + + private static final long serialVersionUID = -1L; + }; + } + + private static VncFunction setHandlerFn(final IRepl repl) { + return + new VncFunction( + "repl/handler", + VncFunction + .meta() + .arglists("(repl/handler f)") + .doc( + "Sets the REPL command handler!") + .examples( + "(do \n" + + " (defn handle-command [cmd] \n" + + " ;; run the command 'cmd' \n" + + " (println \"Demo:\" cmd)) \n" + + " \n" + + " (repl/handler handle-command)) ") + .seeAlso( + "repl?", "repl/prompt", "repl/info") + .build() + ) { + @Override + @SuppressWarnings("unchecked") + public VncVal apply(final VncList args) { + ArityExceptions.assertArity(this, args, 1); + + final VncFunction handlerFn = Coerce.toVncFunction(args.first()); + + if (repl != null) { + final Object handler = + DynamicInvocationHandler.proxify( + new CallFrame("proxify(:" + Consumer.class.getName() +")", args.getMeta()), + Consumer.class, + VncHashMap.of(new VncString("accept"), handlerFn)); + + repl.setHandler((Consumer)handler); + } + + return Constants.Nil; + } + + private static final long serialVersionUID = -1L; + }; + } } diff --git a/src/main/resources/com/github/jlangch/venice/venice.venice b/src/main/resources/com/github/jlangch/venice/venice.venice index d211ee337..8c3fb58a2 100644 --- a/src/main/resources/com/github/jlangch/venice/venice.venice +++ b/src/main/resources/com/github/jlangch/venice/venice.venice @@ -17,6 +17,7 @@ (load-module :gradlew) (load-module :ansi) +(load-module :java) (import :java.util.function.Consumer) (import :com.github.jlangch.venice.EofException) @@ -56,7 +57,7 @@ (defonce java-11-home (str/strip-end (system-env :JAVA_11_HOME) "/")) (defonce java-home java-8-home) -(defonce sonatype-user "jlangch") +(defonce sonatype-user "xxxxxx") (defonce cmd-line-prompt (str proj-name "> ")) @@ -294,8 +295,9 @@ (fatal-error-and-exit "The JAVA home '~{java-home}' does not exist!")) -(. *REPL* :setPrompt "shell> ") -(. *REPL* :setHandler (proxify :Consumer { :accept handle-command })) +;; configure the REPL +(repl/prompt "shell> ") +(repl/handler handle-command) (display-welcome-msg) (display-status)