timetrap 1.5.3 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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