org.aya.cli.repl.ReplCommands Maven / Gradle / Ivy
The newest version!
// Copyright (c) 2020-2024 Tesla (Yinsen) Zhang.
// Use of this source code is governed by the MIT license that can be found in the LICENSE.md file.
package org.aya.cli.repl;
import kala.collection.immutable.ImmutableSeq;
import kala.collection.mutable.MutableList;
import kala.control.Either;
import org.aya.cli.render.RenderOptions;
import org.aya.prettier.AyaPrettierOptions;
import org.aya.prettier.BasePrettier;
import org.aya.pretty.doc.Doc;
import org.aya.producer.AyaParserImpl;
import org.aya.repl.Command;
import org.aya.repl.CommandArg;
import org.aya.repl.ReplUtil;
import org.aya.syntax.core.def.AnyDef;
import org.aya.syntax.core.def.ConDefLike;
import org.aya.syntax.core.def.MemberDefLike;
import org.aya.syntax.core.def.TyckAnyDef;
import org.aya.syntax.literate.CodeOptions;
import org.aya.syntax.ref.AnyDefVar;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
public interface ReplCommands {
record Code(@NotNull String code) { }
record Prompt(@NotNull String prompt) { }
record ColorParam(@NotNull Either value)
implements CommandArg.ArgEither { }
record StyleParam(@NotNull Either value)
implements CommandArg.ArgEither { }
@NotNull Command CHANGE_PROMPT = new Command(ImmutableSeq.of("prompt"), "Change the REPL prompt text") {
@Entry public @NotNull Command.Result execute(@NotNull AyaRepl repl, @NotNull Prompt argument) {
var prompt = argument.prompt;
if (prompt.startsWith("\"") && prompt.endsWith("\"")) prompt = prompt.substring(1, prompt.length() - 1);
repl.config.prompt = prompt;
return Result.ok("Changed prompt to `" + prompt + "`", true);
}
};
@NotNull Command SHOW_TYPE = new Command(ImmutableSeq.of("type"), "Show the type of the given expression") {
@Entry public @NotNull Command.Result execute(@NotNull AyaRepl repl, @NotNull Code code) {
var type = repl.replCompiler.computeType(code.code(), repl.config.normalizeMode);
return type != null ? new Result(Output.stdout(repl.render(type)), true)
: Result.err("Failed to get expression type", true);
}
};
@NotNull Command SHOW_INFO = new Command(ImmutableSeq.of("info"), "Show the information of the given definition") {
@Entry public @NotNull Command.Result execute(@NotNull AyaRepl repl, @NotNull Code code) {
var resolved = repl.replCompiler.parseToAnyVar(code.code);
if (!(resolved instanceof AnyDefVar defVar)) return Result.err("Not a valid reference", true);
var def = AnyDef.fromVar(defVar);
AnyDef topLevel = def;
switch (def) {
case ConDefLike conDefLike -> topLevel = conDefLike.dataRef();
case MemberDefLike memberDefLike -> topLevel = memberDefLike.classRef();
default -> {
}
}
if (topLevel instanceof TyckAnyDef> tyckDef) {
return new Command.Result(Output.stdout(repl.render(tyckDef.core())), true);
}
return Command.Result.ok(topLevel.name(), true); // TODO: pretty print
}
};
@NotNull Command SHOW_PARSE_TREE = new Command(ImmutableSeq.of("parse-tree"), "Show the parse tree of the given expression") {
@Entry public @NotNull Command.Result execute(@NotNull AyaRepl repl, @NotNull Code code) {
var parseTree = new AyaParserImpl(repl.replCompiler.reporter).parseNode(code.code());
return Result.ok(parseTree.toDebugString(), true);
}
};
@NotNull Command SHOW_SHAPES = new Command(ImmutableSeq.of("debug-show-shapes"), "Show recognized shapes") {
@Entry public @NotNull Command.Result execute(@NotNull AyaRepl repl) {
var discovered = repl.replCompiler.getShapeFactory().discovered;
return Result.ok(repl.renderDoc(Doc.vcat(discovered.mapTo(MutableList.create(),
(def, recog) ->
Doc.sep(BasePrettier.refVar(def),
Doc.symbol("=>"),
Doc.plain(recog.shape().name()))))), true);
}
};
@NotNull Command LOAD = new Command(ImmutableSeq.of("load"), "Load a file or library into REPL") {
@Entry public @NotNull Command.Result execute(@NotNull AyaRepl repl, @NotNull Path path) {
try {
repl.replCompiler.loadToContext(path);
} catch (IOException e) {
return Result.err("Unable to load file or library: " + e.getLocalizedMessage(), true);
}
// SingleFileCompiler would print result to REPL.
return new Result(Output.empty(), true);
}
};
@NotNull Command UNIMPORT = new Command(ImmutableSeq.of("unimport"), "Remove an imported module from the context") {
@Entry public @NotNull Command.Result execute(@NotNull AyaRepl repl, @NotNull Code code) {
var index = repl.replCompiler.imports.indexWhere(ii ->
ii.modulePath().toString().equals(code.code));
if (index < 0) return Result.err("Cannot find module after name `" + code.code + "`", true);
repl.replCompiler.imports.removeAt(index);
return Result.ok("Removed module `" + code.code + "`", true);
}
};
@NotNull Command CHANGE_CWD = new Command(ImmutableSeq.of("cd"), "Change current working directory") {
@Entry public @NotNull Command.Result execute(@NotNull AyaRepl repl, @NotNull Path path) {
if (!Files.isDirectory(path)) return Result.err("cd: no such file or directory: " + path, true);
repl.cwd = path;
// for jline completer to work properly, but it does not have any effect actually
System.setProperty("user.dir", path.toAbsolutePath().toString());
return new Result(Output.empty(), true);
}
};
@NotNull Command SHOW_CWD = new Command(ImmutableSeq.of("pwd"), "Show current working directory") {
@Entry public @NotNull Command.Result execute(@NotNull AyaRepl repl) {
return new Result(Output.stdout(repl.cwd.toAbsolutePath().toString()), true);
}
};
@NotNull Command SHOW_PROPERTY = new Command(ImmutableSeq.of("system-property"), "Show a system property") {
@Entry public @NotNull Command.Result execute(@NotNull AyaRepl repl, @NotNull String key) {
var property = key.isBlank() ? null : System.getProperty(key);
var stdout = property != null ? Output.stdout(property) : Output.stderr("No such property");
return new Result(stdout, true);
}
};
@NotNull Command SHOW_MODULE_PATHS = new Command(ImmutableSeq.of("module-path"), "Show module path(s)") {
@Entry public @NotNull Command.Result execute(@NotNull AyaRepl repl) {
return new Result(Output.stdout(repl.replCompiler.modulePaths.joinToString()), true);
}
};
@NotNull Command CHANGE_PP_WIDTH = new Command(ImmutableSeq.of("print-width"), "Set printed output width") {
@Entry public @NotNull Command.Result execute(@NotNull AyaRepl repl, @Nullable Integer width) {
if (width == null) return Result.err("print-width: invalid width", true);
repl.prettyPrintWidth = width;
return Result.ok("Printed output width set to " + width, true);
}
};
@NotNull Command QUIT = new Command(ImmutableSeq.of("quit", "exit"), "Quit the REPL") {
@Entry public @NotNull Command.Result execute(@NotNull AyaRepl repl) {
return Result.ok(repl.config.quiet ? "" :
"See you space cow woof woof :3", false);
}
};
@NotNull Command CHANGE_NORM_MODE = new Command(ImmutableSeq.of("normalize"), "Set or display the normalization mode") {
@Entry
public @NotNull Command.Result execute(@NotNull AyaRepl repl, @Nullable CodeOptions.NormalizeMode normalizeMode) {
if (normalizeMode == null) return Result.ok("Normalization mode: " + repl.config.normalizeMode, true);
else {
repl.config.normalizeMode = normalizeMode;
return Result.ok("Normalization mode set to " + normalizeMode, true);
}
}
};
@NotNull Command TOGGLE_PRETTY = new Command(ImmutableSeq.of("print-toggle"), "Toggle a pretty printing option") {
@Entry public @NotNull Command.Result execute(@NotNull AyaRepl repl, @Nullable AyaPrettierOptions.Key key) {
var builder = new StringBuilder();
var map = repl.prettierOptions().map;
if (key == null) {
builder.append("Current pretty printing options:");
for (var k : AyaPrettierOptions.Key.values())
builder
.append("\n").append(k.name()).append(": ")
.append(map.get(k));
} else {
var newValue = !map.get(key);
map.put(key, newValue);
builder.append(key.name()).append(" changed to ").append(newValue);
}
return Result.ok(builder.toString(), true);
}
};
@NotNull Command TOGGLE_UNICODE = new Command(ImmutableSeq.of("unicode"), "Enable or disable unicode in REPL output") {
@Entry public @NotNull Command.Result execute(@NotNull AyaRepl repl, @Nullable Boolean enable) {
var enableUnicode = enable != null ? enable : !repl.config.enableUnicode;
repl.config.enableUnicode = enableUnicode;
return Result.ok("Toggled Unicode to be " + (enableUnicode ? "enabled" : "disabled"), true);
}
};
@NotNull Command HELP = new Command(ImmutableSeq.of("?", "help"), "Describe a selected command or show all commands") {
@Entry public @NotNull Command.Result execute(@NotNull AyaRepl repl, @Nullable ReplUtil.HelpItem argument) {
return ReplUtil.invokeHelp(repl.commandManager, argument);
}
};
@NotNull Command COLOR = new Command(ImmutableSeq.of("color"), "Display the current color scheme or switch to another") {
@Entry public @NotNull Command.Result execute(@NotNull AyaRepl repl, @Nullable ColorParam colorParam) {
var options = repl.config.literatePrettier.renderOptions;
if (colorParam == null)
return Result.ok(options.prettyColorScheme(), true);
var fallback = options.colorScheme;
var fallbackPath = options.path;
try {
options.updateColorScheme(colorParam.value);
options.stylist(RenderOptions.OutputTarget.Unix); // if there's error, report now.
return Result.ok(options.prettyColorScheme(), true);
} catch (IllegalArgumentException | IOException e) {
options.colorScheme = fallback;
options.path = fallbackPath;
return Result.err((e instanceof IOException ? "Problem reading file: " : "") + e.getMessage(), true);
}
}
};
@NotNull Command STYLE = new Command(ImmutableSeq.of("style"), "Display the current style/Switch to another style") {
@Entry public @NotNull Command.Result execute(@NotNull AyaRepl repl, @Nullable StyleParam styleParam) {
var options = repl.config.literatePrettier.renderOptions;
if (styleParam == null) return Result.ok(options.prettyStyleFamily(), true);
var fallback = options.styleFamily;
try {
options.updateStyleFamily(styleParam.value);
options.stylist(RenderOptions.OutputTarget.Unix); // if there's error, report now.
return Result.ok(options.prettyStyleFamily(), true);
} catch (IllegalArgumentException | IOException e) {
options.styleFamily = fallback;
return Result.err((e instanceof IOException ? "Problem reading file: " : "") + e.getMessage(), true);
}
}
};
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy