All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jio.console.Console Maven / Gradle / Ivy

There is a newer version: 3.0.0-RC2
Show newest version
package jio.console;


import fun.tuple.Pair;
import jio.IO;
import jio.time.Clock;
import jsonvalues.JsObj;

import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

/**
 * Creates a REPL (read eval print loop) program from a list of user commands. It's executed with the method
 * {@link #eval(JsObj)}. The commands returned by the method {@link #getPredefinedCommands()} are always loaded to the
 * console.
 *
 * 

Predefined Commands:

*
    *
  • {@link ListCommand}: Lists available commands.
  • *
  • {@link ReadVarCommand}: Reads a variable value.
  • *
  • {@link SetVarCommand}: Sets a variable value.
  • *
  • {@link LastCommand}: Executes the last command.
  • *
  • {@link HistoryCommand}: Shows the command history.
  • *
  • {@link HelpCommand}: Displays help for available commands.
  • *
  • {@link DumpCommand}: Dumps the current state.
  • *
  • {@link Base64EncodeCommand}: Encodes a string to Base64.
  • *
  • {@link Base64DecodeCommand}: Decodes a Base64 string.
  • *
  • {@link AddToListCommand}: Adds a value into a list variable.
  • *
  • {@link ClearVarCommand}: Removes a variable from the state.
  • *
  • {@link EncodeURLCommand}: Encodes a URL.
  • *
  • {@link ExitCommand}: Exits the console program.
  • *
  • {@link JsPairsCommand}: Lists key-value pairs of a JSON object.
  • *
  • {@link JsPrettyCommand}: Pretty-prints a JSON object.
  • *
  • {@link JsGetValueCommand}: Gets a value from a JSON object.
  • *
  • {@link ClearCommand}: Clears the console screen.
  • *
  • {@link EchoCommand}: Displays a message.
  • *
  • {@link ScriptCommand}: Executes a script.
  • *
  • {@link ReadFileCommand}: Reads a file.
  • *
* *

To add new commands, create classes that implement the {@link Command} interface * or extend existing command classes. Then, add these command instances to the list * of user commands passed to the constructor.

*/ public final class Console { final State state; final List commands; /** * Constructor to create a Console from a list of user commands. * * @param userCommands the list of commands */ public Console(List userCommands) { Objects.requireNonNull(userCommands); this.state = new State(); this.commands = getPredefinedCommands(); this.commands.addAll(userCommands); } private List getPredefinedCommands() { List commands = new ArrayList<>(); commands.add(new ListCommand(commands).setSaveOutput(false)); commands.add(new ReadVarCommand().setSaveOutput(false)); commands.add(new SetVarCommand().setSaveOutput(false)); commands.add(new LastCommand()); commands.add(new HistoryCommand().setSaveOutput(false)); commands.add(new HelpCommand(commands).setSaveOutput(false)); commands.add(new DumpCommand().setSaveOutput(false)); commands.add(new Base64EncodeCommand()); commands.add(new AddToListCommand()); commands.add(new ClearVarCommand()); commands.add(new Base64DecodeCommand()); commands.add(new EncodeURLCommand()); commands.add(new ExitCommand()); commands.add(new JsPairsCommand().setSaveOutput(false)); commands.add(new JsPrettyCommand()); commands.add(new JsGetValueCommand()); commands.add(new ClearCommand().setSaveOutput(false)); commands.add(new EchoCommand()); commands.add(new ScriptCommand(this)); commands.add(new ReadFileCommand()); return commands; } /** * Executes the console program and the REP (read, eval, print) loop starts executing. A JSON can be specified, and it * will be passed into every command in case some configuration is needed. * * @param conf the configuration JSON */ public void eval(JsObj conf) { System.out.println(""" ___ ___ _______ _______ _______ __ _ _______ _______ ___ _______\s | | | | | | | | | | | | | | | | | | _ |____| | _ | |_| | _____| _ | | | ___| | | | | | |____| | | | | | |_____| | | | | | |___\s ___| | | |_| | | _| |_| | _ |_____ | |_| | |___| ___| | | | | | |_| | | | |_____| | | | |___\s |_______|___|_______| |_______|_______|_| |__|_______|_______|_______|_______|"""); for (; ; ) { Programs.READ_LINE .then(line -> { if (line.isBlank()) { return IO.NULL(); } String trimmedLine = line.trim(); Optional>> opt = parse(conf, trimmedLine); if (opt.isPresent()) { IO command = opt.get() .second() .peekSuccess(output -> { if (output != null && opt.get() .first().isSaveOutput) { state.variables.put("output", output ); } } ); state.historyCommands.add(command); return IO.lazy(Clock.realTime) .then(tic -> command.map(result -> Pair.of(tic, result))) .peek(pair -> state.historyResults .add(String.format("%s, OK, %s ms, %s ", trimmedLine, Duration.ofMillis(System.currentTimeMillis() - pair.first()) .toMillis(), Instant.ofEpochMilli(pair.first()) ) ), error -> state.historyResults.add(String.format("%s, KO, %s", trimmedLine, Instant.now() ) ) ) .map(Pair::second); } return IO.fail(new CommandNotFoundException(line)); }) .then(it -> it != null ? Programs.PRINT_NEW_LINE(it + "\n") : IO.NULL(), e -> Programs.PRINT_NEW_LINE(e.getMessage() + "\n") ) .join(); } } private String[] replaceVars(final State state, final String[] tokens ) { for (int i = 1; i < tokens.length; i++) { var token = tokens[i]; if (token.startsWith("$")) { String varName = token.substring(1); if (!varName.isEmpty()) { tokens[i] = state.variables.get(varName); } } } return tokens; } Optional>> parse(JsObj conf, String line ) { for (Command command : commands) { try { Optional> opt = command.executeIfMatch(conf, state) .apply(replaceVars(state, line.split(" "))); if (opt.isPresent()) { return Optional.of(Pair.of(command, opt.get())); } } catch (Exception e) { return Optional.of(Pair.of(command, IO.fail(e))); } } return Optional.empty(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy