timetrap 1.5.3 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,2 +1,3 @@
1
1
  tags
2
2
  pkg
3
+ *.swp
data/README.md CHANGED
@@ -4,18 +4,8 @@ Timetrap
4
4
  Timetrap is a simple command line time tracker written in ruby. It provides an
5
5
  easy to use command line interface for tracking what you spend your time on.
6
6
 
7
- It began as a ruby port of Trevor Caira's Timebook, a small python utility. It
8
- contains several enhancement over Timebook, notably the ability to parse
9
- natural language times (e.g. "30 minutes ago"), additional commands such as
10
- `archive` and `configure`, and support for rounding.
11
-
12
- Timetrap is also able to export entries to several formats (e.g. ical, csv) and
13
- is designed to be easily extended to support additional export formats, by
14
- creating a new formatter class (in ruby.)
15
-
16
- Timetrap maintains its state in a sqlite3 database.
17
-
18
- Timetrap is available as a gem on gemcutter (http://gemcutter.org/gems/timetrap)
7
+ Getting Started
8
+ ---------------
19
9
 
20
10
  To install:
21
11
 
@@ -23,67 +13,88 @@ To install:
23
13
 
24
14
  This will place a ``t`` executable in your path.
25
15
 
26
- Original Timebook available at:
27
- http://bitbucket.org/trevor/timebook/src/
16
+ ### Basic Usage
28
17
 
18
+ $ # get help
19
+ $ t --help
29
20
 
30
- Concepts
31
- --------
21
+ Timetrap maintains a list of *timesheets*.
32
22
 
33
- Timetrap maintains a list of *timesheets* -- distinct lists of timed *periods*.
34
- Each period has a start and end time, with the exception of the most recent
35
- period, which may have no end time set. This indicates that this period is
36
- still running. Timesheets containing such periods are considered *active*. It
37
- is possible to have multiple timesheets active simultaneously, though a single
38
- time sheet may only have one period running at once.
39
-
40
- Interactions with timetrap are performed through the ``t`` command on the
41
- command line. ``t`` is followed by one of timetrap's subcommands. Often used
42
- subcommands include ``in``, ``out``, ``switch``, ``now``, ``list`` and
43
- ``display``. *Commands may be abbreviated as long as they are unambiguous.* thus
44
- ``t switch foo`` and ``t s foo`` are identical. With the default command set,
45
- no two commands share the first same letter, thus it is only necessary to type
46
- the first letter of a command. Likewise, commands which display timesheets
47
- accept abbreviated timesheet names. ``t display f`` is thus equivalent to ``t
48
- display foo`` if ``foo`` is the only timesheet which begins with "f". Note that
49
- this does not apply to ``t switch``, since this command also creates
50
- timesheets. (Using the earlier example, if ``t switch f`` is entered, it would
51
- thus be ambiguous whether a new timesheet ``f`` or switching to the existing
52
- timesheet ``foo`` was desired).
53
-
54
- Usage
55
- -----
56
-
57
- The basic usage is as follows:
58
-
59
- $ # create the "writing" timesheet
60
- $ t switch writing
61
-
62
- $ # check in 5 minutes ago
63
- $ t in document timetrap --at "10 minutes ago"
64
-
65
- $ # check out
66
- $ t out
23
+ $ # create the "coding" timesheet
24
+ $ t sheet coding
25
+ Switching to sheet coding
26
+
27
+ All commands can be abbreviated.
28
+
29
+ $ # same as "t sheet coding"
30
+ $ t s coding
31
+ Switching to sheet coding
32
+
33
+ Each timesheet contains *entries*. Each entry has a start and end time, and a
34
+ note associated with it. An entry without an end time set is considered to be
35
+ *running*.
36
+
37
+ You check in to the current sheet with the `in` command.
38
+
39
+ $ # check in with "document timetrap" note
40
+ $ t in document timetrap
41
+ Checked into sheet "coding".
42
+
43
+ Commands like `display` and `now` will show you the running entry.
67
44
 
68
- $ # view current timesheet
69
45
  $ t display
46
+ Timesheet: coding
47
+ Day Start End Duration Notes
48
+ Sun Nov 28, 2010 12:26:10 - 0:00:03 document timetrap
49
+ 0:00:03
50
+ ---------------------------------------------------------
51
+ Total 0:00:03
52
+
53
+ $ t now
54
+ *coding: 0:01:02 (document timetrap)
55
+
56
+ If you make a mistake use the `edit` command.
57
+
58
+ $ # edit the running entry's note
59
+ $ t edit writing readme
60
+ editing entry #42
61
+
62
+ You check out with the `out` command.
63
+
64
+ $ t out
65
+ Checked out of sheet "coding"
66
+
67
+ ### Natural Language Times
68
+
69
+ Commands such as `in`, `out`, `edit`, and `display` have flags that accept
70
+ times as arguments. Any time you pass Timetrap a time it will try to parse it
71
+ as a natural language time.
72
+
73
+ This is very handy if you start working and forget to start Timetrap. You can
74
+ check in 5 minutes ago using `in`'s `--at` flag.
75
+
76
+ $ t in --at "5 minutes ago"
70
77
 
71
- The first command, ``t switch writing``, switches to the timesheet "writing"
72
- (or creates it if it does not exist). ``t in document timetrap --at "10 minutes
73
- ago"`` creates a new period in the current timesheet, and annotates it with the
74
- description "document timetrap". The optional ``--at`` flag can be passed to start
75
- the entry at a time other than the present. The ``--at`` flag is able to parse
76
- natural language times (via Chronic: http://chronic.rubyforge.org/) and will
77
- understand 'friday 13:00', 'mon 2:35', '4pm', etc. (also true of the ``edit``
78
- command's ``--start`` and ``--end`` flags.) Note that this command would be in
79
- error if the ``writing`` timesheet was already active. Finally, ``t out``
80
- records the current time as the end time for the most recent period in the
81
- ``writing`` timesheet.
78
+ Command line flags also have short versions.
82
79
 
83
- To display the current timesheet, invoke the ``t display`` command::
80
+ $ # equivilent to the command above
81
+ $ t i -a "5 minutes ago"
82
+
83
+ You can consult the Chronic gem (http://chronic.rubyforge.org/) for a full
84
+ list of parsable time formats, but all of these should work.
85
+
86
+ $ t out --at "in 30 minutes"
87
+ $ t edit --start "last monday at 10:30am"
88
+ $ t edit --end "tomorrow at noon"
89
+ $ t display --start "10am" --end "2pm"
90
+ $ t i -a "2010-11-29 12:30:00"
91
+
92
+ ### Output Formats
93
+
94
+ Timetrap supports several output formats. The default is a plain text format.
84
95
 
85
96
  $ t display
86
- Timesheet: timetrap
97
+ Timesheet: coding
87
98
  Day Start End Duration Notes
88
99
  Mon Apr 13, 2009 15:46:51 - 17:03:50 1:16:59 improved display functionality
89
100
  17:25:59 - 17:26:02 0:00:03
@@ -91,20 +102,31 @@ To display the current timesheet, invoke the ``t display`` command::
91
102
  22:37:38 - 23:38:43 1:01:05 work on kill
92
103
  2:18:52
93
104
  Tue Apr 14, 2009 00:41:16 - 01:40:19 0:59:03 gem packaging
94
- 10:20:00 - 10:48:10 0:28:10 enhance edit
105
+ 10:20:00 - 10:48:10 0:28:10 working on readme
95
106
  1:27:13
96
107
  ---------------------------------------------------------
97
108
  Total 3:46:05
98
109
 
99
- Each period in the timesheet is listed on a row. If the timesheet is active,
100
- the final period in the timesheet will have no end time. After each day, the
101
- total time tracked in the timesheet for that day is listed. Note that this is
102
- computed by summing the durations of the periods beginning in the day. In the
103
- last row, the total time tracked in the timesheet is shown.
110
+ You can also output csv for easy import into a spreadsheet.
111
+
112
+ $ t display --format csv
113
+ start,end,note,sheet
114
+ "2010-08-21 11:19:05","2010-08-21 12:12:04","migrated site","coding"
115
+ "2010-08-21 12:44:09","2010-08-21 12:48:46","DNS emails and install email packages","coding"
116
+ "2010-08-21 12:49:57","2010-08-21 13:10:12","A records","coding"
117
+ "2010-08-21 15:09:37","2010-08-21 16:32:26","setup for wiki","coding"
118
+ "2010-08-25 20:42:55","2010-08-25 21:41:49","rewrote index","coding"
119
+ "2010-08-29 15:44:39","2010-08-29 16:21:53","recaptcha","coding"
120
+ "2010-08-29 21:15:58","2010-08-29 21:30:31","backups","coding"
121
+ "2010-08-29 21:40:56","2010-08-29 22:32:26","backups","coding"
122
+
123
+ Or to ical format for import into a calendar program (remember commands can be abbreviated).
124
+
125
+ $ t d -f ical > MyTimeSheet.ics
104
126
 
105
127
  Commands
106
128
  --------
107
- **archives**
129
+ **archive**
108
130
  Archives the selected entries (by moving them to a sheet called ``_[SHEET]``)
109
131
  These entries can be seen by running ``t display _[SHEET]``.
110
132
  usage: ``t archive [--start DATE] [--end DATE] [SHEET]``
@@ -145,10 +167,6 @@ Commands
145
167
 
146
168
  usage: ``t edit [--id ID] [--start TIME] [--end TIME] [--append] [NOTES]``
147
169
 
148
- **format**
149
- Deprecated
150
- Alias for display
151
-
152
170
  **in**
153
171
  Start the timer for the current timesheet. Must be called before out. Notes
154
172
  may be specified for this period. This is exactly equivalent to
@@ -168,32 +186,27 @@ Commands
168
186
  usage: ``t list``
169
187
 
170
188
  **now**
171
- Print the current sheet, whether it's active, and if so, how long it has been
172
- active and what notes are associated with the current period.
189
+ Print a description of all running entries.
173
190
 
174
191
  usage: ``t now``
175
192
 
176
193
  **out**
177
194
  Stop the timer for the current timesheet. Must be called after in. Accepts an
178
- optional --at flag.
179
-
180
- usage: ``t out [--at TIME]``
181
-
182
- **running**
183
- Print all active sheets and any messages associated with them.
195
+ optional --at flag. Accepts an optional TIMESHEET name to check out of a
196
+ running, non-current sheet.
184
197
 
185
- usage: ``t running``
198
+ usage: ``t out [--at TIME] [TIMESHEET]``
186
199
 
187
- **switch**
188
- Switch to a new timesheet. this causes all future operation (except switch)
189
- to operate on that timesheet. The default timesheet is called "default".
200
+ **sheet**
201
+ Switch to a timesheet creating it if necessary. The default timesheet is
202
+ called "default".
190
203
 
191
- usage: ``t switch TIMESHEET``
204
+ usage: ``t sheet TIMESHEET``
192
205
 
193
206
  **week**
194
207
  Shortcut for display with start date set to monday of this week
195
208
 
196
- usage: ``t week [--ids] [--end DATE] [--format FMT] [SHEET | all]``
209
+ usage: ``t week [--ids] [--end DATE] [--format FMT] [TIMESHEET | all]``
197
210
 
198
211
  Global Options
199
212
  --------
@@ -217,11 +230,20 @@ Configuration
217
230
  Configuration of TimeTrap's behavior can be done through a YAML config file.
218
231
  See ``t configure`` for details. Currently supported options are:
219
232
 
220
- round_in_seconds: The duration of time to use for rounding with the -r flag
233
+ ``round_in_seconds``: The duration of time to use for rounding with the -r flag
221
234
 
222
- database_file: The file path of the sqlite database
235
+ ``database_file``: The file path of the sqlite database
223
236
 
224
- append_notes_delimiter: delimiter used when appending notes via ``t edit --append``
237
+ ``append_notes_delimiter``: delimiter used when appending notes via ``t edit --append``
238
+
239
+ Special Thanks
240
+ --------------
241
+
242
+ The initial version of Timetrap was heavily inspired by Trevor Caira's
243
+ Timebook, a small python utility.
244
+
245
+ Original Timebook available at:
246
+ http://bitbucket.org/trevor/timebook/src/
225
247
 
226
248
  Bugs and Feature Requests
227
249
  --------
data/VERSION.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  ---
2
2
  :major: 1
3
- :minor: 5
4
- :patch: 3
3
+ :minor: 6
4
+ :patch: 0
data/lib/timetrap.rb CHANGED
@@ -7,6 +7,7 @@ require 'Getopt/Declare'
7
7
  require File.join(File.dirname(__FILE__), 'timetrap', 'config')
8
8
  require File.join(File.dirname(__FILE__), 'timetrap', 'helpers')
9
9
  require File.join(File.dirname(__FILE__), 'timetrap', 'cli')
10
+ require File.join(File.dirname(__FILE__), 'timetrap', 'timer')
10
11
  DB_NAME = defined?(TEST_MODE) ? nil : Timetrap::Config['database_file']
11
12
  # connect to database. This will create one if it doesn't exist
12
13
  DB = Sequel.sqlite DB_NAME
@@ -16,67 +17,6 @@ Dir["#{File.dirname(__FILE__)}/timetrap/formatters/*.rb"].each do |path|
16
17
  end
17
18
 
18
19
  module Timetrap
19
- extend self
20
-
21
- def current_sheet= sheet
22
- m = Meta.find_or_create(:key => 'current_sheet')
23
- m.value = sheet
24
- m.save
25
- end
26
-
27
- def current_sheet
28
- unless Meta.find(:key => 'current_sheet')
29
- Meta.create(:key => 'current_sheet', :value => 'default')
30
- end
31
- Meta.find(:key => 'current_sheet').value
32
- end
33
-
34
- def entries sheet = nil
35
- Entry.filter(:sheet => sheet).order_by(:start)
36
- end
37
-
38
- def running?
39
- !!active_entry
40
- end
41
-
42
- def active_entry
43
- Entry.find(:sheet => Timetrap.current_sheet, :end => nil)
44
- end
45
-
46
- def stop time = nil
47
- while a = active_entry
48
- time ||= Time.now
49
- a.end = time
50
- a.save
51
- end
52
- end
53
-
54
- def start note, time = nil
55
- raise AlreadyRunning if running?
56
- time ||= Time.now
57
- Entry.create(:sheet => Timetrap.current_sheet, :note => note, :start => time).save
58
- rescue => e
59
- CLI.say e.message
60
- end
61
-
62
- def switch sheet
63
- self.current_sheet = sheet
64
- end
65
-
66
- def kill_sheet sheet
67
- Entry.filter(:sheet => sheet).destroy
68
- end
69
-
70
- def format format_klass, entries
71
- format_klass.new(entries).output
72
- end
73
-
74
- class AlreadyRunning < StandardError
75
- def message
76
- "Timetrap is already running"
77
- end
78
- end
79
-
80
20
  CLI.args = Getopt::Declare.new(<<-EOF)
81
21
  #{CLI::USAGE}
82
22
  EOF
data/lib/timetrap/cli.rb CHANGED
@@ -64,18 +64,19 @@ COMMAND is one of:
64
64
  * list - Show the available timesheets.
65
65
  usage: t list
66
66
 
67
- * now - Show the status of the current timesheet.
67
+ * now - Show all running entries.
68
68
  usage: t now
69
69
 
70
- * out - Stop the timer for the current timesheet.
71
- usage: t out [--at TIME]
70
+ * out - Stop the timer for the a timesheet.
71
+ usage: t out [--at TIME] [TIMESHEET]
72
72
  -a, --at <time:qs> Use this time instead of now
73
73
 
74
- * running - Show all running timesheets.
75
- usage: t running
74
+ * running - Deprecated: alias for now.
76
75
 
77
- * switch - Switch to a new timesheet.
78
- usage: t switch TIMESHEET
76
+ * sheet - Switch to a timesheet creating it if necessary.
77
+ usage: t sheet TIMESHEET
78
+
79
+ * switch - Deprecated: renamed to sheet.
79
80
 
80
81
  * week - Shortcut for display with start date set to monday of this week.
81
82
  usage: t week [--ids] [--end DATE] [--format FMT] [SHEET | all]
@@ -85,11 +86,12 @@ COMMAND is one of:
85
86
  -h, --help Display this help.
86
87
  -r, --round Round output to 15 minute start and end times.
87
88
  -y, --yes Noninteractive, assume yes as answer to all prompts.
89
+ --debug Display stack traces for errors.
88
90
 
89
91
  EXAMPLES
90
92
 
91
93
  # create the "MyTimesheet" timesheet
92
- $ t switch MyTimesheet
94
+ $ t sheet MyTimesheet
93
95
 
94
96
  # check in 5 minutes ago with a note
95
97
  $ t in --at '5 minutes ago' doing some stuff
@@ -108,29 +110,28 @@ COMMAND is one of:
108
110
  end
109
111
 
110
112
  def invoke
111
- args['-h'] ? say(USAGE) : invoke_command_if_valid
113
+ args['-h'] ? puts(USAGE) : invoke_command_if_valid
112
114
  rescue => e
113
- say e.message
114
- exit 1
115
+ raise e if args['--debug']
116
+ warn e.message
117
+ exit 1 unless defined? TEST_MODE
115
118
  end
116
119
 
117
120
  def commands
118
121
  Timetrap::CLI::USAGE.scan(/\* \w+/).map{|s| s.gsub(/\* /, '')}
119
122
  end
120
123
 
121
- def say *something
122
- puts *something
123
- end
124
-
125
124
  def invoke_command_if_valid
126
125
  command = args.unused.shift
127
126
  set_global_options
128
127
  case (valid = commands.select{|name| name =~ %r|^#{command}|}).size
129
- when 0 then say "Invalid command: #{command}"
130
- when 1 then send valid[0]
128
+ when 0 then puts "Invalid command: #{command}"
131
129
  else
132
- say "Ambiguous command: #{command}" if command
133
- say(USAGE)
130
+ if command
131
+ send valid[0]
132
+ else
133
+ puts USAGE
134
+ end
134
135
  end
135
136
  end
136
137
 
@@ -147,25 +148,30 @@ COMMAND is one of:
147
148
  e.update :sheet => "_#{e.sheet}"
148
149
  end
149
150
  else
150
- say "archive aborted!"
151
+ warn "archive aborted!"
151
152
  end
152
153
  end
153
154
 
154
155
  def configure
155
156
  Config.configure!
156
- say "Config file is at #{Config::PATH.inspect}"
157
+ puts "Config file is at #{Config::PATH.inspect}"
157
158
  end
158
159
 
159
160
  def edit
160
- entry = args['-i'] ? Entry[args['-i']] : Timetrap.active_entry
161
- say "can't find entry" && return unless entry
161
+ entry = args['-i'] ? Entry[args['-i']] : Timer.active_entry
162
+ unless entry
163
+ warn "can't find entry"
164
+ return
165
+ else
166
+ warn "editing entry ##{entry.id.inspect}"
167
+ end
162
168
  entry.update :start => args['-s'] if args['-s'] =~ /.+/
163
169
  entry.update :end => args['-e'] if args['-e'] =~ /.+/
164
170
 
165
171
  # update sheet
166
172
  if args['-m'] =~ /.+/
167
- if entry == Timetrap.active_entry
168
- Timetrap.current_sheet = args['-m']
173
+ if entry == Timer.active_entry
174
+ Timer.current_sheet = args['-m']
169
175
  end
170
176
  entry.update :sheet => args['-m']
171
177
  end
@@ -185,11 +191,17 @@ COMMAND is one of:
185
191
  end
186
192
 
187
193
  def in
188
- Timetrap.start unused_args, args['-a']
194
+ Timer.start unused_args, args['-a']
195
+ warn "Checked into sheet #{Timer.current_sheet.inspect}."
189
196
  end
190
197
 
191
198
  def out
192
- Timetrap.stop args['-a']
199
+ sheet = sheet_name_from_string(unused_args)
200
+ if Timer.stop sheet, args['-a']
201
+ warn "Checked out of sheet #{sheet.inspect}."
202
+ else
203
+ warn "No running entry on sheet #{sheet.inspect}."
204
+ end
193
205
  end
194
206
 
195
207
  def kill
@@ -198,21 +210,21 @@ COMMAND is one of:
198
210
  out << "(#{e.note}) " if e.note.to_s =~ /.+/
199
211
  if ask_user out
200
212
  e.destroy
201
- say "it's dead"
213
+ warn "it's dead"
202
214
  else
203
- say "will not kill"
215
+ warn "will not kill"
204
216
  end
205
217
  elsif (sheets = Entry.map{|e| e.sheet }.uniq).include?(sheet = unused_args)
206
218
  victims = Entry.filter(:sheet => sheet).count
207
219
  if ask_user "are you sure you want to delete #{victims} entries on sheet #{sheet.inspect}? "
208
- Timetrap.kill_sheet sheet
209
- say "killed #{victims} entries"
220
+ Entry.filter(:sheet => sheet).destroy
221
+ warn "killed #{victims} entries"
210
222
  else
211
- say "will not kill"
223
+ warn "will not kill"
212
224
  end
213
225
  else
214
226
  victim = args['-i'] ? args['-i'].to_s.inspect : sheet.inspect
215
- say "can't find #{victim} to kill", 'sheets:', *sheets
227
+ warn "can't find #{victim} to kill", 'sheets:', *sheets
216
228
  end
217
229
  end
218
230
 
@@ -224,38 +236,52 @@ COMMAND is one of:
224
236
  Timetrap::Formatters::Text
225
237
  end
226
238
  rescue
227
- say "Invalid format specified `#{args['-f']}'"
239
+ warn "Invalid format #{args['-f'].inspect} specified."
228
240
  return
229
241
  end
230
- say Timetrap.format(fmt_klass, selected_entries.order(:start).all)
242
+ entries = selected_entries.order(:start).all
243
+ if entries == []
244
+ warn "No entries were selected to display."
245
+ else
246
+ puts fmt_klass.new(entries).output
247
+ end
231
248
  end
232
249
  alias_method :format, :display
233
250
 
234
-
235
- def switch
251
+ def sheet
236
252
  sheet = unused_args
237
- if not sheet =~ /.+/ then say "No sheet specified"; return end
238
- say "Switching to sheet " + Timetrap.switch(sheet)
253
+ unless sheet =~ /.+/
254
+ warn "No sheet specified"
255
+ else
256
+ Timer.current_sheet = sheet
257
+ warn "Switching to sheet #{sheet.inspect}"
258
+ end
239
259
  end
240
260
 
261
+ alias_method :switch, :sheet
262
+
241
263
  def list
242
- sheets = Entry.sheets.map do |sheet|
264
+ sheets = ([Timer.current_sheet] | Entry.sheets).map do |sheet|
243
265
  sheet_atts = {:total => 0, :running => 0, :today => 0}
244
- Timetrap::Entry.filter(:sheet => sheet).inject(sheet_atts) do |m, e|
245
- e_end = e.end_or_now
246
- m[:name] ||= sheet
247
- m[:total] += (e_end.to_i - e.start.to_i)
248
- m[:running] += (e_end.to_i - e.start.to_i) unless e.end
249
- m[:today] += (e_end.to_i - e.start.to_i) if same_day?(Time.now, e.start)
250
- m
266
+ entries = Timetrap::Entry.filter(:sheet => sheet)
267
+ if entries.empty?
268
+ sheet_atts.merge(:name => sheet)
269
+ else
270
+ entries.inject(sheet_atts) do |m, e|
271
+ e_end = e.end_or_now
272
+ m[:name] ||= sheet
273
+ m[:total] += (e_end.to_i - e.start.to_i)
274
+ m[:running] += (e_end.to_i - e.start.to_i) unless e.end
275
+ m[:today] += (e_end.to_i - e.start.to_i) if same_day?(Time.now, e.start)
276
+ m
277
+ end
251
278
  end
252
- end
253
- if sheets.empty? then say "No sheets found"; return end
279
+ end.sort_by{|sheet| sheet[:name].downcase}
254
280
  width = sheets.sort_by{|h|h[:name].length }.last[:name].length + 4
255
- say " %-#{width}s%-12s%-12s%s" % ["Timesheet", "Running", "Today", "Total Time"]
281
+ puts " %-#{width}s%-12s%-12s%s" % ["Timesheet", "Running", "Today", "Total Time"]
256
282
  sheets.each do |sheet|
257
- star = sheet[:name] == Timetrap.current_sheet ? '*' : ' '
258
- say "#{star}%-#{width}s%-12s%-12s%s" % [
283
+ star = sheet[:name] == Timer.current_sheet ? '*' : ' '
284
+ puts "#{star}%-#{width}s%-12s%-12s%s" % [
259
285
  sheet[:running],
260
286
  sheet[:today],
261
287
  sheet[:total]
@@ -264,19 +290,18 @@ COMMAND is one of:
264
290
  end
265
291
 
266
292
  def now
267
- if Timetrap.running?
268
- out = "#{Timetrap.current_sheet}: #{format_duration(Timetrap.active_entry.start, Timetrap.active_entry.end_or_now)}".gsub(/ /, ' ')
269
- out << " (#{Timetrap.active_entry.note})" if Timetrap.active_entry.note =~ /.+/
270
- say out
271
- else
272
- say "#{Timetrap.current_sheet}: not running"
293
+ if !Timer.running?
294
+ puts "*#{Timer.current_sheet}: not running"
295
+ end
296
+ Timer.running_entries.each do |entry|
297
+ current = entry[:sheet] == Timer.current_sheet
298
+ out = current ? '*' : ' '
299
+ out << "#{entry[:sheet]}: #{format_duration(entry.start, entry.end_or_now)}".gsub(/ /, ' ')
300
+ out << " (#{entry.note})" if entry.note =~ /.+/
301
+ puts out
273
302
  end
274
303
  end
275
-
276
- def running
277
- say "Running Timesheets:"
278
- say Timetrap::Entry.filter(:end => nil).map{|e| " #{e.sheet}: #{e.note}"}.uniq.sort
279
- end
304
+ alias_method :running, :display
280
305
 
281
306
  def week
282
307
  args['-s'] = Date.today.wday == 1 ? Date.today.to_s : Date.parse(Chronic.parse(%q(last monday)).to_s).to_s
@@ -291,7 +316,7 @@ COMMAND is one of:
291
316
 
292
317
  def ask_user question
293
318
  return true if args['-y']
294
- print question
319
+ $stderr.print question
295
320
  $stdin.gets =~ /\Aye?s?\Z/i
296
321
  end
297
322