From f9d171dbd78c287220c262766637060ec57a882e Mon Sep 17 00:00:00 2001 From: Benjamin Culkin Date: Tue, 4 Jun 2024 17:10:35 -0400 Subject: Work on StreamTerminal and the example Some work on StreamTerminal and its corresponding example --- .../main/java/bjc/utils/cli/StreamTerminal.java | 171 +++++++++++++++++---- 1 file changed, 142 insertions(+), 29 deletions(-) (limited to 'base/src/main/java/bjc/utils/cli/StreamTerminal.java') diff --git a/base/src/main/java/bjc/utils/cli/StreamTerminal.java b/base/src/main/java/bjc/utils/cli/StreamTerminal.java index 185891f..607d87d 100644 --- a/base/src/main/java/bjc/utils/cli/StreamTerminal.java +++ b/base/src/main/java/bjc/utils/cli/StreamTerminal.java @@ -7,13 +7,16 @@ import java.util.*; import java.util.concurrent.*; import java.util.concurrent.locks.*; import java.util.function.Consumer; +import java.util.function.Function; import bjc.data.Either; +import bjc.utils.funcutils.StringUtils; +import bjc.utils.parserutils.TokenUtils; /** * Implementation of {@link Terminal} using {@link Reader} and {@link Writer} * - * @author bjcul + * @author Ben Culkin * */ public class StreamTerminal implements Terminal, Runnable { @@ -25,12 +28,18 @@ public class StreamTerminal implements Terminal, Runnable { private Queue pendingOutput; - private boolean running; + private boolean isRunning; + private boolean isParagraphMode; + private boolean isPromptOnContinue; - private Scanner inputScanner; + private Scanner input; private Writer output; + private Writer status; private String prefix; + private String paragraphTerminator = ""; + private String prompt = "..> "; + private Consumer mode; private long currentRequest = -1; @@ -56,8 +65,9 @@ public class StreamTerminal implements Terminal, Runnable { * written. */ public StreamTerminal(Reader input, Writer output, String prefix, Consumer mode) { - this.inputScanner = new Scanner(input); + this.input = new Scanner(input); this.output = output; + this.status = output; this.pendingRequests = new TreeSet<>(); this.pendingReplies = new ConcurrentHashMap<>(); @@ -72,24 +82,24 @@ public class StreamTerminal implements Terminal, Runnable { @Override public void run() { - running = true; + isRunning = true; try { - output.write(INFO_STARTCOMPROC.toString() + "\n"); - while (!pendingOutput.isEmpty()) - output.write(pendingOutput.remove()); + status.write(INFO_STARTCOMPROC.toString() + "\n"); + status.flush(); + writePendingOutput(); output.flush(); } catch (IOException e) { - // TODO Consider if there is some better way to handle these throw new RuntimeException(e); } - overall: while (running && inputScanner.hasNextLine()) { + StringBuilder pendingInput = new StringBuilder(); + + overall: while (isRunning && input.hasNextLine()) { try { - while (!pendingOutput.isEmpty()) - output.write(pendingOutput.remove()); + writePendingOutput(); output.flush(); - String ln = inputScanner.nextLine(); + String ln = input.nextLine(); if (prefix != null && ln.startsWith(prefix)) { ln = ln.substring(prefix.length()); String com = ""; @@ -102,6 +112,9 @@ public class StreamTerminal implements Terminal, Runnable { } comswt: switch (com) { + case "c": + handleConfigure(ln); + break; case "r": { // General command format is 'r , String subRep = ln.substring(2); @@ -116,8 +129,8 @@ public class StreamTerminal implements Terminal, Runnable { try { repNo = Long.parseLong(repStr); } catch (NumberFormatException nfex) { - output.write(ERROR_INVREPNO.toString() + "\n"); - output.flush(); + status.write(ERROR_INVREPNO.toString() + "\n"); + status.flush(); continue overall; } // Skip over the comma @@ -125,8 +138,8 @@ public class StreamTerminal implements Terminal, Runnable { } if (!pendingRequests.contains(repNo)) { - output.write(ERROR_UNKREPNO.toString() + "\n"); - output.flush(); + status.write(ERROR_UNKREPNO.toString() + "\n"); + status.flush(); continue overall; } @@ -139,35 +152,127 @@ public class StreamTerminal implements Terminal, Runnable { break comswt; } case "q": - running = false; + isRunning = false; break comswt; + case "?": + case "h": + handleHelp(ln); + break; default: - output.write(ERROR_UNRECCOM.toString() + "\n"); - output.flush(); + status.write(ERROR_UNRECCOM.toString() + "\n"); + status.flush(); } } else { - mode.accept(ln); + if (isParagraphMode) { + if (ln.equals(paragraphTerminator)) { + mode.accept(pendingInput.toString()); + pendingInput = new StringBuilder(); + + writePendingOutput(); + output.flush(); + continue; + } + + // Handle line-continuation + if (ln.endsWith("\\")) { + pendingInput.append(ln.substring(0, ln.length() - 1)); + pendingInput.append(" "); + } else { + pendingInput.append(ln); + pendingInput.append("\n"); + } + + addOutput(prompt); + } else { + mode.accept(ln); + } } - - while (!pendingOutput.isEmpty()) - output.write(pendingOutput.remove()); + + writePendingOutput(); output.flush(); } catch (IOException ioex) { throw new RuntimeException(ioex); } } - running = false; + isRunning = false; try { - while (!pendingOutput.isEmpty()) - output.write(pendingOutput.remove()); - output.write(INFO_ENDCOMPROC.toString() + "\n"); + writePendingOutput(); output.flush(); + status.write(INFO_ENDCOMPROC.toString() + "\n"); + status.flush(); } catch (IOException e) { throw new RuntimeException(e); } } + private void writePendingOutput() throws IOException { + while (!pendingOutput.isEmpty()) + output.write(pendingOutput.remove()); + } + + private void handleHelp(String ln) { + addOutput("Help not yet fully implemented"); + } + + private void handleConfigure(String ln) { + int spaceIdx = ln.indexOf(" "); + + String setting = ln.substring(0, spaceIdx); + String setArgs = ln.substring(spaceIdx).strip(); + List args = TokenUtils.processArguments(setArgs); + + switch(setting) { + case "paraTerm": + paragraphTerminator = args.get(0); + break; + case "para": + isParagraphMode = !isParagraphMode; + break; + case "prompt?": + isPromptOnContinue = !isPromptOnContinue; + break; + case "prompt": + prompt = args.get(0); + break; + default: + addOutput(ERROR_UNKCONFSET.toString() + "\n"); + } + } + + + public boolean isParagraphMode() { + return isParagraphMode; + } + + public void setParagraphMode(boolean isParagraphMode) { + this.isParagraphMode = isParagraphMode; + } + + public boolean isPromptOnContinue() { + return isPromptOnContinue; + } + + public void setPromptOnContinue(boolean isPromptOnContinue) { + this.isPromptOnContinue = isPromptOnContinue; + } + + public String getParagraphTerminator() { + return paragraphTerminator; + } + + public void setParagraphTerminator(String paragraphTerminator) { + this.paragraphTerminator = paragraphTerminator; + } + + public String getPrompt() { + return prompt; + } + + public void setPrompt(String prompt) { + this.prompt = prompt; + } + @Override public long submitRequest(String req) { long reqNo = currentRequest + 1; @@ -228,7 +333,7 @@ public class StreamTerminal implements Terminal, Runnable { Optional rep = awaitReply(id, unit, delay); return rep.isEmpty() ? Either.right(id) : Either.left(rep.get()); } - + /** * Add a string to be printed next time output is printed. * @@ -246,4 +351,12 @@ public class StreamTerminal implements Terminal, Runnable { public void setMode(Consumer mode) { this.mode = mode; } + + public Writer getStatus() { + return status; + } + + public void setStatus(Writer status) { + this.status = status; + } } \ No newline at end of file -- cgit v1.2.3