Can now add marks. Display is single-threaded, refresh on command.

Also implemented save and quit (including cases for Ctrl-D, `exit`, and `quit`)
This commit is contained in:
Jonathan Bernard 2013-08-08 20:09:15 -05:00
parent 769245b690
commit f78cd57ec7
2 changed files with 77 additions and 48 deletions

View File

@ -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

View File

@ -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) }
}
}