Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Issue #3

Issue #6
Issue #7
Issue #8
Issue #9
Issue #10 - Clock in / Clock out ADDON
  • Loading branch information...
commit a0a7d0797f9a69619b0e12c0a1b69a49bcc68e01 1 parent 632f4fc
Steve Stepp authored December 29, 2011
2  c.bat
... ...
@@ -0,0 +1,2 @@
  1
+@echo off
  2
+tclsh clock.tcl %*
377  clock.tcl
... ...
@@ -0,0 +1,377 @@
  1
+# Project Creation Date: 2011-12-27                                           #
  2
+#                                                                             #
  3
+# Addon to TickleList (TCL todo.txt implementation                            #
  4
+#                                                                             #
  5
+# ----------------------------------------------------------------------------#
  6
+
  7
+# =============================================================================
  8
+# ======================== PROC LIST ==========================================
  9
+# =============================================================================
  10
+proc read_datafile {filename} {
  11
+	#
  12
+	#   Read in a data file
  13
+	#
  14
+	set file_data ""
  15
+	if {[file exists $filename]} {
  16
+		set fp [open $filename r]
  17
+		set file_data [read $fp]
  18
+		close $fp
  19
+	}
  20
+	return $file_data
  21
+}
  22
+
  23
+proc show_usage { {action "help"} {show_oneline true} {exit_after true}} {
  24
+	#
  25
+	#   Show usage and exit
  26
+	#
  27
+	
  28
+	set oneline {<<COMMAND SHORTCUT>> action [task_number]}
  29
+	if {$show_oneline} {
  30
+		puts ""
  31
+		puts "USAGE: $oneline"
  32
+		puts ""
  33
+	}
  34
+	switch -exact -- $action {
  35
+	
  36
+		cur		-
  37
+		current {
  38
+			puts {   cur}
  39
+			puts {   current}
  40
+			puts {      Displays the active clocked in task.}
  41
+		}
  42
+		
  43
+		in {
  44
+			puts {   in ITEM#}
  45
+			puts {      Appends timestamp to task as in:timestamp}
  46
+			puts {      Will clock out any other tasks that are currently clocked in}
  47
+		}
  48
+		
  49
+		help	{
  50
+			puts {   help}
  51
+			puts {      Display this help message.}
  52
+		}
  53
+
  54
+		laps	{
  55
+			puts {   laps}
  56
+			puts {      Displays report of all tasks with lap:times}
  57
+		}
  58
+		
  59
+		out {
  60
+			puts {   out}
  61
+			puts {      Clocks out all tasks that are clocked in}
  62
+			puts {      Removes in:timestamp, calculates lap:time, appends lap:time to task}
  63
+		}
  64
+		
  65
+		shorthelp {
  66
+			puts {   shorthelp}
  67
+			puts {      List the one-line usage of all built-in and add-on actions.}
  68
+		}
  69
+	}
  70
+	puts ""
  71
+	if {$exit_after} {
  72
+		exit -1;
  73
+	}
  74
+}
  75
+
  76
+proc get_arguments {argc argv} {
  77
+	#
  78
+	# Get the arguments passed in from command line & process them accordingly
  79
+	#
  80
+	global action
  81
+	global terms
  82
+
  83
+	# Read in command-line parameters
  84
+	# TODO - Add check for options before action & terms
  85
+	if {$argc < 1} {
  86
+		# Since there are no arguments passed in we just show the USAGE & exit.
  87
+		show_usage
  88
+	}
  89
+	#
  90
+	# Lets check for any dashes to see if any options were passed in
  91
+	# Set flags for any options found
  92
+	set has_options false
  93
+	#
  94
+	if {$has_options == false} {
  95
+		if {$argc >= 1} {
  96
+			set action [lindex $argv 0]
  97
+		}
  98
+		if {$argc > 1} {
  99
+			set terms ""
  100
+			for {set i 1} {$i < $argc} {incr i} {
  101
+				set terms [concat $terms " " [lindex $argv $i]]
  102
+			}
  103
+		}
  104
+	}
  105
+}
  106
+
  107
+proc append_term {data itemno term} {
  108
+	global todo_path_n_file
  109
+	set loopcount 1
  110
+	
  111
+	set fp [open $todo_path_n_file "w"]
  112
+	foreach line $data {
  113
+		if {$loopcount != $itemno} {
  114
+			if {$loopcount != 1} {
  115
+				puts $fp ""
  116
+			}
  117
+			puts -nonewline $fp $line
  118
+		} else {
  119
+			if {$loopcount != 1} {
  120
+				puts $fp ""
  121
+			}
  122
+			# Append to the end of the item
  123
+			set line [append $line $line " " $term]
  124
+			puts -nonewline $fp $line
  125
+		}
  126
+		incr loopcount
  127
+	}
  128
+	close $fp
  129
+}
  130
+
  131
+proc has_clock_in {data itemno} {
  132
+	set check ""
  133
+	set loopcount 1
  134
+	foreach line $data {
  135
+		if {$loopcount == $itemno} {
  136
+			set check $line
  137
+		}
  138
+		incr loopcount
  139
+	}
  140
+
  141
+	# Return 1 if item is clocked in, 0 if not clocked in.
  142
+	# expected format    2011-12-28T13:29:59      YYYY-MM-DDTHH:MM:SS
  143
+	return [regexp {in:(19|20)\d\d[-](0[1-9]|1[012])[-](0[1-9]|[12]\d|3[01])T(0\d|1\d|2[0-3])[:]([0-5]\d)[:]([0-5]\d)} $check match]
  144
+}
  145
+
  146
+proc get_clock_in {line} {
  147
+	# Return in:time if item has one, otherwise return empty string
  148
+	set result ""
  149
+	if {[regexp {in:(19|20)\d\d[-](0[1-9]|1[012])[-](0[1-9]|[12]\d|3[01])T(0\d|1\d|2[0-3])[:][0-5]\d[:][0-5]\d} $line match]} {
  150
+		#strip first three chars off "in:"
  151
+		set result [string range $match 3 [string length $match]]
  152
+	}
  153
+	return $result
  154
+}
  155
+
  156
+proc has_lap_time {line} {
  157
+	# Return 1 if item has a lap:time, 0 if it does not
  158
+	return [regexp {lap:(\d\d)[:][0-5]\d[:][0-5]\d} $line]
  159
+}
  160
+
  161
+proc get_lap_time {line} {
  162
+	# Return lap:time if item has one, otherwise return empty string
  163
+	set result ""
  164
+	if {[regexp {lap:(\d\d)[:][0-5]\d[:][0-5]\d} $line match]} {
  165
+		#strip first four chars off "lap:"
  166
+		set result [string range $match 4 [string length $match]]
  167
+	}
  168
+	return $result
  169
+}
  170
+
  171
+proc calc_lap_time {in out} {
  172
+	# Return lap:time based on difference between in and out
  173
+	set clockin [clock scan $in]
  174
+	set clockout [clock scan $out]
  175
+	set diff [expr {$clockout - $clockin}]
  176
+	return [seconds_to_time $diff]
  177
+}
  178
+
  179
+proc add_time {x_time y_time} {
  180
+	return [seconds_to_time [expr [time_to_seconds $x_time] + [time_to_seconds $y_time]]]
  181
+}
  182
+
  183
+proc seconds_to_time {total_seconds} {
  184
+	set result ""
  185
+	set hours [expr int($total_seconds / 60 / 60)]
  186
+	set minutes [expr int(($total_seconds - ($hours * 60 * 60)) / 60)]
  187
+	set seconds [expr int($total_seconds - ($hours * 60 *60) - ($minutes * 60))]
  188
+	set result [format "%2.2d:%2.2d:%2.2d" $hours $minutes $seconds]
  189
+}
  190
+
  191
+proc convert_to_integer {number_string} {
  192
+	set result ""
  193
+	set result [string trimleft $number_string 0]
  194
+	if {$result == ""} {
  195
+		set result 0
  196
+	}
  197
+	return $result
  198
+}
  199
+
  200
+proc time_to_seconds {x_time} {
  201
+	set result 0
  202
+	regexp {^(\d\d)[:]([0-5]\d)[:]([0-5]\d)$} $x_time match hours minutes seconds
  203
+	set result [expr [convert_to_integer $hours] * 60 * 60 + [convert_to_integer $minutes] * 60 + [convert_to_integer $seconds]]
  204
+	return $result
  205
+}
  206
+
  207
+proc replace_item {data itemno term} {
  208
+	global todo_path_n_file
  209
+	set loopcount 1
  210
+	
  211
+	set fp [open $todo_path_n_file "w"]
  212
+	foreach line $data {
  213
+		if {$loopcount != 1} {
  214
+			puts $fp ""
  215
+		}
  216
+		if {$loopcount != $itemno} {
  217
+			puts -nonewline $fp $line
  218
+		} else {
  219
+			# This is the line to replace
  220
+			set line [join [lrange $term 0 [llength $term]] " "]
  221
+			puts -nonewline $fp $line
  222
+		}
  223
+		incr loopcount
  224
+	}
  225
+	close $fp
  226
+}
  227
+
  228
+proc get_bare_task {line} {
  229
+	set result $line
  230
+	set clock_in [get_clock_in $line]
  231
+	set lap_time [get_lap_time $line]
  232
+	regsub -all -- "in:$clock_in" $result "" result		;# strip out any clockins
  233
+	regsub -all -- "lap:$lap_time" $result "" result	;# strip out any laptimes
  234
+	return $result
  235
+}
  236
+
  237
+proc process_clock_outs {} {
  238
+	# RECURSIVE FUNCTION
  239
+	# If a task is found that has a clockin, then update file removing that clockin, and call process_clock_outs again
  240
+	# If no task is found with a clockin, then just continue without doing anything.
  241
+	#
  242
+	# Since its recursive, we need to open and read in the file each time the proc is run.
  243
+
  244
+	global todo_path_n_file
  245
+	set file_data [read_datafile $todo_path_n_file]
  246
+	set data [split $file_data "\n"]
  247
+
  248
+	set loopcount 1
  249
+	set found 0
  250
+	
  251
+	foreach line $data {
  252
+		
  253
+		# make sure item has clock in
  254
+		if {[has_clock_in $data $loopcount]} {
  255
+		
  256
+			incr found
  257
+			
  258
+			# get the clock in timestamp
  259
+			set in_time [get_clock_in $line]
  260
+
  261
+			# determine the clock out timestamp
  262
+			set sys_time [clock seconds]
  263
+			set out_time [clock format $sys_time -format %Y-%m-%dT%H:%M:%S] 
  264
+			
  265
+			# calculate the difference between out and in
  266
+			# convert difference to time
  267
+			set diff_time [calc_lap_time $in_time $out_time]
  268
+			
  269
+			# if has lap time already add difference to lap time
  270
+			if {[has_lap_time $line]} {
  271
+				set lap_time [add_time [get_lap_time $line] $diff_time]
  272
+			} else {
  273
+				set lap_time $diff_time
  274
+			}
  275
+			
  276
+			# trim lap time out of task
  277
+			set new_task [get_bare_task $line]
  278
+			
  279
+			# concat new lap time to task
  280
+			set new_task [append $new_task $new_task " lap:" $lap_time]
  281
+			
  282
+			# replace task
  283
+			replace_item $data $loopcount $new_task
  284
+		}
  285
+		incr loopcount
  286
+	}
  287
+	
  288
+	if {$found > 0} {
  289
+		process_clock_outs
  290
+	}
  291
+}
  292
+
  293
+# =============================================================================
  294
+# ======================== MAIN LOOP ==========================================
  295
+# =============================================================================
  296
+global todo_path_n_file
  297
+global action
  298
+global terms
  299
+
  300
+set action ""
  301
+set terms ""
  302
+
  303
+# ---------- TCL INTERPRETER -----------|
  304
+set tcl_interpreter "tclsh"			; # |
  305
+# --------------------------------------|
  306
+
  307
+get_arguments $argc $argv
  308
+
  309
+# Determine path and filename
  310
+set fn todo.txt ;# TODO - Allow for diff filename from command line argument
  311
+set dir [file dirname [info script]]
  312
+set todo_path_n_file [file join $dir $fn]
  313
+
  314
+# Get the data from the file
  315
+set file_data [read_datafile $todo_path_n_file]
  316
+
  317
+#  Process data file
  318
+set data [split $file_data "\n"]
  319
+
  320
+switch -exact -- $action {
  321
+
  322
+	cur		-
  323
+	current	{
  324
+		# Displays the active clocked in task.
  325
+		puts [eval exec [auto_execok $tcl_interpreter] tl.tcl ls in:]
  326
+	}
  327
+	
  328
+	in {
  329
+		# Appends timestamp to task as in:timestamp
  330
+		# Will clock out any other tasks that are currently clocked in
  331
+		if {![has_clock_in $data [lindex $terms 0]]} {
  332
+			set sys_time [clock seconds]
  333
+			set in_time [clock format $sys_time -format %Y-%m-%dT%H:%M:%S] 
  334
+			append_term $data [lindex $terms 0] "in:$in_time"
  335
+		}
  336
+	}
  337
+	
  338
+	help	{
  339
+		show_usage "cur" true false
  340
+		show_usage "in" false false
  341
+		show_usage "help" false false
  342
+		show_usage "laps" false false
  343
+		show_usage "out" false false
  344
+		show_usage "shorthelp" false true
  345
+	}
  346
+	
  347
+	laps {
  348
+		# Displays report of all tasks with lap:times
  349
+		puts [eval exec [auto_execok $tcl_interpreter] tl.tcl ls lap:]
  350
+	}
  351
+	
  352
+	out	{
  353
+		# Clocks out all tasks that are clocked in
  354
+		# Removes in:timestamp, calculates lap:time, appends lap:time to task
  355
+		# 
  356
+		process_clock_outs
  357
+	}
  358
+	
  359
+	shorthelp {
  360
+		#   shorthelp
  361
+		#
  362
+		#      List the one-line usage of all built-in and add-on actions.
  363
+		
  364
+		set oneline {<<COMMAND SHORTCUT>> action [task_number]}
  365
+		puts ""
  366
+		puts "USAGE: $oneline"
  367
+		puts ""
  368
+		puts {   Actions:}
  369
+		puts {     cur|current}
  370
+		puts {     in ITEM#}
  371
+		puts {     help}
  372
+		puts {     laps}
  373
+		puts {     out}
  374
+		puts {     shorthelp}
  375
+		puts ""
  376
+	}
  377
+}
53  tl.tcl
@@ -37,10 +37,12 @@ proc read_datafile {filename} {
37 37
 	#
38 38
 	#   Read in a data file
39 39
 	#
40  
-	
41  
-	set fp [open $filename r]
42  
-	set file_data [read $fp]
43  
-	close $fp
  40
+	set file_data ""
  41
+	if {[file exists $filename]} {
  42
+		set fp [open $filename r]
  43
+		set file_data [read $fp]
  44
+		close $fp
  45
+	}
44 46
 	return $file_data
45 47
 }
46 48
 
@@ -711,26 +713,25 @@ proc archive_items {data} {
711 713
 	set fp_todo [open $todo_path_n_file "w"]
712 714
 	if {[file exists $done_path_n_file] == 1} {
713 715
 		set fp_done [open $done_path_n_file "a"]
714  
-		puts $fp_done ""
715 716
 	} else {
716 717
 		set fp_done [open $done_path_n_file "w"]
717 718
 	}
718 719
 	
719 720
 	foreach line $data {
720  
-		if {[is_complete $line] == 1} {
721  
-			# write to done
722  
-			if {$count_done_items != 0} {
  721
+		if {![string equal [string trim $line] ""]} {
  722
+			if {[is_complete $line] == 1} {
  723
+				# write to done
723 724
 				puts $fp_done ""
  725
+				puts -nonewline $fp_done $line
  726
+				incr count_done_items
  727
+			} else {
  728
+				# write to todo
  729
+				if {$count_todo_items > 0} {
  730
+					puts $fp_todo ""
  731
+				}
  732
+				puts -nonewline $fp_todo $line
  733
+				incr count_todo_items
724 734
 			}
725  
-			puts -nonewline $fp_done $line
726  
-			incr count_done_items
727  
-		} else {
728  
-			# write to todo
729  
-			if {$count_todo_items > 0} {
730  
-				puts $fp_todo ""
731  
-			}
732  
-			puts -nonewline $fp_todo $line
733  
-			incr count_todo_items
734 735
 		}
735 736
 	}
736 737
 	close $fp_todo
@@ -1025,6 +1026,20 @@ proc update_report {} {
1025 1026
 	
1026 1027
 	puts $fp_report "------------------------------------------------------------------------------"
1027 1028
 	puts $fp_report "$report_date  TODO:$todo_count DONE:$done_count TOTAL:$total_count"
  1029
+	
  1030
+	close $fp_todo
  1031
+	close $fp_done
  1032
+	close $fp_report
  1033
+}
  1034
+
  1035
+proc strip_double_quotes {str_source} {
  1036
+	set result $str_source
  1037
+	set stripped ""
  1038
+	regexp {^["](.*)["]$} $str_source match stripped
  1039
+	if {![string equal [string trim $stripped] ""]} {
  1040
+		set result $stripped
  1041
+	}
  1042
+	return $result
1028 1043
 }
1029 1044
 
1030 1045
 # =============================================================================
@@ -1055,7 +1070,7 @@ if {$debug == 1} {
1055 1070
 
1056 1071
 # Determine path and filename
1057 1072
 set fn todo.txt ;# TODO - Allow for diff filename from command line argument
1058  
-set dir [file dirname [info script]]
  1073
+set dir [file dirname [file normalize [info script]]]
1059 1074
 set todo_path_n_file [file join $dir $fn]
1060 1075
 set done_path_n_file [file join $dir "done.txt"]
1061 1076
 set rept_path_n_file [file join $dir "report.txt"]
@@ -1092,6 +1107,7 @@ switch -exact -- $action {
1092 1107
 		set out_file "todo.txt"
1093 1108
 		add_to $out_file $terms
1094 1109
 		gets stdin second_line
  1110
+		set second_line [strip_double_quotes $second_line]
1095 1111
 		add_to $out_file $second_line
1096 1112
 	}
1097 1113
 	
@@ -1305,6 +1321,7 @@ switch -exact -- $action {
1305 1321
 		
1306 1322
 		set list_data $data
1307 1323
 		set list_data [filter_list $list_data "+"]
  1324
+		set list_data [filter_list $list_data $terms]
1308 1325
 		show_result $list_data
1309 1326
 		show_footer $shown_counter $total_counter $todo_path_n_file
1310 1327
 	}

0 notes on commit a0a7d07

Please sign in to comment.
Something went wrong with that request. Please try again.