timeless 0.5.1 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.org +202 -0
- data/elisp/forms.el +2 -0
- data/lib/timeless/cli/command_semantics.rb +17 -27
- data/lib/timeless/cli/command_syntax.rb +36 -0
- data/lib/timeless/storage.rb +57 -42
- data/lib/timeless/version.rb +1 -1
- metadata +3 -3
- data/README.md +0 -152
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f271794edee45ff107dcd0d7858e9fb01c4f670e8b98b76e2c70de39d3353498
|
4
|
+
data.tar.gz: 9e80d347a218de303b7697265e07410d1a460b4262c928fe48bfe711a83002fe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c7d5c0d76111c83e186b38f6be6ccb1d4170ccd27e427f775fa81ce3bcfd69173228b8fe47adea40e926c37f61cb3d1b6c75e808c6926eeb801d9119ce3a5400
|
7
|
+
data.tar.gz: 95b7c4020f915c4807b71c5d3afa05da17e1c1da18bd9b161bfc346a554e935e006d6305b326743d57363ce1a7bb75172a4e24330d913147514e4f73a4cbdf54
|
data/README.org
ADDED
@@ -0,0 +1,202 @@
|
|
1
|
+
#+TITLE: Timeless README
|
2
|
+
#+AUTHOR: Adolfo Villafiorita
|
3
|
+
#+STARTUP: showall
|
4
|
+
|
5
|
+
Timeless is a simple command line time tracker which supports
|
6
|
+
stopwatches, pomodoro timers, and key-value pair in notes.
|
7
|
+
|
8
|
+
Some non nominal conditions are also handled (e.g., starting a clock
|
9
|
+
twice, trying to stop when no clock was started).
|
10
|
+
|
11
|
+
* Installation
|
12
|
+
:PROPERTIES:
|
13
|
+
:CUSTOM_ID: installation
|
14
|
+
:END:
|
15
|
+
|
16
|
+
Install the gem:
|
17
|
+
|
18
|
+
#+BEGIN_EXAMPLE
|
19
|
+
$ gem install timeless
|
20
|
+
#+END_EXAMPLE
|
21
|
+
|
22
|
+
* Usage
|
23
|
+
:PROPERTIES:
|
24
|
+
:CUSTOM_ID: usage
|
25
|
+
:END:
|
26
|
+
|
27
|
+
Run a pomodoro timer:
|
28
|
+
|
29
|
+
#+BEGIN_EXAMPLE
|
30
|
+
timeless pom p:project meeting with c:john
|
31
|
+
timeless pom --duration 60 p:prj2
|
32
|
+
timeless pom --long # default to 50 minutes
|
33
|
+
#+END_EXAMPLE
|
34
|
+
|
35
|
+
Start clocking using a stopwatch:
|
36
|
+
|
37
|
+
#+BEGIN_EXAMPLE
|
38
|
+
timeless start requirements doc
|
39
|
+
timeless start --at 'thirty minutes ago' fixing bug 182 for c:tim
|
40
|
+
timeless start --force --at 'five minutes ago' requirements document for p:prj1
|
41
|
+
#+END_EXAMPLE
|
42
|
+
|
43
|
+
Stop clocking:
|
44
|
+
|
45
|
+
#+BEGIN_EXAMPLE
|
46
|
+
timeless stop
|
47
|
+
timeless stop forgot notes on start
|
48
|
+
timeless stop --last # reuse the notes of previous entry
|
49
|
+
timeless stop --at 'five minutes ago'
|
50
|
+
timeless stop --start '1 hour ago' --at 'now' clocked a full entry
|
51
|
+
#+END_EXAMPLE
|
52
|
+
|
53
|
+
Enter a full entry:
|
54
|
+
|
55
|
+
#+BEGIN_EXAMPLE
|
56
|
+
timeless clock activity on p:project # from end of last entry to now
|
57
|
+
timeless clock --start 'three hours ago' --stop 'five minutes ago'
|
58
|
+
#+END_EXAMPLE
|
59
|
+
|
60
|
+
What was i doing?
|
61
|
+
|
62
|
+
#+BEGIN_EXAMPLE
|
63
|
+
timeless current # print current entry
|
64
|
+
timeless forget # forget pending clock
|
65
|
+
#+END_EXAMPLE
|
66
|
+
|
67
|
+
What did I do?
|
68
|
+
|
69
|
+
#+BEGIN_EXAMPLE
|
70
|
+
timeless last # print last entry
|
71
|
+
#+END_EXAMPLE
|
72
|
+
|
73
|
+
Reporting and exporting
|
74
|
+
|
75
|
+
#+BEGIN_EXAMPLE
|
76
|
+
timeless statement
|
77
|
+
timeless balance --from yesterday --filter p:project
|
78
|
+
timeless export
|
79
|
+
#+END_EXAMPLE
|
80
|
+
|
81
|
+
Notice that even though =timeless= uses CSV as its native format, the
|
82
|
+
export command generates a CSV file which is more easily parsed by a
|
83
|
+
spreadsheet application such as LibreOffice.
|
84
|
+
|
85
|
+
If you do not want to type =timeless= every time, you can invoke a
|
86
|
+
console:
|
87
|
+
|
88
|
+
#+BEGIN_EXAMPLE
|
89
|
+
timeless console
|
90
|
+
timeless:000> start
|
91
|
+
timeless:001> stop
|
92
|
+
timeless:002>
|
93
|
+
#+END_EXAMPLE
|
94
|
+
|
95
|
+
More information with:
|
96
|
+
|
97
|
+
#+BEGIN_EXAMPLE
|
98
|
+
timeless help # get list of available commands
|
99
|
+
timeless help command # help about command
|
100
|
+
timeless man # output this README file
|
101
|
+
#+END_EXAMPLE
|
102
|
+
|
103
|
+
* Key-Value pairs
|
104
|
+
:PROPERTIES:
|
105
|
+
:CUSTOM_ID: key-value-pairs
|
106
|
+
:END:
|
107
|
+
|
108
|
+
Timeless has some basic support for key-pair values in the notes
|
109
|
+
field.
|
110
|
+
|
111
|
+
A key-pair value is entered as:
|
112
|
+
|
113
|
+
#+BEGIN_EXAMPLE
|
114
|
+
key:value
|
115
|
+
#+END_EXAMPLE
|
116
|
+
|
117
|
+
where =key= is any string starting with a letter and containing letters,
|
118
|
+
numbers, and underscores; and =value= is *anything but a space*.
|
119
|
+
|
120
|
+
For instance a note field could look like:
|
121
|
+
|
122
|
+
#+BEGIN_EXAMPLE
|
123
|
+
working for c:john_smith on a:writing_documentation
|
124
|
+
#+END_EXAMPLE
|
125
|
+
|
126
|
+
Key value pairs can be used to assign a special meaning to some
|
127
|
+
strings and improve filtering and exporting.
|
128
|
+
|
129
|
+
Three special keys are =p= for projects, =c= for clients, and =a= for
|
130
|
+
activity. These keys get dedicated columns in the csv file when using
|
131
|
+
the =export= command.
|
132
|
+
|
133
|
+
* If something goes wrong
|
134
|
+
:PROPERTIES:
|
135
|
+
:CUSTOM_ID: if-something-goes-wrong
|
136
|
+
:END:
|
137
|
+
|
138
|
+
Timeless writes entries on =~/.timeless.csv=, storing the following
|
139
|
+
information:
|
140
|
+
|
141
|
+
1. start date and time
|
142
|
+
2. end date and time
|
143
|
+
3. notes
|
144
|
+
|
145
|
+
You can edit the file to manually fix entries if you make some
|
146
|
+
mistake.
|
147
|
+
|
148
|
+
The =~/timeless.csv= file should contain only correct entries, that
|
149
|
+
is, entries with start, stop, and (possibly empty) notes.
|
150
|
+
|
151
|
+
When using a stopwatch, a temporary file =~/.timeless-tmp.csv= is used
|
152
|
+
to store the timestamp of the start command.
|
153
|
+
|
154
|
+
* Version History
|
155
|
+
:PROPERTIES:
|
156
|
+
:CUSTOM_ID: version-history
|
157
|
+
:END:
|
158
|
+
|
159
|
+
*** 0.6.0
|
160
|
+
|
161
|
+
- support for generic keys in notes. Possibility of specifying the same
|
162
|
+
key multiple times in a single note field
|
163
|
+
- balance now produces distinct reports for each key (on top of the three
|
164
|
+
already generated for projects, activities, and clients)
|
165
|
+
- management of empty lines in ~/timeless.csv
|
166
|
+
|
167
|
+
*** 0.5.0
|
168
|
+
|
169
|
+
- updated origin in Gem specification
|
170
|
+
|
171
|
+
*** 0.4.0
|
172
|
+
|
173
|
+
- second public release
|
174
|
+
- new =balance= command
|
175
|
+
- the =report= command has been renamed =statement=
|
176
|
+
- interactive =console=
|
177
|
+
- more detailed help for commands
|
178
|
+
- fixed a bug in the last command: now it returns the last activity in
|
179
|
+
chronological order (rather than the last activity which has been
|
180
|
+
clocked)
|
181
|
+
|
182
|
+
*** 0.2.0
|
183
|
+
|
184
|
+
- initial public release
|
185
|
+
|
186
|
+
** License
|
187
|
+
:PROPERTIES:
|
188
|
+
:CUSTOM_ID: license
|
189
|
+
:END:
|
190
|
+
|
191
|
+
Licensed under the terms of the MIT License.
|
192
|
+
|
193
|
+
** Contributing
|
194
|
+
:PROPERTIES:
|
195
|
+
:CUSTOM_ID: contributing
|
196
|
+
:END:
|
197
|
+
|
198
|
+
1. Fork it ( https://github.com/[my-github-username]/timeless/fork )
|
199
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
200
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
201
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
202
|
+
5. Create a new Pull Request
|
data/elisp/forms.el
CHANGED
@@ -17,7 +17,7 @@ module Timeless
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def self.man opts = nil, argv = []
|
20
|
-
path = File.join(File.dirname(__FILE__), "/../../../README.
|
20
|
+
path = File.join(File.dirname(__FILE__), "/../../../README.org")
|
21
21
|
file = File.open(path, "r")
|
22
22
|
contents = file.read
|
23
23
|
puts contents
|
@@ -215,6 +215,7 @@ module Timeless
|
|
215
215
|
to = opts.to_hash[:to] ? Chronic.parse(opts.to_hash[:to]) : nil
|
216
216
|
|
217
217
|
entries = Timeless::Storage.get(from, to, opts.to_hash[:filter])
|
218
|
+
|
218
219
|
# it could become a function of a reporting module
|
219
220
|
printf "%-18s %-5s - %-5s %-8s %-s\n", "Day", "Start", "End", "Duration", "Notes"
|
220
221
|
total = 0
|
@@ -248,42 +249,31 @@ module Timeless
|
|
248
249
|
# {key1 => {value1 => total .. } , ... }
|
249
250
|
hash = Timeless::Storage::balance from, to, opts.to_hash[:filter]
|
250
251
|
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
hash["p"].each do |key, value|
|
255
|
-
printf "%-20s%5s\n", key, in_hours(value)
|
256
|
-
total += value
|
257
|
-
end
|
258
|
-
puts "-------------------------"
|
259
|
-
printf "%-20s%5s\n", "Total", in_hours(total)
|
252
|
+
report "Projects", "p", hash
|
253
|
+
report "Clients", "c", hash
|
254
|
+
report "Activities", "a", hash
|
260
255
|
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
puts "======="
|
265
|
-
hash["c"].each do |key, value|
|
266
|
-
printf "%-20s%5s\n", key, in_hours(value)
|
267
|
-
total += value
|
256
|
+
remaining_tags = hash.reject! { |k| ["p", "c", "a"].include? k }
|
257
|
+
remaining_tags.keys.each do |k|
|
258
|
+
report k, k, remaining_tags
|
268
259
|
end
|
269
|
-
|
270
|
-
|
260
|
+
end
|
261
|
+
|
262
|
+
private
|
271
263
|
|
264
|
+
def self.report title, key, hash
|
272
265
|
total = 0
|
273
266
|
puts ""
|
274
|
-
puts
|
275
|
-
puts "
|
276
|
-
hash[
|
277
|
-
printf "%-20s%5s\n",
|
278
|
-
total +=
|
267
|
+
puts title
|
268
|
+
puts "=" * title.size
|
269
|
+
(hash[key] || []).each do |k, v|
|
270
|
+
printf "%-20s%5s\n", k, in_hours(v)
|
271
|
+
total += v
|
279
272
|
end
|
280
273
|
puts "-------------------------"
|
281
274
|
printf "%-20s%5s\n", "Total", in_hours(total)
|
282
275
|
end
|
283
276
|
|
284
|
-
|
285
|
-
private
|
286
|
-
|
287
277
|
def self.in_hours value
|
288
278
|
sprintf "%02i:%02i", value / 60, value % 60
|
289
279
|
end
|
@@ -372,7 +372,12 @@ DESCRIPTION
|
|
372
372
|
a project "project_1", using "p:project_1"
|
373
373
|
|
374
374
|
EXAMPLES
|
375
|
+
# extract all entries which have the string p:project_1 in the notes field
|
376
|
+
# (that is, all entries related to project_1)
|
375
377
|
timeless statement --filter p:project_1
|
378
|
+
|
379
|
+
# extract all entries which have the word documentation in the notes field
|
380
|
+
timeless statement --filter documentation
|
376
381
|
EOS
|
377
382
|
return { statement: [opts, :statement, help] }
|
378
383
|
end
|
@@ -407,5 +412,36 @@ EXAMPLES
|
|
407
412
|
EOS
|
408
413
|
return { balance: [opts, :balance, help] }
|
409
414
|
end
|
415
|
+
|
416
|
+
def self.export_opts
|
417
|
+
opts = Slop::Options.new
|
418
|
+
opts.banner = "export -- export timeless.csv to CSV"
|
419
|
+
help = <<EOS
|
420
|
+
NAME
|
421
|
+
#{opts.banner}
|
422
|
+
|
423
|
+
SYNOPSYS
|
424
|
+
#{opts.to_s}
|
425
|
+
|
426
|
+
DESCRIPTION
|
427
|
+
Print data to CSV, with the following columns:
|
428
|
+
|
429
|
+
- Start Date
|
430
|
+
- Start Time
|
431
|
+
- End Date
|
432
|
+
- End Time
|
433
|
+
- Duration in seconds
|
434
|
+
- First project found in notes
|
435
|
+
- First activity found in notes
|
436
|
+
- First client found in notes
|
437
|
+
- Notes attached to entry
|
438
|
+
|
439
|
+
EXAMPLES
|
440
|
+
timeless export
|
441
|
+
timeless export > data.csv
|
442
|
+
EOS
|
443
|
+
return { export: [opts, :export, help] }
|
444
|
+
end
|
445
|
+
|
410
446
|
end
|
411
447
|
end
|
data/lib/timeless/storage.rb
CHANGED
@@ -11,11 +11,11 @@ module Timeless
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def self.last
|
14
|
-
|
14
|
+
my_read(TIMELESS_FILE).sort { |x, y| x[1] <=> y[1] }.last
|
15
15
|
end
|
16
16
|
|
17
17
|
def self.get from_date=nil, to_date=nil, filter=nil
|
18
|
-
entries =
|
18
|
+
entries = my_read(TIMELESS_FILE)
|
19
19
|
entries.select do |x|
|
20
20
|
(from_date ? Time.parse(x[0]) >= from_date : true) and
|
21
21
|
(to_date ? Time.parse(x[1]) <= to_date : true) and
|
@@ -23,70 +23,85 @@ module Timeless
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
-
# get all unique
|
27
|
-
def self.
|
28
|
-
|
29
|
-
|
26
|
+
# get all unique tags in file
|
27
|
+
def self.get_tags
|
28
|
+
tags_regexp = /([a-zA-Z][0-9a-zA-Z_]*):([^ ]+)/
|
29
|
+
|
30
|
+
entries = my_read(TIMELESS_FILE)
|
31
|
+
entries.map { |x|
|
32
|
+
# match returns only the first match, while scan does it for the string
|
33
|
+
# scan returns an array of array ("a:b c:d".scan(tags_regexp) => [["a", "b"], ["c", "d"]]
|
34
|
+
(x[2] || "").scan(tags_regexp).map { |x| x[0] }
|
35
|
+
}.flatten.uniq
|
36
|
+
end
|
37
|
+
|
38
|
+
# get all unique keys of a given tag in file
|
39
|
+
def self.get_key tag
|
40
|
+
entries = my_read(TIMELESS_FILE)
|
41
|
+
entries.map { |x| extract_kpv tag, x[2] }.flatten.uniq.sort
|
30
42
|
end
|
31
43
|
|
32
44
|
def self.balance from, to, filter
|
33
|
-
|
34
|
-
|
35
|
-
hash = {
|
45
|
+
# hash of all keys defined in file
|
46
|
+
array = get_tags
|
47
|
+
hash = Hash[array.collect { |item| [item, {}] } ]
|
36
48
|
|
49
|
+
entries = Timeless::Storage.get(from, to, filter)
|
37
50
|
entries.each do |entry|
|
38
51
|
start = Time.parse(entry[0])
|
39
52
|
stop = Time.parse(entry[1])
|
40
53
|
duration = (stop - start) / 60
|
41
54
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
hash["a"][activity] = (hash["a"][activity] || 0) + duration if activity != ""
|
49
|
-
|
55
|
+
hash.keys.each do |key|
|
56
|
+
values = extract_kpv key, entry[2]
|
57
|
+
values.each do |value|
|
58
|
+
hash[key][value] = (hash[key][value] || 0) + duration
|
59
|
+
end
|
60
|
+
end
|
50
61
|
end
|
51
62
|
hash
|
52
63
|
end
|
53
|
-
|
54
|
-
|
55
64
|
def self.export
|
56
|
-
entries =
|
65
|
+
entries = my_read(TIMELESS_FILE)
|
57
66
|
|
58
67
|
CSV { |csvout| csvout << ["Start Date", "Start Time", "End Date", "End Time", "Duration (s)", "Project", "Client", "Activity", "Notes"] }
|
59
68
|
CSV do |csvout|
|
60
69
|
entries.each do |entry|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
70
|
+
if entry[0] and entry[1]
|
71
|
+
start = Time.parse(entry[0])
|
72
|
+
stop = Time.parse(entry[1])
|
73
|
+
|
74
|
+
start_date = start.strftime("%Y-%m-%d")
|
75
|
+
start_time = start.strftime("%H:%M:%S")
|
76
|
+
|
77
|
+
stop_date = stop.strftime("%Y-%m-%d")
|
78
|
+
stop_time = stop.strftime("%H:%M:%S")
|
79
|
+
|
80
|
+
duration = stop - start
|
81
|
+
|
82
|
+
# extract first project, first client, and first activity, if present
|
83
|
+
project = extract_kpv("p", entry[2]).first
|
84
|
+
client = extract_kpv("c", entry[2]).first
|
85
|
+
activity = extract_kpv("a", entry[2]).first
|
86
|
+
|
87
|
+
notes = entry[2]
|
88
|
+
|
89
|
+
csvout << [start_date, start_time, stop_date, stop_time, duration, project, client, activity, notes]
|
90
|
+
end
|
80
91
|
end
|
81
92
|
end
|
82
93
|
end
|
83
94
|
|
84
95
|
private
|
85
96
|
|
86
|
-
#
|
97
|
+
# read the timeless file into a CSV skipping lines with empty start end stop time
|
98
|
+
def self.my_read timeless_file
|
99
|
+
CSV.read(timeless_file).select { |x| x[0] != nil and x[1] != nil }
|
100
|
+
end
|
101
|
+
|
102
|
+
# return all the values of a given key in string
|
87
103
|
def self.extract_kpv key, string
|
88
|
-
|
89
|
-
match ? match[1] : ""
|
104
|
+
(string || "").scan(/(#{key}):([^ ]+)/).map { |x| x[1] }
|
90
105
|
end
|
91
106
|
end
|
92
107
|
end
|
data/lib/timeless/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: timeless
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Adolfo Villafiorita
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-01-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -107,7 +107,7 @@ files:
|
|
107
107
|
- ".gitignore"
|
108
108
|
- Gemfile
|
109
109
|
- LICENSE.txt
|
110
|
-
- README.
|
110
|
+
- README.org
|
111
111
|
- Rakefile
|
112
112
|
- bin/console
|
113
113
|
- bin/setup
|
data/README.md
DELETED
@@ -1,152 +0,0 @@
|
|
1
|
-
Timeless
|
2
|
-
========
|
3
|
-
|
4
|
-
Timeless is a simple command line time tracker.
|
5
|
-
|
6
|
-
Installation
|
7
|
-
------------
|
8
|
-
|
9
|
-
Add this line to your application's Gemfile:
|
10
|
-
|
11
|
-
ruby
|
12
|
-
gem 'timeless'
|
13
|
-
|
14
|
-
And then execute:
|
15
|
-
|
16
|
-
$ bundle
|
17
|
-
|
18
|
-
Or install it yourself as:
|
19
|
-
|
20
|
-
$ gem install timeless
|
21
|
-
|
22
|
-
Usage
|
23
|
-
-----
|
24
|
-
|
25
|
-
timeless is a simple command line time tracker. Entries store the
|
26
|
-
following information:
|
27
|
-
|
28
|
-
1. start time
|
29
|
-
2. end time
|
30
|
-
3. notes
|
31
|
-
|
32
|
-
timeless allows one to
|
33
|
-
|
34
|
-
- run a pomodoro timer
|
35
|
-
- clock time using a "stopwatch" (with start and stop commands)
|
36
|
-
- manually entering data
|
37
|
-
- print a text report, possibly filtered by date ranges of notes'
|
38
|
-
content
|
39
|
-
- export to csv
|
40
|
-
|
41
|
-
Timeless has also some basic support for key-pair values in the notes
|
42
|
-
form. They can be used to assign a special meaning to some strings and
|
43
|
-
improve filtering and exporting. Two special keys are `p` for projects
|
44
|
-
and `c` for clients. These two keys are exported in dedicated columns
|
45
|
-
when exporting data to csv.
|
46
|
-
|
47
|
-
Some non nominal conditions are also handled (e.g., starting a clock
|
48
|
-
twice, trying to stop when no clock was started).
|
49
|
-
|
50
|
-
If you do not want to type `timeless` every time, you can invoke a console:
|
51
|
-
|
52
|
-
timeless console
|
53
|
-
timeless:000> start
|
54
|
-
timeless:001> stop
|
55
|
-
timeless:002>
|
56
|
-
|
57
|
-
More information with:
|
58
|
-
|
59
|
-
timeless help # get list of available commands
|
60
|
-
timeless help command # help about command
|
61
|
-
timeless man # output this README file
|
62
|
-
|
63
|
-
|
64
|
-
Examples
|
65
|
-
--------
|
66
|
-
|
67
|
-
Get information about command syntax:
|
68
|
-
|
69
|
-
timeless -h
|
70
|
-
|
71
|
-
Run a pomodoro timer:
|
72
|
-
|
73
|
-
timeless pom p:project meeting with c:john
|
74
|
-
timeless pom --duration 60 p:prj2
|
75
|
-
timeless pom --long # default to 50 minutes
|
76
|
-
|
77
|
-
Start clocking using a stopwatch:
|
78
|
-
|
79
|
-
timeless start requirements doc
|
80
|
-
timeless start --at 'thirty minutes ago' fixing bug 182 for c:tim
|
81
|
-
timeless start --force --at 'five minutes ago' requirements document for p:prj1
|
82
|
-
|
83
|
-
Stop clocking:
|
84
|
-
|
85
|
-
timeless stop
|
86
|
-
timeless stop forgot notes on start
|
87
|
-
timeless stop --last # reuse the notes of last entry
|
88
|
-
timeless stop --at 'five minutes ago'
|
89
|
-
timeless stop --start '1 hour ago' --at 'now' clocked a full entry
|
90
|
-
|
91
|
-
Enter a full entry:
|
92
|
-
|
93
|
-
timeless clock activity on p:project # from end of last entry to now
|
94
|
-
timeless clock --start 'three hours ago' --stop 'five minutes ago'
|
95
|
-
|
96
|
-
What was i doing?
|
97
|
-
|
98
|
-
timeless current # print current entry
|
99
|
-
timeless forget # forget pending clock
|
100
|
-
|
101
|
-
What did I do?
|
102
|
-
|
103
|
-
timeless last # print last entry
|
104
|
-
|
105
|
-
Reporting and exporting
|
106
|
-
|
107
|
-
timeless statement
|
108
|
-
timeless balance --from yesterday --filter p:project
|
109
|
-
timeless export
|
110
|
-
|
111
|
-
Notice that even though `timeless` uses CSV as its native format, the
|
112
|
-
export command exports to a CSV file which is more easily parsed by a
|
113
|
-
Spreadsheet such as LibreOffice.
|
114
|
-
|
115
|
-
If something goes wrong
|
116
|
-
-----------------------
|
117
|
-
|
118
|
-
Data is stored in the CSV file `~/.timeless.csv`. You can edit the file
|
119
|
-
to manually fix entries if you make some mistake.
|
120
|
-
|
121
|
-
Version History
|
122
|
-
---------------
|
123
|
-
|
124
|
-
**0.4.0**
|
125
|
-
|
126
|
-
- second public release
|
127
|
-
- new `balance` command
|
128
|
-
- the `report` command has been renamed `statement`
|
129
|
-
- interactive `console`
|
130
|
-
- more detailed help for commands
|
131
|
-
- fixed a bug in the last command: now it returns the last activity in
|
132
|
-
chronological order (rather than the last activity which has been clocked)
|
133
|
-
|
134
|
-
**0.2.0**
|
135
|
-
- initial public release
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
License
|
140
|
-
-------
|
141
|
-
|
142
|
-
Licensed under the terms of the MIT License.
|
143
|
-
|
144
|
-
Contributing
|
145
|
-
------------
|
146
|
-
|
147
|
-
1. Fork it ( https://github.com/\[my-github-username\]/timeless/fork )
|
148
|
-
2. Create your feature branch (\`git checkout -b my-new-feature\`)
|
149
|
-
3. Commit your changes (\`git commit -am 'Add some feature'\`)
|
150
|
-
4. Push to the branch (\`git push origin my-new-feature\`)
|
151
|
-
5. Create a new Pull Request
|
152
|
-
|