From f78cd57ec7806af425090eb5a3f8e5fd579ad0b7 Mon Sep 17 00:00:00 2001 From: Jonathan Bernard Date: Thu, 8 Aug 2013 20:09:15 -0500 Subject: [PATCH] Can now add marks. Display is single-threaded, refresh on command. Also implemented save and quit (including cases for Ctrl-D, `exit`, and `quit`) --- project.properties | 3 +- .../timestamper/cli/TimeStamperCLI.groovy | 122 +++++++++++------- 2 files changed, 77 insertions(+), 48 deletions(-) diff --git a/project.properties b/project.properties index c4f1cfe..f990fd0 100644 --- a/project.properties +++ b/project.properties @@ -1,4 +1,5 @@ +#Thu, 08 Aug 2013 19:52:35 -0500 lib.local=true name=timestamper-cli version=0.1 -build.number=0 +build.number=29 diff --git a/src/main/com/jdblabs/timestamper/cli/TimeStamperCLI.groovy b/src/main/com/jdblabs/timestamper/cli/TimeStamperCLI.groovy index fda887d..0629c1d 100644 --- a/src/main/com/jdblabs/timestamper/cli/TimeStamperCLI.groovy +++ b/src/main/com/jdblabs/timestamper/cli/TimeStamperCLI.groovy @@ -84,48 +84,95 @@ public class TimeStamperCLI { //out.println "" def currentMarker = timeline.getLastMarker(new Date()) + Reader reader = new InputStreamReader(sin) boolean running = true - def reader = new NonBlockingReader(sin) - def readerThread = new Thread(reader) - readerThread.start() + def readNotes = { + out.println(ansi().fg(YELLOW). + a("Notes (end with EOF or a blank line):").reset()) - def blockingReadLine = { - String line = null; - while (line == null && readerThread.isAlive()) { - line = reader.readLine() + String notes = "" + String line = null + line = reader.readLine() - Thread.sleep(200) } + while(line != "" && line != "EOF" && line != null) { + notes += line + EOL + line = reader.readLine() } - return line } + return notes + } String line = null - println "" - while (running && readerThread.isAlive()) { - // Refresh the display - out.print( - ansi().saveCursorPosition(). - cursorUp(1).eraseLine(Erase.ALL).fgBright(CYAN). - a(Timeline.shortFormat.format(currentMarker.timestamp) + " "). - fg(GREEN).a("(" + getDuration(currentMarker) + ") "). - fg(WHITE).a(currentMarker.mark).a(EOL).restorCursorPosition() - ) + while (running) { + + out.println formatMarker(currentMarker) + out.print(ansi().fg(YELLOW).a("> ").reset()) + out.flush(); // Handle user input - if ((line = reader.readLine()) != null) { - if (line =~ /quit|exit/) running = false } - - Thread.sleep(200); } + line = reader.readLine() + + switch (line) { + + case null: + case ~/quit|exit|\u0004/: + running = false; + break + + case ~/r|refresh|^$/: + out.print(ansi().eraseLine().cursorUp(2).eraseLine()) + break + + case ~/n|new/: + + // Read mark + out.println(ansi().fg(YELLOW).a("New timestamp:").reset()) + String mark = reader.readLine() + + // Read notes + String notes = readNotes(); + + // Create marker + currentMarker = new TimelineMarker(new Date(), mark, notes) + timeline.addMarker(currentMarker) + if (timelineProperties.persistOnUpdate) + timelineProperties.save() + break + + case ~/h|help/: + out.println(ansi().eraseLine(). + fg(RED).a("Not yet implemented.")); + break + + case ~/l|list|history/: + out.println(ansi().eraseLine(). + fg(RED).a("Not yet implemented.")); + break + + case ~/s|save/: + timelineProperties.save() + break + + default: + String notes = readNotes() + currentMarker = new TimelineMarker(new Date(), line, notes) + timeline.addMarker(currentMarker) + if (timelineProperties.persistOnUpdate) + timelineProperties.save() + break + } + } - if (readerThread.isAlive()) { - readerThread.interrupt(); - readerThread.join(500); - if (readerThread.isAlive()) readerThread.stop(); } } - protected String getDuration(TimelineMarker tm) { + protected static String formatMarker(TimelineMarker tm) { + return ansi().fgBright(CYAN). + a(Timeline.shortFormat.format(tm.timestamp) + " ").fg(GREEN). + a("(" + getDuration(tm) + ") ").fg(WHITE).a(tm.mark).toString() } + + protected static String getDuration(TimelineMarker tm) { Date currentTime = new Date() long seconds = currentTime.time - tm.timestamp.time seconds /= 1000 @@ -144,23 +191,4 @@ public class TimeStamperCLI { return sb.toString() } - class NonBlockingReader implements Runnable { - - private Reader rin - private LinkedList buffer = [] - - public void run() { - String line = null - try { - while((line = rin.readLine()) != null && - !Thread.currentThread().isInterrupted()) - storeLine(line) } - catch (InterruptedException ie) { Thread.currentThread().interrupt() } } - - public synchronized String readLine() { return buffer.poll() } - private synchronized void storeLine(String line) { buffer << line } - - public NonBlockingReader(def sin) { - this.rin = new InputStreamReader(sin) } - } }